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

</div><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, 458 insertions(+), 7 deletions(-)<br><br></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..023273a 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,377 @@</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* We calculate which bits we want to update the status of. Since a status vector</span><br><span style="color: hsl(120, 100%, 40%);">+      * is 16 bits we take away 2 (for the header), and then we take away any that have</span><br><span style="color: hsl(120, 100%, 40%);">+     * already been used.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* The first bit being 1 indicates that this is a status vector chunk and the second</span><br><span style="color: hsl(120, 100%, 40%);">+   * bit being 1 indicates that we are using 2 bits to represent each status for a</span><br><span style="color: hsl(120, 100%, 40%);">+       * packet.</span><br><span style="color: hsl(120, 100%, 40%);">+     */</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 possible 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 +6759,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 +7728,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 +8047,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 +8196,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: 2 </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: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>