summaryrefslogtreecommitdiff
path: root/res/res_pjsip_sdp_rtp.c
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2017-06-30 18:55:57 +0000
committerJoshua Colp <jcolp@digium.com>2017-07-13 14:47:50 +0000
commit065c3005ad920f5fe2cedcf062e38b8e28eeb015 (patch)
tree6f10effde768ae19faa7342b1eeef1004cf2fddc /res/res_pjsip_sdp_rtp.c
parente1c0e14fac7cdca276a0fd61fa891ea54f4ab5d8 (diff)
res_rtp_asterisk / res_pjsip: Add support for BUNDLE.
BUNDLE is a specification used in WebRTC to allow multiple streams to use the same underlying transport. This reduces the number of ICE and DTLS negotiations that has to occur to 1 normally. This change implements this by adding support for it to the RTP SDP module in PJSIP. BUNDLE can be turned on using the "bundle" option and on an offer we will offer to bundle streams together. On an answer we will accept any bundle groups provided. Once accepted each stream is bundled to another RTP instance for transport. For the res_rtp_asterisk changes the ability to bundle an RTP instance to another based on the SSRC received from the remote side has been added. For outgoing traffic if an RTP instance is bundled to another we will use the other RTP instance for any transport related things. For incoming traffic received from the transport instance we look up the correct instance based on the SSRC and use it for any non-transport related data. ASTERISK-27118 Change-Id: I96c0920b9f9aca7382256484765a239017973c11
Diffstat (limited to 'res/res_pjsip_sdp_rtp.c')
-rw-r--r--res/res_pjsip_sdp_rtp.c411
1 files changed, 294 insertions, 117 deletions
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index a49130868..4ec811528 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -317,6 +317,7 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp
static int set_caps(struct ast_sip_session *session,
struct ast_sip_session_media *session_media,
+ struct ast_sip_session_media *session_media_transport,
const struct pjmedia_sdp_media *stream,
int is_offer, struct ast_stream *asterisk_stream)
{
@@ -376,6 +377,24 @@ static int set_caps(struct ast_sip_session *session,
ast_stream_set_formats(asterisk_stream, joint);
+ /* If this is a bundled stream then apply the payloads to RTP instance acting as transport to prevent conflicts */
+ if (session_media_transport != session_media && session_media->bundled) {
+ int index;
+
+ for (index = 0; index < ast_format_cap_count(joint); ++index) {
+ struct ast_format *format = ast_format_cap_get_format(joint, index);
+ int rtp_code;
+
+ /* Ensure this payload is in the bundle group transport codecs, this purposely doesn't check the return value for
+ * things as the format is guaranteed to have a payload already.
+ */
+ rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0);
+ ast_rtp_codecs_payload_set_rx(ast_rtp_instance_get_codecs(session_media_transport->rtp), rtp_code, format);
+
+ ao2_ref(format, -1);
+ }
+ }
+
if (session->channel && ast_sip_session_is_pending_stream_default(session, asterisk_stream)) {
ast_channel_lock(session->channel);
ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_UNKNOWN);
@@ -496,7 +515,8 @@ static pjmedia_sdp_attr* generate_fmtp_attr(pj_pool_t *pool, struct ast_format *
}
/*! \brief Function which adds ICE attributes to a media stream */
-static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
+static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media,
+ unsigned int include_candidates)
{
struct ast_rtp_engine_ice *ice;
struct ao2_container *candidates;
@@ -506,8 +526,7 @@ static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_se
struct ao2_iterator it_candidates;
struct ast_rtp_engine_ice_candidate *candidate;
- if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp)) ||
- !(candidates = ice->get_local_candidates(session_media->rtp))) {
+ if (!session->endpoint->media.rtp.ice_support || !(ice = ast_rtp_instance_get_ice(session_media->rtp))) {
return;
}
@@ -521,6 +540,15 @@ static void add_ice_to_stream(struct ast_sip_session *session, struct ast_sip_se
media->attr[media->attr_count++] = attr;
}
+ if (!include_candidates) {
+ return;
+ }
+
+ candidates = ice->get_local_candidates(session_media->rtp);
+ if (!candidates) {
+ return;
+ }
+
it_candidates = ao2_iterator_init(candidates, 0);
for (; (candidate = ao2_iterator_next(&it_candidates)); ao2_ref(candidate, -1)) {
struct ast_str *attr_candidate = ast_str_create(128);
@@ -940,6 +968,63 @@ static void set_ice_components(struct ast_sip_session *session, struct ast_sip_s
}
}
+/*! \brief Function which adds ssrc attributes to a media stream */
+static void add_ssrc_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media)
+{
+ pj_str_t stmp;
+ pjmedia_sdp_attr *attr;
+ char tmp[128];
+
+ if (!session->endpoint->media.bundle || session_media->bundle_group == -1) {
+ return;
+ }
+
+ snprintf(tmp, sizeof(tmp), "%u cname:%s", ast_rtp_instance_get_ssrc(session_media->rtp), ast_rtp_instance_get_cname(session_media->rtp));
+ attr = pjmedia_sdp_attr_create(pool, "ssrc", pj_cstr(&stmp, tmp));
+ media->attr[media->attr_count++] = attr;
+}
+
+/*! \brief Function which processes ssrc attributes in a stream */
+static void process_ssrc_attributes(struct ast_sip_session *session, struct ast_sip_session_media *session_media,
+ const struct pjmedia_sdp_media *remote_stream)
+{
+ int index;
+
+ if (!session->endpoint->media.bundle) {
+ return;
+ }
+
+ for (index = 0; index < remote_stream->attr_count; ++index) {
+ pjmedia_sdp_attr *attr = remote_stream->attr[index];
+ char attr_value[pj_strlen(&attr->value) + 1];
+ char *ssrc_attribute_name, *ssrc_attribute_value = NULL;
+ unsigned int ssrc;
+
+ /* We only care about ssrc attributes */
+ if (pj_strcmp2(&attr->name, "ssrc")) {
+ continue;
+ }
+
+ ast_copy_pj_str(attr_value, &attr->value, sizeof(attr_value));
+
+ if ((ssrc_attribute_name = strchr(attr_value, ' '))) {
+ /* This has an actual attribute */
+ *ssrc_attribute_name++ = '\0';
+ ssrc_attribute_value = strchr(ssrc_attribute_name, ':');
+ if (ssrc_attribute_value) {
+ /* Values are actually optional according to the spec */
+ *ssrc_attribute_value++ = '\0';
+ }
+ }
+
+ if (sscanf(attr_value, "%30u", &ssrc) < 1) {
+ continue;
+ }
+
+ ast_rtp_instance_set_remote_ssrc(session_media->rtp, ssrc);
+ }
+}
+
/*! \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, const pjmedia_sdp_session *sdp,
@@ -948,6 +1033,7 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
char host[NI_MAXHOST];
RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free);
pjmedia_sdp_media *stream = sdp->media[index];
+ struct ast_sip_session_media *session_media_transport;
enum ast_media_type media_type = session_media->type;
enum ast_sip_session_media_encryption encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
int res;
@@ -981,38 +1067,51 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
return -1;
}
- session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(stream, "rtcp-mux", NULL) != NULL);
- set_ice_components(session, session_media);
+ process_ssrc_attributes(session, session_media, stream);
- enable_rtcp(session, session_media, stream);
+ session_media_transport = ast_sip_session_media_get_transport(session, session_media);
- res = setup_media_encryption(session, session_media, sdp, stream);
- if (res) {
- if (!session->endpoint->media.rtp.encryption_optimistic ||
- !pj_strncmp2(&stream->desc.transport, "RTP/SAVP", 8)) {
- /* If optimistic encryption is disabled and crypto should have been enabled
- * but was not this session must fail. This must also fail if crypto was
- * required in the offer but could not be set up.
- */
- return -1;
+ if (session_media_transport == session_media || !session_media->bundled) {
+ /* If this media session is carrying actual traffic then set up those aspects */
+ 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);
+ if (res) {
+ if (!session->endpoint->media.rtp.encryption_optimistic ||
+ !pj_strncmp2(&stream->desc.transport, "RTP/SAVP", 8)) {
+ /* If optimistic encryption is disabled and crypto should have been enabled
+ * but was not this session must fail. This must also fail if crypto was
+ * required in the offer but could not be set up.
+ */
+ return -1;
+ }
+ /* There is no encryption, sad. */
+ session_media->encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
}
- /* There is no encryption, sad. */
- session_media->encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
- }
- /* If we've been explicitly configured to use the received transport OR if
- * encryption is on and crypto is present use the received transport.
- * This is done in case of optimistic because it may come in as RTP/AVP or RTP/SAVP depending
- * on the configuration of the remote endpoint (optimistic themselves or mandatory).
- */
- if ((session->endpoint->media.rtp.use_received_transport) ||
- ((encryption == AST_SIP_MEDIA_ENCRYPT_SDES) && !res)) {
- pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport);
- }
+ /* If we've been explicitly configured to use the received transport OR if
+ * encryption is on and crypto is present use the received transport.
+ * This is done in case of optimistic because it may come in as RTP/AVP or RTP/SAVP depending
+ * on the configuration of the remote endpoint (optimistic themselves or mandatory).
+ */
+ if ((session->endpoint->media.rtp.use_received_transport) ||
+ ((encryption == AST_SIP_MEDIA_ENCRYPT_SDES) && !res)) {
+ pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport);
+ }
+ } else {
+ /* This is bundled with another session, so mark it as such */
+ ast_rtp_instance_bundle(session_media->rtp, session_media_transport->rtp);
- if (set_caps(session, session_media, stream, 1, asterisk_stream)) {
+ enable_rtcp(session, session_media, stream);
+ }
+
+ if (set_caps(session, session_media, session_media_transport, stream, 1, asterisk_stream)) {
return 0;
}
+
return 1;
}
@@ -1032,6 +1131,7 @@ static int add_crypto_to_stream(struct ast_sip_session *session,
static const pj_str_t STR_PASSIVE = { "passive", 7 };
static const pj_str_t STR_ACTPASS = { "actpass", 7 };
static const pj_str_t STR_HOLDCONN = { "holdconn", 8 };
+ enum ast_rtp_dtls_setup setup;
switch (session_media->encryption) {
case AST_SIP_MEDIA_ENCRYPT_NONE:
@@ -1085,7 +1185,16 @@ static int add_crypto_to_stream(struct ast_sip_session *session,
break;
}
- switch (dtls->get_setup(session_media->rtp)) {
+ /* If this is an answer we need to use our current state, if it's an offer we need to use
+ * the configured value.
+ */
+ if (pjmedia_sdp_neg_get_state(session->inv_session->neg) != PJMEDIA_SDP_NEG_STATE_DONE) {
+ setup = dtls->get_setup(session_media->rtp);
+ } else {
+ setup = session->endpoint->media.rtp.dtls_cfg.default_setup;
+ }
+
+ switch (setup) {
case AST_RTP_DTLS_SETUP_ACTIVE:
attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTIVE);
media->attr[media->attr_count++] = attr;
@@ -1100,7 +1209,6 @@ static int add_crypto_to_stream(struct ast_sip_session *session,
break;
case AST_RTP_DTLS_SETUP_HOLDCONN:
attr = pjmedia_sdp_attr_create(pool, "setup", &STR_HOLDCONN);
- media->attr[media->attr_count++] = attr;
break;
default:
break;
@@ -1152,6 +1260,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
int rtp_code;
RAII_VAR(struct ast_format_cap *, caps, NULL, ao2_cleanup);
enum ast_media_type media_type = session_media->type;
+ struct ast_sip_session_media *session_media_transport;
int direct_media_enabled = !ast_sockaddr_isnull(&session_media->direct_media_addr) &&
ast_format_cap_count(session->direct_media_cap);
@@ -1195,68 +1304,106 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
return -1;
}
- set_ice_components(session, session_media);
- enable_rtcp(session, session_media, NULL);
+ /* If this stream has not been bundled already it is new and we need to ensure there is no SSRC conflict */
+ if (session_media->bundle_group != -1 && !session_media->bundled) {
+ for (index = 0; index < sdp->media_count; ++index) {
+ struct ast_sip_session_media *other_session_media;
- /* Crypto has to be added before setting the media transport so that SRTP is properly
- * set up according to the configuration. This ends up changing the media transport.
- */
- if (add_crypto_to_stream(session, session_media, pool, media)) {
- return -1;
- }
+ other_session_media = AST_VECTOR_GET(&session->pending_media_state->sessions, index);
+ if (!other_session_media->rtp || other_session_media->bundle_group != session_media->bundle_group) {
+ continue;
+ }
- if (pj_strlen(&session_media->transport)) {
- /* If a transport has already been specified use it */
- media->desc.transport = session_media->transport;
- } else {
- media->desc.transport = pj_str(ast_sdp_get_rtp_profile(
- /* Optimistic encryption places crypto in the normal RTP/AVP profile */
- !session->endpoint->media.rtp.encryption_optimistic &&
- (session_media->encryption == AST_SIP_MEDIA_ENCRYPT_SDES),
- session_media->rtp, session->endpoint->media.rtp.use_avpf,
- session->endpoint->media.rtp.force_avp));
+ if (ast_rtp_instance_get_ssrc(session_media->rtp) == ast_rtp_instance_get_ssrc(other_session_media->rtp)) {
+ ast_rtp_instance_change_source(session_media->rtp);
+ /* Start the conflict check over again */
+ index = -1;
+ continue;
+ }
+ }
}
- media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn));
- if (!media->conn) {
- return -1;
- }
+ session_media_transport = ast_sip_session_media_get_transport(session, session_media);
- /* Add connection level details */
- if (direct_media_enabled) {
- hostip = ast_sockaddr_stringify_fmt(&session_media->direct_media_addr, AST_SOCKADDR_STR_ADDR);
- } else if (ast_strlen_zero(session->endpoint->media.address)) {
- hostip = ast_sip_get_host_ip_string(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET());
- } else {
- hostip = session->endpoint->media.address;
- }
+ if (session_media_transport == session_media || !session_media->bundled) {
+ set_ice_components(session, session_media);
+ enable_rtcp(session, session_media, NULL);
- if (ast_strlen_zero(hostip)) {
- ast_log(LOG_ERROR, "No local host IP available for stream %s\n",
- ast_codec_media_type2str(session_media->type));
- return -1;
- }
+ /* Crypto has to be added before setting the media transport so that SRTP is properly
+ * set up according to the configuration. This ends up changing the media transport.
+ */
+ if (add_crypto_to_stream(session, session_media, pool, media)) {
+ return -1;
+ }
- media->conn->net_type = STR_IN;
- /* Assume that the connection will use IPv4 until proven otherwise */
- media->conn->addr_type = STR_IP4;
- pj_strdup2(pool, &media->conn->addr, hostip);
+ if (pj_strlen(&session_media->transport)) {
+ /* If a transport has already been specified use it */
+ media->desc.transport = session_media->transport;
+ } else {
+ media->desc.transport = pj_str(ast_sdp_get_rtp_profile(
+ /* Optimistic encryption places crypto in the normal RTP/AVP profile */
+ !session->endpoint->media.rtp.encryption_optimistic &&
+ (session_media->encryption == AST_SIP_MEDIA_ENCRYPT_SDES),
+ session_media->rtp, session->endpoint->media.rtp.use_avpf,
+ session->endpoint->media.rtp.force_avp));
+ }
- if (!ast_strlen_zero(session->endpoint->media.address)) {
- pj_sockaddr ip;
+ media->conn = pj_pool_zalloc(pool, sizeof(struct pjmedia_sdp_conn));
+ if (!media->conn) {
+ return -1;
+ }
- if ((pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &media->conn->addr, &ip) == PJ_SUCCESS) &&
- (ip.addr.sa_family == pj_AF_INET6())) {
- media->conn->addr_type = STR_IP6;
+ /* Add connection level details */
+ if (direct_media_enabled) {
+ hostip = ast_sockaddr_stringify_fmt(&session_media->direct_media_addr, AST_SOCKADDR_STR_ADDR);
+ } else if (ast_strlen_zero(session->endpoint->media.address)) {
+ hostip = ast_sip_get_host_ip_string(session->endpoint->media.rtp.ipv6 ? pj_AF_INET6() : pj_AF_INET());
+ } else {
+ hostip = session->endpoint->media.address;
}
- }
- /* Add ICE attributes and candidates */
- add_ice_to_stream(session, session_media, pool, media);
+ if (ast_strlen_zero(hostip)) {
+ ast_log(LOG_ERROR, "No local host IP available for stream %s\n",
+ ast_codec_media_type2str(session_media->type));
+ return -1;
+ }
+
+ media->conn->net_type = STR_IN;
+ /* Assume that the connection will use IPv4 until proven otherwise */
+ media->conn->addr_type = STR_IP4;
+ pj_strdup2(pool, &media->conn->addr, hostip);
+
+ if (!ast_strlen_zero(session->endpoint->media.address)) {
+ pj_sockaddr ip;
+
+ if ((pj_sockaddr_parse(pj_AF_UNSPEC(), 0, &media->conn->addr, &ip) == PJ_SUCCESS) &&
+ (ip.addr.sa_family == pj_AF_INET6())) {
+ media->conn->addr_type = STR_IP6;
+ }
+ }
+
+ /* Add ICE attributes and candidates */
+ add_ice_to_stream(session, session_media, pool, media, 1);
+
+ ast_rtp_instance_get_local_address(session_media->rtp, &addr);
+ media->desc.port = direct_media_enabled ? ast_sockaddr_port(&session_media->direct_media_addr) : (pj_uint16_t) ast_sockaddr_port(&addr);
+ media->desc.port_count = 1;
+ } else {
+ pjmedia_sdp_media *bundle_group_stream = sdp->media[session_media_transport->stream_num];
+
+ /* As this is in a bundle group it shares the same details as the group instance */
+ media->desc.transport = bundle_group_stream->desc.transport;
+ media->conn = bundle_group_stream->conn;
+ media->desc.port = bundle_group_stream->desc.port;
+
+ if (add_crypto_to_stream(session, session_media_transport, pool, media)) {
+ return -1;
+ }
- ast_rtp_instance_get_local_address(session_media->rtp, &addr);
- media->desc.port = direct_media_enabled ? ast_sockaddr_port(&session_media->direct_media_addr) : (pj_uint16_t) ast_sockaddr_port(&addr);
- media->desc.port_count = 1;
+ add_ice_to_stream(session, session_media_transport, pool, media, 0);
+
+ enable_rtcp(session, session_media, NULL);
+ }
if (!(caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
ast_log(LOG_ERROR, "Failed to allocate %s capabilities\n",
@@ -1278,10 +1425,23 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
continue;
}
- if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0)) == -1) {
- ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format));
- ao2_ref(format, -1);
- continue;
+ /* If this stream is not a transport we need to use the transport codecs structure for payload management to prevent
+ * conflicts.
+ */
+ if (session_media_transport != session_media) {
+ if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media_transport->rtp), 1, format, 0)) == -1) {
+ ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format));
+ ao2_ref(format, -1);
+ continue;
+ }
+ /* Our instance has to match the payload number though */
+ ast_rtp_codecs_payload_set_rx(ast_rtp_instance_get_codecs(session_media->rtp), rtp_code, format);
+ } else {
+ if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp), 1, format, 0)) == -1) {
+ ast_log(LOG_WARNING,"Unable to get rtp codec payload code for %s\n", ast_format_get_name(format));
+ ao2_ref(format, -1);
+ continue;
+ }
}
if ((attr = generate_rtpmap_attr(session, media, pool, rtp_code, 1, format, 0))) {
@@ -1332,6 +1492,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
}
}
+
/* If no formats were actually added to the media stream don't add it to the SDP */
if (!media->desc.fmt_count) {
return 1;
@@ -1365,6 +1526,8 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
pjmedia_sdp_attr_add(&media->attr_count, media->attr, attr);
}
+ add_ssrc_to_stream(session, session_media, pool, media);
+
/* Add the media stream to the SDP */
sdp->media[sdp->media_count++] = media;
@@ -1425,6 +1588,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session,
enum ast_media_type media_type = session_media->type;
char host[NI_MAXHOST];
int res;
+ struct ast_sip_session_media *session_media_transport;
if (!session->channel) {
return 1;
@@ -1441,48 +1605,60 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session,
return -1;
}
- session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(remote_stream, "rtcp-mux", NULL) != NULL);
- set_ice_components(session, session_media);
+ process_ssrc_attributes(session, session_media, remote_stream);
- enable_rtcp(session, session_media, remote_stream);
+ session_media_transport = ast_sip_session_media_get_transport(session, session_media);
- res = setup_media_encryption(session, session_media, remote, remote_stream);
- if (!session->endpoint->media.rtp.encryption_optimistic && res) {
- /* If optimistic encryption is disabled and crypto should have been enabled but was not
- * this session must fail.
- */
- return -1;
- }
+ if (session_media_transport == session_media || !session_media->bundled) {
+ session_media->remote_rtcp_mux = (pjmedia_sdp_media_find_attr2(remote_stream, "rtcp-mux", NULL) != NULL);
+ set_ice_components(session, session_media);
- if (!remote_stream->conn && !remote->conn) {
- return 1;
- }
+ enable_rtcp(session, session_media, remote_stream);
- ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
+ res = setup_media_encryption(session, session_media, remote, remote_stream);
+ if (!session->endpoint->media.rtp.encryption_optimistic && res) {
+ /* If optimistic encryption is disabled and crypto should have been enabled but was not
+ * this session must fail.
+ */
+ return -1;
+ }
- /* Ensure that the address provided is valid */
- if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
- /* The provided host was actually invalid so we error out this negotiation */
- return -1;
- }
+ if (!remote_stream->conn && !remote->conn) {
+ return 1;
+ }
- /* Apply connection information to the RTP instance */
- ast_sockaddr_set_port(addrs, remote_stream->desc.port);
- ast_rtp_instance_set_remote_address(session_media->rtp, addrs);
- if (set_caps(session, session_media, remote_stream, 0, asterisk_stream)) {
- return 1;
- }
+ ast_copy_pj_str(host, remote_stream->conn ? &remote_stream->conn->addr : &remote->conn->addr, sizeof(host));
- ast_sip_session_media_set_write_callback(session, session_media, media_session_rtp_write_callback);
- ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 0),
- media_session_rtp_read_callback);
- if (!session->endpoint->media.rtcp_mux || !session_media->remote_rtcp_mux) {
- ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 1),
- media_session_rtcp_read_callback);
+ /* Ensure that the address provided is valid */
+ if (ast_sockaddr_resolve(&addrs, host, PARSE_PORT_FORBID, AST_AF_UNSPEC) <= 0) {
+ /* The provided host was actually invalid so we error out this negotiation */
+ return -1;
+ }
+
+ /* Apply connection information to the RTP instance */
+ ast_sockaddr_set_port(addrs, remote_stream->desc.port);
+ ast_rtp_instance_set_remote_address(session_media->rtp, addrs);
+
+ ast_sip_session_media_set_write_callback(session, session_media, media_session_rtp_write_callback);
+ ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 0),
+ media_session_rtp_read_callback);
+ if (!session->endpoint->media.rtcp_mux || !session_media->remote_rtcp_mux) {
+ ast_sip_session_media_add_read_callback(session, session_media, ast_rtp_instance_fd(session_media->rtp, 1),
+ media_session_rtcp_read_callback);
+ }
+
+ /* If ICE support is enabled find all the needed attributes */
+ process_ice_attributes(session, session_media, remote, remote_stream);
+ } else {
+ /* This is bundled with another session, so mark it as such */
+ ast_rtp_instance_bundle(session_media->rtp, session_media_transport->rtp);
+ ast_sip_session_media_set_write_callback(session, session_media, media_session_rtp_write_callback);
+ enable_rtcp(session, session_media, remote_stream);
}
- /* If ICE support is enabled find all the needed attributes */
- process_ice_attributes(session, session_media, remote, remote_stream);
+ if (set_caps(session, session_media, session_media_transport, remote_stream, 0, asterisk_stream)) {
+ return 1;
+ }
/* Set the channel uniqueid on the RTP instance now that it is becoming active */
ast_channel_lock(session->channel);
@@ -1490,6 +1666,7 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session,
ast_channel_unlock(session->channel);
/* Ensure the RTP instance is active */
+ ast_rtp_instance_set_stream_num(session_media->rtp, ast_stream_get_position(asterisk_stream));
ast_rtp_instance_activate(session_media->rtp);
/* audio stream handles music on hold */