]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add rtcp seperate on audio and video and add passthru
authorAnthony Minessale <anthm@freeswitch.org>
Tue, 20 Apr 2010 21:15:37 +0000 (16:15 -0500)
committerBrian West <brian@freeswitch.org>
Tue, 20 Apr 2010 21:15:53 +0000 (16:15 -0500)
conf/sip_profiles/internal.xml
src/include/switch_rtp.h
src/include/switch_types.h
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c
src/mod/endpoints/mod_sofia/sofia_glue.c
src/switch_rtp.c

index dcce5890139936776d419f135b12f3bc78d47872..2f5636e5a65b35797ea3ef67a103e921c8859c51 100644 (file)
     <!--all inbound reg will stored in the db using this domain -->
     <param name="force-register-db-domain" value="$${domain}"/>
 
-    <!-- enable rtcp on every channel also can be done per leg basis with rtcp_interval_msec variable -->
-    <!--<param name="rtcp-interval-msec" value="10000"/>-->
+    <!-- enable rtcp on every channel also can be done per leg basis with rtcp_audio_interval_msec variable set to passthru to pass it across a call-->
+    <!--<param name="rtcp-audio-interval-msec" value="10000"/>-->
+    <!--<param name="rtcp-video-interval-msec" value="10000"/>-->
 
     <!--force suscription expires to a lower value than requested-->
     <!--<param name="force-subscription-expires" value="60"/>-->
index 4ad264ae8e416241f43892a1c98d7773571891eb..c4bab4819068d51c974f0ba991373b1326684bd3 100644 (file)
@@ -219,7 +219,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_sessio
   \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);
+SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_session, int send_rate, switch_port_t remote_port);
 
 /*! 
   \brief Acvite a jitter buffer on an RTP session
index 52f8ac1c245a64011aaecb2f27135be159519582..2589e2b8c3ab3a1f4b0fad8767c345eba12aebc6 100644 (file)
@@ -535,7 +535,9 @@ typedef enum {
        SWITCH_RTP_FLAG_DEBUG_RTP_READ = (1 << 27),
        SWITCH_RTP_FLAG_DEBUG_RTP_WRITE = (1 << 28),
        SWITCH_RTP_FLAG_VIDEO = (1 << 29),
-       SWITCH_RTP_FLAG_ENABLE_RTCP = (1 << 30)
+       SWITCH_RTP_FLAG_ENABLE_RTCP = (1 << 30),
+       SWITCH_RTP_FLAG_RTCP_PASSTHRU = (1 << 31)
+       /* don't add any more 31 is the limit! gotta chnge to an array to add more */
 } switch_rtp_flag_enum_t;
 typedef uint32_t switch_rtp_flag_t;
 
index ebf669028f4199846e0cf064acc9fe03df4003f2..e1b1e61d537b44367d48c1506b840d062cc8b8ac 100644 (file)
@@ -466,7 +466,8 @@ struct sofia_profile {
        char *record_path;
        char *presence_hosts;
        char *challenge_realm;
-       char *rtcp_interval_msec;
+       char *rtcp_audio_interval_msec;
+       char *rtcp_video_interval_msec;
        sofia_cid_type_t cid_type;
        sofia_dtmf_t dtmf_type;
        int auto_restart;
index 71faa4e7826a3bedad38ce53b74f74adec4d8b73..89940a8cd71f3e786536660fd0732e3f01d2bf5d 100644 (file)
@@ -2459,8 +2459,10 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
                                                profile->hold_music = switch_core_strdup(profile->pool, val);
                                        } else if (!strcasecmp(var, "outbound-proxy")) {
                                                profile->outbound_proxy = switch_core_strdup(profile->pool, val);
-                                       } else if (!strcasecmp(var, "rtcp-interval-msec")) {
-                                               profile->rtcp_interval_msec = switch_core_strdup(profile->pool, val);
+                                       } else if (!strcasecmp(var, "rtcp-audio-interval-msec")) {
+                                               profile->rtcp_audio_interval_msec = switch_core_strdup(profile->pool, val);
+                                       } else if (!strcasecmp(var, "rtcp-video-interval-msec")) {
+                                               profile->rtcp_video_interval_msec = switch_core_strdup(profile->pool, val);
                                        } else if (!strcasecmp(var, "session-timeout")) {
                                                int v_session_timeout = atoi(val);
                                                if (v_session_timeout >= 0) {
@@ -2998,8 +3000,10 @@ switch_status_t config_sofia(int reload, char *profile_name)
                                                profile->hold_music = switch_core_strdup(profile->pool, val);
                                        } else if (!strcasecmp(var, "outbound-proxy")) {
                                                profile->outbound_proxy = switch_core_strdup(profile->pool, val);
-                                       } else if (!strcasecmp(var, "rtcp-interval-msec")) {
-                                               profile->rtcp_interval_msec = switch_core_strdup(profile->pool, val);
+                                       } else if (!strcasecmp(var, "rtcp-audio-interval-msec")) {
+                                               profile->rtcp_audio_interval_msec = switch_core_strdup(profile->pool, val);
+                                       } else if (!strcasecmp(var, "rtcp-video-interval-msec")) {
+                                               profile->rtcp_video_interval_msec = switch_core_strdup(profile->pool, val);
                                        } else if (!strcasecmp(var, "session-timeout")) {
                                                int v_session_timeout = atoi(val);
                                                if (v_session_timeout >= 0) {
index 1143fda5f0cfb8d682a519259c837dc573dc92d2..49b302b7ffd0554662e8ed34db98baadf1ae17d8 100644 (file)
@@ -691,7 +691,7 @@ const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name)
 switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int force)
 {
        char *lookup_rtpip = tech_pvt->profile->rtpip;  /* Pointer to externally looked up address */
-       switch_port_t sdp_port;         /* The external port to be sent in the SDP */
+       switch_port_t sdp_port, rtcp_port;              /* The external port to be sent in the SDP */
        const char *use_ip = NULL;      /* The external IP to be sent in the SDP */
 
        /* Don't do anything if we're in proxy mode or if a (remote) port already has been found */
@@ -734,6 +734,7 @@ switch_status_t sofia_glue_tech_choose_port(private_object_t *tech_pvt, int forc
                                if (!zstr(tech_pvt->remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->remote_ip)) {
                                        /* Yes, map the port through switch_nat */
                                        switch_nat_add_mapping(tech_pvt->local_sdp_audio_port, SWITCH_NAT_UDP, &sdp_port, SWITCH_FALSE);
+                                       switch_nat_add_mapping(tech_pvt->local_sdp_audio_port + 1, SWITCH_NAT_UDP, &rtcp_port, SWITCH_FALSE);
                                } else {
                                        /* No NAT detected */
                                        use_ip = tech_pvt->profile->rtpip;
@@ -2726,12 +2727,23 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
                                                                                  (tech_pvt->stun_flags & STUN_FLAG_FUNNY) ? 1 : 0);
                }
                
-               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);
+               printf("WTF [%s][%s]\n", switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec"), tech_pvt->profile->rtcp_audio_interval_msec);
+
+               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec")) || (val = tech_pvt->profile->rtcp_audio_interval_msec)) {
+                       const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port");
+                       switch_port_t remote_port = 0;
+                       if (rport) {
+                               remote_port = atoi(rport);
+                       }
+                       if (!strcasecmp(val, "passthru")) {
+                               switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
                        } else {
-                               switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval);
+                               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, remote_port);
+                               }
                        }
                }
 
@@ -2949,6 +2961,27 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
                                switch_channel_set_variable_printf(tech_pvt->channel, "sip_use_video_pt", "%d", tech_pvt->video_agreed_pt);
                                tech_pvt->video_ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
                                switch_channel_set_variable_printf(tech_pvt->channel, "rtp_use_video_ssrc", "%u", tech_pvt->ssrc);
+
+
+                               if ((val = switch_channel_get_variable(tech_pvt->channel, "rtcp_audio_interval_msec")) || (val = tech_pvt->profile->rtcp_audio_interval_msec)) {
+                                       const char *rport = switch_channel_get_variable(tech_pvt->channel, "sip_remote_video_rtcp_port");
+                                       switch_port_t remote_port = 0;
+                                       if (rport) {
+                                               remote_port = atoi(rport);
+                                       }
+                                       if (!strcasecmp(val, "passthru")) {
+                                               switch_rtp_activate_rtcp(tech_pvt->rtp_session, -1, remote_port);
+                                       } else {
+                                               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, remote_port);
+                                               }
+                                       }
+                               }
+
+
                        } else {
                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "VIDEO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
                                switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
@@ -3378,6 +3411,11 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
                } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) {
                        sdp_rtpmap_t *map;
                        for (attr = m->m_attributes; attr; attr = attr->a_next) {
+                               
+                               if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
+                                       switch_channel_set_variable(tech_pvt->channel, "sip_remote_audio_rtcp_port", attr->a_value);
+                               }
+
                                if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
                                        ptime = atoi(attr->a_value);
                                } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
@@ -3708,6 +3746,9 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, sdp_session_t *
                                        if (!strcasecmp(attr->a_name, "framerate") && attr->a_value) {
                                                framerate = atoi(attr->a_value);
                                        }
+                                       if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
+                                               switch_channel_set_variable(tech_pvt->channel, "sip_remote_video_rtcp_port", attr->a_value);
+                                       }
                                }
                                if (!(rm_encoding = map->rm_encoding)) {
                                        rm_encoding = "";
index 0cacc3bded51d455a1ee944548d3e24d699253f0..c2b2b457d72c523ec40fb3a338f0804f744180ca 100644 (file)
@@ -195,6 +195,7 @@ struct switch_rtp {
        uint32_t ms_per_packet;
        switch_port_t local_port;
        switch_port_t remote_port;
+       switch_port_t remote_rtcp_port;
        uint32_t stuncount;
        uint32_t funny_stun;
        uint32_t default_stuncount;
@@ -773,10 +774,8 @@ static switch_status_t enable_remote_rtcp_socket(switch_rtp_t *rtp_session, cons
 
        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) {
+                                                                        rtp_session->remote_rtcp_port, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS || !rtp_session->rtcp_remote_addr) {
                        *err = "RTCP Remote Address Error!";
                        return SWITCH_STATUS_FALSE;
                }
@@ -1248,6 +1247,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
 {
        switch_rtp_t *rtp_session = NULL;
        switch_core_session_t *session = switch_core_memory_pool_get_data(pool, "__session");
+       switch_channel_t *channel = NULL;
+
+       if (session) channel = switch_core_session_get_channel(session);
 
        *new_rtp_session = NULL;
 
@@ -1303,13 +1305,13 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
 
        rtp_session->payload = payload;
 
-       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); 
-       }
+
+       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); 
+
 
        switch_rtp_set_interval(rtp_session, ms_per_packet, samples_per_interval);
        rtp_session->conf_samples_per_interval = samples_per_interval;
@@ -1341,12 +1343,13 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
                switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_NOBLOCK);
        }
 
+       switch_channel_set_private(channel, "__rtcp_audio_rtp_session", rtp_session);
+
 #ifdef ENABLE_ZRTP
        if (zrtp_on) {
                switch_rtp_t *master_rtp_session = NULL;
 
                int initiator = 0;
-               switch_channel_t *channel = switch_core_session_get_channel(session);
                const char *zrtp_enabled = switch_channel_get_variable(channel, "zrtp_secure_media");
                const char *srtp_enabled = switch_channel_get_variable(channel, "sip_secure_media");
 
@@ -1531,14 +1534,24 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *
        return SWITCH_STATUS_SUCCESS;
 }
 
-SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_session, int send_rate)
+SWITCH_DECLARE(switch_status_t) switch_rtp_activate_rtcp(switch_rtp_t *rtp_session, int send_rate, switch_port_t remote_port)
 {
        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);
+       if (!(rtp_session->remote_rtcp_port = remote_port)) {
+               rtp_session->remote_rtcp_port = rtp_session->remote_port + 1;
+       }
+       
+       if (send_rate == -1) {
+               switch_set_flag(rtp_session, SWITCH_RTP_FLAG_RTCP_PASSTHRU);
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "RTCP passthru enabled. Remote Port: %d\n", rtp_session->remote_rtcp_port);
+       } else {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "RTCP send rate is: %d and packet rate is: %d Remote Port: %d\n", 
+                                                 send_rate, rtp_session->ms_per_packet, rtp_session->remote_rtcp_port);
+               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);
 
@@ -2236,6 +2249,68 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                                                
                        if (rtcp_poll_status == SWITCH_STATUS_SUCCESS) {
                                rtcp_status = read_rtcp_packet(rtp_session, &rtcp_bytes, flags);
+                               
+                               if (rtcp_status == SWITCH_STATUS_SUCCESS && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_RTCP_PASSTHRU)) {
+                                       switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session");
+                                       switch_channel_t *channel = switch_core_session_get_channel(session);
+
+                                       const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+                                       if (uuid) {
+                                               switch_core_session_t *other_session;
+                                               switch_rtp_t *other_rtp_session = NULL;
+
+                                               if ((other_session = switch_core_session_locate(uuid))) {
+                                                       switch_channel_t *other_channel = switch_core_session_get_channel(other_session);                                       
+                                                       if ((other_rtp_session = switch_channel_get_private(other_channel, "__rtcp_audio_rtp_session")) && 
+                                                               switch_test_flag(other_rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
+                                                               *other_rtp_session->rtcp_send_msg.body = *rtp_session->rtcp_recv_msg.body;
+
+                                                               if (switch_test_flag(other_rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) {
+                                                                       int sbytes = (int) rtcp_bytes;
+                                                                       int stat = srtp_protect_rtcp(other_rtp_session->send_ctx, &other_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(other_rtp_session->zrtp_stream, (void *) &other_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(other_rtp_session->rtcp_sock_output, other_rtp_session->rtcp_remote_addr, 0, 
+                                                                                                                (const char*)&other_rtp_session->rtcp_send_msg, &rtcp_bytes ) != SWITCH_STATUS_SUCCESS) {
+                                                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"RTCP packet not written\n");
+                                                               }
+                                                               
+                                                               
+                                                       }
+                                               }
+                                       }
+                                       
+                               }
                        }
                }
 
@@ -3244,7 +3319,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
 
                rtp_session->last_write_ts = this_ts;
                
-               if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && 
+               if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP) && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_RTCP_PASSTHRU) &&
                        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;