<p>Joshua Colp has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/11315">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">rtp: Add support for transport-cc in receiver direction.<br><br>The transport-cc draft is a mechanism by which additional information<br>about packet reception can be provided to the sender of packets so<br>they can do sender side bandwidth estimation. This is accomplished<br>by having a transport specific sequence number and an RTCP feedback<br>message. This change implements this in the receiver direction.<br><br>For each received RTP packet where transport-cc is negotiated we store<br>the time at which the RTP packet was received and its sequence number.<br>At a 1 second interval we go through all packets in that period of time<br>and use the stored time of each in comparison to its preceding packet to<br>calculate its delta. This delta information is placed in the RTCP<br>feedback message, along with indicators for any packets which were not<br>received.<br><br>The browser then uses this information to better estimate available<br>bandwidth and adjust accordingly. This may result in it lowering the<br>available send bandwidth or adjusting how "bursty" it can be.<br><br>ASTERISK-28400<br><br>Change-Id: I654a2cff5bd5554ab94457a14f70adb71f574afc<br>---<br>M include/asterisk/rtp_engine.h<br>M main/rtp_engine.c<br>M res/res_pjsip_sdp_rtp.c<br>M res/res_rtp_asterisk.c<br>4 files changed, 448 insertions(+), 7 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/15/11315/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h</span><br><span>index 57aaefe..206ed63 100644</span><br><span>--- a/include/asterisk/rtp_engine.h</span><br><span>+++ b/include/asterisk/rtp_engine.h</span><br><span>@@ -306,6 +306,8 @@</span><br><span> #define AST_RTP_RTCP_FMT_FIR 4</span><br><span> /*! REMB Information (From draft-alvestrand-rmcat-remb-03) */</span><br><span> #define AST_RTP_RTCP_FMT_REMB 15</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Transport-wide congestion control feedback (From draft-holmer-rmcat-transport-wide-cc-extensions-01) */</span><br><span style="color: hsl(120, 100%, 40%);">+#define AST_RTP_RTCP_FMT_TRANSPORT_WIDE_CC 15</span><br><span> </span><br><span> /*!</span><br><span> * \since 12</span><br><span>@@ -541,6 +543,8 @@</span><br><span> AST_RTP_EXTENSION_UNSUPPORTED = 0,</span><br><span> /*! abs-send-time from https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03 */</span><br><span> AST_RTP_EXTENSION_ABS_SEND_TIME,</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! transport-cc from https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01 */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_RTP_EXTENSION_TRANSPORT_WIDE_CC,</span><br><span> /*! The maximum number of known RTP extensions */</span><br><span> AST_RTP_EXTENSION_MAX,</span><br><span> };</span><br><span>diff --git a/main/rtp_engine.c b/main/rtp_engine.c</span><br><span>index 90ade04..f409bc2 100644</span><br><span>--- a/main/rtp_engine.c</span><br><span>+++ b/main/rtp_engine.c</span><br><span>@@ -235,6 +235,7 @@</span><br><span> static const char * const rtp_extension_uris[AST_RTP_EXTENSION_MAX] = {</span><br><span> [AST_RTP_EXTENSION_UNSUPPORTED] = "",</span><br><span> [AST_RTP_EXTENSION_ABS_SEND_TIME] = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time",</span><br><span style="color: hsl(120, 100%, 40%);">+ [AST_RTP_EXTENSION_TRANSPORT_WIDE_CC] = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01",</span><br><span> };</span><br><span> </span><br><span> /*! List of RTP engines that are currently registered */</span><br><span>diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c</span><br><span>index cba494a..80ac253 100644</span><br><span>--- a/res/res_pjsip_sdp_rtp.c</span><br><span>+++ b/res/res_pjsip_sdp_rtp.c</span><br><span>@@ -274,6 +274,7 @@</span><br><span> ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_REMB, session->endpoint->media.webrtc);</span><br><span> if (session->endpoint->media.webrtc) {</span><br><span> enable_rtp_extension(session, session_media, AST_RTP_EXTENSION_ABS_SEND_TIME, AST_RTP_EXTENSION_DIRECTION_SENDRECV, sdp);</span><br><span style="color: hsl(120, 100%, 40%);">+ enable_rtp_extension(session, session_media, AST_RTP_EXTENSION_TRANSPORT_WIDE_CC, AST_RTP_EXTENSION_DIRECTION_SENDRECV, sdp);</span><br><span> }</span><br><span> if (session->endpoint->media.tos_video || session->endpoint->media.cos_video) {</span><br><span> ast_rtp_instance_set_qos(session_media->rtp, session->endpoint->media.tos_video,</span><br><span>@@ -1184,7 +1185,18 @@</span><br><span> pj_str_t stmp;</span><br><span> pjmedia_sdp_attr *attr;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (!session->endpoint->media.webrtc || session_media->type != AST_MEDIA_TYPE_VIDEO) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!session->endpoint->media.webrtc) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* transport-cc is supposed to be for the entire transport, and any media sources so</span><br><span style="color: hsl(120, 100%, 40%);">+ * while the header does not appear in audio streams and isn't negotiated there, we still</span><br><span style="color: hsl(120, 100%, 40%);">+ * place this attribute in as Chrome does.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ attr = pjmedia_sdp_attr_create(pool, "rtcp-fb", pj_cstr(&stmp, "* transport-cc"));</span><br><span style="color: hsl(120, 100%, 40%);">+ pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (session_media->type != AST_MEDIA_TYPE_VIDEO) {</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span>diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c</span><br><span>index 80f3d06..d802178 100644</span><br><span>--- a/res/res_rtp_asterisk.c</span><br><span>+++ b/res/res_rtp_asterisk.c</span><br><span>@@ -312,6 +312,32 @@</span><br><span> struct ast_rtp_instance *instance;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Packet statistics (used for transport-cc) */</span><br><span style="color: hsl(120, 100%, 40%);">+struct rtp_transport_wide_cc_packet_statistics {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The transport specific sequence number */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The time at which the packet was received */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timeval received;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The delta between this packet and the previous */</span><br><span style="color: hsl(120, 100%, 40%);">+ int delta;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Statistics information (used for transport-cc) */</span><br><span style="color: hsl(120, 100%, 40%);">+struct rtp_transport_wide_cc_statistics {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! A vector of packet statistics */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR(, struct rtp_transport_wide_cc_packet_statistics) packet_statistics; /*!< Packet statistics, used for transport-cc */</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The last sequence number received */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int last_seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The last extended sequence number */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int last_extended_seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! How many feedback packets have gone out */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int feedback_count;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! How many cycles have occurred for the sequence numbers */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int cycles;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Scheduler id for periodic feedback transmission */</span><br><span style="color: hsl(120, 100%, 40%);">+ int schedid;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief RTP session description */</span><br><span> struct ast_rtp {</span><br><span> int s;</span><br><span>@@ -387,6 +413,8 @@</span><br><span> struct ast_data_buffer *send_buffer; /*!< Buffer for storing sent packets for retransmission */</span><br><span> struct ast_data_buffer *recv_buffer; /*!< Buffer for storing received packets for retransmission */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ struct rtp_transport_wide_cc_statistics transport_wide_cc; /*!< Transport-cc statistics information */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef HAVE_PJPROJECT</span><br><span> ast_cond_t cond; /*!< ICE/TURN condition for signaling */</span><br><span> </span><br><span>@@ -3676,6 +3704,11 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_INIT(&rtp->transport_wide_cc.packet_statistics, 0)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp->transport_wide_cc.schedid = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> rtp->f.subclass.format = ao2_bump(ast_format_none);</span><br><span> rtp->lastrxformat = ao2_bump(ast_format_none);</span><br><span> rtp->lasttxformat = ao2_bump(ast_format_none);</span><br><span>@@ -3752,6 +3785,8 @@</span><br><span> ast_data_buffer_free(rtp->recv_buffer);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_FREE(&rtp->transport_wide_cc.packet_statistics);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ao2_cleanup(rtp->lasttxformat);</span><br><span> ao2_cleanup(rtp->lastrxformat);</span><br><span> ao2_cleanup(rtp->f.subclass.format);</span><br><span>@@ -6308,6 +6343,367 @@</span><br><span> }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int rtp_transport_wide_cc_packet_statistics_cmp(struct rtp_transport_wide_cc_packet_statistics a,</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rtp_transport_wide_cc_packet_statistics b)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return a.seqno - b.seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void rtp_transport_wide_cc_feedback_status_vector_append(unsigned char *rtcpheader, int *packet_len, int *status_vector_chunk_bits,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t *status_vector_chunk, int status)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Appending this status will use up 2 bits */</span><br><span style="color: hsl(120, 100%, 40%);">+ *status_vector_chunk_bits -= 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ *status_vector_chunk |= (status << (16 - 2 - (14 - *status_vector_chunk_bits)));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there are still bits available we can return early */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*status_vector_chunk_bits) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Otherwise we have to place this chunk into the packet */</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_uint16(rtcpheader + *packet_len, htons(*status_vector_chunk));</span><br><span style="color: hsl(120, 100%, 40%);">+ *status_vector_chunk_bits = 14;</span><br><span style="color: hsl(120, 100%, 40%);">+ *status_vector_chunk = (1 << 15) | (1 << 14);</span><br><span style="color: hsl(120, 100%, 40%);">+ *packet_len += 2;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void rtp_transport_wide_cc_feedback_status_append(unsigned char *rtcpheader, int *packet_len, int *status_vector_chunk_bits,</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t *status_vector_chunk, int *run_length_chunk_count, int *run_length_chunk_status, int status)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*run_length_chunk_status != status) {</span><br><span style="color: hsl(120, 100%, 40%);">+ while (*run_length_chunk_count > 0 && *run_length_chunk_count < 8) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Realistically it only makes sense to use a run length chunk if there were 8 or more</span><br><span style="color: hsl(120, 100%, 40%);">+ * consecutive packets of the same type, otherwise we could end up making the packet larger</span><br><span style="color: hsl(120, 100%, 40%);">+ * if we have lots of small blocks of the same type. To help with this we backfill the status</span><br><span style="color: hsl(120, 100%, 40%);">+ * vector (since it always represents 7 packets). Best case we end up with only that single</span><br><span style="color: hsl(120, 100%, 40%);">+ * status vector and the rest are run length chunks.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_transport_wide_cc_feedback_status_vector_append(rtcpheader, packet_len, status_vector_chunk_bits,</span><br><span style="color: hsl(120, 100%, 40%);">+ status_vector_chunk, *run_length_chunk_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ *run_length_chunk_count -= 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*run_length_chunk_count) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* There is a run length chunk which needs to be written out */</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_uint16(rtcpheader + *packet_len, htons((0 << 15) | (*run_length_chunk_status << 13) | *run_length_chunk_count));</span><br><span style="color: hsl(120, 100%, 40%);">+ *packet_len += 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* In all cases the run length chunk has to be reset */</span><br><span style="color: hsl(120, 100%, 40%);">+ *run_length_chunk_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ *run_length_chunk_status = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*status_vector_chunk_bits == 14) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We aren't in the middle of a status vector so we can try for a run length chunk */</span><br><span style="color: hsl(120, 100%, 40%);">+ *run_length_chunk_status = status;</span><br><span style="color: hsl(120, 100%, 40%);">+ *run_length_chunk_count = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We're doing a status vector so populate it accordingly */</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_transport_wide_cc_feedback_status_vector_append(rtcpheader, packet_len, status_vector_chunk_bits,</span><br><span style="color: hsl(120, 100%, 40%);">+ status_vector_chunk, status);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* This is easy, the run length chunk count can just get bumped up */</span><br><span style="color: hsl(120, 100%, 40%);">+ *run_length_chunk_count += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int rtp_transport_wide_cc_feedback_produce(const void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_rtp_instance *instance = (struct ast_rtp_instance *) data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned char *rtcpheader;</span><br><span style="color: hsl(120, 100%, 40%);">+ char bdata[1024];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rtp_transport_wide_cc_packet_statistics *first_packet;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rtp_transport_wide_cc_packet_statistics *previous_packet;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+ int status_vector_chunk_bits = 14;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t status_vector_chunk = (1 << 15) | (1 << 14);</span><br><span style="color: hsl(120, 100%, 40%);">+ int run_length_chunk_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int run_length_chunk_status = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ int packet_len = 20;</span><br><span style="color: hsl(120, 100%, 40%);">+ int delta_len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int packet_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int received_msw;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int received_lsw;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sockaddr remote_address = { { 0, } };</span><br><span style="color: hsl(120, 100%, 40%);">+ int res;</span><br><span style="color: hsl(120, 100%, 40%);">+ int ice;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int large_delta_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int small_delta_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int lost_count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!rtp || !rtp->rtcp || rtp->transport_wide_cc.schedid == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(instance, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_lock(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rtcpheader = (unsigned char *)bdata;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The first packet in the vector acts as our base sequence number and reference time */</span><br><span style="color: hsl(120, 100%, 40%);">+ first_packet = AST_VECTOR_GET_ADDR(&rtp->transport_wide_cc.packet_statistics, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ previous_packet = first_packet;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We go through each packet that we have statistics for, adding it either to a status</span><br><span style="color: hsl(120, 100%, 40%);">+ * vector chunk or a run length chunk. The code tries to be as efficient as people to</span><br><span style="color: hsl(120, 100%, 40%);">+ * reduce packet size and will favor run length chunks when it makes sense.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < AST_VECTOR_SIZE(&rtp->transport_wide_cc.packet_statistics); ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rtp_transport_wide_cc_packet_statistics *statistics;</span><br><span style="color: hsl(120, 100%, 40%);">+ int lost = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ statistics = AST_VECTOR_GET_ADDR(&rtp->transport_wide_cc.packet_statistics, i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ packet_count++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (first_packet != statistics) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The vector stores statistics in a sorted fashion based on the sequence</span><br><span style="color: hsl(120, 100%, 40%);">+ * number. This ensures we can detect any packets that have been lost/not</span><br><span style="color: hsl(120, 100%, 40%);">+ * received by comparing the sequence numbers.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ lost = statistics->seqno - (previous_packet->seqno + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ lost_count += lost;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while (lost) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We append a not received status until all the lost packets have been accounted for */</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_transport_wide_cc_feedback_status_append(rtcpheader, &packet_len, &status_vector_chunk_bits,</span><br><span style="color: hsl(120, 100%, 40%);">+ &status_vector_chunk, &run_length_chunk_count, &run_length_chunk_status, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ packet_count++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there is no more room left for storing packets stop now, we leave 20</span><br><span style="color: hsl(120, 100%, 40%);">+ * extra bits at the end just in case.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((sizeof(bdata) - (packet_len + delta_len + 20)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ lost--;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If the lost packet appending bailed out because we have no more space, then exit here too */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Per the spec the delta is in increments of 250 */</span><br><span style="color: hsl(120, 100%, 40%);">+ statistics->delta = ast_tvdiff_us(statistics->received, previous_packet->received) / 250;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Based on the delta determine the status of this packet */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (statistics->delta < 0 || statistics->delta > 127) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Large or negative delta */</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_transport_wide_cc_feedback_status_append(rtcpheader, &packet_len, &status_vector_chunk_bits,</span><br><span style="color: hsl(120, 100%, 40%);">+ &status_vector_chunk, &run_length_chunk_count, &run_length_chunk_status, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+ delta_len += 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ large_delta_count++;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Small delta */</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_transport_wide_cc_feedback_status_append(rtcpheader, &packet_len, &status_vector_chunk_bits,</span><br><span style="color: hsl(120, 100%, 40%);">+ &status_vector_chunk, &run_length_chunk_count, &run_length_chunk_status, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ delta_len += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ small_delta_count++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ previous_packet = statistics;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there is no more room left in the packet stop handling of any subsequent packets */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((sizeof(bdata) - (packet_len + delta_len + 20)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (status_vector_chunk_bits != 14) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If the status vector chunk has packets in it then place it in the RTCP packet */</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_uint16(rtcpheader + packet_len, htons(status_vector_chunk));</span><br><span style="color: hsl(120, 100%, 40%);">+ packet_len += 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (run_length_chunk_count) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there is a run length chunk in progress then place it in the RTCP packet */</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_uint16(rtcpheader + packet_len, htons((0 << 15) | (run_length_chunk_status << 13) | run_length_chunk_count));</span><br><span style="color: hsl(120, 100%, 40%);">+ packet_len += 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We iterate again to build delta chunks */</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < AST_VECTOR_SIZE(&rtp->transport_wide_cc.packet_statistics); ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rtp_transport_wide_cc_packet_statistics *statistics;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ statistics = AST_VECTOR_GET_ADDR(&rtp->transport_wide_cc.packet_statistics, i);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (statistics->delta < 0 || statistics->delta > 127) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We need 2 bytes to store this delta */</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_uint16(rtcpheader + packet_len, htons(statistics->delta));</span><br><span style="color: hsl(120, 100%, 40%);">+ packet_len += 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We can store this delta in 1 byte */</span><br><span style="color: hsl(120, 100%, 40%);">+ rtcpheader[packet_len] = statistics->delta;</span><br><span style="color: hsl(120, 100%, 40%);">+ packet_len += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If this is the last packet handled by the run length chunk or status vector chunk code</span><br><span style="color: hsl(120, 100%, 40%);">+ * then we can go no further.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (statistics == previous_packet) {</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Zero pad the end of the packet */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (packet_len % 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rtcpheader[packet_len++] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add the general RTCP header information */</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_uint32(rtcpheader, htonl((2 << 30) | (AST_RTP_RTCP_FMT_TRANSPORT_WIDE_CC << 24)</span><br><span style="color: hsl(120, 100%, 40%);">+ | (AST_RTP_RTCP_RTPFB << 16) | ((packet_len / 4) - 1)));</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_uint32(rtcpheader + 4, htonl(rtp->ssrc));</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_uint32(rtcpheader + 8, htonl(rtp->themssrc));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add the transport-cc specific header information */</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_uint32(rtcpheader + 12, htonl((first_packet->seqno << 16) | packet_count));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ timeval2ntp(first_packet->received, &received_msw, &received_lsw);</span><br><span style="color: hsl(120, 100%, 40%);">+ put_unaligned_time24(rtcpheader + 16, received_msw, received_lsw);</span><br><span style="color: hsl(120, 100%, 40%);">+ rtcpheader[19] = rtp->transport_wide_cc.feedback_count;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The packet is now fully constructed so send it out */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(2, "Sending transport-cc feedback packet of size '%d' on '%s' with packet count of %d (small = %d, large = %d, lost = %d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ packet_len, ast_rtp_instance_get_channel_id(instance), packet_count, small_delta_count, large_delta_count, lost_count);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ res = rtcp_sendto(instance, (unsigned int *)rtcpheader, packet_len, 0, &remote_address, &ice);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "RTCP transport-cc feedback error to %s due to %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sockaddr_stringify(&remote_address), strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_RESET(&rtp->transport_wide_cc.packet_statistics, AST_VECTOR_ELEM_CLEANUP_NOOP);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp->transport_wide_cc.feedback_count++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1000;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void rtp_instance_parse_transport_wide_cc(struct ast_rtp_instance *instance, struct ast_rtp *rtp,</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned char *data, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ uint16_t *seqno = (uint16_t *)data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct rtp_transport_wide_cc_packet_statistics statistics;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_rtp_instance *transport = rtp->bundled ? rtp->bundled : instance;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_rtp *transport_rtp = ast_rtp_instance_get_data(transport);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If the sequence number has cycled over then record it as such */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (((int)transport_rtp->transport_wide_cc.last_seqno - (int)ntohs(*seqno)) > 100) {</span><br><span style="color: hsl(120, 100%, 40%);">+ transport_rtp->transport_wide_cc.cycles += RTP_SEQ_MOD;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Populate the statistics information for this packet */</span><br><span style="color: hsl(120, 100%, 40%);">+ statistics.seqno = transport_rtp->transport_wide_cc.cycles + ntohs(*seqno);</span><br><span style="color: hsl(120, 100%, 40%);">+ statistics.received = ast_tvnow();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We allow at a maximum 1000 packet statistics in play at a time, if we hit the</span><br><span style="color: hsl(120, 100%, 40%);">+ * limit we give up and start fresh.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_SIZE(&transport_rtp->transport_wide_cc.packet_statistics) > 1000) {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_RESET(&rtp->transport_wide_cc.packet_statistics, AST_VECTOR_ELEM_CLEANUP_NOOP);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!AST_VECTOR_SIZE(&transport_rtp->transport_wide_cc.packet_statistics) ||</span><br><span style="color: hsl(120, 100%, 40%);">+ statistics.seqno > transport_rtp->transport_wide_cc.last_extended_seqno) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* This is the expected path */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_APPEND(&transport_rtp->transport_wide_cc.packet_statistics, statistics)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ transport_rtp->transport_wide_cc.last_extended_seqno = statistics.seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+ transport_rtp->transport_wide_cc.last_seqno = ntohs(*seqno);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* This packet was out of order, so reorder it within the vector accordingly */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_ADD_SORTED(&transport_rtp->transport_wide_cc.packet_statistics, statistics,</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_transport_wide_cc_packet_statistics_cmp)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If we have not yet scheduled the periodic sending of feedback for this transport then do so */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (transport_rtp->transport_wide_cc.schedid < 0 && transport_rtp->rtcp) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(1, "Starting RTCP transport-cc feedback transmission on RTP instance '%p'\n", transport);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(transport, +1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_NOTICE, "Starting feedback\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ transport_rtp->transport_wide_cc.schedid = ast_sched_add(rtp->sched, 1000,</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_transport_wide_cc_feedback_produce, transport);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (transport_rtp->transport_wide_cc.schedid < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(transport, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Scheduling RTCP transport-cc feedback transmission failed on RTP instance '%p'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ transport);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void rtp_instance_parse_extmap_extensions(struct ast_rtp_instance *instance, struct ast_rtp *rtp,</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned char *extension, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int transport_wide_cc_id = ast_rtp_instance_extmap_get_id(instance, AST_RTP_EXTENSION_TRANSPORT_WIDE_CC);</span><br><span style="color: hsl(120, 100%, 40%);">+ int pos = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We currently only care about the transport-cc extension, so if that's not negotiated then do nothing */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (transport_wide_cc_id == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Only while we do not exceed available extension data do we continue */</span><br><span style="color: hsl(120, 100%, 40%);">+ while (pos < len) {</span><br><span style="color: hsl(120, 100%, 40%);">+ int id = extension[pos] >> 4;</span><br><span style="color: hsl(120, 100%, 40%);">+ int extension_len = (extension[pos] & 0xF) + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We've handled the first byte as it contains the extension id and length, so always</span><br><span style="color: hsl(120, 100%, 40%);">+ * skip ahead now</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ pos += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (id == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* From the RFC:</span><br><span style="color: hsl(120, 100%, 40%);">+ * In both forms, padding bytes have the value of 0 (zero). They may be</span><br><span style="color: hsl(120, 100%, 40%);">+ * placed between extension elements, if desired for alignment, or after</span><br><span style="color: hsl(120, 100%, 40%);">+ * the last extension element, if needed for padding. A padding byte</span><br><span style="color: hsl(120, 100%, 40%);">+ * does not supply the ID of an element, nor the length field. When a</span><br><span style="color: hsl(120, 100%, 40%);">+ * padding byte is found, it is ignored and the parser moves on to</span><br><span style="color: hsl(120, 100%, 40%);">+ * interpreting the next byte.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (id == 15) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* From the RFC:</span><br><span style="color: hsl(120, 100%, 40%);">+ * The local identifier value 15 is reserved for future extension and</span><br><span style="color: hsl(120, 100%, 40%);">+ * MUST NOT be used as an identifier. If the ID value 15 is</span><br><span style="color: hsl(120, 100%, 40%);">+ * encountered, its length field should be ignored, processing of the</span><br><span style="color: hsl(120, 100%, 40%);">+ * entire extension should terminate at that point, and only the</span><br><span style="color: hsl(120, 100%, 40%);">+ * extension elements present prior to the element with ID 15</span><br><span style="color: hsl(120, 100%, 40%);">+ * considered.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if ((pos + extension_len) > len) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The extension is corrupted and is stating that it contains more data than is</span><br><span style="color: hsl(120, 100%, 40%);">+ * available in the extensions data.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If this is transport-cc then we need to parse it further */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (id == transport_wide_cc_id) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_instance_parse_transport_wide_cc(instance, rtp, extension + pos, extension_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Skip ahead to the next extension */</span><br><span style="color: hsl(120, 100%, 40%);">+ pos += extension_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct ast_frame *ast_rtp_interpret(struct ast_rtp_instance *instance, struct ast_srtp *srtp,</span><br><span> const struct ast_sockaddr *remote_address, unsigned char *read_area, int length, int prev_seqno)</span><br><span> {</span><br><span>@@ -6353,18 +6749,24 @@</span><br><span> </span><br><span> /* Look for any RTP extensions, currently we do not support any */</span><br><span> if (ext) {</span><br><span style="color: hsl(0, 100%, 40%);">- hdrlen += (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2;</span><br><span style="color: hsl(0, 100%, 40%);">- hdrlen += 4;</span><br><span style="color: hsl(0, 100%, 40%);">- if (DEBUG_ATLEAST(1)) {</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned int profile;</span><br><span style="color: hsl(0, 100%, 40%);">- profile = (ntohl(rtpheader[3]) & 0xffff0000) >> 16;</span><br><span style="color: hsl(120, 100%, 40%);">+ int extensions_size = (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int profile;</span><br><span style="color: hsl(120, 100%, 40%);">+ profile = (ntohl(rtpheader[3]) & 0xffff0000) >> 16;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (profile == 0xbede) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We skip over the first 4 bytes as they are just for the one byte extension header */</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp_instance_parse_extmap_extensions(instance, rtp, read_area + hdrlen + 4, extensions_size);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (DEBUG_ATLEAST(1)) {</span><br><span> if (profile == 0x505a) {</span><br><span> ast_log(LOG_DEBUG, "Found Zfone extension in RTP stream - zrtp - not supported.\n");</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (profile != 0xbede) {</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span> /* SDP negotiated RTP extensions can not currently be output in logging */</span><br><span> ast_log(LOG_DEBUG, "Found unknown RTP Extensions %x\n", profile);</span><br><span> }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ hdrlen += extensions_size;</span><br><span style="color: hsl(120, 100%, 40%);">+ hdrlen += 4;</span><br><span> }</span><br><span> </span><br><span> /* Make sure after we potentially mucked with the header length that it is once again valid */</span><br><span>@@ -7316,6 +7718,18 @@</span><br><span> ao2_lock(instance);</span><br><span> rtp->rtcp->schedid = -1;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rtp->transport_wide_cc.schedid > -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_sched_del(rtp->sched, rtp->transport_wide_cc.schedid)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(instance, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(1, "Failed to tear down RTCP transport-cc feedback on RTP instance '%p'\n", instance);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_lock(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_lock(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp->transport_wide_cc.schedid = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> if (rtp->rtcp->s > -1 && rtp->rtcp->s != rtp->s) {</span><br><span> close(rtp->rtcp->s);</span><br><span> }</span><br><span>@@ -7623,6 +8037,15 @@</span><br><span> rtp->rtcp->schedid = -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (rtp->transport_wide_cc.schedid > -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_sched_del(rtp->sched, rtp->transport_wide_cc.schedid)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(instance, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_lock(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp->transport_wide_cc.schedid = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (rtp->red) {</span><br><span> ao2_unlock(instance);</span><br><span> AST_SCHED_DEL(rtp->sched, rtp->red->schedid);</span><br><span>@@ -7763,6 +8186,7 @@</span><br><span> {</span><br><span> switch (extension) {</span><br><span> case AST_RTP_EXTENSION_ABS_SEND_TIME:</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_RTP_EXTENSION_TRANSPORT_WIDE_CC:</span><br><span> return 1;</span><br><span> default:</span><br><span> return 0;</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/11315">change 11315</a>. To unsubscribe, or for help writing mail filters, 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/c/asterisk/+/11315"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: I654a2cff5bd5554ab94457a14f70adb71f574afc </div>
<div style="display:none"> Gerrit-Change-Number: 11315 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>