Merge "Add rtcp-mux support"
This commit is contained in:
commit
84f0871cba
10 changed files with 397 additions and 129 deletions
7
CHANGES
7
CHANGES
|
@ -140,6 +140,13 @@ res_pjsip_endpoint_identifier_ip
|
||||||
appropriate, as it now matches inbound requests on more than just IP
|
appropriate, as it now matches inbound requests on more than just IP
|
||||||
address.
|
address.
|
||||||
|
|
||||||
|
res_rtp_asterisk
|
||||||
|
-----------------
|
||||||
|
* The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP
|
||||||
|
Data and Control Packets on a Single Port." So far, the only channel driver
|
||||||
|
that supports this feature is chan_pjsip. You can set "rtcp_mux = yes" on
|
||||||
|
a PJSIP endpoint in pjsip.conf to enable the feature.
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
--- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------
|
--- Functionality changes from Asterisk 14.2.0 to Asterisk 14.3.0 ------------
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
20
UPGRADE.txt
20
UPGRADE.txt
|
@ -23,9 +23,23 @@
|
||||||
=== UPGRADE-14.txt -- Upgrade info for 13 to 14
|
=== UPGRADE-14.txt -- Upgrade info for 13 to 14
|
||||||
===========================================================
|
===========================================================
|
||||||
|
|
||||||
Build System:
|
From 14.3.0 to 14.4.0:
|
||||||
- The LOW_MEMORY compile option no longer disables inline API. To disable
|
|
||||||
inline API you must use the DISABLE_INLINE option.
|
res_rtp_asterisk:
|
||||||
|
- The RTP layer of Asterisk now has support for RFC 5761: "Multiplexing RTP
|
||||||
|
Data and Control Packets on a Single Port." So far, the only channel driver
|
||||||
|
that supports this feature is chan_pjsip. You can set "rtcp_mux = yes" on
|
||||||
|
a PJSIP endpoint in pjsip.conf to enable the feature.
|
||||||
|
|
||||||
|
New in 14.0.0
|
||||||
|
|
||||||
|
ARI:
|
||||||
|
- The policy for when to send "Dial" events has changed. Previously, "Dial"
|
||||||
|
events were sent on the calling channel's topic. However, starting in Asterisk
|
||||||
|
14, if there is no calling channel on which to send the event, the event is
|
||||||
|
instead sent on the called channel's topic. Note that for the ARI channels
|
||||||
|
resource's dial operation, this means that the "Dial" events will always be
|
||||||
|
sent on the called channel's topic.
|
||||||
|
|
||||||
Queue:
|
Queue:
|
||||||
- When reloading the members of a queue, the members added dynamically (i.e.
|
- When reloading the members of a queue, the members added dynamically (i.e.
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
"""empty message
|
||||||
|
|
||||||
|
Revision ID: 15db7b91a97a
|
||||||
|
Revises: 465e70e8c337
|
||||||
|
Create Date: 2017-03-08 16:56:38.108162
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '15db7b91a97a'
|
||||||
|
down_revision = '465e70e8c337'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
YESNO_NAME = 'yesno_values'
|
||||||
|
YESNO_VALUES = ['yes', 'no']
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
############################# Enums ##############################
|
||||||
|
|
||||||
|
# yesno_values have already been created, so use postgres enum object
|
||||||
|
# type to get around "already created" issue - works okay with mysql
|
||||||
|
yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
|
||||||
|
|
||||||
|
op.add_column('ps_endpoints', sa.Column('rtcp_mux', yesno_values))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column('ps_endpoints', 'rtcp_mux')
|
|
@ -676,6 +676,8 @@ struct ast_sip_endpoint_media_configuration {
|
||||||
unsigned int g726_non_standard;
|
unsigned int g726_non_standard;
|
||||||
/*! Bind the RTP instance to the media_address */
|
/*! Bind the RTP instance to the media_address */
|
||||||
unsigned int bind_rtp_to_media_address;
|
unsigned int bind_rtp_to_media_address;
|
||||||
|
/*! Use RTCP-MUX */
|
||||||
|
unsigned int rtcp_mux;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -85,6 +85,8 @@ struct ast_sip_session_media {
|
||||||
unsigned int remotely_held:1;
|
unsigned int remotely_held:1;
|
||||||
/*! \brief Stream is on hold by local side */
|
/*! \brief Stream is on hold by local side */
|
||||||
unsigned int locally_held:1;
|
unsigned int locally_held:1;
|
||||||
|
/*! \brief Does remote support rtcp_mux */
|
||||||
|
unsigned int remote_rtcp_mux:1;
|
||||||
/*! \brief Stream type this session media handles */
|
/*! \brief Stream type this session media handles */
|
||||||
char stream_type[1];
|
char stream_type[1];
|
||||||
};
|
};
|
||||||
|
|
|
@ -237,6 +237,15 @@ enum ast_rtp_instance_stat {
|
||||||
AST_RTP_INSTANCE_STAT_RXOCTETCOUNT,
|
AST_RTP_INSTANCE_STAT_RXOCTETCOUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ast_rtp_instance_rtcp {
|
||||||
|
/*! RTCP should not be sent/received */
|
||||||
|
AST_RTP_INSTANCE_RTCP_DISABLED = 0,
|
||||||
|
/*! RTCP should be sent/received based on standard port rules */
|
||||||
|
AST_RTP_INSTANCE_RTCP_STANDARD,
|
||||||
|
/*! RTCP should be sent/received on the same port as RTP */
|
||||||
|
AST_RTP_INSTANCE_RTCP_MUX,
|
||||||
|
};
|
||||||
|
|
||||||
/* Codes for RTP-specific data - not defined by our AST_FORMAT codes */
|
/* Codes for RTP-specific data - not defined by our AST_FORMAT codes */
|
||||||
/*! DTMF (RFC2833) */
|
/*! DTMF (RFC2833) */
|
||||||
#define AST_RTP_DTMF (1 << 0)
|
#define AST_RTP_DTMF (1 << 0)
|
||||||
|
@ -447,6 +456,8 @@ struct ast_rtp_engine_ice {
|
||||||
void (*turn_request)(struct ast_rtp_instance *instance, enum ast_rtp_ice_component_type component,
|
void (*turn_request)(struct ast_rtp_instance *instance, enum ast_rtp_ice_component_type component,
|
||||||
enum ast_transport transport, const char *server, unsigned int port,
|
enum ast_transport transport, const char *server, unsigned int port,
|
||||||
const char *username, const char *password);
|
const char *username, const char *password);
|
||||||
|
/*! Callback to alter the number of ICE components on a session */
|
||||||
|
void (*change_components)(struct ast_rtp_instance *instance, int num_components);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief DTLS setup types */
|
/*! \brief DTLS setup types */
|
||||||
|
|
|
@ -950,6 +950,16 @@
|
||||||
to the receiving one.
|
to the receiving one.
|
||||||
</para></description>
|
</para></description>
|
||||||
</configOption>
|
</configOption>
|
||||||
|
<configOption name="rtcp_mux" default="no">
|
||||||
|
<synopsis>Enable RFC 5761 RTCP multiplexing on the RTP port</synopsis>
|
||||||
|
<description><para>
|
||||||
|
With this option enabled, Asterisk will attempt to negotiate the use of the "rtcp-mux"
|
||||||
|
attribute on all media streams. This will result in RTP and RTCP being sent and received
|
||||||
|
on the same port. This shifts the demultiplexing logic to the application rather than
|
||||||
|
the transport layer. This option is useful when interoperating with WebRTC endpoints
|
||||||
|
since they mandate this option's use.
|
||||||
|
</para></description>
|
||||||
|
</configOption>
|
||||||
</configObject>
|
</configObject>
|
||||||
<configObject name="auth">
|
<configObject name="auth">
|
||||||
<synopsis>Authentication type</synopsis>
|
<synopsis>Authentication type</synopsis>
|
||||||
|
|
|
@ -1937,6 +1937,7 @@ int ast_res_pjsip_initialize_configuration(void)
|
||||||
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0);
|
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0);
|
||||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "preferred_codec_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, preferred_codec_only));
|
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "preferred_codec_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, preferred_codec_only));
|
||||||
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec));
|
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec));
|
||||||
|
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux));
|
||||||
|
|
||||||
if (ast_sip_initialize_sorcery_transport()) {
|
if (ast_sip_initialize_sorcery_transport()) {
|
||||||
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
|
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
|
||||||
|
|
|
@ -169,6 +169,23 @@ static int rtp_check_timeout(const void *data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Enable RTCP on an RTP session.
|
||||||
|
*/
|
||||||
|
static void enable_rtcp(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
|
||||||
|
const struct pjmedia_sdp_media *remote_media)
|
||||||
|
{
|
||||||
|
enum ast_rtp_instance_rtcp rtcp_type;
|
||||||
|
|
||||||
|
if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux) {
|
||||||
|
rtcp_type = AST_RTP_INSTANCE_RTCP_MUX;
|
||||||
|
} else {
|
||||||
|
rtcp_type = AST_RTP_INSTANCE_RTCP_STANDARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RTCP, rtcp_type);
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief Internal function which creates an RTP instance */
|
/*! \brief Internal function which creates an RTP instance */
|
||||||
static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
|
static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
|
||||||
{
|
{
|
||||||
|
@ -186,7 +203,6 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RTCP, 1);
|
|
||||||
ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_NAT, session->endpoint->media.rtp.symmetric);
|
ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_NAT, session->endpoint->media.rtp.symmetric);
|
||||||
|
|
||||||
if (!session->endpoint->media.rtp.ice_support && (ice = ast_rtp_instance_get_ice(session_media->rtp))) {
|
if (!session->endpoint->media.rtp.ice_support && (ice = ast_rtp_instance_get_ice(session_media->rtp))) {
|
||||||
|
@ -569,6 +585,13 @@ static void process_ice_attributes(struct ast_sip_session *session, struct ast_s
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux && candidate.id > 1) {
|
||||||
|
/* Remote side may have offered RTP and RTCP candidates. However, if we're using RTCP MUX,
|
||||||
|
* then we should ignore RTCP candidates.
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
candidate.foundation = foundation;
|
candidate.foundation = foundation;
|
||||||
candidate.transport = transport;
|
candidate.transport = transport;
|
||||||
|
|
||||||
|
@ -865,6 +888,26 @@ static int setup_media_encryption(struct ast_sip_session *session,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_ice_components(struct ast_sip_session *session, struct ast_sip_session_media *session_media)
|
||||||
|
{
|
||||||
|
struct ast_rtp_engine_ice *ice;
|
||||||
|
|
||||||
|
ast_assert(session_media->rtp != NULL);
|
||||||
|
|
||||||
|
ice = ast_rtp_instance_get_ice(session_media->rtp);
|
||||||
|
if (!session->endpoint->media.rtp.ice_support || !ice) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->endpoint->media.rtcp_mux && session_media->remote_rtcp_mux) {
|
||||||
|
/* We both support RTCP mux. Only one ICE component necessary */
|
||||||
|
ice->change_components(session_media->rtp, 1);
|
||||||
|
} else {
|
||||||
|
/* They either don't support RTCP mux or we don't know if they do yet. */
|
||||||
|
ice->change_components(session_media->rtp, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*! \brief Function which negotiates an incoming media stream */
|
/*! \brief Function which negotiates an incoming media stream */
|
||||||
static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
|
static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
|
||||||
const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
|
const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
|
||||||
|
@ -909,6 +952,11 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(stream, "rtcp-mux", NULL) != NULL);
|
||||||
|
set_ice_components(session, session_media);
|
||||||
|
|
||||||
|
enable_rtcp(session, session_media, stream);
|
||||||
|
|
||||||
res = setup_media_encryption(session, session_media, sdp, stream);
|
res = setup_media_encryption(session, session_media, sdp, stream);
|
||||||
if (res) {
|
if (res) {
|
||||||
if (!session->endpoint->media.rtp.encryption_optimistic ||
|
if (!session->endpoint->media.rtp.encryption_optimistic ||
|
||||||
|
@ -1087,6 +1135,9 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_ice_components(session, session_media);
|
||||||
|
enable_rtcp(session, session_media, NULL);
|
||||||
|
|
||||||
if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
|
if (!(media = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_media))) ||
|
||||||
!(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
|
!(media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn)))) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1250,6 +1301,12 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
|
||||||
attr->name = !session_media->locally_held ? STR_SENDRECV : STR_SENDONLY;
|
attr->name = !session_media->locally_held ? STR_SENDRECV : STR_SENDONLY;
|
||||||
media->attr[media->attr_count++] = attr;
|
media->attr[media->attr_count++] = attr;
|
||||||
|
|
||||||
|
/* If we've got rtcp-mux enabled, just unconditionally offer it in all SDPs */
|
||||||
|
if (session->endpoint->media.rtcp_mux) {
|
||||||
|
attr = pjmedia_sdp_attr_create(pool, "rtcp-mux", NULL);
|
||||||
|
pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Add the media stream to the SDP */
|
/* Add the media stream to the SDP */
|
||||||
sdp->media[sdp->media_count++] = media;
|
sdp->media[sdp->media_count++] = media;
|
||||||
|
|
||||||
|
@ -1284,6 +1341,11 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(remote_stream, "rtcp-mux", NULL) != NULL);
|
||||||
|
set_ice_components(session, session_media);
|
||||||
|
|
||||||
|
enable_rtcp(session, session_media, remote_stream);
|
||||||
|
|
||||||
res = setup_media_encryption(session, session_media, remote, remote_stream);
|
res = setup_media_encryption(session, session_media, remote, remote_stream);
|
||||||
if (!session->endpoint->media.rtp.encryption_optimistic && res) {
|
if (!session->endpoint->media.rtp.encryption_optimistic && res) {
|
||||||
/* If optimistic encryption is disabled and crypto should have been enabled but was not
|
/* If optimistic encryption is disabled and crypto should have been enabled but was not
|
||||||
|
@ -1315,7 +1377,9 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ast_channel_set_fd(session->channel, fdno, ast_rtp_instance_fd(session_media->rtp, 0));
|
ast_channel_set_fd(session->channel, fdno, ast_rtp_instance_fd(session_media->rtp, 0));
|
||||||
ast_channel_set_fd(session->channel, fdno + 1, ast_rtp_instance_fd(session_media->rtp, 1));
|
if (!session->endpoint->media.rtcp_mux || !session_media->remote_rtcp_mux) {
|
||||||
|
ast_channel_set_fd(session->channel, fdno + 1, ast_rtp_instance_fd(session_media->rtp, 1));
|
||||||
|
}
|
||||||
|
|
||||||
/* If ICE support is enabled find all the needed attributes */
|
/* If ICE support is enabled find all the needed attributes */
|
||||||
process_ice_attributes(session, session_media, remote, remote_stream);
|
process_ice_attributes(session, session_media, remote, remote_stream);
|
||||||
|
|
|
@ -329,6 +329,7 @@ struct ast_rtp {
|
||||||
struct ao2_container *ice_active_remote_candidates; /*!< The remote ICE candidates */
|
struct ao2_container *ice_active_remote_candidates; /*!< The remote ICE candidates */
|
||||||
struct ao2_container *ice_proposed_remote_candidates; /*!< Incoming remote ICE candidates for new session */
|
struct ao2_container *ice_proposed_remote_candidates; /*!< Incoming remote ICE candidates for new session */
|
||||||
struct ast_sockaddr ice_original_rtp_addr; /*!< rtp address that ICE started on first session */
|
struct ast_sockaddr ice_original_rtp_addr; /*!< rtp address that ICE started on first session */
|
||||||
|
unsigned int ice_num_components; /*!< The number of ICE components */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL_SRTP
|
#ifdef HAVE_OPENSSL_SRTP
|
||||||
|
@ -417,6 +418,9 @@ struct ast_rtcp {
|
||||||
* own address every time
|
* own address every time
|
||||||
*/
|
*/
|
||||||
char *local_addr_str;
|
char *local_addr_str;
|
||||||
|
enum ast_rtp_instance_rtcp type;
|
||||||
|
/* Buffer for frames created during RTCP interpretation */
|
||||||
|
unsigned char frame_buf[512 + AST_FRIENDLY_OFFSET];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rtp_red {
|
struct rtp_red {
|
||||||
|
@ -658,6 +662,22 @@ static int ice_reset_session(struct ast_rtp_instance *instance)
|
||||||
pj_ice_sess_change_role(rtp->ice, role);
|
pj_ice_sess_change_role(rtp->ice, role);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we only have one component now, and we previously set up TURN for RTCP,
|
||||||
|
* we need to destroy that TURN socket.
|
||||||
|
*/
|
||||||
|
if (rtp->ice_num_components == 1 && rtp->turn_rtcp) {
|
||||||
|
struct timeval wait = ast_tvadd(ast_tvnow(), ast_samp2tv(TURN_STATE_WAIT_TIME, 1000));
|
||||||
|
struct timespec ts = { .tv_sec = wait.tv_sec, .tv_nsec = wait.tv_usec * 1000, };
|
||||||
|
|
||||||
|
ast_mutex_lock(&rtp->lock);
|
||||||
|
pj_turn_sock_destroy(rtp->turn_rtcp);
|
||||||
|
rtp->turn_state = PJ_TURN_STATE_NULL;
|
||||||
|
while (rtp->turn_state != PJ_TURN_STATE_DESTROYING) {
|
||||||
|
ast_cond_timedwait(&rtp->cond, &rtp->lock, &ts);
|
||||||
|
}
|
||||||
|
ast_mutex_unlock(&rtp->lock);
|
||||||
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -773,11 +793,12 @@ static void ast_rtp_ice_start(struct ast_rtp_instance *instance)
|
||||||
ast_log(LOG_WARNING, "No RTP candidates; skipping ICE checklist (%p)\n", instance);
|
ast_log(LOG_WARNING, "No RTP candidates; skipping ICE checklist (%p)\n", instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_rtcp) {
|
/* If we're only dealing with one ICE component, then we don't care about the lack of RTCP candidates */
|
||||||
|
if (!has_rtcp && rtp->ice_num_components > 1) {
|
||||||
ast_log(LOG_WARNING, "No RTCP candidates; skipping ICE checklist (%p)\n", instance);
|
ast_log(LOG_WARNING, "No RTCP candidates; skipping ICE checklist (%p)\n", instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_rtp && has_rtcp) {
|
if (has_rtp && (has_rtcp || rtp->ice_num_components == 1)) {
|
||||||
pj_status_t res = pj_ice_sess_create_check_list(rtp->ice, &ufrag, &passwd, cand_cnt, &candidates[0]);
|
pj_status_t res = pj_ice_sess_create_check_list(rtp->ice, &ufrag, &passwd, cand_cnt, &candidates[0]);
|
||||||
char reason[80];
|
char reason[80];
|
||||||
|
|
||||||
|
@ -1269,6 +1290,21 @@ static char *generate_random_string(char *buf, size_t size)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ast_rtp_ice_change_components(struct ast_rtp_instance *instance, int num_components)
|
||||||
|
{
|
||||||
|
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
|
||||||
|
|
||||||
|
/* Don't do anything if ICE is unsupported or if we're not changing the
|
||||||
|
* number of components
|
||||||
|
*/
|
||||||
|
if (!icesupport || !rtp->ice || rtp->ice_num_components == num_components) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtp->ice_num_components = num_components;
|
||||||
|
ice_reset_session(instance);
|
||||||
|
}
|
||||||
|
|
||||||
/* ICE RTP Engine interface declaration */
|
/* ICE RTP Engine interface declaration */
|
||||||
static struct ast_rtp_engine_ice ast_rtp_ice = {
|
static struct ast_rtp_engine_ice ast_rtp_ice = {
|
||||||
.set_authentication = ast_rtp_ice_set_authentication,
|
.set_authentication = ast_rtp_ice_set_authentication,
|
||||||
|
@ -1281,6 +1317,7 @@ static struct ast_rtp_engine_ice ast_rtp_ice = {
|
||||||
.ice_lite = ast_rtp_ice_lite,
|
.ice_lite = ast_rtp_ice_lite,
|
||||||
.set_role = ast_rtp_ice_set_role,
|
.set_role = ast_rtp_ice_set_role,
|
||||||
.turn_request = ast_rtp_ice_turn_request,
|
.turn_request = ast_rtp_ice_turn_request,
|
||||||
|
.change_components = ast_rtp_ice_change_components,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1540,6 +1577,7 @@ static int ast_rtp_dtls_active(struct ast_rtp_instance *instance)
|
||||||
static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance)
|
static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance)
|
||||||
{
|
{
|
||||||
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
|
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
|
||||||
|
int rtcp_dtls_unique = (rtp->dtls.ssl != rtp->rtcp->dtls.ssl);
|
||||||
|
|
||||||
dtls_srtp_stop_timeout_timer(instance, rtp, 0);
|
dtls_srtp_stop_timeout_timer(instance, rtp, 0);
|
||||||
|
|
||||||
|
@ -1557,7 +1595,7 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance)
|
||||||
if (rtp->rtcp) {
|
if (rtp->rtcp) {
|
||||||
dtls_srtp_stop_timeout_timer(instance, rtp, 1);
|
dtls_srtp_stop_timeout_timer(instance, rtp, 1);
|
||||||
|
|
||||||
if (rtp->rtcp->dtls.ssl) {
|
if (rtp->rtcp->dtls.ssl && rtcp_dtls_unique) {
|
||||||
SSL_free(rtp->rtcp->dtls.ssl);
|
SSL_free(rtp->rtcp->dtls.ssl);
|
||||||
rtp->rtcp->dtls.ssl = NULL;
|
rtp->rtcp->dtls.ssl = NULL;
|
||||||
ast_mutex_destroy(&rtp->rtcp->dtls.lock);
|
ast_mutex_destroy(&rtp->rtcp->dtls.lock);
|
||||||
|
@ -1785,7 +1823,7 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
|
||||||
#ifdef HAVE_OPENSSL_SRTP
|
#ifdef HAVE_OPENSSL_SRTP
|
||||||
dtls_perform_handshake(instance, &rtp->dtls, 0);
|
dtls_perform_handshake(instance, &rtp->dtls, 0);
|
||||||
|
|
||||||
if (rtp->rtcp) {
|
if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) {
|
||||||
dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1);
|
dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2025,7 +2063,7 @@ static int dtls_srtp_renegotiate(const void *data)
|
||||||
SSL_do_handshake(rtp->dtls.ssl);
|
SSL_do_handshake(rtp->dtls.ssl);
|
||||||
dtls_srtp_check_pending(instance, rtp, 0);
|
dtls_srtp_check_pending(instance, rtp, 0);
|
||||||
|
|
||||||
if (rtp->rtcp && rtp->rtcp->dtls.ssl) {
|
if (rtp->rtcp && rtp->rtcp->dtls.ssl && rtp->rtcp->dtls.ssl != rtp->dtls.ssl) {
|
||||||
SSL_renegotiate(rtp->rtcp->dtls.ssl);
|
SSL_renegotiate(rtp->rtcp->dtls.ssl);
|
||||||
SSL_do_handshake(rtp->rtcp->dtls.ssl);
|
SSL_do_handshake(rtp->rtcp->dtls.ssl);
|
||||||
dtls_srtp_check_pending(instance, rtp, 1);
|
dtls_srtp_check_pending(instance, rtp, 1);
|
||||||
|
@ -2616,7 +2654,7 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad
|
||||||
passwd = pj_str(rtp->local_passwd);
|
passwd = pj_str(rtp->local_passwd);
|
||||||
|
|
||||||
/* Create an ICE session for ICE negotiation */
|
/* Create an ICE session for ICE negotiation */
|
||||||
if (pj_ice_sess_create(&stun_config, NULL, PJ_ICE_SESS_ROLE_UNKNOWN, 2,
|
if (pj_ice_sess_create(&stun_config, NULL, PJ_ICE_SESS_ROLE_UNKNOWN, rtp->ice_num_components,
|
||||||
&ast_rtp_ice_sess_cb, &ufrag, &passwd, NULL, &rtp->ice) == PJ_SUCCESS) {
|
&ast_rtp_ice_sess_cb, &ufrag, &passwd, NULL, &rtp->ice) == PJ_SUCCESS) {
|
||||||
/* Make this available for the callbacks */
|
/* Make this available for the callbacks */
|
||||||
rtp->ice->user_data = instance;
|
rtp->ice->user_data = instance;
|
||||||
|
@ -2625,9 +2663,10 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad
|
||||||
rtp_add_candidates_to_ice(instance, rtp, addr, port, AST_RTP_ICE_COMPONENT_RTP,
|
rtp_add_candidates_to_ice(instance, rtp, addr, port, AST_RTP_ICE_COMPONENT_RTP,
|
||||||
TRANSPORT_SOCKET_RTP);
|
TRANSPORT_SOCKET_RTP);
|
||||||
|
|
||||||
/* Only add the RTCP candidates to ICE when replacing the session. New sessions
|
/* Only add the RTCP candidates to ICE when replacing the session and if
|
||||||
|
* the ICE session contains more than just an RTP component. New sessions
|
||||||
* handle this in a separate part of the setup phase */
|
* handle this in a separate part of the setup phase */
|
||||||
if (replace && rtp->rtcp) {
|
if (replace && rtp->rtcp && rtp->ice_num_components > 1) {
|
||||||
rtp_add_candidates_to_ice(instance, rtp, &rtp->rtcp->us,
|
rtp_add_candidates_to_ice(instance, rtp, &rtp->rtcp->us,
|
||||||
ast_sockaddr_port(&rtp->rtcp->us), AST_RTP_ICE_COMPONENT_RTCP,
|
ast_sockaddr_port(&rtp->rtcp->us), AST_RTP_ICE_COMPONENT_RTCP,
|
||||||
TRANSPORT_SOCKET_RTCP);
|
TRANSPORT_SOCKET_RTCP);
|
||||||
|
@ -2712,6 +2751,7 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
|
||||||
#ifdef HAVE_PJPROJECT
|
#ifdef HAVE_PJPROJECT
|
||||||
/* Create an ICE session for ICE negotiation */
|
/* Create an ICE session for ICE negotiation */
|
||||||
if (icesupport) {
|
if (icesupport) {
|
||||||
|
rtp->ice_num_components = 2;
|
||||||
ast_debug(3, "Creating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(addr), x, instance);
|
ast_debug(3, "Creating ICE session %s (%d) for RTP instance '%p'\n", ast_sockaddr_stringify(addr), x, instance);
|
||||||
if (ice_create(instance, addr, x, 0)) {
|
if (ice_create(instance, addr, x, 0)) {
|
||||||
ast_log(LOG_NOTICE, "Failed to start ICE session\n");
|
ast_log(LOG_NOTICE, "Failed to start ICE session\n");
|
||||||
|
@ -2721,7 +2761,6 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Record any information we may need */
|
/* Record any information we may need */
|
||||||
rtp->sched = sched;
|
rtp->sched = sched;
|
||||||
|
|
||||||
|
@ -4150,63 +4189,21 @@ static void update_lost_stats(struct ast_rtp *rtp, unsigned int lost_packets)
|
||||||
rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
|
rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
static struct ast_frame *ast_rtcp_interpret(struct ast_rtp_instance *instance, const unsigned char *rtcpdata, size_t size, struct ast_sockaddr *addr)
|
||||||
{
|
{
|
||||||
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
|
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
|
||||||
struct ast_sockaddr addr;
|
unsigned int *rtcpheader = (unsigned int *)(rtcpdata);
|
||||||
unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET];
|
int packetwords, position = 0;
|
||||||
unsigned int *rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
|
|
||||||
int res, packetwords, position = 0;
|
|
||||||
int report_counter = 0;
|
int report_counter = 0;
|
||||||
struct ast_rtp_rtcp_report_block *report_block;
|
struct ast_rtp_rtcp_report_block *report_block;
|
||||||
struct ast_frame *f = &ast_null_frame;
|
struct ast_frame *f = &ast_null_frame;
|
||||||
|
|
||||||
/* Read in RTCP data from the socket */
|
packetwords = size / 4;
|
||||||
if ((res = rtcp_recvfrom(instance, rtcpdata + AST_FRIENDLY_OFFSET,
|
|
||||||
sizeof(rtcpdata) - AST_FRIENDLY_OFFSET,
|
|
||||||
0, &addr)) < 0) {
|
|
||||||
ast_assert(errno != EBADF);
|
|
||||||
if (errno != EAGAIN) {
|
|
||||||
ast_log(LOG_WARNING, "RTCP Read error: %s. Hanging up.\n",
|
|
||||||
(errno) ? strerror(errno) : "Unspecified");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return &ast_null_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If this was handled by the ICE session don't do anything further */
|
|
||||||
if (!res) {
|
|
||||||
return &ast_null_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!*(rtcpdata + AST_FRIENDLY_OFFSET)) {
|
|
||||||
struct sockaddr_in addr_tmp;
|
|
||||||
struct ast_sockaddr addr_v4;
|
|
||||||
|
|
||||||
if (ast_sockaddr_is_ipv4(&addr)) {
|
|
||||||
ast_sockaddr_to_sin(&addr, &addr_tmp);
|
|
||||||
} else if (ast_sockaddr_ipv4_mapped(&addr, &addr_v4)) {
|
|
||||||
ast_debug(1, "Using IPv6 mapped address %s for STUN\n",
|
|
||||||
ast_sockaddr_stringify(&addr));
|
|
||||||
ast_sockaddr_to_sin(&addr_v4, &addr_tmp);
|
|
||||||
} else {
|
|
||||||
ast_debug(1, "Cannot do STUN for non IPv4 address %s\n",
|
|
||||||
ast_sockaddr_stringify(&addr));
|
|
||||||
return &ast_null_frame;
|
|
||||||
}
|
|
||||||
if ((ast_stun_handle_packet(rtp->rtcp->s, &addr_tmp, rtcpdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT)) {
|
|
||||||
ast_sockaddr_from_sin(&addr, &addr_tmp);
|
|
||||||
ast_sockaddr_copy(&rtp->rtcp->them, &addr);
|
|
||||||
}
|
|
||||||
return &ast_null_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
packetwords = res / 4;
|
|
||||||
|
|
||||||
if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
|
if (ast_rtp_instance_get_prop(instance, AST_RTP_PROPERTY_NAT)) {
|
||||||
/* Send to whoever sent to us */
|
/* Send to whoever sent to us */
|
||||||
if (ast_sockaddr_cmp(&rtp->rtcp->them, &addr)) {
|
if (ast_sockaddr_cmp(&rtp->rtcp->them, addr)) {
|
||||||
ast_sockaddr_copy(&rtp->rtcp->them, &addr);
|
ast_sockaddr_copy(&rtp->rtcp->them, addr);
|
||||||
if (rtpdebug) {
|
if (rtpdebug) {
|
||||||
ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",
|
ast_debug(0, "RTCP NAT: Got RTCP from other end. Now sending to address %s\n",
|
||||||
ast_sockaddr_stringify(&rtp->rtcp->them));
|
ast_sockaddr_stringify(&rtp->rtcp->them));
|
||||||
|
@ -4214,7 +4211,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_debug(1, "Got RTCP report of %d bytes\n", res);
|
ast_debug(1, "Got RTCP report of %zu bytes\n", size);
|
||||||
|
|
||||||
while (position < packetwords) {
|
while (position < packetwords) {
|
||||||
int i, pt, rc;
|
int i, pt, rc;
|
||||||
|
@ -4242,9 +4239,9 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
return &ast_null_frame;
|
return &ast_null_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rtcp_debug_test_addr(&addr)) {
|
if (rtcp_debug_test_addr(addr)) {
|
||||||
ast_verbose("\n\nGot RTCP from %s\n",
|
ast_verbose("\n\nGot RTCP from %s\n",
|
||||||
ast_sockaddr_stringify(&addr));
|
ast_sockaddr_stringify(addr));
|
||||||
ast_verbose("PT: %d(%s)\n", pt, (pt == RTCP_PT_SR) ? "Sender Report" :
|
ast_verbose("PT: %d(%s)\n", pt, (pt == RTCP_PT_SR) ? "Sender Report" :
|
||||||
(pt == RTCP_PT_RR) ? "Receiver Report" :
|
(pt == RTCP_PT_RR) ? "Receiver Report" :
|
||||||
(pt == RTCP_PT_FUR) ? "H.261 FUR" : "Unknown");
|
(pt == RTCP_PT_FUR) ? "H.261 FUR" : "Unknown");
|
||||||
|
@ -4267,7 +4264,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
(unsigned int)ntohl(rtcpheader[i + 1]),
|
(unsigned int)ntohl(rtcpheader[i + 1]),
|
||||||
&rtcp_report->sender_information.ntp_timestamp);
|
&rtcp_report->sender_information.ntp_timestamp);
|
||||||
rtcp_report->sender_information.rtp_timestamp = ntohl(rtcpheader[i + 2]);
|
rtcp_report->sender_information.rtp_timestamp = ntohl(rtcpheader[i + 2]);
|
||||||
if (rtcp_debug_test_addr(&addr)) {
|
if (rtcp_debug_test_addr(addr)) {
|
||||||
ast_verbose("NTP timestamp: %u.%06u\n",
|
ast_verbose("NTP timestamp: %u.%06u\n",
|
||||||
(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
|
(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_sec,
|
||||||
(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec);
|
(unsigned int)rtcp_report->sender_information.ntp_timestamp.tv_usec);
|
||||||
|
@ -4299,7 +4296,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
report_block->dlsr = ntohl(rtcpheader[i + 5]);
|
report_block->dlsr = ntohl(rtcpheader[i + 5]);
|
||||||
if (report_block->lsr
|
if (report_block->lsr
|
||||||
&& update_rtt_stats(rtp, report_block->lsr, report_block->dlsr)
|
&& update_rtt_stats(rtp, report_block->lsr, report_block->dlsr)
|
||||||
&& rtcp_debug_test_addr(&addr)) {
|
&& rtcp_debug_test_addr(addr)) {
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
unsigned int lsr_now, lsw, msw;
|
unsigned int lsr_now, lsw, msw;
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
|
@ -4316,7 +4313,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
update_lost_stats(rtp, report_block->lost_count.packets);
|
update_lost_stats(rtp, report_block->lost_count.packets);
|
||||||
rtp->rtcp->reported_jitter_count++;
|
rtp->rtcp->reported_jitter_count++;
|
||||||
|
|
||||||
if (rtcp_debug_test_addr(&addr)) {
|
if (rtcp_debug_test_addr(addr)) {
|
||||||
ast_verbose(" Fraction lost: %d\n", report_block->lost_count.fraction);
|
ast_verbose(" Fraction lost: %d\n", report_block->lost_count.fraction);
|
||||||
ast_verbose(" Packets lost so far: %u\n", report_block->lost_count.packets);
|
ast_verbose(" Packets lost so far: %u\n", report_block->lost_count.packets);
|
||||||
ast_verbose(" Highest sequence number: %u\n", report_block->highest_seq_no & 0x0000ffff);
|
ast_verbose(" Highest sequence number: %u\n", report_block->highest_seq_no & 0x0000ffff);
|
||||||
|
@ -4344,7 +4341,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
/* Return an AST_FRAME_RTCP frame with the ast_rtp_rtcp_report
|
/* Return an AST_FRAME_RTCP frame with the ast_rtp_rtcp_report
|
||||||
* object as a its data */
|
* object as a its data */
|
||||||
rtp->f.frametype = AST_FRAME_RTCP;
|
rtp->f.frametype = AST_FRAME_RTCP;
|
||||||
rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET;
|
rtp->f.data.ptr = rtp->rtcp->frame_buf + AST_FRIENDLY_OFFSET;
|
||||||
memcpy(rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report));
|
memcpy(rtp->f.data.ptr, rtcp_report, sizeof(struct ast_rtp_rtcp_report));
|
||||||
rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report);
|
rtp->f.datalen = sizeof(struct ast_rtp_rtcp_report);
|
||||||
if (rc > 0) {
|
if (rc > 0) {
|
||||||
|
@ -4367,7 +4364,7 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
case RTCP_PT_FUR:
|
case RTCP_PT_FUR:
|
||||||
/* Handle RTCP FIR as FUR */
|
/* Handle RTCP FIR as FUR */
|
||||||
case RTCP_PT_PSFB:
|
case RTCP_PT_PSFB:
|
||||||
if (rtcp_debug_test_addr(&addr)) {
|
if (rtcp_debug_test_addr(addr)) {
|
||||||
ast_verbose("Received an RTCP Fast Update Request\n");
|
ast_verbose("Received an RTCP Fast Update Request\n");
|
||||||
}
|
}
|
||||||
rtp->f.frametype = AST_FRAME_CONTROL;
|
rtp->f.frametype = AST_FRAME_CONTROL;
|
||||||
|
@ -4379,13 +4376,13 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
f = &rtp->f;
|
f = &rtp->f;
|
||||||
break;
|
break;
|
||||||
case RTCP_PT_SDES:
|
case RTCP_PT_SDES:
|
||||||
if (rtcp_debug_test_addr(&addr)) {
|
if (rtcp_debug_test_addr(addr)) {
|
||||||
ast_verbose("Received an SDES from %s\n",
|
ast_verbose("Received an SDES from %s\n",
|
||||||
ast_sockaddr_stringify(&rtp->rtcp->them));
|
ast_sockaddr_stringify(&rtp->rtcp->them));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RTCP_PT_BYE:
|
case RTCP_PT_BYE:
|
||||||
if (rtcp_debug_test_addr(&addr)) {
|
if (rtcp_debug_test_addr(addr)) {
|
||||||
ast_verbose("Received a BYE from %s\n",
|
ast_verbose("Received a BYE from %s\n",
|
||||||
ast_sockaddr_stringify(&rtp->rtcp->them));
|
ast_sockaddr_stringify(&rtp->rtcp->them));
|
||||||
}
|
}
|
||||||
|
@ -4400,6 +4397,58 @@ static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
rtp->rtcp->rtcp_info = 1;
|
rtp->rtcp->rtcp_info = 1;
|
||||||
|
|
||||||
return f;
|
return f;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ast_frame *ast_rtcp_read(struct ast_rtp_instance *instance)
|
||||||
|
{
|
||||||
|
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
|
||||||
|
struct ast_sockaddr addr;
|
||||||
|
unsigned char rtcpdata[8192 + AST_FRIENDLY_OFFSET];
|
||||||
|
unsigned char *read_area = rtcpdata + AST_FRIENDLY_OFFSET;
|
||||||
|
size_t read_area_size = sizeof(rtcpdata) - AST_FRIENDLY_OFFSET;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
/* Read in RTCP data from the socket */
|
||||||
|
if ((res = rtcp_recvfrom(instance, read_area, read_area_size,
|
||||||
|
0, &addr)) < 0) {
|
||||||
|
ast_assert(errno != EBADF);
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
ast_log(LOG_WARNING, "RTCP Read error: %s. Hanging up.\n",
|
||||||
|
(errno) ? strerror(errno) : "Unspecified");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return &ast_null_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this was handled by the ICE session don't do anything further */
|
||||||
|
if (!res) {
|
||||||
|
return &ast_null_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*(read_area)) {
|
||||||
|
struct sockaddr_in addr_tmp;
|
||||||
|
struct ast_sockaddr addr_v4;
|
||||||
|
|
||||||
|
if (ast_sockaddr_is_ipv4(&addr)) {
|
||||||
|
ast_sockaddr_to_sin(&addr, &addr_tmp);
|
||||||
|
} else if (ast_sockaddr_ipv4_mapped(&addr, &addr_v4)) {
|
||||||
|
ast_debug(1, "Using IPv6 mapped address %s for STUN\n",
|
||||||
|
ast_sockaddr_stringify(&addr));
|
||||||
|
ast_sockaddr_to_sin(&addr_v4, &addr_tmp);
|
||||||
|
} else {
|
||||||
|
ast_debug(1, "Cannot do STUN for non IPv4 address %s\n",
|
||||||
|
ast_sockaddr_stringify(&addr));
|
||||||
|
return &ast_null_frame;
|
||||||
|
}
|
||||||
|
if ((ast_stun_handle_packet(rtp->rtcp->s, &addr_tmp, read_area, res, NULL, NULL) == AST_STUN_ACCEPT)) {
|
||||||
|
ast_sockaddr_from_sin(&addr, &addr_tmp);
|
||||||
|
ast_sockaddr_copy(&rtp->rtcp->them, &addr);
|
||||||
|
}
|
||||||
|
return &ast_null_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast_rtcp_interpret(instance, read_area, read_area_size, &addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int *rtpheader, int len, int hdrlen)
|
static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int *rtpheader, int len, int hdrlen)
|
||||||
|
@ -4507,19 +4556,54 @@ static int bridge_p2p_rtp_write(struct ast_rtp_instance *instance, unsigned int
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtcp_mux(struct ast_rtp *rtp, const unsigned char *packet)
|
||||||
|
{
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t pt;
|
||||||
|
uint8_t m;
|
||||||
|
|
||||||
|
if (!rtp->rtcp || rtp->rtcp->type != AST_RTP_INSTANCE_RTCP_MUX) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
version = (packet[0] & 0XC0) >> 6;
|
||||||
|
if (version == 0) {
|
||||||
|
/* version 0 indicates this is a STUN packet and shouldn't
|
||||||
|
* be interpreted as a possible RTCP packet
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The second octet of a packet will be one of the following:
|
||||||
|
* For RTP: The marker bit (1 bit) and the RTP payload type (7 bits)
|
||||||
|
* For RTCP: The payload type (8)
|
||||||
|
*
|
||||||
|
* RTP has a forbidden range of payload types (64-95) since these
|
||||||
|
* will conflict with RTCP payload numbers if the marker bit is set.
|
||||||
|
*/
|
||||||
|
m = packet[1] & 0x80;
|
||||||
|
pt = packet[1] & 0x7F;
|
||||||
|
if (m && pt >= 64 && pt <= 95) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp)
|
static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtcp)
|
||||||
{
|
{
|
||||||
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
|
struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
|
||||||
struct ast_sockaddr addr;
|
struct ast_sockaddr addr;
|
||||||
int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno;
|
int res, hdrlen = 12, version, payloadtype, padding, mark, ext, cc, prev_seqno;
|
||||||
unsigned int *rtpheader = (unsigned int*)(rtp->rawdata + AST_FRIENDLY_OFFSET), seqno, ssrc, timestamp;
|
unsigned char *read_area = rtp->rawdata + AST_FRIENDLY_OFFSET;
|
||||||
|
size_t read_area_size = sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET;
|
||||||
|
unsigned int *rtpheader = (unsigned int*)(read_area), seqno, ssrc, timestamp;
|
||||||
RAII_VAR(struct ast_rtp_payload_type *, payload, NULL, ao2_cleanup);
|
RAII_VAR(struct ast_rtp_payload_type *, payload, NULL, ao2_cleanup);
|
||||||
struct ast_sockaddr remote_address = { {0,} };
|
struct ast_sockaddr remote_address = { {0,} };
|
||||||
struct frame_list frames;
|
struct frame_list frames;
|
||||||
|
|
||||||
/* If this is actually RTCP let's hop on over and handle it */
|
/* If this is actually RTCP let's hop on over and handle it */
|
||||||
if (rtcp) {
|
if (rtcp) {
|
||||||
if (rtp->rtcp) {
|
if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) {
|
||||||
return ast_rtcp_read(instance);
|
return ast_rtcp_read(instance);
|
||||||
}
|
}
|
||||||
return &ast_null_frame;
|
return &ast_null_frame;
|
||||||
|
@ -4531,8 +4615,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actually read in the data from the socket */
|
/* Actually read in the data from the socket */
|
||||||
if ((res = rtp_recvfrom(instance, rtp->rawdata + AST_FRIENDLY_OFFSET,
|
if ((res = rtp_recvfrom(instance, read_area, read_area_size, 0,
|
||||||
sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET, 0,
|
|
||||||
&addr)) < 0) {
|
&addr)) < 0) {
|
||||||
ast_assert(errno != EBADF);
|
ast_assert(errno != EBADF);
|
||||||
if (errno != EAGAIN) {
|
if (errno != EAGAIN) {
|
||||||
|
@ -4548,12 +4631,17 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
|
||||||
return &ast_null_frame;
|
return &ast_null_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This could be a multiplexed RTCP packet. If so, be sure to interpret it correctly */
|
||||||
|
if (rtcp_mux(rtp, read_area)) {
|
||||||
|
return ast_rtcp_interpret(instance, read_area, read_area_size, &addr);
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure the data that was read in is actually enough to make up an RTP packet */
|
/* Make sure the data that was read in is actually enough to make up an RTP packet */
|
||||||
if (res < hdrlen) {
|
if (res < hdrlen) {
|
||||||
/* If this is a keepalive containing only nulls, don't bother with a warning */
|
/* If this is a keepalive containing only nulls, don't bother with a warning */
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < res; ++i) {
|
for (i = 0; i < res; ++i) {
|
||||||
if (rtp->rawdata[AST_FRIENDLY_OFFSET + i] != '\0') {
|
if (read_area[i] != '\0') {
|
||||||
ast_log(LOG_WARNING, "RTP Read too short\n");
|
ast_log(LOG_WARNING, "RTP Read too short\n");
|
||||||
return &ast_null_frame;
|
return &ast_null_frame;
|
||||||
}
|
}
|
||||||
|
@ -4580,7 +4668,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
|
||||||
ast_sockaddr_stringify(&addr));
|
ast_sockaddr_stringify(&addr));
|
||||||
return &ast_null_frame;
|
return &ast_null_frame;
|
||||||
}
|
}
|
||||||
if ((ast_stun_handle_packet(rtp->s, &addr_tmp, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == AST_STUN_ACCEPT) &&
|
if ((ast_stun_handle_packet(rtp->s, &addr_tmp, read_area, res, NULL, NULL) == AST_STUN_ACCEPT) &&
|
||||||
ast_sockaddr_isnull(&remote_address)) {
|
ast_sockaddr_isnull(&remote_address)) {
|
||||||
ast_sockaddr_from_sin(&addr, &addr_tmp);
|
ast_sockaddr_from_sin(&addr, &addr_tmp);
|
||||||
ast_rtp_instance_set_remote_address(instance, &addr);
|
ast_rtp_instance_set_remote_address(instance, &addr);
|
||||||
|
@ -4629,7 +4717,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
|
||||||
/* do not update the originally given address, but only the remote */
|
/* do not update the originally given address, but only the remote */
|
||||||
ast_rtp_instance_set_incoming_source_address(instance, &addr);
|
ast_rtp_instance_set_incoming_source_address(instance, &addr);
|
||||||
ast_sockaddr_copy(&remote_address, &addr);
|
ast_sockaddr_copy(&remote_address, &addr);
|
||||||
if (rtp->rtcp) {
|
if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) {
|
||||||
ast_sockaddr_copy(&rtp->rtcp->them, &addr);
|
ast_sockaddr_copy(&rtp->rtcp->them, &addr);
|
||||||
ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(&addr) + 1);
|
ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(&addr) + 1);
|
||||||
}
|
}
|
||||||
|
@ -4696,7 +4784,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
|
||||||
|
|
||||||
/* Remove any padding bytes that may be present */
|
/* Remove any padding bytes that may be present */
|
||||||
if (padding) {
|
if (padding) {
|
||||||
res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1];
|
res -= read_area[res - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip over any CSRC fields */
|
/* Skip over any CSRC fields */
|
||||||
|
@ -4770,11 +4858,11 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
|
||||||
* by passing the pointer to the frame list to it so that the method
|
* by passing the pointer to the frame list to it so that the method
|
||||||
* can append frames to the list as needed.
|
* can append frames to the list as needed.
|
||||||
*/
|
*/
|
||||||
process_dtmf_rfc2833(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames);
|
process_dtmf_rfc2833(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark, &frames);
|
||||||
} else if (payload->rtp_code == AST_RTP_CISCO_DTMF) {
|
} else if (payload->rtp_code == AST_RTP_CISCO_DTMF) {
|
||||||
f = process_dtmf_cisco(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
|
f = process_dtmf_cisco(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
|
||||||
} else if (payload->rtp_code == AST_RTP_CN) {
|
} else if (payload->rtp_code == AST_RTP_CN) {
|
||||||
f = process_cn_rfc3389(instance, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
|
f = process_cn_rfc3389(instance, read_area + hdrlen, res - hdrlen, seqno, timestamp, &addr, payloadtype, mark);
|
||||||
} else {
|
} else {
|
||||||
ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n",
|
ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n",
|
||||||
payloadtype,
|
payloadtype,
|
||||||
|
@ -4830,7 +4918,7 @@ static struct ast_frame *ast_rtp_read(struct ast_rtp_instance *instance, int rtc
|
||||||
rtp->f.src = "RTP";
|
rtp->f.src = "RTP";
|
||||||
rtp->f.mallocd = 0;
|
rtp->f.mallocd = 0;
|
||||||
rtp->f.datalen = res - hdrlen;
|
rtp->f.datalen = res - hdrlen;
|
||||||
rtp->f.data.ptr = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
|
rtp->f.data.ptr = read_area + hdrlen;
|
||||||
rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
|
rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
|
||||||
rtp->f.seqno = seqno;
|
rtp->f.seqno = seqno;
|
||||||
|
|
||||||
|
@ -4941,19 +5029,29 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
|
||||||
if (value) {
|
if (value) {
|
||||||
struct ast_sockaddr local_addr;
|
struct ast_sockaddr local_addr;
|
||||||
|
|
||||||
if (rtp->rtcp) {
|
if (rtp->rtcp && rtp->rtcp->type == value) {
|
||||||
ast_debug(1, "Ignoring duplicate RTCP property on RTP instance '%p'\n", instance);
|
ast_debug(1, "Ignoring duplicate RTCP property on RTP instance '%p'\n", instance);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Setup RTCP to be activated on the next RTP write */
|
|
||||||
if (!(rtp->rtcp = ast_calloc(1, sizeof(*rtp->rtcp)))) {
|
if (!rtp->rtcp) {
|
||||||
return;
|
rtp->rtcp = ast_calloc(1, sizeof(*rtp->rtcp));
|
||||||
|
if (!rtp->rtcp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rtp->rtcp->s = -1;
|
||||||
|
rtp->rtcp->dtls.timeout_timer = -1;
|
||||||
|
rtp->rtcp->schedid = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtp->rtcp->type = value;
|
||||||
|
|
||||||
/* Grab the IP address and port we are going to use */
|
/* Grab the IP address and port we are going to use */
|
||||||
ast_rtp_instance_get_local_address(instance, &rtp->rtcp->us);
|
ast_rtp_instance_get_local_address(instance, &rtp->rtcp->us);
|
||||||
ast_sockaddr_set_port(&rtp->rtcp->us,
|
if (value == AST_RTP_INSTANCE_RTCP_STANDARD) {
|
||||||
ast_sockaddr_port(&rtp->rtcp->us) + 1);
|
ast_sockaddr_set_port(&rtp->rtcp->us,
|
||||||
|
ast_sockaddr_port(&rtp->rtcp->us) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
ast_sockaddr_copy(&local_addr, &rtp->rtcp->us);
|
ast_sockaddr_copy(&local_addr, &rtp->rtcp->us);
|
||||||
if (!ast_find_ourip(&local_addr, &rtp->rtcp->us, 0)) {
|
if (!ast_find_ourip(&local_addr, &rtp->rtcp->us, 0)) {
|
||||||
|
@ -4963,6 +5061,7 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
|
||||||
ast_sockaddr_copy(&local_addr, &rtp->rtcp->us);
|
ast_sockaddr_copy(&local_addr, &rtp->rtcp->us);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast_free(rtp->rtcp->local_addr_str);
|
||||||
rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&local_addr));
|
rtp->rtcp->local_addr_str = ast_strdup(ast_sockaddr_stringify(&local_addr));
|
||||||
if (!rtp->rtcp->local_addr_str) {
|
if (!rtp->rtcp->local_addr_str) {
|
||||||
ast_free(rtp->rtcp);
|
ast_free(rtp->rtcp);
|
||||||
|
@ -4970,43 +5069,67 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rtp->rtcp->s =
|
if (value == AST_RTP_INSTANCE_RTCP_STANDARD) {
|
||||||
create_new_socket("RTCP",
|
/* We're either setting up RTCP from scratch or
|
||||||
ast_sockaddr_is_ipv4(&rtp->rtcp->us) ?
|
* switching from MUX. Either way, we won't have
|
||||||
AF_INET :
|
* a socket set up, and we need to set it up
|
||||||
ast_sockaddr_is_ipv6(&rtp->rtcp->us) ?
|
*/
|
||||||
AF_INET6 : -1)) < 0) {
|
if ((rtp->rtcp->s =
|
||||||
ast_debug(1, "Failed to create a new socket for RTCP on instance '%p'\n", instance);
|
create_new_socket("RTCP",
|
||||||
ast_free(rtp->rtcp->local_addr_str);
|
ast_sockaddr_is_ipv4(&rtp->rtcp->us) ?
|
||||||
ast_free(rtp->rtcp);
|
AF_INET :
|
||||||
rtp->rtcp = NULL;
|
ast_sockaddr_is_ipv6(&rtp->rtcp->us) ?
|
||||||
return;
|
AF_INET6 : -1)) < 0) {
|
||||||
}
|
ast_debug(1, "Failed to create a new socket for RTCP on instance '%p'\n", instance);
|
||||||
|
ast_free(rtp->rtcp->local_addr_str);
|
||||||
|
ast_free(rtp->rtcp);
|
||||||
|
rtp->rtcp = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to actually bind to the IP address and port we are going to use for RTCP, if this fails we have to bail out */
|
/* Try to actually bind to the IP address and port we are going to use for RTCP, if this fails we have to bail out */
|
||||||
if (ast_bind(rtp->rtcp->s, &rtp->rtcp->us)) {
|
if (ast_bind(rtp->rtcp->s, &rtp->rtcp->us)) {
|
||||||
ast_debug(1, "Failed to setup RTCP on RTP instance '%p'\n", instance);
|
ast_debug(1, "Failed to setup RTCP on RTP instance '%p'\n", instance);
|
||||||
close(rtp->rtcp->s);
|
close(rtp->rtcp->s);
|
||||||
ast_free(rtp->rtcp->local_addr_str);
|
ast_free(rtp->rtcp->local_addr_str);
|
||||||
ast_free(rtp->rtcp);
|
ast_free(rtp->rtcp);
|
||||||
rtp->rtcp = NULL;
|
rtp->rtcp = NULL;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
#ifdef HAVE_PJPROJECT
|
||||||
|
if (rtp->ice) {
|
||||||
|
rtp_add_candidates_to_ice(instance, rtp, &rtp->rtcp->us, ast_sockaddr_port(&rtp->rtcp->us), AST_RTP_ICE_COMPONENT_RTCP, TRANSPORT_SOCKET_RTCP);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_OPENSSL_SRTP
|
||||||
|
dtls_setup_rtcp(instance);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
struct ast_sockaddr addr;
|
||||||
|
/* RTCPMUX uses the same socket as RTP. If we were previously using standard RTCP
|
||||||
|
* then close the socket we previously created.
|
||||||
|
*
|
||||||
|
* It may seem as though there is a possible race condition here where we might try
|
||||||
|
* to close the RTCP socket while it is being used to send data. However, this is not
|
||||||
|
* a problem in practice since setting and adjusting of RTCP properties happens prior
|
||||||
|
* to activating RTP. It is not until RTP is activated that timers start for RTCP
|
||||||
|
* transmission
|
||||||
|
*/
|
||||||
|
if (rtp->rtcp->s > -1) {
|
||||||
|
close(rtp->rtcp->s);
|
||||||
|
}
|
||||||
|
rtp->rtcp->s = rtp->s;
|
||||||
|
ast_rtp_instance_get_remote_address(instance, &addr);
|
||||||
|
ast_sockaddr_copy(&rtp->rtcp->them, &addr);
|
||||||
|
#ifdef HAVE_OPENSSL_SRTP
|
||||||
|
if (rtp->rtcp->dtls.ssl) {
|
||||||
|
SSL_free(rtp->rtcp->dtls.ssl);
|
||||||
|
}
|
||||||
|
rtp->rtcp->dtls.ssl = rtp->dtls.ssl;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_debug(1, "Setup RTCP on RTP instance '%p'\n", instance);
|
ast_debug(1, "Setup RTCP on RTP instance '%p'\n", instance);
|
||||||
rtp->rtcp->schedid = -1;
|
|
||||||
|
|
||||||
#ifdef HAVE_PJPROJECT
|
|
||||||
if (rtp->ice) {
|
|
||||||
rtp_add_candidates_to_ice(instance, rtp, &rtp->rtcp->us, ast_sockaddr_port(&rtp->rtcp->us), AST_RTP_ICE_COMPONENT_RTCP, TRANSPORT_SOCKET_RTCP);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL_SRTP
|
|
||||||
rtp->rtcp->dtls.timeout_timer = -1;
|
|
||||||
dtls_setup_rtcp(instance);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (rtp->rtcp) {
|
if (rtp->rtcp) {
|
||||||
|
@ -5021,9 +5144,11 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro
|
||||||
}
|
}
|
||||||
rtp->rtcp->schedid = -1;
|
rtp->rtcp->schedid = -1;
|
||||||
}
|
}
|
||||||
close(rtp->rtcp->s);
|
if (rtp->rtcp->s > -1 && rtp->rtcp->s != rtp->s) {
|
||||||
|
close(rtp->rtcp->s);
|
||||||
|
}
|
||||||
#ifdef HAVE_OPENSSL_SRTP
|
#ifdef HAVE_OPENSSL_SRTP
|
||||||
if (rtp->rtcp->dtls.ssl) {
|
if (rtp->rtcp->dtls.ssl && rtp->rtcp->dtls.ssl != rtp->dtls.ssl) {
|
||||||
SSL_free(rtp->rtcp->dtls.ssl);
|
SSL_free(rtp->rtcp->dtls.ssl);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -5065,10 +5190,12 @@ static void ast_rtp_remote_address_set(struct ast_rtp_instance *instance, struct
|
||||||
ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance);
|
ast_debug(1, "Setting RTCP address on RTP instance '%p'\n", instance);
|
||||||
ast_sockaddr_copy(&rtp->rtcp->them, addr);
|
ast_sockaddr_copy(&rtp->rtcp->them, addr);
|
||||||
if (!ast_sockaddr_isnull(addr)) {
|
if (!ast_sockaddr_isnull(addr)) {
|
||||||
ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(addr) + 1);
|
if (rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) {
|
||||||
|
ast_sockaddr_set_port(&rtp->rtcp->them, ast_sockaddr_port(addr) + 1);
|
||||||
|
|
||||||
/* Update the local RTCP address with what is being used */
|
/* Update the local RTCP address with what is being used */
|
||||||
ast_sockaddr_set_port(&local, ast_sockaddr_port(&local) + 1);
|
ast_sockaddr_set_port(&local, ast_sockaddr_port(&local) + 1);
|
||||||
|
}
|
||||||
ast_sockaddr_copy(&rtp->rtcp->us, &local);
|
ast_sockaddr_copy(&rtp->rtcp->us, &local);
|
||||||
|
|
||||||
ast_free(rtp->rtcp->local_addr_str);
|
ast_free(rtp->rtcp->local_addr_str);
|
||||||
|
@ -5356,7 +5483,7 @@ static int ast_rtp_activate(struct ast_rtp_instance *instance)
|
||||||
|
|
||||||
dtls_perform_handshake(instance, &rtp->dtls, 0);
|
dtls_perform_handshake(instance, &rtp->dtls, 0);
|
||||||
|
|
||||||
if (rtp->rtcp) {
|
if (rtp->rtcp && rtp->rtcp->type == AST_RTP_INSTANCE_RTCP_STANDARD) {
|
||||||
dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1);
|
dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue