<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>