This commit is contained in:
Anthony Minessale 2010-04-19 19:07:23 -05:00 committed by Brian West
parent 9a74958b22
commit 70d73cafb7
10 changed files with 600 additions and 41 deletions

View File

@ -116,6 +116,7 @@
#include "switch_utils.h" #include "switch_utils.h"
#include "switch_caller.h" #include "switch_caller.h"
#include "switch_frame.h" #include "switch_frame.h"
#include "switch_rtcp_frame.h"
#include "switch_module_interfaces.h" #include "switch_module_interfaces.h"
#include "switch_channel.h" #include "switch_channel.h"
#include "switch_buffer.h" #include "switch_buffer.h"

View File

@ -0,0 +1,74 @@
/*
* 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:
*/

View File

@ -41,6 +41,7 @@
SWITCH_BEGIN_EXTERN_C SWITCH_BEGIN_EXTERN_C
#define SWITCH_RTP_MAX_BUF_LEN 16384 #define SWITCH_RTP_MAX_BUF_LEN 16384
#define SWITCH_RTCP_MAX_BUF_LEN 16384
#define SWITCH_RTP_MAX_CRYPTO_LEN 64 #define SWITCH_RTP_MAX_CRYPTO_LEN 64
#define SWITCH_RTP_KEY_LEN 30 #define SWITCH_RTP_KEY_LEN 30
#define SWITCH_RTP_CRYPTO_KEY_32 "AES_CM_128_HMAC_SHA1_32" #define SWITCH_RTP_CRYPTO_KEY_32 "AES_CM_128_HMAC_SHA1_32"
@ -213,6 +214,13 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session);
*/ */
SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin); SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin);
/*!
\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);
/*! /*!
\brief Acvite a jitter buffer on an RTP session \brief Acvite a jitter buffer on an RTP session
\param rtp_session the rtp session \param rtp_session the rtp session
@ -347,6 +355,15 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_sessi
*/ */
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); 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);
/*!
\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);
SWITCH_DECLARE(void) rtp_flush_read_buffer(switch_rtp_t *rtp_session, switch_rtp_flush_t flush); SWITCH_DECLARE(void) rtp_flush_read_buffer(switch_rtp_t *rtp_session, switch_rtp_flush_t flush);
/*! /*!

View File

@ -534,7 +534,8 @@ typedef enum {
SWITCH_ZRTP_FLAG_SECURE_MITM_RECV = (1 << 26), SWITCH_ZRTP_FLAG_SECURE_MITM_RECV = (1 << 26),
SWITCH_RTP_FLAG_DEBUG_RTP_READ = (1 << 27), SWITCH_RTP_FLAG_DEBUG_RTP_READ = (1 << 27),
SWITCH_RTP_FLAG_DEBUG_RTP_WRITE = (1 << 28), SWITCH_RTP_FLAG_DEBUG_RTP_WRITE = (1 << 28),
SWITCH_RTP_FLAG_VIDEO = (1 << 29) SWITCH_RTP_FLAG_VIDEO = (1 << 29),
SWITCH_RTP_FLAG_ENABLE_RTCP = (1 << 30)
} switch_rtp_flag_enum_t; } switch_rtp_flag_enum_t;
typedef uint32_t switch_rtp_flag_t; typedef uint32_t switch_rtp_flag_t;
@ -607,6 +608,35 @@ typedef struct {
#pragma pack(pop, r1) #pragma pack(pop, r1)
#endif #endif
#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
/*! /*!
\enum switch_priority_t \enum switch_priority_t
\brief Priority Indication \brief Priority Indication
@ -1352,6 +1382,7 @@ typedef enum {
SWITCH_EVENT_SERVER_DISCONNECTED, SWITCH_EVENT_SERVER_DISCONNECTED,
SWITCH_EVENT_SEND_INFO, SWITCH_EVENT_SEND_INFO,
SWITCH_EVENT_RECV_INFO, SWITCH_EVENT_RECV_INFO,
SWITCH_EVENT_RECV_RTCP_MESSAGE,
SWITCH_EVENT_CALL_SECURE, SWITCH_EVENT_CALL_SECURE,
SWITCH_EVENT_NAT, SWITCH_EVENT_NAT,
SWITCH_EVENT_RECORD_START, SWITCH_EVENT_RECORD_START,
@ -1472,6 +1503,7 @@ typedef uint16_t switch_port_t;
typedef uint8_t switch_payload_t; typedef uint8_t switch_payload_t;
typedef struct switch_app_log switch_app_log_t; typedef struct switch_app_log switch_app_log_t;
typedef struct switch_rtp switch_rtp_t; typedef struct switch_rtp switch_rtp_t;
typedef struct switch_rtcp switch_rtcp_t;
typedef struct switch_core_session_message switch_core_session_message_t; typedef struct switch_core_session_message switch_core_session_message_t;
typedef struct switch_event_header switch_event_header_t; typedef struct switch_event_header switch_event_header_t;
typedef struct switch_event switch_event_t; typedef struct switch_event switch_event_t;
@ -1479,6 +1511,7 @@ typedef struct switch_event_subclass switch_event_subclass_t;
typedef struct switch_event_node switch_event_node_t; typedef struct switch_event_node switch_event_node_t;
typedef struct switch_loadable_module switch_loadable_module_t; typedef struct switch_loadable_module switch_loadable_module_t;
typedef struct switch_frame switch_frame_t; typedef struct switch_frame switch_frame_t;
typedef struct switch_rtcp_frame switch_rtcp_frame_t;
typedef struct switch_channel switch_channel_t; typedef struct switch_channel switch_channel_t;
typedef struct switch_file_handle switch_file_handle_t; typedef struct switch_file_handle switch_file_handle_t;
typedef struct switch_core_session switch_core_session_t; typedef struct switch_core_session switch_core_session_t;

View File

@ -802,6 +802,7 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
switch_channel_t *channel = switch_core_session_get_channel(session); switch_channel_t *channel = switch_core_session_get_channel(session);
int payload = 0; int payload = 0;
uint32_t sanity = 1000; uint32_t sanity = 1000;
switch_rtcp_frame_t rtcp_frame;
switch_assert(tech_pvt != NULL); switch_assert(tech_pvt != NULL);
@ -860,6 +861,50 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
return status; return status;
} }
/* 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;
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");
}
}
/* Fast PASS! */ /* Fast PASS! */
if (switch_test_flag((&tech_pvt->read_frame), SFF_PROXY_PACKET)) { if (switch_test_flag((&tech_pvt->read_frame), SFF_PROXY_PACKET)) {
sofia_clear_flag_locked(tech_pvt, TFLAG_READING); sofia_clear_flag_locked(tech_pvt, TFLAG_READING);

View File

@ -466,6 +466,7 @@ struct sofia_profile {
char *record_path; char *record_path;
char *presence_hosts; char *presence_hosts;
char *challenge_realm; char *challenge_realm;
char *rtcp_interval_msec;
sofia_cid_type_t cid_type; sofia_cid_type_t cid_type;
sofia_dtmf_t dtmf_type; sofia_dtmf_t dtmf_type;
int auto_restart; int auto_restart;

View File

@ -2459,6 +2459,8 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
profile->hold_music = switch_core_strdup(profile->pool, val); profile->hold_music = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "outbound-proxy")) { } else if (!strcasecmp(var, "outbound-proxy")) {
profile->outbound_proxy = switch_core_strdup(profile->pool, val); 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, "session-timeout")) { } else if (!strcasecmp(var, "session-timeout")) {
int v_session_timeout = atoi(val); int v_session_timeout = atoi(val);
if (v_session_timeout >= 0) { if (v_session_timeout >= 0) {
@ -2996,6 +2998,8 @@ switch_status_t config_sofia(int reload, char *profile_name)
profile->hold_music = switch_core_strdup(profile->pool, val); profile->hold_music = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "outbound-proxy")) { } else if (!strcasecmp(var, "outbound-proxy")) {
profile->outbound_proxy = switch_core_strdup(profile->pool, val); 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, "session-timeout")) { } else if (!strcasecmp(var, "session-timeout")) {
int v_session_timeout = atoi(val); int v_session_timeout = atoi(val);
if (v_session_timeout >= 0) { if (v_session_timeout >= 0) {

View File

@ -2726,6 +2726,15 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
(tech_pvt->stun_flags & STUN_FLAG_FUNNY) ? 1 : 0); (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);
} else {
switch_rtp_activate_rtcp(tech_pvt->rtp_session, interval);
}
}
if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec"))) { if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec"))) {
int len = atoi(val); int len = atoi(val);

View File

@ -180,6 +180,7 @@ static char *EVENT_NAMES[] = {
"SERVER_DISCONNECTED", "SERVER_DISCONNECTED",
"SEND_INFO", "SEND_INFO",
"RECV_INFO", "RECV_INFO",
"RECV_RTCP_MESSAGE",
"CALL_SECURE", "CALL_SECURE",
"NAT", "NAT",
"RECORD_START", "RECORD_START",

View File

@ -89,6 +89,11 @@ typedef struct {
char body[SWITCH_RTP_MAX_BUF_LEN]; char body[SWITCH_RTP_MAX_BUF_LEN];
} rtp_msg_t; } rtp_msg_t;
typedef struct {
switch_rtcp_hdr_t header;
char body[SWITCH_RTCP_MAX_BUF_LEN];
} rtcp_msg_t;
struct switch_rtp_vad_data { struct switch_rtp_vad_data {
switch_core_session_t *session; switch_core_session_t *session;
switch_codec_t vad_codec; switch_codec_t vad_codec;
@ -137,16 +142,17 @@ struct switch_rtp {
* families are equal, sock_input == sock_output and only one socket is * families are equal, sock_input == sock_output and only one socket is
* used. * used.
*/ */
switch_socket_t *sock_input, *sock_output; switch_socket_t *sock_input, *sock_output, *rtcp_sock_input, *rtcp_sock_output;
switch_pollfd_t *read_pollfd; switch_pollfd_t *read_pollfd, *rtcp_read_pollfd;
switch_pollfd_t *jb_pollfd; switch_pollfd_t *jb_pollfd;
switch_sockaddr_t *local_addr; switch_sockaddr_t *local_addr, *rtcp_local_addr;
rtp_msg_t send_msg; rtp_msg_t send_msg;
rtcp_msg_t rtcp_send_msg;
switch_sockaddr_t *remote_addr; switch_sockaddr_t *remote_addr, *rtcp_remote_addr;
rtp_msg_t recv_msg; rtp_msg_t recv_msg;
rtcp_msg_t rtcp_recv_msg;
switch_sockaddr_t *remote_stun_addr; switch_sockaddr_t *remote_stun_addr;
@ -173,12 +179,13 @@ struct switch_rtp {
switch_time_t last_write_timestamp; switch_time_t last_write_timestamp;
uint32_t flags; uint32_t flags;
switch_memory_pool_t *pool; switch_memory_pool_t *pool;
switch_sockaddr_t *from_addr; switch_sockaddr_t *from_addr, *rtcp_from_addr;
char *rx_host; char *rx_host;
switch_port_t rx_port; switch_port_t rx_port;
char *ice_user; char *ice_user;
char *user_ice; char *user_ice;
char *timer_name; char *timer_name;
char *local_host_str;
char *remote_host_str; char *remote_host_str;
switch_time_t last_stun; switch_time_t last_stun;
uint32_t samples_per_interval; uint32_t samples_per_interval;
@ -186,6 +193,7 @@ struct switch_rtp {
uint32_t conf_samples_per_interval; uint32_t conf_samples_per_interval;
uint32_t rsamples_per_interval; uint32_t rsamples_per_interval;
uint32_t ms_per_packet; uint32_t ms_per_packet;
switch_port_t local_port;
switch_port_t remote_port; switch_port_t remote_port;
uint32_t stuncount; uint32_t stuncount;
uint32_t funny_stun; uint32_t funny_stun;
@ -216,6 +224,8 @@ struct switch_rtp {
switch_rtp_stats_t stats; switch_rtp_stats_t stats;
uint32_t hot_hits; uint32_t hot_hits;
uint32_t sync_packets; uint32_t sync_packets;
int rtcp_interval;
switch_bool_t rtcp_fresh_frame;
#ifdef ENABLE_ZRTP #ifdef ENABLE_ZRTP
zrtp_session_t *zrtp_session; zrtp_session_t *zrtp_session;
@ -225,10 +235,16 @@ struct switch_rtp {
int zinit; int zinit;
#endif #endif
#ifdef RTP_DEBUG_WRITE_DELTA
switch_time_t send_time; switch_time_t send_time;
#endif };
struct switch_rtcp_senderinfo {
unsigned ssrc:32;
unsigned ntp_msw:32;
unsigned ntp_lsw:32;
unsigned ts:32;
unsigned pc:32;
unsigned oc:32;
}; };
static int global_init = 0; static int global_init = 0;
@ -750,6 +766,104 @@ SWITCH_DECLARE(void) switch_rtp_intentional_bugs(switch_rtp_t *rtp_session, swit
rtp_session->rtp_bugs = bugs; rtp_session->rtp_bugs = bugs;
} }
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;
}
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) 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)
{ {
switch_socket_t *new_sock = NULL, *old_sock = NULL; switch_socket_t *new_sock = NULL, *old_sock = NULL;
@ -781,11 +895,17 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
goto done; goto done;
} }
rtp_session->local_host_str = switch_core_strdup(rtp_session->pool, host);
rtp_session->local_port = port;
if (switch_sockaddr_info_get(&rtp_session->local_addr, host, SWITCH_UNSPEC, port, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) { if (switch_sockaddr_info_get(&rtp_session->local_addr, host, SWITCH_UNSPEC, port, 0, rtp_session->pool) != SWITCH_STATUS_SUCCESS) {
*err = "Local Address Error!"; *err = "Local Address Error!";
goto done; goto done;
} }
if (rtp_session->sock_input) { if (rtp_session->sock_input) {
switch_rtp_kill_socket(rtp_session); switch_rtp_kill_socket(rtp_session);
} }
@ -804,6 +924,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
*err = "Bind Error!"; *err = "Bind Error!";
goto done; goto done;
} }
#ifndef WIN32 #ifndef WIN32
len = sizeof(i); len = sizeof(i);
switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, TRUE); switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, TRUE);
@ -827,12 +948,15 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
} }
switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, FALSE); switch_socket_opt_set(new_sock, SWITCH_SO_NONBLOCK, FALSE);
#endif
old_sock = rtp_session->sock_input; old_sock = rtp_session->sock_input;
rtp_session->sock_input = new_sock; rtp_session->sock_input = new_sock;
new_sock = NULL; new_sock = NULL;
#endif
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_NOBLOCK)) { if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_NOBLOCK)) {
switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, TRUE); switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, TRUE);
switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_NOBLOCK); switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_NOBLOCK);
@ -840,8 +964,15 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
switch_socket_create_pollset(&rtp_session->read_pollfd, rtp_session->sock_input, SWITCH_POLLIN | SWITCH_POLLERR, rtp_session->pool); switch_socket_create_pollset(&rtp_session->read_pollfd, rtp_session->sock_input, SWITCH_POLLIN | SWITCH_POLLERR, rtp_session->pool);
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; status = SWITCH_STATUS_SUCCESS;
*err = "Success"; *err = "Success";
}
switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_IO); switch_set_flag_locked(rtp_session, SWITCH_RTP_FLAG_IO);
done: done:
@ -854,6 +985,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s
switch_socket_close(old_sock); switch_socket_close(old_sock);
} }
if (rtp_session->ready != 1) { if (rtp_session->ready != 1) {
WRITE_DEC(rtp_session); WRITE_DEC(rtp_session);
READ_DEC(rtp_session); READ_DEC(rtp_session);
@ -901,6 +1033,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
} }
switch_mutex_lock(rtp_session->write_mutex); switch_mutex_lock(rtp_session->write_mutex);
rtp_session->remote_addr = remote_addr; rtp_session->remote_addr = remote_addr;
@ -923,6 +1056,10 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_remote_address(switch_rtp_t *rtp_
} }
} }
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
status = enable_remote_rtcp_socket(rtp_session, err);
}
switch_mutex_unlock(rtp_session->write_mutex); switch_mutex_unlock(rtp_session->write_mutex);
return status; return status;
@ -985,8 +1122,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_crypto_key(switch_rtp_t *rtp_sess
policy->next = NULL; policy->next = NULL;
policy->key = (uint8_t *) crypto_key->key; policy->key = (uint8_t *) crypto_key->key;
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
crypto_policy_set_rtcp_default(&policy->rtcp); crypto_policy_set_rtcp_default(&policy->rtcp);
policy->rtcp.sec_serv = sec_serv_none; policy->rtcp.sec_serv = sec_serv_none;
}
policy->rtp.sec_serv = sec_serv_conf_and_auth; policy->rtp.sec_serv = sec_serv_conf_and_auth;
switch (direction) { switch (direction) {
@ -1136,8 +1276,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
/* for from address on recvfrom calls */ /* for from address on recvfrom calls */
switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool); switch_sockaddr_info_get(&rtp_session->from_addr, NULL, SWITCH_UNSPEC, 0, 0, pool);
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);
}
rtp_session->seq = (uint16_t) rand(); rtp_session->seq = (uint16_t) rand();
rtp_session->ssrc = (uint32_t) ((intptr_t) rtp_session + (uint32_t) switch_epoch_time_now(NULL)); rtp_session->ssrc = (uint32_t) ((intptr_t) rtp_session + (uint32_t) switch_epoch_time_now(NULL));
@ -1162,6 +1303,14 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
rtp_session->payload = payload; 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);
}
switch_rtp_set_interval(rtp_session, ms_per_packet, samples_per_interval); switch_rtp_set_interval(rtp_session, ms_per_packet, samples_per_interval);
rtp_session->conf_samples_per_interval = samples_per_interval; rtp_session->conf_samples_per_interval = samples_per_interval;
@ -1382,6 +1531,19 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
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);
}
SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin) SWITCH_DECLARE(switch_status_t) switch_rtp_activate_ice(switch_rtp_t *rtp_session, char *login, char *rlogin)
{ {
char ice_user[80]; char ice_user[80];
@ -1407,6 +1569,10 @@ static void ping_socket(switch_rtp_t *rtp_session)
uint32_t o = UINT_MAX; uint32_t o = UINT_MAX;
switch_size_t len = sizeof(o); switch_size_t len = sizeof(o);
switch_socket_sendto(rtp_session->sock_input, rtp_session->local_addr, 0, (void *) &o, &len); switch_socket_sendto(rtp_session->sock_input, rtp_session->local_addr, 0, (void *) &o, &len);
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);
}
} }
SWITCH_DECLARE(void) switch_rtp_break(switch_rtp_t *rtp_session) SWITCH_DECLARE(void) switch_rtp_break(switch_rtp_t *rtp_session)
@ -1443,6 +1609,16 @@ SWITCH_DECLARE(void) switch_rtp_kill_socket(switch_rtp_t *rtp_session)
if (rtp_session->sock_output && rtp_session->sock_output != rtp_session->sock_input) { if (rtp_session->sock_output && rtp_session->sock_output != rtp_session->sock_input) {
switch_socket_shutdown(rtp_session->sock_output, SWITCH_SHUTDOWN_READWRITE); switch_socket_shutdown(rtp_session->sock_output, SWITCH_SHUTDOWN_READWRITE);
} }
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);
}
}
} }
switch_mutex_unlock(rtp_session->flag_mutex); switch_mutex_unlock(rtp_session->flag_mutex);
} }
@ -1841,18 +2017,126 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
return status; return status;
} }
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;
}
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) 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)
{ {
switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session"); switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session");
switch_channel_t *channel = NULL; switch_channel_t *channel = NULL;
switch_size_t bytes = 0; switch_size_t bytes = 0;
switch_size_t rtcp_bytes = 0;
switch_status_t status = SWITCH_STATUS_SUCCESS, poll_status = SWITCH_STATUS_SUCCESS; switch_status_t status = SWITCH_STATUS_SUCCESS, poll_status = SWITCH_STATUS_SUCCESS;
switch_status_t rtcp_status = SWITCH_STATUS_SUCCESS, rtcp_poll_status = SWITCH_STATUS_SUCCESS;
int check = 0; int check = 0;
int ret = -1; int ret = -1;
int sleep_mss = 1000; int sleep_mss = 1000;
int poll_sec = 5; int poll_sec = 5;
int poll_loop = 0; int poll_loop = 0;
int fdr = 0; int fdr = 0;
int rtcp_fdr = 0;
int hot_socket = 0; int hot_socket = 0;
if (session) { if (session) {
@ -1947,6 +2231,14 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
} }
} }
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);
}
}
if (bytes < 0) { if (bytes < 0) {
ret = (int) bytes; ret = (int) bytes;
goto end; goto end;
@ -2513,6 +2805,33 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_read(switch_rtp_t *rtp_session, void
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
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;
}
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) 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)
{ {
int bytes = 0; int bytes = 0;
@ -2625,10 +2944,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read(switch_rtp_t *rtp_sessi
static int rtp_common_write(switch_rtp_t *rtp_session, static int rtp_common_write(switch_rtp_t *rtp_session,
rtp_msg_t *send_msg, void *data, uint32_t datalen, switch_payload_t payload, uint32_t timestamp, switch_frame_flag_t *flags) rtp_msg_t *send_msg, void *data, uint32_t datalen, switch_payload_t payload, uint32_t timestamp, switch_frame_flag_t *flags)
{ {
switch_size_t bytes; switch_size_t bytes, rtcp_bytes;
uint8_t send = 1; uint8_t send = 1;
uint32_t this_ts = 0; uint32_t this_ts = 0;
int ret; int ret;
switch_time_t now;
if (!switch_rtp_ready(rtp_session)) { if (!switch_rtp_ready(rtp_session)) {
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
@ -2860,15 +3180,14 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
} }
#endif #endif
now = switch_time_now();
#ifdef RTP_DEBUG_WRITE_DELTA #ifdef RTP_DEBUG_WRITE_DELTA
{ {
switch_time_t now = switch_time_now();
int delta = (int) (now - rtp_session->send_time) / 1000; int delta = (int) (now - rtp_session->send_time) / 1000;
printf("WRITE %d delta %d\n", (int) bytes, delta); printf("WRITE %d delta %d\n", (int) bytes, delta);
rtp_session->send_time = now;
} }
#endif #endif
rtp_session->send_time = now;
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_DEBUG_RTP_WRITE)) { if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_DEBUG_RTP_WRITE)) {
switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session"); switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session");
@ -2924,6 +3243,61 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
} }
rtp_session->last_write_ts = this_ts; rtp_session->last_write_ts = this_ts;
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");
}
}
} }
if (rtp_session->remote_stun_addr) { if (rtp_session->remote_stun_addr) {