<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][17339] </title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=17339">17339</a></dd>
<dt>Author</dt> <dd>brian</dd>
<dt>Date</dt> <dd>2010-04-20 11:08:39 -0500 (Tue, 20 Apr 2010)</dd>
</dl>
<h3>Log Message</h3>
<pre><a href="http://jira.freeswitch.org/browse/FSRTP-14">FSRTP-14</a></pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#freeswitchtrunksrcincludeswitchh">freeswitch/trunk/src/include/switch.h</a></li>
<li><a href="#freeswitchtrunksrcincludeswitch_rtph">freeswitch/trunk/src/include/switch_rtp.h</a></li>
<li><a href="#freeswitchtrunksrcincludeswitch_typesh">freeswitch/trunk/src/include/switch_types.h</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiamod_sofiac">freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiamod_sofiah">freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiasofiac">freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_sofiasofia_gluec">freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c</a></li>
<li><a href="#freeswitchtrunksrcswitch_eventc">freeswitch/trunk/src/switch_event.c</a></li>
<li><a href="#freeswitchtrunksrcswitch_rtpc">freeswitch/trunk/src/switch_rtp.c</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#freeswitchtrunksrcincludeswitch_rtcp_frameh">freeswitch/trunk/src/include/switch_rtcp_frame.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchtrunksrcincludeswitchh"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/include/switch.h (17338 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/include/switch.h        2010-04-19 19:42:41 UTC (rev 17338)
+++ freeswitch/trunk/src/include/switch.h        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -116,6 +116,7 @@
</span><span class="cx"> #include "switch_utils.h"
</span><span class="cx"> #include "switch_caller.h"
</span><span class="cx"> #include "switch_frame.h"
</span><ins>+#include "switch_rtcp_frame.h"
</ins><span class="cx"> #include "switch_module_interfaces.h"
</span><span class="cx"> #include "switch_channel.h"
</span><span class="cx"> #include "switch_buffer.h"
</span></span></pre></div>
<a id="freeswitchtrunksrcincludeswitch_rtcp_frameh"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/include/switch_rtcp_frame.h (0 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/include/switch_rtcp_frame.h         (rev 0)
+++ freeswitch/trunk/src/include/switch_rtcp_frame.h        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2009, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Sherwin Sim
+ *
+ *
+ * switch_rtcp_frame.h -- RTCP Frame Structure
+ *
+ */
+/*! \file switch_rtcp_frame.h
+ \brief RTCP Frame Structure
+*/
+
+#ifndef SWITCH_RTCP_FRAME_H
+#define SWITCH_RTCP_FRAME_H
+
+#include <switch.h>
+
+SWITCH_BEGIN_EXTERN_C
+/*! \brief An abstraction of a rtcp frame */
+        struct switch_rtcp_frame {
+
+        uint16_t report_count;
+
+        uint16_t packet_type;
+
+        uint32_t ssrc;
+
+        uint32_t ntp_msw;
+
+        uint32_t ntp_lsw;
+
+        uint32_t timestamp;
+
+        uint32_t packet_count;
+
+        uint32_t octect_count;
+
+};
+
+SWITCH_END_EXTERN_C
+#endif
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
</ins></span></pre></div>
<a id="freeswitchtrunksrcincludeswitch_rtph"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/include/switch_rtp.h (17338 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/include/switch_rtp.h        2010-04-19 19:42:41 UTC (rev 17338)
+++ freeswitch/trunk/src/include/switch_rtp.h        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx">
</span><span class="cx"> SWITCH_BEGIN_EXTERN_C
</span><span class="cx"> #define SWITCH_RTP_MAX_BUF_LEN 16384
</span><ins>+#define SWITCH_RTCP_MAX_BUF_LEN 16384
</ins><span class="cx"> #define SWITCH_RTP_MAX_CRYPTO_LEN 64
</span><span class="cx"> #define SWITCH_RTP_KEY_LEN 30
</span><span class="cx"> #define SWITCH_RTP_CRYPTO_KEY_32 "AES_CM_128_HMAC_SHA1_32"
</span><span class="lines">@@ -214,6 +215,13 @@
</span><span class="cx"> SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin);
</span><span class="cx">
</span><span class="cx"> /*!
</span><ins>+ \brief Activate sending RTCP Sender Reports (SR's)
+ \param send_rate interval in milliseconds to send at
+ \return SWITCH_STATUS_SUCCESS
+*/
+SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_session, int send_rate);
+
+/*!
</ins><span class="cx"> \brief Acvite a jitter buffer on an RTP session
</span><span class="cx"> \param rtp_session the rtp session
</span><span class="cx"> \param queue_frames the number of frames to delay
</span><span class="lines">@@ -347,6 +355,15 @@
</span><span class="cx"> */
</span><span class="cx"> SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp_session, switch_frame_t *frame, switch_io_flag_t io_flags);
</span><span class="cx">
</span><ins>+
+/*!
+ \brief Read RTCP data from a given RTP session without copying
+ \param rtp_session the RTP session to read from
+ \param frame an RTCP frame to populate with information
+ \return the number of bytes read
+*/
+SWITCH_DECLARE(switch_status_t) switch_rtcp_zerocopy_read_frame(switch_rtp_t *rtp_session, switch_rtcp_frame_t *frame);
+
</ins><span class="cx"> SWITCH_DECLARE(void) rtp_flush_read_buffer(switch_rtp_t *rtp_session, switch_rtp_flush_t flush);
</span><span class="cx">
</span><span class="cx"> /*!
</span></span></pre></div>
<a id="freeswitchtrunksrcincludeswitch_typesh"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/include/switch_types.h (17338 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/include/switch_types.h        2010-04-19 19:42:41 UTC (rev 17338)
+++ freeswitch/trunk/src/include/switch_types.h        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -534,7 +534,8 @@
</span><span class="cx">         SWITCH_ZRTP_FLAG_SECURE_MITM_RECV = (1 << 26),
</span><span class="cx">         SWITCH_RTP_FLAG_DEBUG_RTP_READ = (1 << 27),
</span><span class="cx">         SWITCH_RTP_FLAG_DEBUG_RTP_WRITE = (1 << 28),
</span><del>-        SWITCH_RTP_FLAG_VIDEO = (1 << 29)
</del><ins>+        SWITCH_RTP_FLAG_VIDEO = (1 << 29),
+        SWITCH_RTP_FLAG_ENABLE_RTCP = (1 << 30)
</ins><span class="cx"> } switch_rtp_flag_enum_t;
</span><span class="cx"> typedef uint32_t switch_rtp_flag_t;
</span><span class="cx">
</span><span class="lines">@@ -607,6 +608,35 @@
</span><span class="cx"> #pragma pack(pop, r1)
</span><span class="cx"> #endif
</span><span class="cx">
</span><ins>+#ifdef _MSC_VER
+#pragma pack(push, r1, 1)
+#endif
+
+#if SWITCH_BYTE_ORDER == __BIG_ENDIAN
+typedef struct {
+        unsigned version:2;                        /* protocol version */
+        unsigned p:1;                                /* padding flag */
+        unsigned count:5;                        /* number of reception report blocks */
+        unsigned type:8;                        /* packet type */
+        unsigned length:16;                        /* length in 32-bit words - 1 */
+} switch_rtcp_hdr_t;
+
+#else /* BIG_ENDIAN */
+
+typedef struct {
+        unsigned count:5;                        /* number of reception report blocks */
+        unsigned p:1;                                /* padding flag */
+        unsigned version:2;                        /* protocol version */
+        unsigned type:8;                        /* packet type */
+        unsigned length:16;                        /* length in 32-bit words - 1 */
+} switch_rtcp_hdr_t;
+
+#endif
+
+#ifdef _MSC_VER
+#pragma pack(pop, r1)
+#endif
+
</ins><span class="cx"> /*!
</span><span class="cx"> \enum switch_priority_t
</span><span class="cx"> \brief Priority Indication
</span><span class="lines">@@ -1352,6 +1382,7 @@
</span><span class="cx">         SWITCH_EVENT_SERVER_DISCONNECTED,
</span><span class="cx">         SWITCH_EVENT_SEND_INFO,
</span><span class="cx">         SWITCH_EVENT_RECV_INFO,
</span><ins>+        SWITCH_EVENT_RECV_RTCP_MESSAGE,
</ins><span class="cx">         SWITCH_EVENT_CALL_SECURE,
</span><span class="cx">         SWITCH_EVENT_NAT,
</span><span class="cx">         SWITCH_EVENT_RECORD_START,
</span><span class="lines">@@ -1472,6 +1503,7 @@
</span><span class="cx"> typedef uint8_t switch_payload_t;
</span><span class="cx"> typedef struct switch_app_log switch_app_log_t;
</span><span class="cx"> typedef struct switch_rtp switch_rtp_t;
</span><ins>+typedef struct switch_rtcp switch_rtcp_t;
</ins><span class="cx"> typedef struct switch_core_session_message switch_core_session_message_t;
</span><span class="cx"> typedef struct switch_event_header switch_event_header_t;
</span><span class="cx"> typedef struct switch_event switch_event_t;
</span><span class="lines">@@ -1479,6 +1511,7 @@
</span><span class="cx"> typedef struct switch_event_node switch_event_node_t;
</span><span class="cx"> typedef struct switch_loadable_module switch_loadable_module_t;
</span><span class="cx"> typedef struct switch_frame switch_frame_t;
</span><ins>+typedef struct switch_rtcp_frame switch_rtcp_frame_t;
</ins><span class="cx"> typedef struct switch_channel switch_channel_t;
</span><span class="cx"> typedef struct switch_file_handle switch_file_handle_t;
</span><span class="cx"> typedef struct switch_core_session switch_core_session_t;
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiamod_sofiac"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c (17338 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c        2010-04-19 19:42:41 UTC (rev 17338)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -802,6 +802,7 @@
</span><span class="cx">         switch_channel_t *channel = switch_core_session_get_channel(session);
</span><span class="cx">         int payload = 0;
</span><span class="cx">         uint32_t sanity = 1000;
</span><ins>+        switch_rtcp_frame_t rtcp_frame;
</ins><span class="cx">
</span><span class="cx">         switch_assert(tech_pvt != NULL);
</span><span class="cx">
</span><span class="lines">@@ -859,7 +860,51 @@
</span><span class="cx">                                 }
</span><span class="cx">                                 return status;
</span><span class="cx">                         }
</span><ins>+                        
+                        /* Try to read an RTCP frame, if successful raise an event */
+                        if (switch_rtcp_zerocopy_read_frame(tech_pvt->rtp_session, &rtcp_frame) == SWITCH_STATUS_SUCCESS) {
+                                switch_event_t *event;
</ins><span class="cx">
</span><ins>+                                if (switch_event_create(&event, SWITCH_EVENT_RECV_RTCP_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+                                        char buf[30];
+
+                                        char* uuid = switch_core_session_get_uuid(session);
+                                        if (uuid) {
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session));
+                                        }
+
+                                        snprintf(buf, sizeof(buf), "%.8x", rtcp_frame.ssrc);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "SSRC", buf);
+
+                                        snprintf(buf, sizeof(buf), "%u", rtcp_frame.ntp_msw);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Most-Significant-Word", buf);
+
+                                        snprintf(buf, sizeof(buf), "%u", rtcp_frame.ntp_lsw);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "NTP-Least-Significant-Word", buf);
+
+                                        snprintf(buf, sizeof(buf), "%u", rtcp_frame.timestamp);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Timestamp", buf);
+
+                                        snprintf(buf, sizeof(buf), "%u", rtcp_frame.packet_count);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Sender-Packet-Count", buf);
+
+                                        snprintf(buf, sizeof(buf), "%u", rtcp_frame.octect_count);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Octect-Packet-Count", buf);
+
+                                        snprintf(buf, sizeof(buf), "%lu", tech_pvt->read_frame.timestamp);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Last-RTP-Timestamp", buf);
+
+                                        snprintf(buf, sizeof(buf), "%u", tech_pvt->read_frame.rate);
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "RTP-Rate", buf);
+
+                                        snprintf(buf, sizeof(buf), "%lu", switch_time_now());
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Capture-Time", buf);
+
+                                        switch_event_fire(&event);
+                                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "Dispatched RTCP event\n");
+                                }
+                        }
+
</ins><span class="cx">                         /* Fast PASS! */
</span><span class="cx">                         if (switch_test_flag((&tech_pvt->read_frame), SFF_PROXY_PACKET)) {
</span><span class="cx">                                 sofia_clear_flag_locked(tech_pvt, TFLAG_READING);
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiamod_sofiah"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h (17338 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h        2010-04-19 19:42:41 UTC (rev 17338)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -466,6 +466,7 @@
</span><span class="cx">         char *record_path;
</span><span class="cx">         char *presence_hosts;
</span><span class="cx">         char *challenge_realm;
</span><ins>+        char *rtcp_interval_msec;
</ins><span class="cx">         sofia_cid_type_t cid_type;
</span><span class="cx">         sofia_dtmf_t dtmf_type;
</span><span class="cx">         int auto_restart;
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiasofiac"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c (17338 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c        2010-04-19 19:42:41 UTC (rev 17338)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -2459,6 +2459,8 @@
</span><span class="cx">                                                 profile->hold_music = switch_core_strdup(profile->pool, val);
</span><span class="cx">                                         } else if (!strcasecmp(var, "outbound-proxy")) {
</span><span class="cx">                                                 profile->outbound_proxy = switch_core_strdup(profile->pool, val);
</span><ins>+                                        } else if (!strcasecmp(var, "rtcp-interval-msec")) {
+                                                profile->rtcp_interval_msec = switch_core_strdup(profile->pool, val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, "session-timeout")) {
</span><span class="cx">                                                 int v_session_timeout = atoi(val);
</span><span class="cx">                                                 if (v_session_timeout >= 0) {
</span><span class="lines">@@ -2996,6 +2998,8 @@
</span><span class="cx">                                                 profile->hold_music = switch_core_strdup(profile->pool, val);
</span><span class="cx">                                         } else if (!strcasecmp(var, "outbound-proxy")) {
</span><span class="cx">                                                 profile->outbound_proxy = switch_core_strdup(profile->pool, val);
</span><ins>+                                        } else if (!strcasecmp(var, "rtcp-interval-msec")) {
+                                                profile->rtcp_interval_msec = switch_core_strdup(profile->pool, val);
</ins><span class="cx">                                         } else if (!strcasecmp(var, "session-timeout")) {
</span><span class="cx">                                                 int v_session_timeout = atoi(val);
</span><span class="cx">                                                 if (v_session_timeout >= 0) {
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_sofiasofia_gluec"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c (17338 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c        2010-04-19 19:42:41 UTC (rev 17338)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -2725,6 +2725,15 @@
</span><span class="cx">                         switch_rtp_activate_stun_ping(tech_pvt->rtp_session, tech_pvt->stun_ip, tech_pvt->stun_port, stun_ping,
</span><span class="cx">                                                                                  (tech_pvt->stun_flags & STUN_FLAG_FUNNY) ? 1 : 0);
</span><span class="cx">                 }
</span><ins>+                
+                if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_interval_msec")) || (val = tech_pvt->profile->rtcp_interval_msec)) {
+                        int interval = atoi(val);
+                        if (interval < 100 || interval > 5000) {
+                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Invalid rtcp interval spec [%d] must be between 100 and 5000\n", interval);
+                        } else {
+                                switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval);
+                        }
+                }
</ins><span class="cx">
</span><span class="cx">                 if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec"))) {
</span><span class="cx">                         int len = atoi(val);
</span></span></pre></div>
<a id="freeswitchtrunksrcswitch_eventc"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/switch_event.c (17338 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/switch_event.c        2010-04-19 19:42:41 UTC (rev 17338)
+++ freeswitch/trunk/src/switch_event.c        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -180,6 +180,7 @@
</span><span class="cx">         "SERVER_DISCONNECTED",
</span><span class="cx">         "SEND_INFO",
</span><span class="cx">         "RECV_INFO",
</span><ins>+        "RECV_RTCP_MESSAGE",
</ins><span class="cx">         "CALL_SECURE",
</span><span class="cx">         "NAT",
</span><span class="cx">         "RECORD_START",
</span></span></pre></div>
<a id="freeswitchtrunksrcswitch_rtpc"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/switch_rtp.c (17338 => 17339)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/switch_rtp.c        2010-04-19 19:42:41 UTC (rev 17338)
+++ freeswitch/trunk/src/switch_rtp.c        2010-04-20 16:08:39 UTC (rev 17339)
</span><span class="lines">@@ -89,6 +89,11 @@
</span><span class="cx">         char body[SWITCH_RTP_MAX_BUF_LEN];
</span><span class="cx"> } rtp_msg_t;
</span><span class="cx">
</span><ins>+typedef struct {
+        switch_rtcp_hdr_t header;
+        char body[SWITCH_RTCP_MAX_BUF_LEN];
+} rtcp_msg_t;
+
</ins><span class="cx"> struct switch_rtp_vad_data {
</span><span class="cx">         switch_core_session_t *session;
</span><span class="cx">         switch_codec_t vad_codec;
</span><span class="lines">@@ -137,17 +142,18 @@
</span><span class="cx">          * families are equal, sock_input == sock_output and only one socket is
</span><span class="cx">          * used.
</span><span class="cx">          */
</span><del>-        switch_socket_t *sock_input, *sock_output;
-        switch_pollfd_t *read_pollfd;
</del><ins>+        switch_socket_t *sock_input, *sock_output, *rtcp_sock_input, *rtcp_sock_output;
+        switch_pollfd_t *read_pollfd, *rtcp_read_pollfd;
</ins><span class="cx">         switch_pollfd_t *jb_pollfd;
</span><span class="cx">
</span><del>-        switch_sockaddr_t *local_addr;
</del><ins>+        switch_sockaddr_t *local_addr, *rtcp_local_addr;
</ins><span class="cx">         rtp_msg_t send_msg;
</span><ins>+        rtcp_msg_t rtcp_send_msg;
</ins><span class="cx">
</span><del>-        switch_sockaddr_t *remote_addr;
</del><ins>+        switch_sockaddr_t *remote_addr, *rtcp_remote_addr;
</ins><span class="cx">         rtp_msg_t recv_msg;
</span><ins>+        rtcp_msg_t rtcp_recv_msg;
</ins><span class="cx">
</span><del>-
</del><span class="cx">         switch_sockaddr_t *remote_stun_addr;
</span><span class="cx">
</span><span class="cx">         uint32_t autoadj_window;
</span><span class="lines">@@ -173,12 +179,13 @@
</span><span class="cx">         switch_time_t last_write_timestamp;
</span><span class="cx">         uint32_t flags;
</span><span class="cx">         switch_memory_pool_t *pool;
</span><del>-        switch_sockaddr_t *from_addr;
</del><ins>+        switch_sockaddr_t *from_addr, *rtcp_from_addr;
</ins><span class="cx">         char *rx_host;
</span><span class="cx">         switch_port_t rx_port;
</span><span class="cx">         char *ice_user;
</span><span class="cx">         char *user_ice;
</span><span class="cx">         char *timer_name;
</span><ins>+        char *local_host_str;
</ins><span class="cx">         char *remote_host_str;
</span><span class="cx">         switch_time_t last_stun;
</span><span class="cx">         uint32_t samples_per_interval;
</span><span class="lines">@@ -186,6 +193,7 @@
</span><span class="cx">         uint32_t conf_samples_per_interval;
</span><span class="cx">         uint32_t rsamples_per_interval;
</span><span class="cx">         uint32_t ms_per_packet;
</span><ins>+        switch_port_t local_port;
</ins><span class="cx">         switch_port_t remote_port;
</span><span class="cx">         uint32_t stuncount;
</span><span class="cx">         uint32_t funny_stun;
</span><span class="lines">@@ -216,6 +224,8 @@
</span><span class="cx">         switch_rtp_stats_t stats;
</span><span class="cx">         uint32_t hot_hits;
</span><span class="cx">         uint32_t sync_packets;
</span><ins>+        int rtcp_interval;
+        switch_bool_t rtcp_fresh_frame;
</ins><span class="cx">
</span><span class="cx"> #ifdef ENABLE_ZRTP
</span><span class="cx">         zrtp_session_t *zrtp_session;
</span><span class="lines">@@ -225,10 +235,16 @@
</span><span class="cx">         int zinit;
</span><span class="cx"> #endif
</span><span class="cx">
</span><del>-#ifdef RTP_DEBUG_WRITE_DELTA
</del><span class="cx">         switch_time_t send_time;
</span><del>-#endif
</del><ins>+};
</ins><span class="cx">
</span><ins>+struct switch_rtcp_senderinfo {
+        unsigned ssrc:32;
+        unsigned ntp_msw:32;
+        unsigned ntp_lsw:32;
+        unsigned ts:32;
+        unsigned pc:32;
+        unsigned oc:32;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> static int global_init = 0;
</span><span class="lines">@@ -284,7 +300,7 @@
</span><span class="cx">         switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_stun_addr, 0, (void *) packet, &bytes);
</span><span class="cx">         rtp_session->stuncount = rtp_session->default_stuncount;
</span><span class="cx">
</span><del>- end:
</del><ins>+ end:
</ins><span class="cx">         WRITE_DEC(rtp_session);
</span><span class="cx">
</span><span class="cx">         return status;
</span><span class="lines">@@ -324,7 +340,7 @@
</span><span class="cx">         switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, (void *) packet, &bytes);
</span><span class="cx">         rtp_session->stuncount = rtp_session->default_stuncount;
</span><span class="cx">
</span><del>- end:
</del><ins>+ end:
</ins><span class="cx">         WRITE_DEC(rtp_session);
</span><span class="cx">
</span><span class="cx">         return status;
</span><span class="lines">@@ -410,7 +426,7 @@
</span><span class="cx">                 switch_socket_sendto(rtp_session->sock_output, rtp_session->from_addr, 0, (void *) rpacket, &bytes);
</span><span class="cx">         }
</span><span class="cx">
</span><del>- end:
</del><ins>+ end:
</ins><span class="cx">
</span><span class="cx">         READ_DEC(rtp_session);
</span><span class="cx">         WRITE_DEC(rtp_session);
</span><span class="lines">@@ -750,6 +766,104 @@
</span><span class="cx">         rtp_session->rtp_bugs = bugs;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+
+static switch_status_t enable_remote_rtcp_socket(switch_rtp_t *rtp_session, const char **err) {
+        
+        switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
+
+                rtp_session->rtcp_remote_addr = rtp_session->remote_addr;
+                
+                if (switch_sockaddr_info_get(&rtp_session->rtcp_remote_addr, rtp_session->remote_host_str, SWITCH_UNSPEC,
+                                                                         rtp_session->remote_port + 1, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS || !rtp_session->rtcp_remote_addr) {
+                        *err = "RTCP Remote Address Error!";
+                        return SWITCH_STATUS_FALSE;
+                }
+
+                if (rtp_session->rtcp_sock_input && switch_sockaddr_get_family(rtp_session->rtcp_remote_addr) ==
+                        switch_sockaddr_get_family(rtp_session->rtcp_local_addr)) {
+                        rtp_session->rtcp_sock_output = rtp_session->rtcp_sock_input;
+                } else {
+                        if (rtp_session->rtcp_sock_output && rtp_session->rtcp_sock_output != rtp_session->rtcp_sock_input) {
+                                switch_socket_close(rtp_session->rtcp_sock_output);
+                        }
+                        if ((status = switch_socket_create(&rtp_session->rtcp_sock_output,
+                                                                                         switch_sockaddr_get_family(rtp_session->rtcp_remote_addr),
+                                                                                         SOCK_DGRAM, 0, rtp_session->pool)) != SWITCH_STATUS_SUCCESS) {
+                                *err = "RTCP Socket Error!";
+                        }
+                }
+        } else {
+                *err = "RTCP NOT ACTIVE!";
+        }
+        
+        return status;
+        
+}
+
+static switch_status_t enable_local_rtcp_socket(switch_rtp_t *rtp_session, const char **err) {
+
+        const char *host = rtp_session->local_host_str;
+        switch_port_t port = rtp_session->local_port;
+        switch_socket_t *rtcp_new_sock = NULL, *rtcp_old_sock = NULL;
+        switch_status_t status = SWITCH_STATUS_SUCCESS;
+        char bufa[30];
+
+        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
+                if (switch_sockaddr_info_get(&rtp_session->rtcp_local_addr, host, SWITCH_UNSPEC, port+1, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) {
+                        *err = "RTCP Local Address Error!";
+                        goto done;
+                }
+                
+                if (switch_socket_create(&rtcp_new_sock, switch_sockaddr_get_family(rtp_session->rtcp_local_addr), SOCK_DGRAM, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) {
+                        *err = "RTCP Socket Error!";
+                        goto done;
+                }
+                
+                if (switch_socket_opt_set(rtcp_new_sock, SWITCH_SO_REUSEADDR, 1) != SWITCH_STATUS_SUCCESS) {
+                        *err = "RTCP Socket Error!";
+                        goto done;
+                }
+                
+                if (switch_socket_bind(rtcp_new_sock, rtp_session->rtcp_local_addr) != SWITCH_STATUS_SUCCESS) {
+                        *err = "RTCP Bind Error!";
+                        goto done;
+                }
+                
+                if (switch_sockaddr_info_get(&rtp_session->rtcp_from_addr, switch_get_addr(bufa, sizeof(bufa), rtp_session->from_addr),
+                                                                                         SWITCH_UNSPEC, switch_sockaddr_get_port(rtp_session->from_addr) + 1, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) {
+                        *err = "RTCP From Address Error!";
+                        goto done;
+                }
+
+                rtcp_old_sock = rtp_session->rtcp_sock_input;
+                rtp_session->rtcp_sock_input = rtcp_new_sock;
+                rtcp_new_sock = NULL;
+
+                switch_socket_create_pollset(&rtp_session->rtcp_read_pollfd, rtp_session->rtcp_sock_input, SWITCH_POLLIN | SWITCH_POLLERR, rtp_session->pool);
+
+ done:
+                
+                if (*err) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error allocating rtcp [%s]\n", *err);
+                        status = SWITCH_STATUS_FALSE;
+                }
+
+                if (rtcp_new_sock) {
+                        switch_socket_close(rtcp_new_sock);
+                }
+                        
+                if (rtcp_old_sock) {
+                        switch_socket_close(rtcp_old_sock);
+                }
+        } else {
+                status = SWITCH_STATUS_FALSE;
+        }
+
+        return status;
+}
+
</ins><span class="cx"> SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_session, const char *host, switch_port_t port, const char **err)
</span><span class="cx"> {
</span><span class="cx">         switch_socket_t *new_sock = NULL, *old_sock = NULL;
</span><span class="lines">@@ -781,11 +895,17 @@
</span><span class="cx">                 goto done;
</span><span class="cx">         }
</span><span class="cx">
</span><ins>+
+        rtp_session->local_host_str = switch_core_strdup(rtp_session->pool, host);
+        rtp_session->local_port = port;
+
+
</ins><span class="cx">         if (switch_sockaddr_info_get(&rtp_session->local_addr, host, SWITCH_UNSPEC, port, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                 *err = "Local Address Error!";
</span><span class="cx">                 goto done;
</span><span class="cx">         }
</span><span class="cx">
</span><ins>+        
</ins><span class="cx">         if (rtp_session->sock_input) {
</span><span class="cx">                 switch_rtp_kill_socket(rtp_session);
</span><span class="cx">         }
</span><span class="lines">@@ -799,11 +919,12 @@
</span><span class="cx">                 *err = "Socket Error!";
</span><span class="cx">                 goto done;
</span><span class="cx">         }
</span><del>-
</del><ins>+        
</ins><span class="cx">         if (switch_socket_bind(new_sock, rtp_session->local_addr) != SWITCH_STATUS_SUCCESS) {
</span><span class="cx">                 *err = "Bind Error!";
</span><span class="cx">                 goto done;
</span><span class="cx">         }
</span><ins>+
</ins><span class="cx"> #ifndef WIN32
</span><span class="cx">         len = sizeof(i);
</span><span class="cx">         switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, TRUE);
</span><span class="lines">@@ -827,12 +948,15 @@
</span><span class="cx">         }
</span><span class="cx">         switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, FALSE);
</span><span class="cx">
</span><del>-#endif
</del><span class="cx">
</span><span class="cx">         old_sock = rtp_session->sock_input;
</span><span class="cx">         rtp_session->sock_input = new_sock;
</span><span class="cx">         new_sock = NULL;
</span><span class="cx">
</span><ins>+
+#endif
+
+
</ins><span class="cx">         if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_NOBLOCK)) {
</span><span class="cx">                 switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, TRUE);
</span><span class="cx">                 switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_NOBLOCK);
</span><span class="lines">@@ -840,11 +964,18 @@
</span><span class="cx">
</span><span class="cx">         switch_socket_create_pollset(&rtp_session->read_pollfd, rtp_session->sock_input, SWITCH_POLLIN | SWITCH_POLLERR, rtp_session->pool);
</span><span class="cx">
</span><del>-        status = SWITCH_STATUS_SUCCESS;
-        *err = "Success";
</del><ins>+        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
+                if ((status = enable_local_rtcp_socket(rtp_session, err)) == SWITCH_STATUS_SUCCESS) {
+                        *err = "Success";
+                }
+        } else {
+                status = SWITCH_STATUS_SUCCESS;
+                *err = "Success";
+        }
+        
</ins><span class="cx">         switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_IO);
</span><span class="cx">
</span><del>- done:
</del><ins>+ done:
</ins><span class="cx">
</span><span class="cx">         if (new_sock) {
</span><span class="cx">                 switch_socket_close(new_sock);
</span><span class="lines">@@ -854,6 +985,7 @@
</span><span class="cx">                 switch_socket_close(old_sock);
</span><span class="cx">         }
</span><span class="cx">
</span><ins>+
</ins><span class="cx">         if (rtp_session->ready != 1) {
</span><span class="cx">                 WRITE_DEC(rtp_session);
</span><span class="cx">                 READ_DEC(rtp_session);
</span><span class="lines">@@ -901,6 +1033,7 @@
</span><span class="cx">                 return SWITCH_STATUS_FALSE;
</span><span class="cx">         }
</span><span class="cx">
</span><ins>+
</ins><span class="cx">         switch_mutex_lock(rtp_session->write_mutex);
</span><span class="cx">
</span><span class="cx">         rtp_session->remote_addr = remote_addr;
</span><span class="lines">@@ -923,6 +1056,10 @@
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx">
</span><ins>+        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {        
+                status = enable_remote_rtcp_socket(rtp_session, err);
+        }
+
</ins><span class="cx">         switch_mutex_unlock(rtp_session->write_mutex);
</span><span class="cx">
</span><span class="cx">         return status;
</span><span class="lines">@@ -985,9 +1122,12 @@
</span><span class="cx">
</span><span class="cx">         policy->next = NULL;
</span><span class="cx">         policy->key = (uint8_t *) crypto_key->key;
</span><del>-        crypto_policy_set_rtcp_default(&policy->rtcp);
-        policy->rtcp.sec_serv = sec_serv_none;
</del><span class="cx">
</span><ins>+        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
+                crypto_policy_set_rtcp_default(&policy->rtcp);
+                policy->rtcp.sec_serv = sec_serv_none;
+        }
+
</ins><span class="cx">         policy->rtp.sec_serv = sec_serv_conf_and_auth;
</span><span class="cx">         switch (direction) {
</span><span class="cx">         case SWITCH_RTP_CRYPTO_RECV:
</span><span class="lines">@@ -1136,8 +1276,9 @@
</span><span class="cx">
</span><span class="cx">         /* for from address on recvfrom calls */
</span><span class="cx">         switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool);
</span><del>-
-
</del><ins>+        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
+                switch_sockaddr_info_get(&rtp_session->rtcp_from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool);
+        }
</ins><span class="cx">         rtp_session->seq = (uint16_t) rand();
</span><span class="cx">         rtp_session->ssrc = (uint32_t) ((intptr_t) rtp_session + (uint32_t) switch_epoch_time_now(NULL));
</span><span class="cx">
</span><span class="lines">@@ -1162,6 +1303,14 @@
</span><span class="cx">
</span><span class="cx">         rtp_session->payload = payload;
</span><span class="cx">
</span><ins>+        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {        
+                rtp_session->rtcp_send_msg.header.version = 2;
+                rtp_session->rtcp_send_msg.header.p = 0;
+                rtp_session->rtcp_send_msg.header.type = 200;
+                rtp_session->rtcp_send_msg.header.count = 0;
+                rtp_session->rtcp_send_msg.header.length = htons(6);
+        }
+
</ins><span class="cx">         switch_rtp_set_interval(rtp_session, ms_per_packet, samples_per_interval);
</span><span class="cx">         rtp_session->conf_samples_per_interval = samples_per_interval;
</span><span class="cx">
</span><span class="lines">@@ -1257,7 +1406,7 @@
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx">
</span><del>- end:
</del><ins>+ end:
</ins><span class="cx">
</span><span class="cx"> #endif
</span><span class="cx">
</span><span class="lines">@@ -1316,7 +1465,7 @@
</span><span class="cx">                 goto end;
</span><span class="cx">         }
</span><span class="cx">
</span><del>- end:
</del><ins>+ end:
</ins><span class="cx">
</span><span class="cx">         if (rtp_session) {
</span><span class="cx">                 switch_mutex_unlock(rtp_session->flag_mutex);
</span><span class="lines">@@ -1382,6 +1531,19 @@
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_session, int send_rate)
+{
+        const char *err = NULL;
+        
+        switch_set_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP);
+
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTCP send rate is: %d and packet rate is: %d\n", send_rate, rtp_session->ms_per_packet);
+        rtp_session->rtcp_interval = send_rate/(rtp_session->ms_per_packet/1000);
+
+        return enable_local_rtcp_socket(rtp_session, &err) || enable_remote_rtcp_socket(rtp_session, &err);
+
+}
+
</ins><span class="cx"> SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin)
</span><span class="cx"> {
</span><span class="cx">         char ice_user[80];
</span><span class="lines">@@ -1407,6 +1569,10 @@
</span><span class="cx">         uint32_t o = UINT_MAX;
</span><span class="cx">         switch_size_t len = sizeof(o);
</span><span class="cx">         switch_socket_sendto(rtp_session->sock_input, rtp_session->local_addr, 0, (void *) &o, &len);
</span><ins>+
+        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && rtp_session->rtcp_sock_input) {
+                switch_socket_sendto(rtp_session->rtcp_sock_input, rtp_session->rtcp_local_addr, 0, (void *) &o, &len);
+        }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> SWITCH_DECLARE(void) switch_rtp_break(switch_rtp_t *rtp_session)
</span><span class="lines">@@ -1443,6 +1609,16 @@
</span><span class="cx">                 if (rtp_session->sock_output && rtp_session->sock_output != rtp_session->sock_input) {
</span><span class="cx">                         switch_socket_shutdown(rtp_session->sock_output, SWITCH_SHUTDOWN_READWRITE);
</span><span class="cx">                 }
</span><ins>+                
+                if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
+                        if (rtp_session->rtcp_sock_input) {
+                                ping_socket(rtp_session);
+                                switch_socket_shutdown(rtp_session->rtcp_sock_input, SWITCH_SHUTDOWN_READWRITE);
+                        }
+                        if (rtp_session->rtcp_sock_output && rtp_session->rtcp_sock_output != rtp_session->rtcp_sock_input) {
+                                switch_socket_shutdown(rtp_session->rtcp_sock_output, SWITCH_SHUTDOWN_READWRITE);
+                        }
+                }
</ins><span class="cx">         }
</span><span class="cx">         switch_mutex_unlock(rtp_session->flag_mutex);
</span><span class="cx"> }
</span><span class="lines">@@ -1746,7 +1922,7 @@
</span><span class="cx">                         } else {
</span><span class="cx">                                 switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
</span><span class="cx">                                                                  SWITCH_LOG_CONSOLE, "%s FLUSH\n", switch_channel_get_name(switch_core_session_get_channel(session))
</span><del>-                                        );
</del><ins>+                                                                 );
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">
</span><span class="lines">@@ -1841,18 +2017,126 @@
</span><span class="cx">         return status;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static switch_status_t read_rtcp_packet(switch_rtp_t *rtp_session, switch_size_t *bytes, switch_frame_flag_t *flags)
+{
+        switch_status_t status = SWITCH_STATUS_FALSE;
+
+        if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch_assert(bytes);
+
+        *bytes = sizeof(rtcp_msg_t);
+        if ((status = switch_socket_recvfrom(rtp_session->rtcp_from_addr, rtp_session->rtcp_sock_input, 0, (void *) &rtp_session->rtcp_recv_msg, bytes))
+                != SWITCH_STATUS_SUCCESS) {
+                *bytes = 0;
+        }
+
+        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV)) {
+                int sbytes = (int) *bytes;
+                err_status_t stat = 0;
+
+                stat = srtp_unprotect_rtcp(rtp_session->recv_ctx, &rtp_session->rtcp_recv_msg.header, &sbytes);
+                
+                if (stat) {
+                        if (++rtp_session->srtp_errs >= MAX_SRTP_ERRS) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+                                                                 "Error: SRTP RTCP unprotect failed with code %d%s\n", stat,
+                                                                 stat == err_status_replay_fail ? " (replay check failed)" : stat ==
+                                                                 err_status_auth_fail ? " (auth check failed)" : "");
+                                return SWITCH_STATUS_FALSE;
+                        } else {
+                                sbytes = 0;
+                        }
+                } else {
+                        rtp_session->srtp_errs = 0;
+                }
+                
+                *bytes = sbytes;
+                
+        }
+
+
+#ifdef ENABLE_ZRTP
+        /* ZRTP Recv */
+        if (bytes) {
+                unsigned int sbytes = (int) bytes;
+                zrtp_status_t stat = 0;
+
+                stat = zrtp_process_srtcp(rtp_session->zrtp_stream, (void *) &rtp_session->rtcp_recv_msg, &sbytes);
+
+                switch (stat) {
+                case zrtp_status_ok:
+                        bytes = sbytes;
+                        break;
+                case zrtp_status_drop:
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat);
+                        bytes = 0;
+                        goto do_continue;
+                case zrtp_status_fail:
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat);
+                        ret = -1;
+                        goto end;
+                default:
+                        break;
+                }
+        }
+#endif
+
+
+        if (*bytes) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10,"Received an RTCP packet of length %lu bytes\n", *bytes);
+                if (rtp_session->rtcp_recv_msg.header.version == 2) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10,"RTCP packet type is %d\n", rtp_session->rtcp_recv_msg.header.type);
+                        if (rtp_session->rtcp_recv_msg.header.type == 200) {
+                                struct switch_rtcp_senderinfo* sr = (struct switch_rtcp_senderinfo*)rtp_session->rtcp_recv_msg.body;
+
+                                rtp_session->rtcp_fresh_frame = 1;
+
+                                /* sender report */
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10,"Received a SR with %d report blocks, " \
+                                                                 "length in words = %d, " \
+                                                                 "SSRC = 0x%X, " \
+                                                                 "NTP MSW = %u, " \
+                                                                 "NTP LSW = %u, " \
+                                                                 "RTP timestamp = %u, " \
+                                                                 "Sender Packet Count = %u, " \
+                                                                 "Sender Octet Count = %u\n",
+                                                                 rtp_session->rtcp_recv_msg.header.count,
+                                                                 ntohs(rtp_session->rtcp_recv_msg.header.length),
+                                                                 ntohl(sr->ssrc),
+                                                                 ntohl(sr->ntp_msw),
+                                                                 ntohl(sr->ntp_lsw),
+                                                                 ntohl(sr->ts),
+                                                                 ntohl(sr->pc),
+                                                                 ntohl(sr->oc));
+                        }
+                } else {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received an unsupported RTCP packet version %d\nn", rtp_session->rtcp_recv_msg.header.version);
+                }
+                
+                status = SWITCH_STATUS_SUCCESS;
+        }
+
+        return status;
+}
+
</ins><span class="cx"> static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_type, switch_frame_flag_t *flags, switch_io_flag_t io_flags)
</span><span class="cx"> {
</span><span class="cx">         switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session");
</span><span class="cx">         switch_channel_t *channel = NULL;
</span><span class="cx">         switch_size_t bytes = 0;
</span><ins>+        switch_size_t rtcp_bytes = 0;
</ins><span class="cx">         switch_status_t status = SWITCH_STATUS_SUCCESS, poll_status = SWITCH_STATUS_SUCCESS;
</span><ins>+        switch_status_t rtcp_status = SWITCH_STATUS_SUCCESS, rtcp_poll_status = SWITCH_STATUS_SUCCESS;
</ins><span class="cx">         int check = 0;
</span><span class="cx">         int ret = -1;
</span><span class="cx">         int sleep_mss = 1000;
</span><span class="cx">         int poll_sec = 5;
</span><span class="cx">         int poll_loop = 0;
</span><span class="cx">         int fdr = 0;
</span><ins>+        int rtcp_fdr = 0;
</ins><span class="cx">         int hot_socket = 0;
</span><span class="cx">
</span><span class="cx">         if (session) {
</span><span class="lines">@@ -1904,7 +2188,7 @@
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">
</span><del>-         recvfrom:
</del><ins>+        recvfrom:
</ins><span class="cx">                 bytes = 0;
</span><span class="cx">
</span><span class="cx">                 if (!switch_rtp_ready(rtp_session)) {
</span><span class="lines">@@ -1946,6 +2230,14 @@
</span><span class="cx">                                 return_cng_frame();
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><ins>+                
+                if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && rtp_session->rtcp_read_pollfd) {
+                        rtcp_poll_status = switch_poll(rtp_session->rtcp_read_pollfd, 1, &rtcp_fdr, 0);
+                                                
+                        if (rtcp_poll_status == SWITCH_STATUS_SUCCESS) {
+                                rtcp_status = read_rtcp_packet(rtp_session, &rtcp_bytes, flags);
+                        }
+                }
</ins><span class="cx">
</span><span class="cx">                 if (bytes < 0) {
</span><span class="cx">                         ret = (int) bytes;
</span><span class="lines">@@ -2210,7 +2502,7 @@
</span><span class="cx">                  We know the real rules here, but if we enforce them, it's an interop nightmare so,
</span><span class="cx">                  we put up with as much as we can so we don't have to deal with being punished for
</span><span class="cx">                  doing it right. Nice guys finish last!
</span><del>-                 */
</del><ins>+                */
</ins><span class="cx">                 if (bytes && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) &&
</span><span class="cx">                         !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833) && rtp_session->recv_msg.header.pt == rtp_session->recv_te) {
</span><span class="cx">                         switch_size_t len = bytes - rtp_header_len;
</span><span class="lines">@@ -2324,7 +2616,7 @@
</span><span class="cx">                         return_cng_frame();
</span><span class="cx">                 }
</span><span class="cx">
</span><del>-         timer_check:
</del><ins>+        timer_check:
</ins><span class="cx">
</span><span class="cx">                 if (do_cng) {
</span><span class="cx">                         uint8_t *data = (uint8_t *) rtp_session->recv_msg.body;
</span><span class="lines">@@ -2371,7 +2663,7 @@
</span><span class="cx">
</span><span class="cx">                 break;
</span><span class="cx">
</span><del>-         do_continue:
</del><ins>+        do_continue:
</ins><span class="cx">
</span><span class="cx">                 if (!bytes && !rtp_session->timer.interval) {
</span><span class="cx">                         switch_yield(sleep_mss);
</span><span class="lines">@@ -2391,7 +2683,7 @@
</span><span class="cx">                 ret = -1;
</span><span class="cx">         }
</span><span class="cx">
</span><del>- end:
</del><ins>+ end:
</ins><span class="cx">
</span><span class="cx">         READ_DEC(rtp_session);
</span><span class="cx">
</span><span class="lines">@@ -2513,6 +2805,33 @@
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+SWITCH_DECLARE(switch_status_t) switch_rtcp_zerocopy_read_frame(switch_rtp_t *rtp_session, switch_rtcp_frame_t *frame)
+{
+
+        if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
+                return SWITCH_STATUS_FALSE;
+        }
+
+        /* A fresh frame has been found! */
+        if (rtp_session->rtcp_fresh_frame) {
+                struct switch_rtcp_senderinfo* sr = (struct switch_rtcp_senderinfo*)rtp_session->rtcp_recv_msg.body;
+                /* turn the flag off! */
+                rtp_session->rtcp_fresh_frame = 0;
+
+                frame->ssrc = ntohl(sr->ssrc);
+                frame->packet_type = rtp_session->rtcp_recv_msg.header.type;
+                frame->ntp_msw = ntohl(sr->ntp_msw);
+                frame->ntp_lsw = ntohl(sr->ntp_lsw);
+                frame->timestamp = ntohl(sr->ts);
+                frame->packet_count = ntohl(sr->pc);
+                frame->octect_count = ntohl(sr->oc);
+
+                return SWITCH_STATUS_SUCCESS;
+        }
+
+        return SWITCH_STATUS_TIMEOUT;
+}
+
</ins><span class="cx"> SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp_session, switch_frame_t *frame, switch_io_flag_t io_flags)
</span><span class="cx"> {
</span><span class="cx">         int bytes = 0;
</span><span class="lines">@@ -2625,10 +2944,11 @@
</span><span class="cx"> static int rtp_common_write(switch_rtp_t *rtp_session,
</span><span class="cx">                                                         rtp_msg_t *send_msg, void *data, uint32_t datalen, switch_payload_t payload, uint32_t timestamp, switch_frame_flag_t *flags)
</span><span class="cx"> {
</span><del>-        switch_size_t bytes;
</del><ins>+        switch_size_t bytes, rtcp_bytes;
</ins><span class="cx">         uint8_t send = 1;
</span><span class="cx">         uint32_t this_ts = 0;
</span><span class="cx">         int ret;
</span><ins>+        switch_time_t now;
</ins><span class="cx">
</span><span class="cx">         if (!switch_rtp_ready(rtp_session)) {
</span><span class="cx">                 return SWITCH_STATUS_FALSE;
</span><span class="lines">@@ -2860,16 +3180,15 @@
</span><span class="cx">                 }
</span><span class="cx"> #endif
</span><span class="cx">
</span><ins>+                now = switch_time_now();
</ins><span class="cx"> #ifdef RTP_DEBUG_WRITE_DELTA
</span><span class="cx">                 {
</span><del>-                        switch_time_t now = switch_time_now();
</del><span class="cx">                         int delta = (int) (now - rtp_session->send_time) / 1000;
</span><span class="cx">                         printf("WRITE %d delta %d\n", (int) bytes, delta);
</span><del>-                        rtp_session->send_time = now;
</del><span class="cx">                 }
</span><span class="cx"> #endif
</span><ins>+                rtp_session->send_time = now;
</ins><span class="cx">
</span><del>-
</del><span class="cx">                 if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_DEBUG_RTP_WRITE)) {
</span><span class="cx">                         switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session");
</span><span class="cx">
</span><span class="lines">@@ -2924,6 +3243,61 @@
</span><span class="cx">                 }
</span><span class="cx">
</span><span class="cx">                 rtp_session->last_write_ts = this_ts;
</span><ins>+                
+                if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) &&
+                        rtp_session->rtcp_interval && (rtp_session->stats.outbound.packet_count % rtp_session->rtcp_interval) == 0) {
+                        struct switch_rtcp_senderinfo* sr = (struct switch_rtcp_senderinfo*)rtp_session->rtcp_send_msg.body;
+
+                        sr->ssrc = send_msg->header.ssrc;
+                        sr->ntp_msw = htonl(rtp_session->send_time / 1000000 + 2208988800UL);
+                        sr->ntp_lsw = htonl(rtp_session->send_time % 1000000 * ((UINT_MAX * 1.0)/ 1000000.0));
+                        sr->ts = send_msg->header.ts;
+                        sr->pc = htonl(rtp_session->stats.outbound.packet_count);
+                        sr->oc = htonl((rtp_session->stats.outbound.raw_bytes - rtp_session->stats.outbound.packet_count * sizeof(srtp_hdr_t)));
+
+                        rtcp_bytes = sizeof(switch_rtcp_hdr_t) + sizeof(struct switch_rtcp_senderinfo);
+
+                        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) {
+                                int sbytes = (int) rtcp_bytes;
+                                int stat = srtp_protect_rtcp(rtp_session->send_ctx, &rtp_session->rtcp_send_msg.header, &sbytes);
+                                if (stat) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: SRTP RTCP protection failed with code %d\n", stat);
+                                }
+                                rtcp_bytes = sbytes;
+                        }
+
+#ifdef ENABLE_ZRTP
+                        /* ZRTP Send */
+                        if (1) {
+                                unsigned int sbytes = (int) bytes;
+                                zrtp_status_t stat = zrtp_status_fail;
+
+                                stat = zrtp_process_rtcp(rtp_session->zrtp_stream, (void *) &rtp_session->rtcp_send_msg, &sbytes);
+
+                                switch (stat) {
+                                case zrtp_status_ok:
+                                        break;
+                                case zrtp_status_drop:
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat);
+                                        ret = (int) bytes;
+                                        goto end;
+                                        break;
+                                case zrtp_status_fail:
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat);
+                                        break;
+                                default:
+                                        break;
+                                }
+
+                                bytes = sbytes;
+                        }
+#endif
+
+                        if (switch_socket_sendto(rtp_session->rtcp_sock_output, rtp_session->rtcp_remote_addr, 0,
+                                                                         (const char*)&rtp_session->rtcp_send_msg, &rtcp_bytes ) != SWITCH_STATUS_SUCCESS) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"RTCP packet not written\n");
+                        }
+                }
</ins><span class="cx">         }
</span><span class="cx">
</span><span class="cx">         if (rtp_session->remote_stun_addr) {
</span><span class="lines">@@ -2939,7 +3313,7 @@
</span><span class="cx">
</span><span class="cx">         ret = (int) bytes;
</span><span class="cx">
</span><del>- end:
</del><ins>+ end:
</ins><span class="cx">
</span><span class="cx">         WRITE_DEC(rtp_session);
</span><span class="cx">
</span><span class="lines">@@ -3031,9 +3405,9 @@
</span><span class="cx">                 send_msg = frame->packet;
</span><span class="cx">
</span><span class="cx">                 /*
</span><del>-                if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) {
-                        send_msg->header.pt = rtp_session->payload;
-                }
</del><ins>+                 if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) {
+                 send_msg->header.pt = rtp_session->payload;
+                 }
</ins><span class="cx">                 */
</span><span class="cx">
</span><span class="cx">                 if (switch_socket_sendto(rtp_session->sock_output, rtp_session->remote_addr, 0, frame->packet, &bytes) != SWITCH_STATUS_SUCCESS) {
</span><span class="lines">@@ -3131,9 +3505,9 @@
</span><span class="cx">         }
</span><span class="cx">
</span><span class="cx">         /*
</span><del>-        if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) {
-                send_msg->header.pt = rtp_session->payload;
-        }
</del><ins>+         if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_VIDEO)) {
+         send_msg->header.pt = rtp_session->payload;
+         }
</ins><span class="cx">         */
</span><span class="cx">
</span><span class="cx">         return rtp_common_write(rtp_session, send_msg, data, len, payload, ts, &frame->flags);
</span><span class="lines">@@ -3234,7 +3608,7 @@
</span><span class="cx">
</span><span class="cx">         ret = (int) bytes;
</span><span class="cx">
</span><del>- end:
</del><ins>+ end:
</ins><span class="cx">
</span><span class="cx">         WRITE_DEC(rtp_session);
</span><span class="cx">
</span></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>
</body>
</html>