int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) { belle_sdp_connection_t* cnx; belle_sip_list_t* media_desc_it; belle_sdp_media_description_t* media_desc; belle_sdp_session_name_t *sname; const char* value; desc->n_active_streams = 0; desc->n_total_streams = 0; desc->dir = SalStreamSendRecv; if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) -1 ); } if ( (sname=belle_sdp_session_description_get_session_name(session_desc)) && belle_sdp_session_name_get_value(sname) ){ strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name) - 1); } if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) { desc->bandwidth=belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ); } /*in some very rare case, session attribute may set stream dir*/ if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) { desc->dir=SalStreamSendRecv; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) { desc->dir=SalStreamSendOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) { desc->dir=SalStreamRecvOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) { desc->dir=SalStreamInactive; } /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag"); if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd"); if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)-1); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); if (value) desc->ice_lite = TRUE; /* Get session RTCP-XR attributes if any */ sdp_parse_session_rtcp_xr_parameters(session_desc, &desc->rtcp_xr); for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc ) ; media_desc_it!=NULL ; media_desc_it=media_desc_it->next ) { if (desc->n_total_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){ ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->n_total_streams); break; } media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data ); sdp_to_stream_description(desc, media_desc); } return 0; }
const char * sal_custom_sdp_attribute_find(const SalCustomSdpAttribute *csa, const char *name) { if (csa) { return belle_sdp_session_description_get_attribute_value((belle_sdp_session_description_t *)csa, name); } return NULL; }
int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) { belle_sdp_connection_t* cnx; belle_sip_list_t* media_desc_it; belle_sdp_media_description_t* media_desc; belle_sdp_session_name_t *sname; const char* value; SalDtlsRole session_role=SalDtlsRoleInvalid; int i; desc->nb_streams = 0; desc->dir = SalStreamSendRecv; if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) -1 ); } if ( (sname=belle_sdp_session_description_get_session_name(session_desc)) && belle_sdp_session_name_get_value(sname) ){ strncpy(desc->name,belle_sdp_session_name_get_value(sname),sizeof(desc->name) - 1); } if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) { desc->bandwidth=belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ); } /*in some very rare case, session attribute may set stream dir*/ if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) { desc->dir=SalStreamSendRecv; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) { desc->dir=SalStreamSendOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) { desc->dir=SalStreamRecvOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) { desc->dir=SalStreamInactive; } /*DTLS attributes can be defined at session level.*/ value=belle_sdp_session_description_get_attribute_value(session_desc,"setup"); if (value){ if (strncmp(value, "actpass", 7) == 0) { session_role = SalDtlsRoleUnset; } else if (strncmp(value, "active", 6) == 0) { session_role = SalDtlsRoleIsClient; } else if (strncmp(value, "passive", 7) == 0) { session_role = SalDtlsRoleIsServer; } } value=belle_sdp_session_description_get_attribute_value(session_desc,"fingerprint"); /*copy dtls attributes to every streams, might be overwritten stream by stream*/ for (i=0;i<SAL_MEDIA_DESCRIPTION_MAX_STREAMS;i++) { if (value) strncpy(desc->streams[i].dtls_fingerprint, value, sizeof(desc->streams[i].dtls_fingerprint)); desc->streams[i].dtls_role=session_role; /*set or reset value*/ } /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag"); if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag) - 1); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd"); if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)-1); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); if (value) desc->ice_lite = TRUE; /* Get session RTCP-XR attributes if any */ sdp_parse_session_rtcp_xr_parameters(session_desc, &desc->rtcp_xr); for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc ) ; media_desc_it!=NULL ; media_desc_it=media_desc_it->next ) { if (desc->nb_streams==SAL_MEDIA_DESCRIPTION_MAX_STREAMS){ ms_warning("Cannot convert mline at position [%i] from SDP to SalMediaDescription",desc->nb_streams); break; } media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data ); sdp_to_stream_description(desc, media_desc); } return 0; }
int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) { /* typedef struct SalMediaDescription{ int refcount; char addr[64]; char username[64]; int nstreams; int bandwidth; unsigned int session_ver; unsigned int session_id; SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; } SalMediaDescription; */ belle_sdp_connection_t* cnx; belle_sip_list_t* media_desc_it; belle_sdp_media_description_t* media_desc; const char *mtype,*proto; SalStreamDescription *stream; belle_sdp_media_t* media; belle_sip_list_t* mime_params=NULL; belle_sip_list_t* mime_param_it=NULL; belle_sdp_mime_parameter_t* mime_param; PayloadType *pt; belle_sip_list_t* attribute_it; const belle_sdp_attribute_t* attribute; int valid_count = 0; char tmp[256], tmp2[256]; int nb=0; SalStreamDir stream_dir=SalStreamSendRecv; const char* value; desc->n_active_streams = 0; desc->n_total_streams = 0; if ( ( cnx=belle_sdp_session_description_get_connection ( session_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { strncpy ( desc->addr,belle_sdp_connection_get_address ( cnx ),sizeof ( desc->addr ) ); } if ( belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ) >0 ) { desc->bandwidth=belle_sdp_session_description_get_bandwidth ( session_desc,"AS" ); } /*in some very rare case, session attribute may set stream dir*/ if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) { stream_dir=SalStreamSendRecv; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) { stream_dir=SalStreamSendOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) { stream_dir=SalStreamRecvOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) { stream_dir=SalStreamInactive; } /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-ufrag"); if (value) strncpy(desc->ice_ufrag, value, sizeof(desc->ice_ufrag)); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-pwd"); if (value) strncpy(desc->ice_pwd, value, sizeof(desc->ice_pwd)); value=belle_sdp_session_description_get_attribute_value(session_desc,"ice-lite"); if (value) desc->ice_lite = TRUE; for ( media_desc_it=belle_sdp_session_description_get_media_descriptions ( session_desc ) ; media_desc_it!=NULL ; media_desc_it=media_desc_it->next ) { int nb_ice_candidates=0; media_desc=BELLE_SDP_MEDIA_DESCRIPTION ( media_desc_it->data ); stream=&desc->streams[desc->n_total_streams]; media=belle_sdp_media_description_get_media ( media_desc ); memset ( stream,0,sizeof ( *stream ) ); proto = belle_sdp_media_get_protocol ( media ); stream->proto=SalProtoUnknown; if ( proto ) { if ( strcasecmp ( proto,"RTP/AVP" ) ==0 ) stream->proto=SalProtoRtpAvp; else if ( strcasecmp ( proto,"RTP/SAVP" ) ==0 ) { stream->proto=SalProtoRtpSavp; } } if ( ( cnx=belle_sdp_media_description_get_connection ( media_desc ) ) && belle_sdp_connection_get_address ( cnx ) ) { strncpy ( stream->rtp_addr,belle_sdp_connection_get_address ( cnx ),sizeof ( stream->rtp_addr ) ); } stream->rtp_port=belle_sdp_media_get_media_port ( media ); if ( stream->rtp_port > 0 ) desc->n_active_streams++; mtype = belle_sdp_media_get_media_type ( media ); if ( strcasecmp ( "audio", mtype ) == 0 ) { stream->type=SalAudio; } else if ( strcasecmp ( "video", mtype ) == 0 ) { stream->type=SalVideo; } else { stream->type=SalOther; strncpy ( stream->typeother,mtype,sizeof ( stream->typeother )-1 ); } if ( belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ) >0 ) { stream->bandwidth=belle_sdp_media_description_get_bandwidth ( media_desc,"AS" ); } if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) { stream->dir=SalStreamSendRecv; } else if ( belle_sdp_media_description_get_attribute ( media_desc,"sendonly" ) ) { stream->dir=SalStreamSendOnly; } else if ( belle_sdp_media_description_get_attribute ( media_desc,"recvonly" ) ) { stream->dir=SalStreamRecvOnly; } else if ( belle_sdp_media_description_get_attribute ( media_desc,"inactive" ) ) { stream->dir=SalStreamInactive; } else { stream->dir=stream_dir; /*takes default value if not present*/ } /* for each payload type */ mime_params=belle_sdp_media_description_build_mime_parameters ( media_desc ); for ( mime_param_it=mime_params ; mime_param_it!=NULL ; mime_param_it=mime_param_it->next ) { mime_param=BELLE_SDP_MIME_PARAMETER ( mime_param_it->data ) pt=payload_type_new(); payload_type_set_number ( pt,belle_sdp_mime_parameter_get_media_format ( mime_param ) ); pt->clock_rate=belle_sdp_mime_parameter_get_rate ( mime_param ); pt->mime_type=ms_strdup ( belle_sdp_mime_parameter_get_type ( mime_param ) ); pt->channels=belle_sdp_mime_parameter_get_channel_count ( mime_param ); payload_type_set_send_fmtp ( pt,belle_sdp_mime_parameter_get_parameters ( mime_param ) ); stream->payloads=ms_list_append ( stream->payloads,pt ); stream->ptime=belle_sdp_mime_parameter_get_ptime ( mime_param ); ms_message ( "Found payload %s/%i fmtp=%s",pt->mime_type,pt->clock_rate, pt->send_fmtp ? pt->send_fmtp : "" ); } if ( mime_params ) belle_sip_list_free_with_data ( mime_params,belle_sip_object_unref ); /* Get media specific RTCP attribute */ stream->rtcp_port = stream->rtp_port + 1; snprintf(stream->rtcp_addr, sizeof(stream->rtcp_addr), "%s", stream->rtp_addr); attribute=belle_sdp_media_description_get_attribute(media_desc,"rtcp"); if (attribute && (value=belle_sdp_attribute_get_value(attribute))!=NULL){ char tmp[256]; int nb = sscanf(value, "%d IN IP4 %s", &stream->rtcp_port, tmp); if (nb == 1) { /* SDP rtcp attribute only contains the port */ } else if (nb == 2) { strncpy(stream->rtcp_addr, tmp, sizeof(stream->rtcp_addr)); } else { ms_warning("sdp has a strange a=rtcp line (%s) nb=%i", value, nb); } } /* read crypto lines if any */ if ( stream->proto == SalProtoRtpSavp ) { valid_count=0; memset ( &stream->crypto, 0, sizeof ( stream->crypto ) ); for ( attribute_it=belle_sdp_media_description_get_attributes ( media_desc ) ; valid_count < SAL_CRYPTO_ALGO_MAX && attribute_it!=NULL; attribute_it=attribute_it->next ) { attribute=BELLE_SDP_ATTRIBUTE ( attribute_it->data ); if ( keywordcmp ( "crypto",belle_sdp_attribute_get_name ( attribute ) ) ==0 && belle_sdp_attribute_get_value ( attribute ) !=NULL ) { nb = sscanf ( belle_sdp_attribute_get_value ( attribute ), "%d %256s inline:%256s", &stream->crypto[valid_count].tag, tmp, tmp2 ); ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'", stream->crypto[valid_count].tag, tmp, tmp2 ); if ( nb == 3 ) { if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_80",tmp ) == 0 ) stream->crypto[valid_count].algo = AES_128_SHA1_80; else if ( keywordcmp ( "AES_CM_128_HMAC_SHA1_32",tmp ) == 0 ) stream->crypto[valid_count].algo = AES_128_SHA1_32; else { ms_warning ( "Failed to parse crypto-algo: '%s'", tmp ); stream->crypto[valid_count].algo = 0; } if ( stream->crypto[valid_count].algo ) { strncpy ( stream->crypto[valid_count].master_key, tmp2, 41 ); stream->crypto[valid_count].master_key[40] = '\0'; ms_message ( "Found valid crypto line (tag:%d algo:'%s' key:'%s'", stream->crypto[valid_count].tag, tmp, stream->crypto[valid_count].master_key ); valid_count++; } } else { ms_warning ( "sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value ( attribute ),nb ); } } } ms_message ( "Found: %d valid crypto lines", valid_count ); } /* Get ICE candidate attributes if any */ for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) { const char *att_name; attribute=(belle_sdp_attribute_t*)attribute_it->data; att_name=belle_sdp_attribute_get_name(attribute); value=belle_sdp_attribute_get_value(attribute); if ((keywordcmp("candidate", att_name) == 0) && (value != NULL)) { SalIceCandidate *candidate = &stream->ice_candidates[nb_ice_candidates]; int nb = sscanf(value, "%s %u UDP %u %s %d typ %s raddr %s rport %d", candidate->foundation, &candidate->componentID, &candidate->priority, candidate->addr, &candidate->port, candidate->type, candidate->raddr, &candidate->rport); if ((nb == 6) || (nb == 8)) nb_ice_candidates++; else memset(candidate, 0, sizeof(*candidate)); } else if ((keywordcmp("remote-candidates", att_name) == 0) && (value != NULL)) { SalIceRemoteCandidate candidate; unsigned int componentID; int offset; const char *ptr = value; const char *endptr=value+strlen(ptr); while (3 == sscanf(ptr, "%u %s %u%n", &componentID, candidate.addr, &candidate.port, &offset)) { if ((componentID > 0) && (componentID <= SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES)) { SalIceRemoteCandidate *remote_candidate = &stream->ice_remote_candidates[componentID - 1]; strncpy(remote_candidate->addr, candidate.addr, sizeof(remote_candidate->addr)); remote_candidate->port = candidate.port; } ptr += offset; if (ptr<endptr){ if (ptr[offset] == ' ') ptr += 1; }else break; } } else if ((keywordcmp("ice-ufrag", att_name) == 0) && (value != NULL)) { strncpy(stream->ice_ufrag, value, sizeof(stream->ice_ufrag)); } else if ((keywordcmp("ice-pwd", att_name) == 0) && (value != NULL)) { strncpy(stream->ice_pwd, value, sizeof(stream->ice_pwd)); } else if (keywordcmp("ice-mismatch", att_name) == 0) { stream->ice_mismatch = TRUE; } } desc->n_total_streams++; } return 0; }