<p>George Joseph <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/9224">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  George Joseph: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_rtp_asterisk: Add support for sending NACK requests.<br><br>Support has been added for receiving a NACK request and handling it.<br>Now, Asterisk can detect when a NACK request should be sent and knows<br>how to construct one based on the packets we've received from the remote<br>end. A buffer has been added that will store out of order packets until<br>we receive the packet we are expecting. Then, these packets are handled<br>like normal and frames are queued to the core like normal. Asterisk<br>knows which packets to request in the NACK request using a vector<br>which stores the sequence numbers of the packets we are currently missing.<br><br>If a missing packet is received, cycle through the buffer until we reach<br>another packet we have not received yet. If the buffer reaches a certain<br>size, send a NACK request. If the buffer reaches its max size, queue all<br>frames to the core and wipe the buffer and vector.<br><br>According to RFC3711, the NACK request must be sent out in a compound<br>packet. All compound packets must start with a sender or receiver<br>report, so some work was done to refactor the current sender / receiver<br>code to allow it to be used without having to also include sdes<br>information and automatically send the report.<br><br>Also added additional functionality to ast_data_buffer, along with some<br>testing.<br><br>For more information, refer to the wiki page:<br>https://wiki.asterisk.org/wiki/display/AST/WebRTC+User+Experience+Improvements<br><br>ASTERISK-27810 #close<br><br>Change-Id: Idab644b08a1593659c92cda64132ccc203fe991d<br>---<br>M include/asterisk/data_buffer.h<br>M main/data_buffer.c<br>M res/res_rtp_asterisk.c<br>M tests/test_data_buffer.c<br>4 files changed, 902 insertions(+), 352 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/data_buffer.h b/include/asterisk/data_buffer.h</span><br><span>index dacbaa5..66aad27 100644</span><br><span>--- a/include/asterisk/data_buffer.h</span><br><span>+++ b/include/asterisk/data_buffer.h</span><br><span>@@ -111,6 +111,35 @@</span><br><span> void *ast_data_buffer_get(const struct ast_data_buffer *buffer, size_t pos);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Remove a data payload from the data buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buffer The data buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param pos The position of the data payload</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-NULL success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL failure</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note This DOES remove the data payload from the data buffer. It does not free it, though.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 15.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void *ast_data_buffer_remove(struct ast_data_buffer *buffer, size_t pos);</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 Remove the first payload from the data buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param buffer The data buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-NULL success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL failure</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note This DOES remove the data payload from the data buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 15.5.0</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void *ast_data_buffer_remove_head(struct ast_data_buffer *buffer);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Free a data buffer (and all held data payloads)</span><br><span>  *</span><br><span>  * \param buffer The data buffer</span><br><span>diff --git a/main/data_buffer.c b/main/data_buffer.c</span><br><span>index ccbffd2..cfc323c 100644</span><br><span>--- a/main/data_buffer.c</span><br><span>+++ b/main/data_buffer.c</span><br><span>@@ -281,6 +281,60 @@</span><br><span>  return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void data_buffer_free_buffer_payload(struct ast_data_buffer *buffer,</span><br><span style="color: hsl(120, 100%, 40%);">+    struct data_buffer_payload_entry *buffer_payload)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  buffer_payload->payload = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+    buffer->count--;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (buffer->cache_count < CACHED_PAYLOAD_MAX</span><br><span style="color: hsl(120, 100%, 40%);">+                    && buffer->cache_count < (buffer->max - buffer->count)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_LIST_INSERT_TAIL(&buffer->cached_payloads, buffer_payload, list);</span><br><span style="color: hsl(120, 100%, 40%);">+          buffer->cache_count++;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_free(buffer_payload);</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%);">+void *ast_data_buffer_remove(struct ast_data_buffer *buffer, size_t pos)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct data_buffer_payload_entry *buffer_payload;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_assert(buffer != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_TRAVERSE_SAFE_BEGIN(&buffer->payloads, buffer_payload, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (buffer_payload->pos == pos) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  void *payload = buffer_payload->payload;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 AST_LIST_REMOVE_CURRENT(list);</span><br><span style="color: hsl(120, 100%, 40%);">+                        data_buffer_free_buffer_payload(buffer, buffer_payload);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    return payload;</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_LIST_TRAVERSE_SAFE_END;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</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%);">+void *ast_data_buffer_remove_head(struct ast_data_buffer *buffer)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_assert(buffer != NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (buffer->count > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                struct data_buffer_payload_entry *buffer_payload;</span><br><span style="color: hsl(120, 100%, 40%);">+             void *payload;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              buffer_payload = AST_LIST_REMOVE_HEAD(&buffer->payloads, list);</span><br><span style="color: hsl(120, 100%, 40%);">+                payload = buffer_payload->payload;</span><br><span style="color: hsl(120, 100%, 40%);">+         data_buffer_free_buffer_payload(buffer, buffer_payload);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            return payload;</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%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void ast_data_buffer_free(struct ast_data_buffer *buffer)</span><br><span> {</span><br><span>  struct data_buffer_payload_entry *buffer_payload;</span><br><span>diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c</span><br><span>index f6e26d6..36b9cb9 100644</span><br><span>--- a/res/res_rtp_asterisk.c</span><br><span>+++ b/res/res_rtp_asterisk.c</span><br><span>@@ -103,7 +103,8 @@</span><br><span> </span><br><span> #define TURN_STATE_WAIT_TIME 2000</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#define DEFAULT_RTP_BUFFER_SIZE        250</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_RTP_SEND_BUFFER_SIZE       250</span><br><span style="color: hsl(120, 100%, 40%);">+#define DEFAULT_RTP_RECV_BUFFER_SIZE       20</span><br><span> </span><br><span> /*! Full INTRA-frame Request / Fast Update Request (From RFC2032) */</span><br><span> #define RTCP_PT_FUR     192</span><br><span>@@ -323,6 +324,8 @@</span><br><span>  unsigned int lastotexttimestamp;</span><br><span>     unsigned int lasteventseqn;</span><br><span>  int lastrxseqno;                /*!< Last received sequence number, from the network */</span><br><span style="color: hsl(120, 100%, 40%);">+    int expectedrxseqno;            /*!< Next expected sequence number, from the network */</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_VECTOR(, int) missing_seqno; /*!< A vector of sequence numbers we never received */</span><br><span>   int expectedseqno;              /*!< Next expected sequence number, from the core */</span><br><span>      unsigned short seedrxseqno;     /*!< What sequence number did they start with?*/</span><br><span>  unsigned int seedrxts;          /*!< What RTP timestamp did they start with? */</span><br><span>@@ -388,6 +391,7 @@</span><br><span>     struct rtp_red *red;</span><br><span> </span><br><span>     struct ast_data_buffer *send_buffer;            /*!< Buffer for storing sent packets for retransmission */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_data_buffer *recv_buffer;            /*!< Buffer for storing received packets for retransmission */</span><br><span> </span><br><span> #ifdef HAVE_PJPROJECT</span><br><span>       ast_cond_t cond;            /*!< ICE/TURN condition for signaling */</span><br><span>@@ -2771,6 +2775,18 @@</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Helper function to compare an elem in a vector by value */</span><br><span style="color: hsl(120, 100%, 40%);">+static int compare_by_value(int elem, int value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return elem - value;</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 Helper function to find an elem in a vector by value */</span><br><span style="color: hsl(120, 100%, 40%);">+static int find_by_value(int elem, int value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return elem == value;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int rtcp_mux(struct ast_rtp *rtp, const unsigned char *packet)</span><br><span> {</span><br><span>     uint8_t version;</span><br><span>@@ -2941,11 +2957,6 @@</span><br><span>    }</span><br><span> #endif</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if ((*in & 0xC0) && res_srtp && srtp && res_srtp->unprotect(</span><br><span style="color: hsl(0, 100%, 40%);">-                 srtp, buf, &len, rtcp || rtcp_mux(rtp, buf)) < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-     return -1;</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    return len;</span><br><span> }</span><br><span> </span><br><span>@@ -3629,6 +3640,7 @@</span><br><span>         rtp->ssrc = ast_random();</span><br><span>         ast_uuid_generate_str(rtp->cname, sizeof(rtp->cname));</span><br><span>         rtp->seqno = ast_random() & 0x7fff;</span><br><span style="color: hsl(120, 100%, 40%);">+    rtp->expectedrxseqno = -1;</span><br><span>        rtp->expectedseqno = -1;</span><br><span>  rtp->sched = sched;</span><br><span>       ast_sockaddr_copy(&rtp->bind_address, addr);</span><br><span>@@ -3713,10 +3725,16 @@</span><br><span>                ast_data_buffer_free(rtp->send_buffer);</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Destroy the recv buffer if it was being used */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rtp->recv_buffer) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_data_buffer_free(rtp->recv_buffer);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</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>      AST_VECTOR_FREE(&rtp->ssrc_mapping);</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_VECTOR_FREE(&rtp->missing_seqno);</span><br><span> </span><br><span>     /* Finally destroy ourselves */</span><br><span>      ast_free(rtp);</span><br><span>@@ -3983,6 +4001,9 @@</span><br><span> </span><br><span>   rtp->ssrc = ssrc;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      /* Since the source is changing, we don't know what sequence number to expect next */</span><br><span style="color: hsl(120, 100%, 40%);">+     rtp->expectedrxseqno = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      return;</span><br><span> }</span><br><span> </span><br><span>@@ -4078,39 +4099,24 @@</span><br><span>   rtp->rtcp->rxlost_count++;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*!</span><br><span style="color: hsl(0, 100%, 40%);">- * \brief Send RTCP SR or RR report</span><br><span style="color: hsl(0, 100%, 40%);">- *</span><br><span style="color: hsl(0, 100%, 40%);">- * \pre instance is locked</span><br><span style="color: hsl(0, 100%, 40%);">- */</span><br><span style="color: hsl(0, 100%, 40%);">-static int ast_rtcp_write_report(struct ast_rtp_instance *instance, int sr)</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_rtcp_generate_report(struct ast_rtp_instance *instance, unsigned char *rtcpheader,</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_rtp_rtcp_report *rtcp_report, int *sr)</span><br><span> {</span><br><span>       struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);</span><br><span style="color: hsl(0, 100%, 40%);">-      RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref);</span><br><span style="color: hsl(0, 100%, 40%);">-        int res;</span><br><span>     int len = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-    uint16_t sdes_packet_len_bytes, sdes_packet_len_rounded;</span><br><span>     struct timeval now;</span><br><span>  unsigned int now_lsw;</span><br><span>        unsigned int now_msw;</span><br><span style="color: hsl(0, 100%, 40%);">-   unsigned char *rtcpheader;</span><br><span>   unsigned int lost_packets;</span><br><span>   int fraction_lost;</span><br><span>   struct timeval dlsr = { 0, };</span><br><span style="color: hsl(0, 100%, 40%);">-   unsigned char bdata[AST_UUID_STR_LEN + 128] = ""; /* More than enough */</span><br><span style="color: hsl(0, 100%, 40%);">-      int rate = rtp_get_rate(rtp->f.subclass.format);</span><br><span style="color: hsl(0, 100%, 40%);">-     int ice;</span><br><span style="color: hsl(0, 100%, 40%);">-        struct ast_sockaddr remote_address = { { 0, } };</span><br><span>     struct ast_rtp_rtcp_report_block *report_block = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-  RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,</span><br><span style="color: hsl(0, 100%, 40%);">-                     ast_rtp_rtcp_report_alloc(rtp->themssrc_valid ? 1 : 0),</span><br><span style="color: hsl(0, 100%, 40%);">-                      ao2_cleanup);</span><br><span> </span><br><span>    if (!rtp || !rtp->rtcp) {</span><br><span>                 return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (ast_sockaddr_isnull(&rtp->rtcp->them)) {  /* This'll stop rtcp for this rtp session */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (ast_sockaddr_isnull(&rtp->rtcp->them)) { /* This'll stop rtcp for this rtp session */</span><br><span>              /* RTCP was stopped. */</span><br><span>              return 0;</span><br><span>    }</span><br><span>@@ -4119,14 +4125,16 @@</span><br><span>          return 1;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ *sr = rtp->txcount > rtp->rtcp->lastsrtxcount ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         /* Compute statistics */</span><br><span>     calculate_lost_packet_statistics(rtp, &lost_packets, &fraction_lost);</span><br><span> </span><br><span>    gettimeofday(&now, NULL);</span><br><span>        rtcp_report->reception_report_count = rtp->themssrc_valid ? 1 : 0;</span><br><span>     rtcp_report->ssrc = rtp->ssrc;</span><br><span style="color: hsl(0, 100%, 40%);">-    rtcp_report->type = sr ? RTCP_PT_SR : RTCP_PT_RR;</span><br><span style="color: hsl(0, 100%, 40%);">-    if (sr) {</span><br><span style="color: hsl(120, 100%, 40%);">+     rtcp_report->type = *sr ? RTCP_PT_SR : RTCP_PT_RR;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (*sr) {</span><br><span>           rtcp_report->sender_information.ntp_timestamp = now;</span><br><span>              rtcp_report->sender_information.rtp_timestamp = rtp->lastts;</span><br><span>           rtcp_report->sender_information.packet_count = rtp->txcount;</span><br><span>@@ -4144,7 +4152,7 @@</span><br><span>           report_block->lost_count.fraction = (fraction_lost & 0xff);</span><br><span>           report_block->lost_count.packets = (lost_packets & 0xffffff);</span><br><span>                 report_block->highest_seq_no = (rtp->cycles | (rtp->lastrxseqno & 0xffff));</span><br><span style="color: hsl(0, 100%, 40%);">-                report_block->ia_jitter = (unsigned int)(rtp->rxjitter * rate);</span><br><span style="color: hsl(120, 100%, 40%);">+         report_block->ia_jitter = (unsigned int)(rtp->rxjitter * rtp_get_rate(rtp->f.subclass.format));</span><br><span>             report_block->lsr = rtp->rtcp->themrxlsr;</span><br><span>           /* If we haven't received an SR report, DLSR should be 0 */</span><br><span>              if (!ast_tvzero(rtp->rtcp->rxlsr)) {</span><br><span>@@ -4153,11 +4161,10 @@</span><br><span>                 }</span><br><span>    }</span><br><span>    timeval2ntp(rtcp_report->sender_information.ntp_timestamp, &now_msw, &now_lsw);</span><br><span style="color: hsl(0, 100%, 40%);">-      rtcpheader = bdata;</span><br><span>  put_unaligned_uint32(rtcpheader + 4, htonl(rtcp_report->ssrc)); /* Our SSRC */</span><br><span>    len += 8;</span><br><span style="color: hsl(0, 100%, 40%);">-       if (sr) {</span><br><span style="color: hsl(0, 100%, 40%);">-               put_unaligned_uint32(rtcpheader + len, htonl(now_msw)); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/</span><br><span style="color: hsl(120, 100%, 40%);">+     if (*sr) {</span><br><span style="color: hsl(120, 100%, 40%);">+            put_unaligned_uint32(rtcpheader + len, htonl(now_msw)); /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970 */</span><br><span>           put_unaligned_uint32(rtcpheader + len + 4, htonl(now_lsw)); /* now, LSW */</span><br><span>           put_unaligned_uint32(rtcpheader + len + 8, htonl(rtcp_report->sender_information.rtp_timestamp));</span><br><span>                 put_unaligned_uint32(rtcpheader + len + 12, htonl(rtcp_report->sender_information.packet_count));</span><br><span>@@ -4175,53 +4182,32 @@</span><br><span>       }</span><br><span> </span><br><span>        put_unaligned_uint32(rtcpheader, htonl((2 << 30) | (rtcp_report->reception_report_count << 24)</span><br><span style="color: hsl(0, 100%, 40%);">-                                   | ((sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1)));</span><br><span style="color: hsl(120, 100%, 40%);">+                               | ((*sr ? RTCP_PT_SR : RTCP_PT_RR) << 16) | ((len/4)-1)));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    sdes_packet_len_bytes =</span><br><span style="color: hsl(0, 100%, 40%);">-         4 + /* RTCP Header */</span><br><span style="color: hsl(0, 100%, 40%);">-           4 + /* SSRC */</span><br><span style="color: hsl(0, 100%, 40%);">-          1 + /* Type (CNAME) */</span><br><span style="color: hsl(0, 100%, 40%);">-          1 + /* Text Length */</span><br><span style="color: hsl(0, 100%, 40%);">-           AST_UUID_STR_LEN /* Text and NULL terminator */</span><br><span style="color: hsl(0, 100%, 40%);">-         ;</span><br><span style="color: hsl(120, 100%, 40%);">+     return len;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      /* Round to 32 bit boundary */</span><br><span style="color: hsl(0, 100%, 40%);">-  sdes_packet_len_rounded = (sdes_packet_len_bytes + 3) & ~0x3;</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_rtcp_calculate_sr_rr_statistics(struct ast_rtp_instance *instance,</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_rtp_rtcp_report *rtcp_report, struct ast_sockaddr remote_address, int ice, int sr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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%);">+    struct ast_rtp_rtcp_report_block *report_block = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        RAII_VAR(struct ast_json *, message_blob, NULL, ast_json_unref);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    put_unaligned_uint32(rtcpheader + len, htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | ((sdes_packet_len_rounded / 4) - 1)));</span><br><span style="color: hsl(0, 100%, 40%);">-    put_unaligned_uint32(rtcpheader + len + 4, htonl(rtcp_report->ssrc));</span><br><span style="color: hsl(0, 100%, 40%);">-        rtcpheader[len + 8] = 0x01; /* CNAME */</span><br><span style="color: hsl(0, 100%, 40%);">- rtcpheader[len + 9] = AST_UUID_STR_LEN - 1; /* Number of bytes of text */</span><br><span style="color: hsl(0, 100%, 40%);">-       memcpy(rtcpheader + len + 10, rtp->cname, AST_UUID_STR_LEN);</span><br><span style="color: hsl(0, 100%, 40%);">- len += 10 + AST_UUID_STR_LEN;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   /* Padding - Note that we don't set the padded bit on the packet. From</span><br><span style="color: hsl(0, 100%, 40%);">-       * RFC 3550 Section 6.5:</span><br><span style="color: hsl(0, 100%, 40%);">-         *</span><br><span style="color: hsl(0, 100%, 40%);">-       *    No length octet follows the null item type octet, but additional null</span><br><span style="color: hsl(0, 100%, 40%);">-      *    octets MUST be included if needed to pad until the next 32-bit</span><br><span style="color: hsl(0, 100%, 40%);">-     *    boundary.  Note that this padding is separate from that indicated by</span><br><span style="color: hsl(0, 100%, 40%);">-       *    the P bit in the RTCP header.</span><br><span style="color: hsl(0, 100%, 40%);">-      *</span><br><span style="color: hsl(0, 100%, 40%);">-       * These bytes will already be zeroed out during array initialization.</span><br><span style="color: hsl(0, 100%, 40%);">-   */</span><br><span style="color: hsl(0, 100%, 40%);">-     len += (sdes_packet_len_rounded - sdes_packet_len_bytes);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (rtp->bundled) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_rtp_instance_get_remote_address(instance, &remote_address);</span><br><span style="color: hsl(0, 100%, 40%);">-     } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-       res = rtcp_sendto(instance, (unsigned int *)rtcpheader, len, 0, &remote_address, &ice);</span><br><span style="color: hsl(0, 100%, 40%);">- if (res < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-               ast_log(LOG_ERROR, "RTCP %s transmission error to %s, rtcp halted %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                      sr ? "SR" : "RR",</span><br><span style="color: hsl(0, 100%, 40%);">-                   ast_sockaddr_stringify(&rtp->rtcp->them),</span><br><span style="color: hsl(0, 100%, 40%);">-                     strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!rtp || !rtp->rtcp) {</span><br><span>                 return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Update RTCP SR/RR statistics */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ast_sockaddr_isnull(&rtp->rtcp->them)) {</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%);">+   if (!rtcp_report) {</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   report_block = rtcp_report->report_block[0];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    if (sr) {</span><br><span>            rtp->rtcp->txlsr = rtcp_report->sender_information.ntp_timestamp;</span><br><span>           rtp->rtcp->sr_count++;</span><br><span>@@ -4248,7 +4234,7 @@</span><br><span>                         ast_verbose("    Fraction lost: %d\n", report_block->lost_count.fraction);</span><br><span>                      ast_verbose("    Cumulative loss: %u\n", report_block->lost_count.packets);</span><br><span>                     ast_verbose("    Highest seq no: %u\n", report_block->highest_seq_no);</span><br><span style="color: hsl(0, 100%, 40%);">-                     ast_verbose("    IA jitter: %.4f\n", (double)report_block->ia_jitter / rate);</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_verbose("    IA jitter: %.4f\n", (double)report_block->ia_jitter / rtp_get_rate(rtp->f.subclass.format));</span><br><span>                        ast_verbose("    Their last SR: %u\n", report_block->lsr);</span><br><span>                      ast_verbose("    DLSR: %4.4f (sec)\n\n", (double)(report_block->dlsr / 65536.0));</span><br><span>               }</span><br><span>@@ -4258,9 +4244,121 @@</span><br><span>                  "to", ast_sockaddr_stringify(&remote_address),</span><br><span>                         "from", rtp->rtcp->local_addr_str);</span><br><span>  ast_rtp_publish_rtcp_message(instance, ast_rtp_rtcp_sent_type(),</span><br><span style="color: hsl(0, 100%, 40%);">-                        rtcp_report,</span><br><span style="color: hsl(0, 100%, 40%);">-                    message_blob);</span><br><span style="color: hsl(0, 100%, 40%);">-  return res;</span><br><span style="color: hsl(120, 100%, 40%);">+                   rtcp_report, message_blob);</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_rtcp_generate_sdes(struct ast_rtp_instance *instance, unsigned char *rtcpheader,</span><br><span style="color: hsl(120, 100%, 40%);">+               struct ast_rtp_rtcp_report *rtcp_report)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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%);">+    int len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint16_t sdes_packet_len_bytes;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t sdes_packet_len_rounded;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!rtp || !rtp->rtcp) {</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%);">+   if (ast_sockaddr_isnull(&rtp->rtcp->them)) {</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%);">+   if (!rtcp_report) {</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   sdes_packet_len_bytes =</span><br><span style="color: hsl(120, 100%, 40%);">+               4 + /* RTCP Header */</span><br><span style="color: hsl(120, 100%, 40%);">+         4 + /* SSRC */</span><br><span style="color: hsl(120, 100%, 40%);">+                1 + /* Type (CNAME) */</span><br><span style="color: hsl(120, 100%, 40%);">+                1 + /* Text Length */</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_UUID_STR_LEN /* Text and NULL terminator */</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%);">+   /* Round to 32 bit boundary */</span><br><span style="color: hsl(120, 100%, 40%);">+        sdes_packet_len_rounded = (sdes_packet_len_bytes + 3) & ~0x3;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   put_unaligned_uint32(rtcpheader, htonl((2 << 30) | (1 << 24) | (RTCP_PT_SDES << 16) | ((sdes_packet_len_rounded / 4) - 1)));</span><br><span style="color: hsl(120, 100%, 40%);">+        put_unaligned_uint32(rtcpheader + 4, htonl(rtcp_report->ssrc));</span><br><span style="color: hsl(120, 100%, 40%);">+    rtcpheader[8] = 0x01; /* CNAME */</span><br><span style="color: hsl(120, 100%, 40%);">+     rtcpheader[9] = AST_UUID_STR_LEN - 1; /* Number of bytes of text */</span><br><span style="color: hsl(120, 100%, 40%);">+   memcpy(rtcpheader + 10, rtp->cname, AST_UUID_STR_LEN);</span><br><span style="color: hsl(120, 100%, 40%);">+     len += 10 + AST_UUID_STR_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Padding - Note that we don't set the padded bit on the packet. From</span><br><span style="color: hsl(120, 100%, 40%);">+     * RFC 3550 Section 6.5:</span><br><span style="color: hsl(120, 100%, 40%);">+       *</span><br><span style="color: hsl(120, 100%, 40%);">+     *   No length octet follows the null item type octet, but additional null</span><br><span style="color: hsl(120, 100%, 40%);">+     *   octets MUST be included if needd to pad until the next 32-bit</span><br><span style="color: hsl(120, 100%, 40%);">+     *   boundary. Note that this padding is separate from that indicated by</span><br><span style="color: hsl(120, 100%, 40%);">+       *   the P bit in the RTCP header.</span><br><span style="color: hsl(120, 100%, 40%);">+     *</span><br><span style="color: hsl(120, 100%, 40%);">+     * These bytes will already be zeroed out during array initialization.</span><br><span style="color: hsl(120, 100%, 40%);">+         */</span><br><span style="color: hsl(120, 100%, 40%);">+   len += (sdes_packet_len_rounded - sdes_packet_len_bytes);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 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%);">+static int ast_rtcp_generate_nack(struct ast_rtp_instance *instance, unsigned char *rtcpheader)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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%);">+    int packet_len;</span><br><span style="color: hsl(120, 100%, 40%);">+       int blp_index;</span><br><span style="color: hsl(120, 100%, 40%);">+        int current_seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+    int seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int fci;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!rtp || !rtp->rtcp) {</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%);">+   if (ast_sockaddr_isnull(&rtp->rtcp->them)) {</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%);">+   current_seqno = rtp->expectedrxseqno;</span><br><span style="color: hsl(120, 100%, 40%);">+      seqno = rtp->lastrxseqno;</span><br><span style="color: hsl(120, 100%, 40%);">+  packet_len = 12; /* The header length is 12 (version line, packet source SSRC, media source SSRC) */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Get the missing sequence numbers for the FCI section of the NACK request */</span><br><span style="color: hsl(120, 100%, 40%);">+        for (blp_index = 0, fci = 0; current_seqno < seqno; current_seqno++, blp_index++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                int *missing_seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         missing_seqno = AST_VECTOR_GET_CMP(&rtp->missing_seqno, current_seqno,</span><br><span style="color: hsl(120, 100%, 40%);">+                         find_by_value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!missing_seqno) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</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 hit the max blp size, reset */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (blp_index >= 17) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     put_unaligned_uint32(rtcpheader + packet_len, htonl(fci));</span><br><span style="color: hsl(120, 100%, 40%);">+                    fci = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                      blp_index = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                        packet_len += 4;</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 (blp_index == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 fci |= (current_seqno << 16);</span><br><span style="color: hsl(120, 100%, 40%);">+           } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      fci |= (1 << (blp_index - 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%);">+   put_unaligned_uint32(rtcpheader + packet_len, htonl(fci));</span><br><span style="color: hsl(120, 100%, 40%);">+    packet_len += 4;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Length MUST be 2+n, where n is the number of NACKs. Same as length in words minus 1 */</span><br><span style="color: hsl(120, 100%, 40%);">+     put_unaligned_uint32(rtcpheader, htonl((2 << 30) | (AST_RTP_RTCP_FMT_NACK << 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%);">+      return packet_len;</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span>@@ -4276,6 +4374,15 @@</span><br><span>  struct ast_rtp_instance *instance = (struct ast_rtp_instance *) data;</span><br><span>        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);</span><br><span>   int res;</span><br><span style="color: hsl(120, 100%, 40%);">+      int sr = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   int packet_len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   int ice;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ast_sockaddr remote_address = { { 0, } };</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned char *rtcpheader;</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned char bdata[AST_UUID_STR_LEN + 128] = ""; /* More than enough */</span><br><span style="color: hsl(120, 100%, 40%);">+    RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_rtp_rtcp_report_alloc(rtp->themssrc_valid ? 1 : 0),</span><br><span style="color: hsl(120, 100%, 40%);">+                    ao2_cleanup);</span><br><span> </span><br><span>    if (!rtp || !rtp->rtcp || rtp->rtcp->schedid == -1) {</span><br><span>               ao2_ref(instance, -1);</span><br><span>@@ -4283,13 +4390,44 @@</span><br><span>     }</span><br><span> </span><br><span>        ao2_lock(instance);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (rtp->txcount > rtp->rtcp->lastsrtxcount) {</span><br><span style="color: hsl(0, 100%, 40%);">-              /* Send an SR */</span><br><span style="color: hsl(0, 100%, 40%);">-                res = ast_rtcp_write_report(instance, 1);</span><br><span style="color: hsl(0, 100%, 40%);">-       } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                /* Send an RR */</span><br><span style="color: hsl(0, 100%, 40%);">-                res = ast_rtcp_write_report(instance, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+     rtcpheader = bdata;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ res = ast_rtcp_generate_report(instance, rtcpheader, rtcp_report, &sr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res == 0 || res == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_debug(1, "Failed to add %s report to RTCP packet!\n", sr ? "SR" : "RR");</span><br><span style="color: hsl(120, 100%, 40%);">+            goto cleanup;</span><br><span>        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   packet_len += res;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  res = ast_rtcp_generate_sdes(instance, rtcpheader + packet_len, rtcp_report);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (res == 0 || res == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_debug(1, "Failed to add SDES to RTCP packet!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               goto cleanup;</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%);">+   packet_len += res;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rtp->bundled) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_rtp_instance_get_remote_address(instance, &remote_address);</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</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%);">+</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 %s transmission error to %s, rtcp halted %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            sr ? "SR" : "RR",</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_sockaddr_stringify(&rtp->rtcp->them),</span><br><span style="color: hsl(120, 100%, 40%);">+                           strerror(errno));</span><br><span style="color: hsl(120, 100%, 40%);">+             res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_rtcp_calculate_sr_rr_statistics(instance, rtcp_report, remote_address, ice, sr);</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%);">+cleanup:</span><br><span>        ao2_unlock(instance);</span><br><span> </span><br><span>    if (!res) {</span><br><span>@@ -4872,7 +5010,7 @@</span><br><span>  return &rtp->f;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark, struct frame_list *frames)</span><br><span style="color: hsl(120, 100%, 40%);">+static void process_dtmf_rfc2833(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, int payloadtype, int mark, struct frame_list *frames)</span><br><span> {</span><br><span>      struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);</span><br><span>   struct ast_sockaddr remote_address = { {0,} };</span><br><span>@@ -5007,7 +5145,7 @@</span><br><span>       return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_frame *process_dtmf_cisco(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, int payloadtype, int mark)</span><br><span> {</span><br><span>     struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);</span><br><span>   unsigned int event, flags, power;</span><br><span>@@ -5087,7 +5225,7 @@</span><br><span>    return f;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct ast_sockaddr *addr, int payloadtype, int mark)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_frame *process_cn_rfc3389(struct ast_rtp_instance *instance, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, int payloadtype, int mark)</span><br><span> {</span><br><span>   struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);</span><br><span> </span><br><span>@@ -5438,10 +5576,12 @@</span><br><span> #define RTCP_FB_REMB_BLOCK_WORD_LENGTH 4</span><br><span> #define RTCP_FB_NACK_BLOCK_WORD_LENGTH 2</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, struct ast_srtp *srtp,</span><br><span style="color: hsl(120, 100%, 40%);">+      const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr)</span><br><span> {</span><br><span>  struct ast_rtp_instance *transport = instance;</span><br><span>       struct ast_rtp *transport_rtp = ast_rtp_instance_get_data(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+  int len = size;</span><br><span>      unsigned int *rtcpheader = (unsigned int *)(rtcpdata);</span><br><span>       unsigned int packetwords;</span><br><span>    unsigned int position;</span><br><span>@@ -5451,10 +5591,16 @@</span><br><span>     struct ast_rtp_rtcp_report_block *report_block;</span><br><span>      struct ast_frame *f = &ast_null_frame;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  packetwords = size / 4;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* If this is encrypted then decrypt the payload */</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((*rtcpheader & 0xC0) && res_srtp && srtp && res_srtp->unprotect(</span><br><span style="color: hsl(120, 100%, 40%);">+               srtp, rtcpheader, &len, 1) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+     return &ast_null_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ast_debug(1, "Got RTCP report of %zu bytes from %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                size, ast_sockaddr_stringify(addr));</span><br><span style="color: hsl(120, 100%, 40%);">+  packetwords = len / 4;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_debug(1, "Got RTCP report of %d bytes from %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               len, ast_sockaddr_stringify(addr));</span><br><span> </span><br><span>      /*</span><br><span>    * Validate the RTCP packet according to an adapted and slightly</span><br><span>@@ -5899,6 +6045,7 @@</span><br><span> static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)</span><br><span> {</span><br><span>   struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+    struct ast_srtp *srtp = ast_rtp_instance_get_srtp(instance, 1);</span><br><span>      struct ast_sockaddr addr;</span><br><span>    unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET];</span><br><span>  unsigned char *read_area = rtcpdata + AST_FRIENDLY_OFFSET;</span><br><span>@@ -5950,7 +6097,7 @@</span><br><span>           return &ast_null_frame;</span><br><span>  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return ast_rtcp_interpret(instance, read_area, res, &addr);</span><br><span style="color: hsl(120, 100%, 40%);">+       return ast_rtcp_interpret(instance, srtp, read_area, res, &addr);</span><br><span> }</span><br><span> </span><br><span> /*! \pre instance is locked */</span><br><span>@@ -6123,20 +6270,304 @@</span><br><span>  }</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_frame *ast_rtp_interpret(struct ast_rtp_instance *instance, struct ast_srtp *srtp,</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct ast_sockaddr *remote_address, unsigned char *read_area, int length, int prev_seqno)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int *rtpheader = (unsigned int*)(read_area);</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%);">+    struct ast_rtp_instance *instance1;</span><br><span style="color: hsl(120, 100%, 40%);">+   int res = length, hdrlen = 12, seqno, timestamp, payloadtype, padding, mark, ext, cc;</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct ast_rtp_payload_type *, payload, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct frame_list frames;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* If this payload is encrypted then decrypt it using the given SRTP instance */</span><br><span style="color: hsl(120, 100%, 40%);">+      if ((*read_area & 0xC0) && res_srtp && srtp && res_srtp->unprotect(</span><br><span style="color: hsl(120, 100%, 40%);">+                srtp, read_area, &res, 0) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return &ast_null_frame;</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 are currently sending DTMF to the remote party send a continuation packet */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rtp->sending_digit) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_rtp_dtmf_continuation(instance);</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%);">+   /* Pull out the various other fields we will need */</span><br><span style="color: hsl(120, 100%, 40%);">+  seqno = ntohl(rtpheader[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+  payloadtype = (seqno & 0x7f0000) >> 16;</span><br><span style="color: hsl(120, 100%, 40%);">+     padding = seqno & (1 << 29);</span><br><span style="color: hsl(120, 100%, 40%);">+        mark = seqno & (1 << 23);</span><br><span style="color: hsl(120, 100%, 40%);">+   ext = seqno & (1 << 28);</span><br><span style="color: hsl(120, 100%, 40%);">+    cc = (seqno & 0xF000000) >> 24;</span><br><span style="color: hsl(120, 100%, 40%);">+     seqno &= 0xffff;</span><br><span style="color: hsl(120, 100%, 40%);">+  timestamp = ntohl(rtpheader[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    AST_LIST_HEAD_INIT_NOLOCK(&frames);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Remove any padding bytes that may be present */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (padding) {</span><br><span style="color: hsl(120, 100%, 40%);">+                res -= read_area[res - 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%);">+   /* Skip over any CSRC fields */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (cc) {</span><br><span style="color: hsl(120, 100%, 40%);">+             hdrlen += cc * 4;</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%);">+   /* Look for any RTP extensions, currently we do not support any */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ext) {</span><br><span style="color: hsl(120, 100%, 40%);">+            hdrlen += (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2;</span><br><span style="color: hsl(120, 100%, 40%);">+               hdrlen += 4;</span><br><span style="color: hsl(120, 100%, 40%);">+          if (DEBUG_ATLEAST(1)) {</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%);">+                 if (profile == 0x505a) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              ast_log(LOG_DEBUG, "Found Zfone extension in RTP stream - zrtp - not supported.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                        } else if (profile != 0xbede) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               /* SDP negotiated RTP extensions can not currently be output in logging */</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_log(LOG_DEBUG, "Found unknown RTP Extensions %x\n", profile);</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%);">+   /* Make sure after we potentially mucked with the header length that it is once again valid */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (res < hdrlen) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d\n", res, hdrlen);</span><br><span style="color: hsl(120, 100%, 40%);">+                return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</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%);">+   rtp->rxcount++;</span><br><span style="color: hsl(120, 100%, 40%);">+    rtp->rxoctetcount += (res - hdrlen);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rtp->rxcount == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           rtp->seedrxseqno = 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%);">+   /* Do not schedule RR if RTCP isn't run */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rtp->rtcp && !ast_sockaddr_isnull(&rtp->rtcp->them) && rtp->rtcp->schedid < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* Schedule transmission of Receiver Report */</span><br><span style="color: hsl(120, 100%, 40%);">+                ao2_ref(instance, +1);</span><br><span style="color: hsl(120, 100%, 40%);">+                rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (rtp->rtcp->schedid < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        ao2_ref(instance, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_log(LOG_WARNING, "scheduling RTCP transmission failed.\n");</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 ((int)rtp->lastrxseqno - (int)seqno  > 100) /* if so it would indicate that the sender cycled; allow for misordering */</span><br><span style="color: hsl(120, 100%, 40%);">+              rtp->cycles += RTP_SEQ_MOD;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* If we are directly bridged to another instance send the audio directly out,</span><br><span style="color: hsl(120, 100%, 40%);">+         * but only after updating core information about the received traffic so that</span><br><span style="color: hsl(120, 100%, 40%);">+         * outgoing RTCP reflects it.</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   instance1 = ast_rtp_instance_get_bridged(instance);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (instance1</span><br><span style="color: hsl(120, 100%, 40%);">+         && !bridge_p2p_rtp_write(instance, instance1, rtpheader, res, hdrlen)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct timeval rxtime;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct ast_frame *f;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Update statistics for jitter so they are correct in RTCP */</span><br><span style="color: hsl(120, 100%, 40%);">+                calc_rxstamp(&rxtime, rtp, timestamp, mark);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            /* When doing P2P we don't need to raise any frames about SSRC change to the core */</span><br><span style="color: hsl(120, 100%, 40%);">+              while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list)) != NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_frfree(f);</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%);">+           return &ast_null_frame;</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%);">+   payload = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payloadtype);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Unknown payload type. */</span><br><span style="color: hsl(120, 100%, 40%);">+           return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</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 payload is not actually an Asterisk one but a special one pass it off to the respective handler */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!payload->asterisk_format) {</span><br><span style="color: hsl(120, 100%, 40%);">+           struct ast_frame *f = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (payload->rtp_code == AST_RTP_DTMF) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* process_dtmf_rfc2833 may need to return multiple frames. We do this</span><br><span style="color: hsl(120, 100%, 40%);">+                         * by passing the pointer to the frame list to it so that the method</span><br><span style="color: hsl(120, 100%, 40%);">+                   * can append frames to the list as needed.</span><br><span style="color: hsl(120, 100%, 40%);">+                    */</span><br><span style="color: hsl(120, 100%, 40%);">+                   process_dtmf_rfc2833(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, payloadtype, mark, &frames);</span><br><span style="color: hsl(120, 100%, 40%);">+           } else if (payload->rtp_code == AST_RTP_CISCO_DTMF) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      f = process_dtmf_cisco(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, payloadtype, mark);</span><br><span style="color: hsl(120, 100%, 40%);">+              } else if (payload->rtp_code == AST_RTP_CN) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      f = process_cn_rfc3389(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, payloadtype, mark);</span><br><span style="color: hsl(120, 100%, 40%);">+              } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            payloadtype,</span><br><span style="color: hsl(120, 100%, 40%);">+                          ast_sockaddr_stringify(remote_address));</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 (f) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      AST_LIST_INSERT_TAIL(&frames, f, frame_list);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             /* Even if no frame was returned by one of the above methods,</span><br><span style="color: hsl(120, 100%, 40%);">+          * we may have a frame to return in our frame list</span><br><span style="color: hsl(120, 100%, 40%);">+             */</span><br><span style="color: hsl(120, 100%, 40%);">+           return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</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_replace(rtp->lastrxformat, payload->format);</span><br><span style="color: hsl(120, 100%, 40%);">+        ao2_replace(rtp->f.subclass.format, payload->format);</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (ast_format_get_type(rtp->f.subclass.format)) {</span><br><span style="color: hsl(120, 100%, 40%);">+     case AST_MEDIA_TYPE_AUDIO:</span><br><span style="color: hsl(120, 100%, 40%);">+            rtp->f.frametype = AST_FRAME_VOICE;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AST_MEDIA_TYPE_VIDEO:</span><br><span style="color: hsl(120, 100%, 40%);">+            rtp->f.frametype = AST_FRAME_VIDEO;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AST_MEDIA_TYPE_TEXT:</span><br><span style="color: hsl(120, 100%, 40%);">+             rtp->f.frametype = AST_FRAME_TEXT;</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case AST_MEDIA_TYPE_IMAGE:</span><br><span style="color: hsl(120, 100%, 40%);">+            /* Fall through */</span><br><span style="color: hsl(120, 100%, 40%);">+    default:</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));</span><br><span style="color: hsl(120, 100%, 40%);">+            return &ast_null_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     rtp->rxseqno = seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rtp->dtmf_timeout && rtp->dtmf_timeout < timestamp) {</span><br><span style="color: hsl(120, 100%, 40%);">+            rtp->dtmf_timeout = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rtp->resp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   struct ast_frame *f;</span><br><span style="color: hsl(120, 100%, 40%);">+                  f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+                       f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0));</span><br><span style="color: hsl(120, 100%, 40%);">+                     rtp->resp = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                     rtp->dtmf_timeout = rtp->dtmf_duration = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                     AST_LIST_INSERT_TAIL(&frames, f, frame_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                     return AST_LIST_FIRST(&frames);</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%);">+   rtp->lastrxts = timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rtp->f.src = "RTP";</span><br><span style="color: hsl(120, 100%, 40%);">+      rtp->f.mallocd = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        rtp->f.datalen = res - hdrlen;</span><br><span style="color: hsl(120, 100%, 40%);">+     rtp->f.data.ptr = read_area + hdrlen;</span><br><span style="color: hsl(120, 100%, 40%);">+      rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_set_flag(&rtp->f, AST_FRFLAG_HAS_SEQUENCE_NUMBER);</span><br><span style="color: hsl(120, 100%, 40%);">+ rtp->f.seqno = seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+      rtp->f.stream_num = rtp->stream_num;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if ((ast_format_cmp(rtp->f.subclass.format, ast_format_t140) == AST_FORMAT_CMP_EQUAL)</span><br><span style="color: hsl(120, 100%, 40%);">+              && ((int)seqno - (prev_seqno + 1) > 0)</span><br><span style="color: hsl(120, 100%, 40%);">+             && ((int)seqno - (prev_seqno + 1) < 10)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         unsigned char *data = rtp->f.data.ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);</span><br><span style="color: hsl(120, 100%, 40%);">+         rtp->f.datalen +=3;</span><br><span style="color: hsl(120, 100%, 40%);">+                *data++ = 0xEF;</span><br><span style="color: hsl(120, 100%, 40%);">+               *data++ = 0xBF;</span><br><span style="color: hsl(120, 100%, 40%);">+               *data = 0xBD;</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_format_cmp(rtp->f.subclass.format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) {</span><br><span style="color: hsl(120, 100%, 40%);">+         unsigned char *data = rtp->f.data.ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+             unsigned char *header_end;</span><br><span style="color: hsl(120, 100%, 40%);">+            int num_generations;</span><br><span style="color: hsl(120, 100%, 40%);">+          int header_length;</span><br><span style="color: hsl(120, 100%, 40%);">+            int len;</span><br><span style="color: hsl(120, 100%, 40%);">+              int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/</span><br><span style="color: hsl(120, 100%, 40%);">+              int x;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              ao2_replace(rtp->f.subclass.format, ast_format_t140);</span><br><span style="color: hsl(120, 100%, 40%);">+              header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (header_end == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             header_end++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               header_length = header_end - data;</span><br><span style="color: hsl(120, 100%, 40%);">+            num_generations = header_length / 4;</span><br><span style="color: hsl(120, 100%, 40%);">+          len = header_length;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!diff) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  for (x = 0; x < num_generations; x++)</span><br><span style="color: hsl(120, 100%, 40%);">+                              len += data[x * 4 + 3];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!(rtp->f.datalen - len))</span><br><span style="color: hsl(120, 100%, 40%);">+                               return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     rtp->f.data.ptr += len;</span><br><span style="color: hsl(120, 100%, 40%);">+                    rtp->f.datalen -= len;</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (diff > num_generations && diff < 10) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       len -= 3;</span><br><span style="color: hsl(120, 100%, 40%);">+                     rtp->f.data.ptr += len;</span><br><span style="color: hsl(120, 100%, 40%);">+                    rtp->f.datalen -= len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   data = rtp->f.data.ptr;</span><br><span style="color: hsl(120, 100%, 40%);">+                    *data++ = 0xEF;</span><br><span style="color: hsl(120, 100%, 40%);">+                       *data++ = 0xBF;</span><br><span style="color: hsl(120, 100%, 40%);">+                       *data = 0xBD;</span><br><span style="color: hsl(120, 100%, 40%);">+         } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      for ( x = 0; x < num_generations - diff; x++)</span><br><span style="color: hsl(120, 100%, 40%);">+                              len += data[x * 4 + 3];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     rtp->f.data.ptr += len;</span><br><span style="color: hsl(120, 100%, 40%);">+                    rtp->f.datalen -= 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 style="color: hsl(120, 100%, 40%);">+   if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_AUDIO) {</span><br><span style="color: hsl(120, 100%, 40%);">+         rtp->f.samples = ast_codec_samples_count(&rtp->f);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (ast_format_cache_is_slinear(rtp->f.subclass.format)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 ast_frame_byteswap_be(&rtp->f);</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+             rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000);</span><br><span style="color: hsl(120, 100%, 40%);">+          rtp->f.len = rtp->f.samples / ((ast_format_get_sample_rate(rtp->f.subclass.format) / 1000));</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_VIDEO) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* Video -- samples is # of samples vs. 90000 */</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!rtp->lastividtimestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+                       rtp->lastividtimestamp = timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span style="color: hsl(120, 100%, 40%);">+             rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000);</span><br><span style="color: hsl(120, 100%, 40%);">+          rtp->f.samples = timestamp - rtp->lastividtimestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+            rtp->lastividtimestamp = timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+                rtp->f.delivery.tv_sec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                rtp->f.delivery.tv_usec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               /* Pass the RTP marker bit as bit */</span><br><span style="color: hsl(120, 100%, 40%);">+          rtp->f.subclass.frame_ending = mark ? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_TEXT) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* TEXT -- samples is # of samples vs. 1000 */</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!rtp->lastitexttimestamp)</span><br><span style="color: hsl(120, 100%, 40%);">+                      rtp->lastitexttimestamp = timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->f.samples = timestamp - rtp->lastitexttimestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+           rtp->lastitexttimestamp = timestamp;</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->f.delivery.tv_sec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                rtp->f.delivery.tv_usec = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));</span><br><span style="color: hsl(120, 100%, 40%);">+            return &ast_null_frame;</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_LIST_INSERT_TAIL(&frames, &rtp->f, frame_list);</span><br><span style="color: hsl(120, 100%, 40%);">+        return AST_LIST_FIRST(&frames);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \pre instance is locked */</span><br><span> static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp)</span><br><span> {</span><br><span>        struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);</span><br><span style="color: hsl(0, 100%, 40%);">-      struct ast_rtp_instance *instance1;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct ast_srtp *srtp;</span><br><span>       RAII_VAR(struct ast_rtp_instance *, child, NULL, rtp_instance_unlock);</span><br><span>       struct ast_sockaddr addr;</span><br><span style="color: hsl(0, 100%, 40%);">-       int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+       int res, hdrlen = 12, version, payloadtype, mark;</span><br><span>    unsigned char *read_area = rtp->rawdata + AST_FRIENDLY_OFFSET;</span><br><span>    size_t read_area_size = sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET;</span><br><span style="color: hsl(0, 100%, 40%);">-  unsigned int *rtpheader = (unsigned int*)(read_area), seqno, ssrc, timestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-   RAII_VAR(struct ast_rtp_payload_type *, payload, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int *rtpheader = (unsigned int*)(read_area), seqno, ssrc, timestamp, prev_seqno;</span><br><span>    struct ast_sockaddr remote_address = { {0,} };</span><br><span>       struct frame_list frames;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_frame *frame;</span><br><span> </span><br><span>         /* If this is actually RTCP let's hop on over and handle it */</span><br><span>   if (rtcp) {</span><br><span>@@ -6171,7 +6602,7 @@</span><br><span> </span><br><span>      /* This could be a multiplexed RTCP packet. If so, be sure to interpret it correctly */</span><br><span>      if (rtcp_mux(rtp, read_area)) {</span><br><span style="color: hsl(0, 100%, 40%);">-         return ast_rtcp_interpret(instance, read_area, res, &addr);</span><br><span style="color: hsl(120, 100%, 40%);">+               return ast_rtcp_interpret(instance, ast_rtp_instance_get_srtp(instance, 1), read_area, res, &addr);</span><br><span>      }</span><br><span> </span><br><span>        /* Make sure the data that was read in is actually enough to make up an RTP packet */</span><br><span>@@ -6222,6 +6653,9 @@</span><br><span>        /* We use the SSRC to determine what RTP instance this packet is actually for */</span><br><span>     ssrc = ntohl(rtpheader[2]);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       /* We use the SRTP data from the provided instance that it came in on, not the child */</span><br><span style="color: hsl(120, 100%, 40%);">+       srtp = ast_rtp_instance_get_srtp(instance, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     /* Determine the appropriate instance for this */</span><br><span>    child = rtp_find_instance_by_packet_source_ssrc(instance, rtp, ssrc);</span><br><span>        if (!child) {</span><br><span>@@ -6397,20 +6831,18 @@</span><br><span>              }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* If we are currently sending DTMF to the remote party send a continuation packet */</span><br><span style="color: hsl(0, 100%, 40%);">-   if (rtp->sending_digit) {</span><br><span style="color: hsl(0, 100%, 40%);">-            ast_rtp_dtmf_continuation(instance);</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>    /* Pull out the various other fields we will need */</span><br><span>         payloadtype = (seqno & 0x7f0000) >> 16;</span><br><span style="color: hsl(0, 100%, 40%);">-       padding = seqno & (1 << 29);</span><br><span>       mark = seqno & (1 << 23);</span><br><span style="color: hsl(0, 100%, 40%);">-     ext = seqno & (1 << 28);</span><br><span style="color: hsl(0, 100%, 40%);">-      cc = (seqno & 0xF000000) >> 24;</span><br><span>    seqno &= 0xffff;</span><br><span>         timestamp = ntohl(rtpheader[1]);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  if (rtp_debug_test_addr(&addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_verbose("Got  RTP packet from    %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_sockaddr_stringify(&addr),</span><br><span style="color: hsl(120, 100%, 40%);">+                            payloadtype, seqno, timestamp, res - hdrlen);</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  AST_LIST_HEAD_INIT_NOLOCK(&frames);</span><br><span> </span><br><span>  /* Only non-bundled instances can change/learn the remote's SSRC implicitly. */</span><br><span>@@ -6449,264 +6881,264 @@</span><br><span>              rtp->themssrc_valid = 1;</span><br><span>  }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Remove any padding bytes that may be present */</span><br><span style="color: hsl(0, 100%, 40%);">-      if (padding) {</span><br><span style="color: hsl(0, 100%, 40%);">-          res -= read_area[res - 1];</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Skip over any CSRC fields */</span><br><span style="color: hsl(0, 100%, 40%);">- if (cc) {</span><br><span style="color: hsl(0, 100%, 40%);">-               hdrlen += cc * 4;</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Look for any RTP extensions, currently we do not support any */</span><br><span style="color: hsl(0, 100%, 40%);">-      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(0, 100%, 40%);">-                   if (profile == 0x505a) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_log(LOG_DEBUG, "Found Zfone extension in RTP stream - zrtp - not supported.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-                  } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                                ast_log(LOG_DEBUG, "Found unknown RTP Extensions %x\n", profile);</span><br><span style="color: hsl(0, 100%, 40%);">-                     }</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Make sure after we potentially mucked with the header length that it is once again valid */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (res < hdrlen) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d\n", res, hdrlen);</span><br><span style="color: hsl(0, 100%, 40%);">-          return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       rtp->rxcount++;</span><br><span style="color: hsl(0, 100%, 40%);">-      rtp->rxoctetcount += (res - hdrlen);</span><br><span style="color: hsl(0, 100%, 40%);">- if (rtp->rxcount == 1) {</span><br><span style="color: hsl(0, 100%, 40%);">-             rtp->seedrxseqno = seqno;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* Do not schedule RR if RTCP isn't run */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (rtp->rtcp && !ast_sockaddr_isnull(&rtp->rtcp->them) && rtp->rtcp->schedid < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-              /* Schedule transmission of Receiver Report */</span><br><span style="color: hsl(0, 100%, 40%);">-          ao2_ref(instance, +1);</span><br><span style="color: hsl(0, 100%, 40%);">-          rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, instance);</span><br><span style="color: hsl(0, 100%, 40%);">-         if (rtp->rtcp->schedid < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  ao2_ref(instance, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-                  ast_log(LOG_WARNING, "scheduling RTCP transmission failed.\n");</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-       if ((int)rtp->lastrxseqno - (int)seqno  > 100) /* if so it would indicate that the sender cycled; allow for misordering */</span><br><span style="color: hsl(0, 100%, 40%);">-                rtp->cycles += RTP_SEQ_MOD;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>       prev_seqno = rtp->lastrxseqno;</span><br><span>    rtp->lastrxseqno = seqno;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      if (!rtp->recv_buffer) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* If there is no receive buffer then we can pass back the frame directly */</span><br><span style="color: hsl(120, 100%, 40%);">+          return ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (rtp->expectedrxseqno == -1 || seqno == rtp->expectedrxseqno) {</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->expectedrxseqno = seqno + 1;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        /* If we are directly bridged to another instance send the audio directly out,</span><br><span style="color: hsl(0, 100%, 40%);">-   * but only after updating core information about the received traffic so that</span><br><span style="color: hsl(0, 100%, 40%);">-   * outgoing RTCP reflects it.</span><br><span style="color: hsl(0, 100%, 40%);">-    */</span><br><span style="color: hsl(0, 100%, 40%);">-     instance1 = ast_rtp_instance_get_bridged(instance);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (instance1</span><br><span style="color: hsl(0, 100%, 40%);">-           && !bridge_p2p_rtp_write(instance, instance1, rtpheader, res, hdrlen)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                struct timeval rxtime;</span><br><span style="color: hsl(0, 100%, 40%);">-          struct ast_frame *f;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            /* Update statistics for jitter so they are correct in RTCP */</span><br><span style="color: hsl(0, 100%, 40%);">-          calc_rxstamp(&rxtime, rtp, timestamp, mark);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                /* When doing P2P we don't need to raise any frames about SSRC change to the core */</span><br><span style="color: hsl(0, 100%, 40%);">-                while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list)) != NULL) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   ast_frfree(f);</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               return &ast_null_frame;</span><br><span style="color: hsl(0, 100%, 40%);">-     }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (rtp_debug_test_addr(&addr)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           ast_verbose("Got  RTP packet from    %s (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6d)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                      ast_sockaddr_stringify(&addr),</span><br><span style="color: hsl(0, 100%, 40%);">-                      payloadtype, seqno, timestamp,res - hdrlen);</span><br><span style="color: hsl(0, 100%, 40%);">-        }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       payload = ast_rtp_codecs_get_payload(ast_rtp_instance_get_codecs(instance), payloadtype);</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!payload) {</span><br><span style="color: hsl(0, 100%, 40%);">-         /* Unknown payload type. */</span><br><span style="color: hsl(0, 100%, 40%);">-             return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       /* If the payload is not actually an Asterisk one but a special one pass it off to the respective handler */</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!payload->asterisk_format) {</span><br><span style="color: hsl(0, 100%, 40%);">-             struct ast_frame *f = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-             if (payload->rtp_code == AST_RTP_DTMF) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     /* process_dtmf_rfc2833 may need to return multiple frames. We do this</span><br><span style="color: hsl(0, 100%, 40%);">-                   * by passing the pointer to the frame list to it so that the method</span><br><span style="color: hsl(0, 100%, 40%);">-                     * can append frames to the list as needed.</span><br><span style="color: hsl(0, 100%, 40%);">-                      */</span><br><span style="color: hsl(0, 100%, 40%);">-                     process_dtmf_rfc2833(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames);</span><br><span style="color: hsl(0, 100%, 40%);">-          } else if (payload->rtp_code == AST_RTP_CISCO_DTMF) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        f = process_dtmf_cisco(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);</span><br><span style="color: hsl(0, 100%, 40%);">-             } else if (payload->rtp_code == AST_RTP_CN) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        f = process_cn_rfc3389(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);</span><br><span style="color: hsl(0, 100%, 40%);">-             } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                              payloadtype,</span><br><span style="color: hsl(0, 100%, 40%);">-                            ast_sockaddr_stringify(&remote_address));</span><br><span style="color: hsl(0, 100%, 40%);">-           }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               if (f) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        AST_LIST_INSERT_TAIL(&frames, f, frame_list);</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-               /* Even if no frame was returned by one of the above methods,</span><br><span style="color: hsl(0, 100%, 40%);">-            * we may have a frame to return in our frame list</span><br><span style="color: hsl(120, 100%, 40%);">+            /* If there are no buffered packets that will be placed after this frame then we can</span><br><span style="color: hsl(120, 100%, 40%);">+           * return it directly without duplicating it.</span><br><span>                 */</span><br><span style="color: hsl(0, 100%, 40%);">-             return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!ast_data_buffer_count(rtp->recv_buffer)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    return ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   ao2_replace(rtp->lastrxformat, payload->format);</span><br><span style="color: hsl(0, 100%, 40%);">-  ao2_replace(rtp->f.subclass.format, payload->format);</span><br><span style="color: hsl(0, 100%, 40%);">-     switch (ast_format_get_type(rtp->f.subclass.format)) {</span><br><span style="color: hsl(0, 100%, 40%);">-       case AST_MEDIA_TYPE_AUDIO:</span><br><span style="color: hsl(0, 100%, 40%);">-              rtp->f.frametype = AST_FRAME_VOICE;</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case AST_MEDIA_TYPE_VIDEO:</span><br><span style="color: hsl(0, 100%, 40%);">-              rtp->f.frametype = AST_FRAME_VIDEO;</span><br><span style="color: hsl(0, 100%, 40%);">-          break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case AST_MEDIA_TYPE_TEXT:</span><br><span style="color: hsl(0, 100%, 40%);">-               rtp->f.frametype = AST_FRAME_TEXT;</span><br><span style="color: hsl(0, 100%, 40%);">-           break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case AST_MEDIA_TYPE_IMAGE:</span><br><span style="color: hsl(0, 100%, 40%);">-              /* Fall through */</span><br><span style="color: hsl(0, 100%, 40%);">-      default:</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!AST_VECTOR_REMOVE_CMP_ORDERED(&rtp->missing_seqno, seqno, find_by_value,</span><br><span style="color: hsl(120, 100%, 40%);">+                  AST_VECTOR_ELEM_CLEANUP_NOOP)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_debug(2, "Packet with sequence number '%d' on RTP instance '%p' is no longer missing\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                seqno, instance);</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 don't have the next packet after this we can directly return the frame, as there is no</span><br><span style="color: hsl(120, 100%, 40%);">+            * chance it will be overwritten.</span><br><span style="color: hsl(120, 100%, 40%);">+              */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!ast_data_buffer_get(rtp->recv_buffer, seqno + 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   return ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_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%);">+           /* Otherwise we need to dupe the frame so that the potential processing of frames placed after</span><br><span style="color: hsl(120, 100%, 40%);">+                 * it do not overwrite the data. You may be thinking that we could just add the current packet</span><br><span style="color: hsl(120, 100%, 40%);">+                 * to the head of the frames list and avoid having to duplicate it but this would result in out</span><br><span style="color: hsl(120, 100%, 40%);">+                * of order packet processing by libsrtp which we are trying to avoid.</span><br><span style="color: hsl(120, 100%, 40%);">+                 */</span><br><span style="color: hsl(120, 100%, 40%);">+           frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, read_area, res, seqno - 1));</span><br><span style="color: hsl(120, 100%, 40%);">+           if (frame) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  AST_LIST_INSERT_TAIL(&frames, frame, frame_list);</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 any additional packets that we have buffered and that are available */</span><br><span style="color: hsl(120, 100%, 40%);">+         while (ast_data_buffer_count(rtp->recv_buffer)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct ast_rtp_rtcp_nack_payload *payload;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  payload = (struct ast_rtp_rtcp_nack_payload *)ast_data_buffer_remove(rtp->recv_buffer, rtp->expectedrxseqno);</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!payload) {</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%);">+                   frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, payload->buf, payload->size, rtp->expectedrxseqno - 1));</span><br><span style="color: hsl(120, 100%, 40%);">+                      ast_free(payload);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (!frame) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         /* If this packet can't be interpeted due to being out of memory we return what we have and assume</span><br><span style="color: hsl(120, 100%, 40%);">+                                 * that we will determine it is a missing packet later and NACK for it.</span><br><span style="color: hsl(120, 100%, 40%);">+                                */</span><br><span style="color: hsl(120, 100%, 40%);">+                           return AST_LIST_FIRST(&frames);</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_debug(2, "Pulled buffered packet with sequence number '%d' to additionally return on RTP instance '%p'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              frame->seqno, instance);</span><br><span style="color: hsl(120, 100%, 40%);">+                   AST_LIST_INSERT_TAIL(&frames, frame, frame_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                 rtp->expectedrxseqno++;</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%);">+           return AST_LIST_FIRST(&frames);</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if ((abs(seqno - rtp->expectedrxseqno) > 100) ||</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_data_buffer_count(rtp->recv_buffer) == ast_data_buffer_max(rtp->recv_buffer)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             int inserted = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* We have a large number of outstanding buffered packets or we've jumped far ahead in time.</span><br><span style="color: hsl(120, 100%, 40%);">+               * To compensate we dump what we have in the buffer and place the current packet in a logical</span><br><span style="color: hsl(120, 100%, 40%);">+          * spot. In the case of video we also require a full frame to give the decoding side a fighting</span><br><span style="color: hsl(120, 100%, 40%);">+                * chance.</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 (rtp->rtp_source_learn.stream_type == AST_MEDIA_TYPE_VIDEO) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   ast_debug(2, "Source on RTP instance '%p' has wild gap or packet loss, sending FIR\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              instance);</span><br><span style="color: hsl(120, 100%, 40%);">+                    rtp_write_rtcp_fir(instance, rtp, &remote_address);</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 (ast_data_buffer_count(rtp->recv_buffer)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct ast_rtp_rtcp_nack_payload *payload;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  payload = (struct ast_rtp_rtcp_nack_payload *)ast_data_buffer_remove_head(rtp->recv_buffer);</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (!payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               continue;</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%);">+                   /* Even when dumping the receive buffer we do our best to order things, so we ensure that the</span><br><span style="color: hsl(120, 100%, 40%);">+                  * packet we just received is processed in the correct order, so see if we need to insert it now.</span><br><span style="color: hsl(120, 100%, 40%);">+                      */</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!inserted) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              int buffer_seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                           buffer_seqno = ntohl(payload->buf[0]) & 0xffff;</span><br><span style="color: hsl(120, 100%, 40%);">+                                if (seqno < buffer_seqno) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                        frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno));</span><br><span style="color: hsl(120, 100%, 40%);">+                                  if (frame) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                          AST_LIST_INSERT_TAIL(&frames, frame, frame_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                                         rtp->expectedrxseqno = seqno + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                                          prev_seqno = seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+                                           ast_debug(2, "Inserted just received packet with sequence number '%d' in correct order on RTP instance '%p'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     seqno, instance);</span><br><span style="color: hsl(120, 100%, 40%);">+                                     }</span><br><span style="color: hsl(120, 100%, 40%);">+                                     inserted = 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%);">+                   frame = ast_frdup(ast_rtp_interpret(instance, srtp, &addr, payload->buf, payload->size, prev_seqno));</span><br><span style="color: hsl(120, 100%, 40%);">+                       if (frame) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          AST_LIST_INSERT_TAIL(&frames, frame, frame_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                         prev_seqno = frame->seqno;</span><br><span style="color: hsl(120, 100%, 40%);">+                         ast_debug(2, "Emptying queue and returning packet with sequence number '%d' from RTP instance '%p'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                      frame->seqno, instance);</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_free(payload);</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 (!inserted) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* This current packet goes after them, and we assume that packets going forward will follow</span><br><span style="color: hsl(120, 100%, 40%);">+                   * that new sequence number increment. It is okay for this to not be duplicated as it is guaranteed</span><br><span style="color: hsl(120, 100%, 40%);">+                    * to be the last packet processed right now and it is also guaranteed that it will always return</span><br><span style="color: hsl(120, 100%, 40%);">+                      * non-NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+                   */</span><br><span style="color: hsl(120, 100%, 40%);">+                   frame = ast_rtp_interpret(instance, srtp, &addr, read_area, res, prev_seqno);</span><br><span style="color: hsl(120, 100%, 40%);">+                     AST_LIST_INSERT_TAIL(&frames, frame, frame_list);</span><br><span style="color: hsl(120, 100%, 40%);">+                 rtp->expectedrxseqno = seqno + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                        ast_debug(2, "Adding just received packet with sequence number '%d' to end of dumped queue on RTP instance '%p'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                         seqno, instance);</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%);">+           /* As there is such a large gap we don't want to flood the order side with missing packets, so we</span><br><span style="color: hsl(120, 100%, 40%);">+          * give up and start anew.</span><br><span style="color: hsl(120, 100%, 40%);">+             */</span><br><span style="color: hsl(120, 100%, 40%);">+           AST_VECTOR_RESET(&rtp->missing_seqno, AST_VECTOR_ELEM_CLEANUP_NOOP);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         return AST_LIST_FIRST(&frames);</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if (seqno < rtp->expectedrxseqno) {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* If this is a packet from the past then we have received a duplicate packet, so just drop it */</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_debug(2, "Received an old packet with sequence number '%d' on RTP instance '%p', dropping it\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        seqno, instance);</span><br><span style="color: hsl(120, 100%, 40%);">+             return &ast_null_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else if (ast_data_buffer_get(rtp->recv_buffer, seqno)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* If this is a packet we already have buffered then it is a duplicate, so just drop it */</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_debug(2, "Received a duplicate transmission of packet with sequence number '%d' on RTP instance '%p', dropping it\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   seqno, instance);</span><br><span style="color: hsl(120, 100%, 40%);">+             return &ast_null_frame;</span><br><span style="color: hsl(120, 100%, 40%);">+   } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* This is an out of order packet from the future */</span><br><span style="color: hsl(120, 100%, 40%);">+          struct ast_rtp_rtcp_nack_payload *payload;</span><br><span style="color: hsl(120, 100%, 40%);">+            int difference;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_debug(2, "Received an out of order packet with sequence number '%d' from the future on RTP instance '%p'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    seqno, instance);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           payload = ast_malloc(sizeof(*payload) + res);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* If the payload can't be allocated then we can't defer this packet right now.</span><br><span style="color: hsl(120, 100%, 40%);">+                        * Instead of dumping what we have we pretend we lost this packet. It will then</span><br><span style="color: hsl(120, 100%, 40%);">+                        * get NACKed later or the existing buffer will be returned entirely. Well, we may</span><br><span style="color: hsl(120, 100%, 40%);">+                     * try since we're seemingly out of memory. It's a bad situation all around and</span><br><span style="color: hsl(120, 100%, 40%);">+                        * packets are likely to get lost anyway.</span><br><span style="color: hsl(120, 100%, 40%);">+                      */</span><br><span style="color: hsl(120, 100%, 40%);">+                   return &ast_null_frame;</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%);">+           payload->size = res;</span><br><span style="color: hsl(120, 100%, 40%);">+               memcpy(payload->buf, rtpheader, res);</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_data_buffer_put(rtp->recv_buffer, seqno, payload);</span><br><span style="color: hsl(120, 100%, 40%);">+             AST_VECTOR_REMOVE_CMP_ORDERED(&rtp->missing_seqno, seqno, find_by_value,</span><br><span style="color: hsl(120, 100%, 40%);">+                       AST_VECTOR_ELEM_CLEANUP_NOOP);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              difference = seqno - (prev_seqno + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                while (difference > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* We don't want missing sequence number duplicates. If, for some reason,</span><br><span style="color: hsl(120, 100%, 40%);">+                  * packets are really out of order, we could end up in this scenario:</span><br><span style="color: hsl(120, 100%, 40%);">+                  *</span><br><span style="color: hsl(120, 100%, 40%);">+                     * We are expecting sequence number 100</span><br><span style="color: hsl(120, 100%, 40%);">+                        * We receive sequence number 105</span><br><span style="color: hsl(120, 100%, 40%);">+                      * Sequence numbers 100 through 104 get added to the vector</span><br><span style="color: hsl(120, 100%, 40%);">+                    * We receive sequence number 101 (this section is skipped)</span><br><span style="color: hsl(120, 100%, 40%);">+                    * We receive sequence number 103</span><br><span style="color: hsl(120, 100%, 40%);">+                      * Sequence number 102 is added to the vector</span><br><span style="color: hsl(120, 100%, 40%);">+                  *</span><br><span style="color: hsl(120, 100%, 40%);">+                     * This will prevent the duplicate from being added.</span><br><span style="color: hsl(120, 100%, 40%);">+                   */</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (AST_VECTOR_GET_CMP(&rtp->missing_seqno, seqno - difference,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                find_by_value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             difference--;</span><br><span style="color: hsl(120, 100%, 40%);">+                         continue;</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_debug(2, "Added missing sequence number '%d' to RTP instance '%p'\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                           seqno - difference, instance);</span><br><span style="color: hsl(120, 100%, 40%);">+                        AST_VECTOR_ADD_SORTED(&rtp->missing_seqno, seqno - difference,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 compare_by_value);</span><br><span style="color: hsl(120, 100%, 40%);">+                    difference--;</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%);">+           /* When our data buffer is half full we assume that the packets aren't just out of order but</span><br><span style="color: hsl(120, 100%, 40%);">+               * have actually been lost. To get them back we construct and send a NACK causing the sender to</span><br><span style="color: hsl(120, 100%, 40%);">+                * retransmit them.</span><br><span style="color: hsl(120, 100%, 40%);">+            */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ast_data_buffer_count(rtp->recv_buffer) == ast_data_buffer_max(rtp->recv_buffer) / 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     int packet_len = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                   int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                  int ice;</span><br><span style="color: hsl(120, 100%, 40%);">+                      int sr;</span><br><span style="color: hsl(120, 100%, 40%);">+                       size_t data_size = AST_UUID_STR_LEN + 128 + (seqno - rtp->expectedrxseqno) / 17;</span><br><span style="color: hsl(120, 100%, 40%);">+                   RAII_VAR(unsigned char *, rtcpheader, NULL, ast_free_ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+                    RAII_VAR(struct ast_rtp_rtcp_report *, rtcp_report,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ast_rtp_rtcp_report_alloc(rtp->themssrc_valid ? 1 : 0),</span><br><span style="color: hsl(120, 100%, 40%);">+                                    ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       rtcpheader = ast_malloc(sizeof(*rtcpheader) + data_size);</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (!rtcpheader) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_debug(1, "Failed to allocate memory for NACK\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                               return &ast_null_frame;</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%);">+                   memset(rtcpheader, 0, data_size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   res = ast_rtcp_generate_report(instance, rtcpheader, rtcp_report, &sr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (res == 0 || res == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           ast_debug(1, "Failed to add %s report to NACK, stopping here\n", sr ? "SR" : "RR");</span><br><span style="color: hsl(120, 100%, 40%);">+                             return &ast_null_frame;</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%);">+                   packet_len += res;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  res = ast_rtcp_generate_nack(instance, rtcpheader + packet_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (res == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               ast_debug(1, "Failed to construct NACK, stopping here\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                          return &ast_null_frame;</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%);">+                   packet_len += res;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  res = rtcp_sendto(instance, 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_debug(1, "Failed to send NACK request out\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* Update RTCP SR/RR statistics */</span><br><span style="color: hsl(120, 100%, 40%);">+                            ast_rtcp_calculate_sr_rr_statistics(instance, rtcp_report, remote_address, ice, sr);</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_debug(2, "Sending a NACK request on RTP instance '%p' to get missing packets\n", instance);</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          return &ast_null_frame;</span><br><span>  }</span><br><span style="color: hsl(0, 100%, 40%);">-       rtp->rxseqno = seqno;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    if (rtp->dtmf_timeout && rtp->dtmf_timeout < timestamp) {</span><br><span style="color: hsl(0, 100%, 40%);">-              rtp->dtmf_timeout = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               if (rtp->resp) {</span><br><span style="color: hsl(0, 100%, 40%);">-                     struct ast_frame *f;</span><br><span style="color: hsl(0, 100%, 40%);">-                    f = create_dtmf_frame(instance, AST_FRAME_DTMF_END, 0);</span><br><span style="color: hsl(0, 100%, 40%);">-                 f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass.format)), ast_tv(0, 0));</span><br><span style="color: hsl(0, 100%, 40%);">-                       rtp->resp = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                       rtp->dtmf_timeout = rtp->dtmf_duration = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-                       AST_LIST_INSERT_TAIL(&frames, f, frame_list);</span><br><span style="color: hsl(0, 100%, 40%);">-                       return AST_LIST_FIRST(&frames);</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       rtp->lastrxts = timestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   rtp->f.src = "RTP";</span><br><span style="color: hsl(0, 100%, 40%);">-        rtp->f.mallocd = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-  rtp->f.datalen = res - hdrlen;</span><br><span style="color: hsl(0, 100%, 40%);">-       rtp->f.data.ptr = read_area + hdrlen;</span><br><span style="color: hsl(0, 100%, 40%);">-        rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;</span><br><span style="color: hsl(0, 100%, 40%);">-        ast_set_flag(&rtp->f, AST_FRFLAG_HAS_SEQUENCE_NUMBER);</span><br><span style="color: hsl(0, 100%, 40%);">-   rtp->f.seqno = seqno;</span><br><span style="color: hsl(0, 100%, 40%);">-        rtp->f.stream_num = rtp->stream_num;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      if ((ast_format_cmp(rtp->f.subclass.format, ast_format_t140) == AST_FORMAT_CMP_EQUAL)</span><br><span style="color: hsl(0, 100%, 40%);">-                && ((int)seqno - (prev_seqno + 1) > 0)</span><br><span style="color: hsl(0, 100%, 40%);">-               && ((int)seqno - (prev_seqno + 1) < 10)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           unsigned char *data = rtp->f.data.ptr;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);</span><br><span style="color: hsl(0, 100%, 40%);">-           rtp->f.datalen +=3;</span><br><span style="color: hsl(0, 100%, 40%);">-          *data++ = 0xEF;</span><br><span style="color: hsl(0, 100%, 40%);">-         *data++ = 0xBF;</span><br><span style="color: hsl(0, 100%, 40%);">-         *data = 0xBD;</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (ast_format_cmp(rtp->f.subclass.format, ast_format_t140_red) == AST_FORMAT_CMP_EQUAL) {</span><br><span style="color: hsl(0, 100%, 40%);">-           unsigned char *data = rtp->f.data.ptr;</span><br><span style="color: hsl(0, 100%, 40%);">-               unsigned char *header_end;</span><br><span style="color: hsl(0, 100%, 40%);">-              int num_generations;</span><br><span style="color: hsl(0, 100%, 40%);">-            int header_length;</span><br><span style="color: hsl(0, 100%, 40%);">-              int len;</span><br><span style="color: hsl(0, 100%, 40%);">-                int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/</span><br><span style="color: hsl(0, 100%, 40%);">-                int x;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-          ao2_replace(rtp->f.subclass.format, ast_format_t140);</span><br><span style="color: hsl(0, 100%, 40%);">-                header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);</span><br><span style="color: hsl(0, 100%, 40%);">-             if (header_end == NULL) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-               header_end++;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-           header_length = header_end - data;</span><br><span style="color: hsl(0, 100%, 40%);">-              num_generations = header_length / 4;</span><br><span style="color: hsl(0, 100%, 40%);">-            len = header_length;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            if (!diff) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    for (x = 0; x < num_generations; x++)</span><br><span style="color: hsl(0, 100%, 40%);">-                                len += data[x * 4 + 3];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 if (!(rtp->f.datalen - len))</span><br><span style="color: hsl(0, 100%, 40%);">-                         return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 rtp->f.data.ptr += len;</span><br><span style="color: hsl(0, 100%, 40%);">-                      rtp->f.datalen -= len;</span><br><span style="color: hsl(0, 100%, 40%);">-               } else if (diff > num_generations && diff < 10) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 len -= 3;</span><br><span style="color: hsl(0, 100%, 40%);">-                       rtp->f.data.ptr += len;</span><br><span style="color: hsl(0, 100%, 40%);">-                      rtp->f.datalen -= len;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                       data = rtp->f.data.ptr;</span><br><span style="color: hsl(0, 100%, 40%);">-                      *data++ = 0xEF;</span><br><span style="color: hsl(0, 100%, 40%);">-                 *data++ = 0xBF;</span><br><span style="color: hsl(0, 100%, 40%);">-                 *data = 0xBD;</span><br><span style="color: hsl(0, 100%, 40%);">-           } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                        for ( x = 0; x < num_generations - diff; x++)</span><br><span style="color: hsl(0, 100%, 40%);">-                                len += data[x * 4 + 3];</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 rtp->f.data.ptr += len;</span><br><span style="color: hsl(0, 100%, 40%);">-                      rtp->f.datalen -= len;</span><br><span style="color: hsl(0, 100%, 40%);">-               }</span><br><span style="color: hsl(0, 100%, 40%);">-       }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_AUDIO) {</span><br><span style="color: hsl(0, 100%, 40%);">-           rtp->f.samples = ast_codec_samples_count(&rtp->f);</span><br><span style="color: hsl(0, 100%, 40%);">-            if (ast_format_cache_is_slinear(rtp->f.subclass.format)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   ast_frame_byteswap_be(&rtp->f);</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(0, 100%, 40%);">-               calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);</span><br><span style="color: hsl(0, 100%, 40%);">-            /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span style="color: hsl(0, 100%, 40%);">-               rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000);</span><br><span style="color: hsl(0, 100%, 40%);">-            rtp->f.len = rtp->f.samples / ((ast_format_get_sample_rate(rtp->f.subclass.format) / 1000));</span><br><span style="color: hsl(0, 100%, 40%);">-   } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_VIDEO) {</span><br><span style="color: hsl(0, 100%, 40%);">-            /* Video -- samples is # of samples vs. 90000 */</span><br><span style="color: hsl(0, 100%, 40%);">-                if (!rtp->lastividtimestamp)</span><br><span style="color: hsl(0, 100%, 40%);">-                 rtp->lastividtimestamp = timestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);</span><br><span style="color: hsl(0, 100%, 40%);">-               rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass.format) / 1000);</span><br><span style="color: hsl(0, 100%, 40%);">-            rtp->f.samples = timestamp - rtp->lastividtimestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-              rtp->lastividtimestamp = timestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-          rtp->f.delivery.tv_sec = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-          rtp->f.delivery.tv_usec = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-         /* Pass the RTP marker bit as bit */</span><br><span style="color: hsl(0, 100%, 40%);">-            rtp->f.subclass.frame_ending = mark ? 1 : 0;</span><br><span style="color: hsl(0, 100%, 40%);">- } else if (ast_format_get_type(rtp->f.subclass.format) == AST_MEDIA_TYPE_TEXT) {</span><br><span style="color: hsl(0, 100%, 40%);">-             /* TEXT -- samples is # of samples vs. 1000 */</span><br><span style="color: hsl(0, 100%, 40%);">-          if (!rtp->lastitexttimestamp)</span><br><span style="color: hsl(0, 100%, 40%);">-                        rtp->lastitexttimestamp = timestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-         rtp->f.samples = timestamp - rtp->lastitexttimestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-             rtp->lastitexttimestamp = timestamp;</span><br><span style="color: hsl(0, 100%, 40%);">-         rtp->f.delivery.tv_sec = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-          rtp->f.delivery.tv_usec = 0;</span><br><span style="color: hsl(0, 100%, 40%);">- } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_log(LOG_WARNING, "Unknown or unsupported media type: %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                       ast_codec_media_type2str(ast_format_get_type(rtp->f.subclass.format)));</span><br><span style="color: hsl(0, 100%, 40%);">-              return &ast_null_frame;;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       AST_LIST_INSERT_TAIL(&frames, &rtp->f, frame_list);</span><br><span style="color: hsl(0, 100%, 40%);">-  return AST_LIST_FIRST(&frames);</span><br><span style="color: hsl(120, 100%, 40%);">+   return &ast_null_frame;</span><br><span> }</span><br><span> </span><br><span> /*! \pre instance is locked */</span><br><span>@@ -6857,7 +7289,10 @@</span><br><span>      } else if (property == AST_RTP_PROPERTY_ASYMMETRIC_CODEC) {</span><br><span>          rtp->asymmetric_codec = value;</span><br><span>    } else if (property == AST_RTP_PROPERTY_RETRANS_SEND) {</span><br><span style="color: hsl(0, 100%, 40%);">-         rtp->send_buffer = ast_data_buffer_alloc(ast_free_ptr, DEFAULT_RTP_BUFFER_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+           rtp->send_buffer = ast_data_buffer_alloc(ast_free_ptr, DEFAULT_RTP_SEND_BUFFER_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+      } else if (property == AST_RTP_PROPERTY_RETRANS_RECV) {</span><br><span style="color: hsl(120, 100%, 40%);">+               rtp->recv_buffer = ast_data_buffer_alloc(ast_free_ptr, DEFAULT_RTP_RECV_BUFFER_SIZE);</span><br><span style="color: hsl(120, 100%, 40%);">+              AST_VECTOR_INIT(&rtp->missing_seqno, 0);</span><br><span>      }</span><br><span> }</span><br><span> </span><br><span>diff --git a/tests/test_data_buffer.c b/tests/test_data_buffer.c</span><br><span>index 11fdc7b..93c2c06 100644</span><br><span>--- a/tests/test_data_buffer.c</span><br><span>+++ b/tests/test_data_buffer.c</span><br><span>@@ -217,6 +217,7 @@</span><br><span> AST_TEST_DEFINE(buffer_nominal)</span><br><span> {</span><br><span>        RAII_VAR(struct ast_data_buffer *, buffer, NULL, ast_data_buffer_free_wrapper);</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(struct mock_payload *, removed_payload, NULL, ast_free_ptr);</span><br><span>        struct mock_payload *payload;</span><br><span>        struct mock_payload *fetched_payload;</span><br><span>        int ret;</span><br><span>@@ -247,6 +248,9 @@</span><br><span>                               "Failed to allocate memory for payload %d", i);</span><br><span> </span><br><span>                ret = ast_data_buffer_put(buffer, i, payload);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ret) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_free(payload);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span> </span><br><span>                ast_test_validate(test, ret == 0,</span><br><span>                            "Failed to add payload %d to buffer", i);</span><br><span>@@ -268,7 +272,11 @@</span><br><span>           ast_test_validate(test, payload != NULL,</span><br><span>                             "Failed to allocate memory for payload %d", i + BUFFER_MAX_NOMINAL);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+            payload->id = i;</span><br><span>          ret = ast_data_buffer_put(buffer, i + BUFFER_MAX_NOMINAL, payload);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ret) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    ast_free(payload);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span> </span><br><span>                ast_test_validate(test, ret == 0,</span><br><span>                            "Failed to add payload %d to buffer", i + BUFFER_MAX_NOMINAL);</span><br><span>@@ -289,6 +297,30 @@</span><br><span>                              "Failed to get payload at position %d during second loop", i + BUFFER_MAX_NOMINAL);</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ removed_payload = (struct mock_payload *)ast_data_buffer_remove_head(buffer);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_test_validate(test, removed_payload != NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "Failed to get the payload at the HEAD of the buffer");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_test_validate(test, ast_data_buffer_count(buffer) == BUFFER_MAX_NOMINAL - 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "Removing payload from HEAD of buffer did not decrease buffer size");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_test_validate(test, removed_payload->id == 1,</span><br><span style="color: hsl(120, 100%, 40%);">+                  "Removing payload from HEAD of buffer did not return expected payload");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_free(removed_payload);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  removed_payload = (struct mock_payload *)ast_data_buffer_remove(buffer, BUFFER_MAX_NOMINAL * 2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_test_validate(test, removed_payload != NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "Failed to get payload at position %d from buffer", BUFFER_MAX_NOMINAL * 2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_test_validate(test, ast_data_buffer_count(buffer) == BUFFER_MAX_NOMINAL - 2,</span><br><span style="color: hsl(120, 100%, 40%);">+                      "Removing payload from buffer did not decrease buffer size");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ast_test_validate(test, removed_payload->id == BUFFER_MAX_NOMINAL,</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Removing payload from buffer did not return expected payload");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         return AST_TEST_PASS;</span><br><span> }</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/9224">change 9224</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/9224"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 15 </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Idab644b08a1593659c92cda64132ccc203fe991d </div>
<div style="display:none"> Gerrit-Change-Number: 9224 </div>
<div style="display:none"> Gerrit-PatchSet: 7 </div>
<div style="display:none"> Gerrit-Owner: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </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-Reviewer: Matthew Fredrickson <creslin@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>