@ -151,8 +151,57 @@ static void enable_rtcp(struct ast_sip_session *session, struct ast_sip_session_
ast_rtp_instance_set_prop ( session_media - > rtp , AST_RTP_PROPERTY_RTCP , rtcp_type ) ;
}
/*!
* \ brief Enable an RTP extension on an RTP session .
*/
static void enable_rtp_extension ( struct ast_sip_session * session , struct ast_sip_session_media * session_media ,
enum ast_rtp_extension extension , enum ast_rtp_extension_direction direction ,
const pjmedia_sdp_session * sdp )
{
int id = - 1 ;
/* For a bundle group the local unique identifier space is shared across all streams within
* it .
*/
if ( session_media - > bundle_group ! = - 1 ) {
int index ;
for ( index = 0 ; index < sdp - > media_count ; + + index ) {
struct ast_sip_session_media * other_session_media ;
int other_id ;
if ( index > = AST_VECTOR_SIZE ( & session - > pending_media_state - > sessions ) ) {
break ;
}
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 ;
}
other_id = ast_rtp_instance_extmap_get_id ( other_session_media - > rtp , extension ) ;
if ( other_id = = - 1 ) {
/* Worst case we have to fall back to the highest available free local unique identifier
* for the bundle group .
*/
other_id = ast_rtp_instance_extmap_count ( other_session_media - > rtp ) + 1 ;
if ( id < other_id ) {
id = other_id ;
}
continue ;
}
id = other_id ;
break ;
}
}
ast_rtp_instance_extmap_enable ( session_media - > rtp , id , extension , direction ) ;
}
/*! \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 ,
const pjmedia_sdp_session * sdp )
{
struct ast_rtp_engine_ice * ice ;
struct ast_sockaddr temp_media_address ;
@ -223,6 +272,7 @@ static int create_rtp(struct ast_sip_session *session, struct ast_sip_session_me
ast_rtp_instance_set_prop ( session_media - > rtp , AST_RTP_PROPERTY_RETRANS_RECV , session - > endpoint - > media . webrtc ) ;
ast_rtp_instance_set_prop ( session_media - > rtp , AST_RTP_PROPERTY_RETRANS_SEND , session - > endpoint - > media . webrtc ) ;
ast_rtp_instance_set_prop ( session_media - > rtp , AST_RTP_PROPERTY_REMB , session - > endpoint - > media . webrtc ) ;
enable_rtp_extension ( session , session_media , AST_RTP_EXTENSION_ABS_SEND_TIME , AST_RTP_EXTENSION_DIRECTION_SENDRECV , sdp ) ;
if ( session - > endpoint - > media . tos_video | | session - > endpoint - > media . cos_video ) {
ast_rtp_instance_set_qos ( session_media - > rtp , session - > endpoint - > media . tos_video ,
session - > endpoint - > media . cos_video , " SIP RTP Video " ) ;
@ -1101,6 +1151,113 @@ static void add_rtcp_fb_to_stream(struct ast_sip_session *session,
pjmedia_sdp_attr_add ( & media - > attr_count , media - > attr , attr ) ;
}
static void add_extmap_to_stream ( struct ast_sip_session * session ,
struct ast_sip_session_media * session_media , pj_pool_t * pool , pjmedia_sdp_media * media )
{
int idx ;
char extmap_value [ 256 ] ;
if ( ! session - > endpoint - > media . webrtc | | session_media - > type ! = AST_MEDIA_TYPE_VIDEO ) {
return ;
}
/* RTP extension local unique identifiers start at '1' */
for ( idx = 1 ; idx < = ast_rtp_instance_extmap_count ( session_media - > rtp ) ; + + idx ) {
enum ast_rtp_extension extension = ast_rtp_instance_extmap_get_extension ( session_media - > rtp , idx ) ;
const char * direction_str = " " ;
pj_str_t stmp ;
pjmedia_sdp_attr * attr ;
/* If this is an unsupported RTP extension we can't place it into the SDP */
if ( extension = = AST_RTP_EXTENSION_UNSUPPORTED ) {
continue ;
}
switch ( ast_rtp_instance_extmap_get_direction ( session_media - > rtp , idx ) ) {
case AST_RTP_EXTENSION_DIRECTION_SENDRECV :
/* Lack of a direction indicates sendrecv, so we leave it out */
direction_str = " " ;
break ;
case AST_RTP_EXTENSION_DIRECTION_SENDONLY :
direction_str = " /sendonly " ;
break ;
case AST_RTP_EXTENSION_DIRECTION_RECVONLY :
direction_str = " /recvonly " ;
break ;
case AST_RTP_EXTENSION_DIRECTION_NONE :
/* It is impossible for a "none" direction extension to be negotiated but just in case
* we treat it as inactive .
*/
case AST_RTP_EXTENSION_DIRECTION_INACTIVE :
direction_str = " /inactive " ;
break ;
}
snprintf ( extmap_value , sizeof ( extmap_value ) , " %d%s %s " , idx , direction_str ,
ast_rtp_instance_extmap_get_uri ( session_media - > rtp , idx ) ) ;
attr = pjmedia_sdp_attr_create ( pool , " extmap " , pj_cstr ( & stmp , extmap_value ) ) ;
pjmedia_sdp_attr_add ( & media - > attr_count , media - > attr , attr ) ;
}
}
/*! \brief Function which processes extmap attributes in a stream */
static void process_extmap_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 . webrtc | | session_media - > type ! = AST_MEDIA_TYPE_VIDEO ) {
return ;
}
ast_rtp_instance_extmap_clear ( session_media - > rtp ) ;
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 * uri ;
int id ;
char direction_str [ 10 ] = " " ;
char * attributes ;
enum ast_rtp_extension_direction direction = AST_RTP_EXTENSION_DIRECTION_SENDRECV ;
/* We only care about extmap attributes */
if ( pj_strcmp2 ( & attr - > name , " extmap " ) ) {
continue ;
}
ast_copy_pj_str ( attr_value , & attr - > value , sizeof ( attr_value ) ) ;
/* Split the combined unique identifier and direction away from the URI and attributes for easier parsing */
uri = strchr ( attr_value , ' ' ) ;
if ( ast_strlen_zero ( uri ) ) {
continue ;
}
* uri + + = ' \0 ' ;
if ( ( sscanf ( attr_value , " %30d%9s " , & id , direction_str ) < 1 ) | | ( id < 1 ) ) {
/* We require at a minimum the unique identifier */
continue ;
}
/* Convert from the string to the internal representation */
if ( ! strcasecmp ( direction_str , " /sendonly " ) ) {
direction = AST_RTP_EXTENSION_DIRECTION_SENDONLY ;
} else if ( ! strcasecmp ( direction_str , " /recvonly " ) ) {
direction = AST_RTP_EXTENSION_DIRECTION_RECVONLY ;
} else if ( ! strcasecmp ( direction_str , " /inactive " ) ) {
direction = AST_RTP_EXTENSION_DIRECTION_INACTIVE ;
}
attributes = strchr ( uri , ' ' ) ;
if ( ! ast_strlen_zero ( attributes ) ) {
* attributes + + = ' \0 ' ;
}
ast_rtp_instance_extmap_negotiate ( session_media - > rtp , id , direction , uri , attributes ) ;
}
}
/*! \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 ,
@ -1139,11 +1296,12 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session,
}
/* Using the connection information create an appropriate RTP instance */
if ( ! session_media - > rtp & & create_rtp ( session , session_media )) {
if ( ! session_media - > rtp & & create_rtp ( session , session_media , sdp )) {
return - 1 ;
}
process_ssrc_attributes ( session , session_media , stream ) ;
process_extmap_attributes ( session , session_media , stream ) ;
session_media_transport = ast_sip_session_media_get_transport ( session , session_media ) ;
if ( session_media_transport = = session_media | | ! session_media - > bundled ) {
@ -1377,7 +1535,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
return 1 ;
}
if ( ! session_media - > rtp & & create_rtp ( session , session_media )) {
if ( ! session_media - > rtp & & create_rtp ( session , session_media , sdp )) {
return - 1 ;
}
@ -1602,6 +1760,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
add_ssrc_to_stream ( session , session_media , pool , media ) ;
add_msid_to_stream ( session , session_media , pool , media , stream ) ;
add_rtcp_fb_to_stream ( session , session_media , pool , media ) ;
add_extmap_to_stream ( session , session_media , pool , media ) ;
/* Add the media stream to the SDP */
sdp - > media [ sdp - > media_count + + ] = media ;
@ -1676,11 +1835,12 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session,
}
/* Create an RTP instance if need be */
if ( ! session_media - > rtp & & create_rtp ( session , session_media )) {
if ( ! session_media - > rtp & & create_rtp ( session , session_media , local )) {
return - 1 ;
}
process_ssrc_attributes ( session , session_media , remote_stream ) ;
process_extmap_attributes ( session , session_media , remote_stream ) ;
session_media_transport = ast_sip_session_media_get_transport ( session , session_media ) ;