diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 667c1e22b..8f470c052 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -251,28 +251,223 @@ belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescr } +static void sdp_parse_payload_types(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + PayloadType *pt; + belle_sip_list_t* mime_param_it=NULL; + belle_sdp_mime_parameter_t* mime_param; + belle_sip_list_t* 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 ); +} + +static void sdp_parse_media_crypto_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + belle_sip_list_t *attribute_it; + const belle_sdp_attribute_t *attribute; + char tmp[256], tmp2[256]; + int valid_count = 0; + int nb; + + 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 ); +} + +static void sdp_parse_ice_media_parameters(belle_sdp_media_description_t *media_desc, SalStreamDescription *stream) { + belle_sip_list_t *attribute_it; + const belle_sdp_attribute_t *attribute; + const char *att_name; + const char *value; + int nb_ice_candidates = 0; + + for (attribute_it = belle_sdp_media_description_get_attributes(media_desc); attribute_it != NULL; attribute_it=attribute_it->next) { + 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; + } + } +} + +static SalStreamDescription * sdp_to_stream_description(SalMediaDescription *md, belle_sdp_media_description_t *media_desc) { + SalStreamDescription *stream; + belle_sdp_connection_t* cnx; + belle_sdp_media_t* media; + const belle_sdp_attribute_t* attribute; + const char* value; + const char *mtype,*proto; + + stream=&md->streams[md->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 ) + md->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=md->dir; /*takes default value if not present*/ + } + + /* Get media payload types */ + sdp_parse_payload_types(media_desc, stream); + + /* 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 ) { + sdp_parse_media_crypto_parameters(media_desc, stream); + } + + /* Get ICE candidate attributes if any */ + sdp_parse_ice_media_parameters(media_desc, stream); + + md->n_total_streams++; + return stream; +} + + 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 *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; + 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 ) ); @@ -287,13 +482,13 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S /*in some very rare case, session attribute may set stream dir*/ if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) { - stream_dir=SalStreamSendRecv; + desc->dir=SalStreamSendRecv; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"sendonly" ) ) { - stream_dir=SalStreamSendOnly; + desc->dir=SalStreamSendOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"recvonly" ) ) { - stream_dir=SalStreamRecvOnly; + desc->dir=SalStreamRecvOnly; } else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) { - stream_dir=SalStreamInactive; + desc->dir=SalStreamInactive; } /* Get ICE remote ufrag and remote pwd, and ice_lite flag */ @@ -309,189 +504,12 @@ int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, S 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; - 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 ); - 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 (ptrice_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++; + sdp_to_stream_description(desc, media_desc); } return 0; } - - - - - diff --git a/include/sal/sal.h b/include/sal/sal.h index 8ff57dc12..3deb3ddb4 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -211,6 +211,7 @@ typedef struct SalMediaDescription{ int bandwidth; unsigned int session_ver; unsigned int session_id; + SalStreamDir dir; SalStreamDescription streams[SAL_MEDIA_DESCRIPTION_MAX_STREAMS]; char ice_ufrag[SAL_MEDIA_DESCRIPTION_MAX_ICE_UFRAG_LEN]; char ice_pwd[SAL_MEDIA_DESCRIPTION_MAX_ICE_PWD_LEN];