mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-20 20:48:07 +00:00
add ICE support to SDP parser/writer.
add a test to check basic ICE functionality.
This commit is contained in:
parent
8b571c2edf
commit
46bf8a0684
2 changed files with 382 additions and 182 deletions
|
|
@ -19,128 +19,221 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|||
#include "sal_impl.h"
|
||||
#define keywordcmp(key,b) strncmp(key,b,sizeof(key))
|
||||
|
||||
belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescription *desc) {
|
||||
belle_sdp_session_description_t* session_desc=belle_sdp_session_description_new();
|
||||
bool_t inet6;
|
||||
belle_sdp_origin_t* origin;
|
||||
|
||||
static void add_ice_candidates(belle_sdp_media_description_t *md, const SalStreamDescription *desc){
|
||||
char buffer[1024];
|
||||
const SalIceCandidate *candidate;
|
||||
int nb;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; i++) {
|
||||
candidate = &desc->ice_candidates[i];
|
||||
if ((candidate->addr[0] == '\0') || (candidate->port == 0)) break;
|
||||
nb = snprintf(buffer, sizeof(buffer), "%s %u UDP %u %s %d typ %s",
|
||||
candidate->foundation, candidate->componentID, candidate->priority, candidate->addr, candidate->port, candidate->type);
|
||||
if (nb < 0) {
|
||||
ms_error("Cannot add ICE candidate attribute!");
|
||||
return;
|
||||
}
|
||||
if (candidate->raddr[0] != '\0') {
|
||||
nb = snprintf(buffer + nb, sizeof(buffer) - nb, " raddr %s rport %d", candidate->raddr, candidate->rport);
|
||||
if (nb < 0) {
|
||||
ms_error("Cannot add ICE candidate attribute!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("candidate",buffer));
|
||||
}
|
||||
}
|
||||
|
||||
static void add_ice_remote_candidates(belle_sdp_media_description_t *md, const SalStreamDescription *desc){
|
||||
char buffer[1024];
|
||||
char *ptr = buffer;
|
||||
const SalIceRemoteCandidate *candidate;
|
||||
int offset = 0;
|
||||
int i;
|
||||
|
||||
buffer[0] = '\0';
|
||||
for (i = 0; i < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; i++) {
|
||||
candidate = &desc->ice_remote_candidates[i];
|
||||
if ((candidate->addr[0] != '\0') && (candidate->port != 0)) {
|
||||
offset = snprintf(ptr, buffer + sizeof(buffer) - ptr, "%s%d %s %d", (i > 0) ? " " : "", i + 1, candidate->addr, candidate->port);
|
||||
if (offset < 0) {
|
||||
ms_error("Cannot add ICE remote-candidates attribute!");
|
||||
return;
|
||||
}
|
||||
ptr += offset;
|
||||
}
|
||||
}
|
||||
if (buffer[0] != '\0') belle_sdp_media_description_add_attribute(md,belle_sdp_attribute_create("remote-candidates",buffer));
|
||||
}
|
||||
|
||||
static belle_sdp_media_description_t *stream_description_to_sdp ( const SalStreamDescription *stream ) {
|
||||
belle_sdp_mime_parameter_t* mime_param;
|
||||
belle_sdp_media_description_t* media_desc;
|
||||
int i,j;
|
||||
int j;
|
||||
MSList* pt_it;
|
||||
PayloadType* pt;
|
||||
char buffer[1024];
|
||||
char* dir=NULL;
|
||||
const char *rtp_addr;
|
||||
const char *rtcp_addr;
|
||||
int rtp_port;
|
||||
int rtcp_port;
|
||||
bool_t different_rtp_and_rtcp_addr;
|
||||
|
||||
rtp_addr=stream->rtp_addr;
|
||||
rtcp_addr=stream->rtcp_addr;
|
||||
rtp_port=stream->rtp_port;
|
||||
rtcp_port=stream->rtcp_port;
|
||||
|
||||
media_desc = belle_sdp_media_description_create ( sal_stream_type_to_string ( stream->type )
|
||||
,stream->rtp_port
|
||||
,1
|
||||
,sal_media_proto_to_string ( stream->proto )
|
||||
,NULL );
|
||||
for ( pt_it=stream->payloads; pt_it!=NULL; pt_it=pt_it->next ) {
|
||||
pt= ( PayloadType* ) pt_it->data;
|
||||
mime_param= belle_sdp_mime_parameter_create ( pt->mime_type
|
||||
, payload_type_get_number ( pt )
|
||||
, pt->clock_rate
|
||||
,stream->type==SalAudio?1:-1 );
|
||||
belle_sdp_mime_parameter_set_parameters ( mime_param,pt->recv_fmtp );
|
||||
if ( stream->ptime>0 ) {
|
||||
belle_sdp_mime_parameter_set_ptime ( mime_param,stream->ptime );
|
||||
}
|
||||
belle_sdp_media_description_append_values_from_mime_parameter ( media_desc,mime_param );
|
||||
belle_sip_object_unref ( mime_param );
|
||||
}
|
||||
if ( stream->bandwidth>0 )
|
||||
belle_sdp_media_description_set_bandwidth ( media_desc,"AS",stream->bandwidth );
|
||||
|
||||
if (strchr(desc->addr,':')!=NULL){
|
||||
inet6=1;
|
||||
}else inet6=0;
|
||||
belle_sdp_session_description_set_version(session_desc,belle_sdp_version_create(0));
|
||||
if ( stream->proto == SalProtoRtpSavp ) {
|
||||
/* add crypto lines */
|
||||
for ( j=0; j<SAL_CRYPTO_ALGO_MAX; j++ ) {
|
||||
|
||||
origin = belle_sdp_origin_create(desc->username
|
||||
,desc->session_id
|
||||
,desc->session_ver
|
||||
,"IN"
|
||||
, inet6 ? "IP6" :"IP4"
|
||||
,desc->addr);
|
||||
switch ( stream->crypto[j].algo ) {
|
||||
case AES_128_SHA1_80:
|
||||
snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s",
|
||||
stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", stream->crypto[j].master_key );
|
||||
belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) );
|
||||
break;
|
||||
case AES_128_SHA1_32:
|
||||
snprintf ( buffer, sizeof ( buffer ), "%d %s inline:%s",
|
||||
stream->crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", stream->crypto[j].master_key );
|
||||
belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( "crypto",buffer ) );
|
||||
break;
|
||||
case AES_128_NO_AUTH:
|
||||
ms_warning ( "Unsupported crypto suite: AES_128_NO_AUTH" );
|
||||
break;
|
||||
case NO_CIPHER_SHA1_80:
|
||||
ms_warning ( "Unsupported crypto suite: NO_CIPHER_SHA1_80" );
|
||||
break;
|
||||
default:
|
||||
j = SAL_CRYPTO_ALGO_MAX;
|
||||
/* no break */
|
||||
}
|
||||
}
|
||||
}
|
||||
switch ( stream->dir ) {
|
||||
case SalStreamSendRecv:
|
||||
/*dir="sendrecv";*/
|
||||
dir=NULL;
|
||||
break;
|
||||
case SalStreamRecvOnly:
|
||||
dir="recvonly";
|
||||
break;
|
||||
case SalStreamSendOnly:
|
||||
dir="sendonly";
|
||||
break;
|
||||
case SalStreamInactive:
|
||||
dir="inactive";
|
||||
break;
|
||||
}
|
||||
if ( dir ) belle_sdp_media_description_add_attribute ( media_desc,belle_sdp_attribute_create ( dir,NULL ) );
|
||||
|
||||
if (rtp_port != 0) {
|
||||
different_rtp_and_rtcp_addr = (rtcp_addr[0] != '\0') && (strcmp(rtp_addr, rtcp_addr) != 0);
|
||||
if ((rtcp_port != (rtp_port + 1)) || (different_rtp_and_rtcp_addr == TRUE)) {
|
||||
if (different_rtp_and_rtcp_addr == TRUE) {
|
||||
snprintf(buffer, sizeof(buffer), "%u IN IP4 %s", rtcp_port, rtcp_addr);
|
||||
} else {
|
||||
snprintf(buffer, sizeof(buffer), "%u",rtcp_port);
|
||||
}
|
||||
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("rtcp",buffer));
|
||||
}
|
||||
}
|
||||
if (stream->ice_completed == TRUE) {
|
||||
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("nortpproxy","yes"));
|
||||
}
|
||||
if (stream->ice_mismatch == TRUE) {
|
||||
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-mismatch",NULL));
|
||||
} else {
|
||||
if (rtp_port != 0) {
|
||||
if (stream->ice_pwd[0] != '\0')
|
||||
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-pwd",stream->ice_pwd));
|
||||
if (stream->ice_ufrag[0] != '\0')
|
||||
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create ("ice-ufrag",stream->ice_ufrag));
|
||||
add_ice_candidates(media_desc,stream);
|
||||
add_ice_remote_candidates(media_desc,stream);
|
||||
}
|
||||
}
|
||||
|
||||
return media_desc;
|
||||
}
|
||||
|
||||
belle_sdp_session_description_set_origin(session_desc,origin);
|
||||
belle_sdp_session_description_t * media_description_to_sdp ( const SalMediaDescription *desc ) {
|
||||
belle_sdp_session_description_t* session_desc=belle_sdp_session_description_new();
|
||||
bool_t inet6;
|
||||
belle_sdp_origin_t* origin;
|
||||
int i;
|
||||
|
||||
belle_sdp_session_description_set_session_name(session_desc,belle_sdp_session_name_create("Talk"));
|
||||
if ( strchr ( desc->addr,':' ) !=NULL ) {
|
||||
inet6=1;
|
||||
} else inet6=0;
|
||||
belle_sdp_session_description_set_version ( session_desc,belle_sdp_version_create ( 0 ) );
|
||||
|
||||
if(!sal_media_description_has_dir (desc,SalStreamSendOnly) && !sal_media_description_has_dir (desc,SalStreamInactive)) {
|
||||
belle_sdp_session_description_set_connection(session_desc
|
||||
,belle_sdp_connection_create("IN",inet6 ? "IP6" :"IP4",desc->addr));
|
||||
origin = belle_sdp_origin_create ( desc->username
|
||||
,desc->session_id
|
||||
,desc->session_ver
|
||||
,"IN"
|
||||
, inet6 ? "IP6" :"IP4"
|
||||
,desc->addr );
|
||||
|
||||
belle_sdp_session_description_set_origin ( session_desc,origin );
|
||||
|
||||
belle_sdp_session_description_set_session_name ( session_desc,belle_sdp_session_name_create ( "Talk" ) );
|
||||
|
||||
if ( !sal_media_description_has_dir ( desc,SalStreamSendOnly ) && !sal_media_description_has_dir ( desc,SalStreamInactive ) ) {
|
||||
belle_sdp_session_description_set_connection ( session_desc
|
||||
,belle_sdp_connection_create ( "IN",inet6 ? "IP6" :"IP4",desc->addr ) );
|
||||
|
||||
} else {
|
||||
belle_sdp_session_description_set_connection(session_desc
|
||||
,belle_sdp_connection_create("IN"
|
||||
,inet6 ? "IP6" :"IP4"
|
||||
,inet6 ? "::0" :"0.0.0.0"));
|
||||
belle_sdp_session_description_set_connection ( session_desc
|
||||
,belle_sdp_connection_create ( "IN"
|
||||
,inet6 ? "IP6" :"IP4"
|
||||
,inet6 ? "::0" :"0.0.0.0" ) );
|
||||
|
||||
}
|
||||
|
||||
belle_sdp_session_description_set_time_description(session_desc,belle_sdp_time_description_create(0,0));
|
||||
belle_sdp_session_description_set_time_description ( session_desc,belle_sdp_time_description_create ( 0,0 ) );
|
||||
|
||||
if (desc->bandwidth>0) {
|
||||
belle_sdp_session_description_set_bandwidth(session_desc,"AS",desc->bandwidth);
|
||||
if ( desc->bandwidth>0 ) {
|
||||
belle_sdp_session_description_set_bandwidth ( session_desc,"AS",desc->bandwidth );
|
||||
}
|
||||
|
||||
for (i=0; i<desc->n_total_streams;i++) {
|
||||
media_desc = belle_sdp_media_description_create(sal_stream_type_to_string(desc->streams[i].type)
|
||||
,desc->streams[i].rtp_port
|
||||
,1
|
||||
,sal_media_proto_to_string(desc->streams[i].proto)
|
||||
,NULL);
|
||||
for (pt_it=desc->streams[i].payloads;pt_it!=NULL;pt_it=pt_it->next) {
|
||||
pt=(PayloadType*)pt_it->data;
|
||||
mime_param= belle_sdp_mime_parameter_create(pt->mime_type
|
||||
, payload_type_get_number(pt)
|
||||
, pt->clock_rate
|
||||
,desc->streams[i].type==SalAudio?1:-1);
|
||||
belle_sdp_mime_parameter_set_parameters(mime_param,pt->recv_fmtp);
|
||||
if (desc->streams[i].ptime>0) {
|
||||
belle_sdp_mime_parameter_set_ptime(mime_param,desc->streams[i].ptime);
|
||||
}
|
||||
belle_sdp_media_description_append_values_from_mime_parameter(media_desc,mime_param);
|
||||
belle_sip_object_unref(mime_param);
|
||||
}
|
||||
if (desc->streams[i].bandwidth>0)
|
||||
belle_sdp_media_description_set_bandwidth(media_desc,"AS",desc->streams[i].bandwidth);
|
||||
|
||||
if (desc->streams[i].proto == SalProtoRtpSavp) {
|
||||
/* add crypto lines */
|
||||
for(j=0; j<SAL_CRYPTO_ALGO_MAX; j++) {
|
||||
|
||||
switch (desc->streams[i].crypto[j].algo) {
|
||||
case AES_128_SHA1_80:
|
||||
snprintf(buffer, sizeof(buffer), "%d %s inline:%s",
|
||||
desc->streams[i].crypto[j].tag, "AES_CM_128_HMAC_SHA1_80", desc->streams[i].crypto[j].master_key);
|
||||
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create("crypto",buffer));
|
||||
break;
|
||||
case AES_128_SHA1_32:
|
||||
snprintf(buffer, sizeof(buffer), "%d %s inline:%s",
|
||||
desc->streams[i].crypto[j].tag, "AES_CM_128_HMAC_SHA1_32", desc->streams[i].crypto[j].master_key);
|
||||
belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create("crypto",buffer));
|
||||
break;
|
||||
case AES_128_NO_AUTH:
|
||||
ms_warning("Unsupported crypto suite: AES_128_NO_AUTH");
|
||||
break;
|
||||
case NO_CIPHER_SHA1_80:
|
||||
ms_warning("Unsupported crypto suite: NO_CIPHER_SHA1_80");
|
||||
break;
|
||||
default:
|
||||
j = SAL_CRYPTO_ALGO_MAX;
|
||||
/* no break */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
switch(desc->streams[i].dir){
|
||||
case SalStreamSendRecv:
|
||||
/*dir="sendrecv";*/
|
||||
dir=NULL;
|
||||
break;
|
||||
case SalStreamRecvOnly:
|
||||
dir="recvonly";
|
||||
break;
|
||||
case SalStreamSendOnly:
|
||||
dir="sendonly";
|
||||
break;
|
||||
case SalStreamInactive:
|
||||
dir="inactive";
|
||||
break;
|
||||
}
|
||||
if (dir) belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create(dir,NULL));
|
||||
|
||||
belle_sdp_session_description_add_media_description(session_desc,media_desc);
|
||||
|
||||
|
||||
if (desc->ice_completed == TRUE) belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("nortpproxy","yes"));
|
||||
if (desc->ice_pwd[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-pwd",desc->ice_pwd));
|
||||
if (desc->ice_ufrag[0] != '\0') belle_sdp_session_description_add_attribute(session_desc, belle_sdp_attribute_create("ice-ufrag",desc->ice_ufrag));
|
||||
|
||||
for ( i=0; i<desc->n_total_streams; i++ ) {
|
||||
belle_sdp_session_description_add_media_description ( session_desc,stream_description_to_sdp(&desc->streams[i]));
|
||||
}
|
||||
return session_desc;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int sdp_to_media_description(belle_sdp_session_description_t *session_desc, SalMediaDescription *desc) {
|
||||
int sdp_to_media_description ( belle_sdp_session_description_t *session_desc, SalMediaDescription *desc ) {
|
||||
/*
|
||||
typedef struct SalMediaDescription{
|
||||
int refcount;
|
||||
|
|
@ -164,154 +257,218 @@ int sdp_to_media_description(belle_sdp_session_description_t *session_desc, Sal
|
|||
belle_sdp_mime_parameter_t* mime_param;
|
||||
PayloadType *pt;
|
||||
belle_sip_list_t* attribute_it;
|
||||
belle_sdp_attribute_t* attribute;
|
||||
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;
|
||||
int nb_ice_candidates=0;
|
||||
|
||||
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 ( ( 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");
|
||||
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")) {
|
||||
if ( belle_sdp_session_description_get_attribute ( session_desc,"sendrecv" ) ) {
|
||||
stream_dir=SalStreamSendRecv;
|
||||
} else if (belle_sdp_session_description_get_attribute(session_desc,"sendonly")) {
|
||||
} 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")) {
|
||||
} 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")) {
|
||||
} else if ( belle_sdp_session_description_get_attribute ( session_desc,"inactive" ) ) {
|
||||
stream_dir=SalStreamInactive;
|
||||
}
|
||||
|
||||
|
||||
for(media_desc_it=belle_sdp_session_description_get_media_descriptions(session_desc)
|
||||
;media_desc_it!=NULL
|
||||
;media_desc_it=media_desc_it->next) {
|
||||
media_desc=BELLE_SDP_MEDIA_DESCRIPTION(media_desc_it->data);
|
||||
/* 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 ) {
|
||||
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);
|
||||
media=belle_sdp_media_description_get_media ( media_desc );
|
||||
|
||||
memset(stream,0,sizeof(*stream));
|
||||
memset ( stream,0,sizeof ( *stream ) );
|
||||
|
||||
proto = belle_sdp_media_get_protocol(media);
|
||||
proto = belle_sdp_media_get_protocol ( media );
|
||||
stream->proto=SalProtoUnknown;
|
||||
if (proto){
|
||||
if (strcasecmp(proto,"RTP/AVP")==0)
|
||||
if ( proto ) {
|
||||
if ( strcasecmp ( proto,"RTP/AVP" ) ==0 )
|
||||
stream->proto=SalProtoRtpAvp;
|
||||
else if (strcasecmp(proto,"RTP/SAVP")==0){
|
||||
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));
|
||||
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);
|
||||
stream->rtp_port=belle_sdp_media_get_media_port ( media );
|
||||
stream->rtcp_port = stream->rtp_port + 1;
|
||||
if (stream->rtp_port > 0)
|
||||
desc->n_active_streams++;
|
||||
if ( stream->rtp_port > 0 )
|
||||
desc->n_active_streams++;
|
||||
|
||||
mtype = belle_sdp_media_get_media_type(media);
|
||||
if (strcasecmp("audio", mtype) == 0){
|
||||
mtype = belle_sdp_media_get_media_type ( media );
|
||||
if ( strcasecmp ( "audio", mtype ) == 0 ) {
|
||||
stream->type=SalAudio;
|
||||
}else if (strcasecmp("video", mtype) == 0){
|
||||
} else if ( strcasecmp ( "video", mtype ) == 0 ) {
|
||||
stream->type=SalVideo;
|
||||
}else {
|
||||
} else {
|
||||
stream->type=SalOther;
|
||||
strncpy(stream->typeother,mtype,sizeof(stream->typeother)-1);
|
||||
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_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")) {
|
||||
if ( belle_sdp_media_description_get_attribute ( media_desc,"sendrecv" ) ) {
|
||||
stream->dir=SalStreamSendRecv;
|
||||
} else if (belle_sdp_media_description_get_attribute(media_desc,"sendonly")) {
|
||||
} 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")) {
|
||||
} 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")) {
|
||||
} 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)
|
||||
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 : "");
|
||||
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);
|
||||
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) {
|
||||
if ( stream->proto == SalProtoRtpSavp ) {
|
||||
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 );
|
||||
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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_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);
|
||||
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) {
|
||||
attribute=(belle_sdp_attribute_t*)attribute_it->data;
|
||||
const char *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;
|
||||
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[offset] == ' ') ptr += 1;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ static void call_declined(void) {
|
|||
static void call_terminated_by_caller(void) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc");
|
||||
|
||||
|
||||
CU_ASSERT_TRUE(call(pauline,marie));
|
||||
/*just to sleep*/
|
||||
linphone_core_terminate_all_calls(pauline->lc);
|
||||
|
|
@ -382,6 +382,48 @@ static void call_terminated_by_caller(void) {
|
|||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
static void call_with_ice(void) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc");
|
||||
int i;
|
||||
LinphoneCall *c1,*c2;
|
||||
bool_t success=FALSE;
|
||||
|
||||
linphone_core_set_firewall_policy(marie->lc,LinphonePolicyUseIce);
|
||||
linphone_core_set_stun_server(marie->lc,"stun.linphone.org");
|
||||
linphone_core_set_firewall_policy(pauline->lc,LinphonePolicyUseIce);
|
||||
linphone_core_set_stun_server(pauline->lc,"stun.linphone.org");
|
||||
|
||||
CU_ASSERT_TRUE(call(pauline,marie));
|
||||
|
||||
c1=linphone_core_get_current_call(marie->lc);
|
||||
c2=linphone_core_get_current_call(pauline->lc);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(c1);
|
||||
CU_ASSERT_PTR_NOT_NULL(c2);
|
||||
|
||||
for (i=0;i<100;i++){
|
||||
if (linphone_call_get_audio_stats(c1)->ice_state==LinphoneIceStateHostConnection &&
|
||||
linphone_call_get_audio_stats(c2)->ice_state==LinphoneIceStateHostConnection ){
|
||||
success=TRUE;
|
||||
break;
|
||||
}
|
||||
linphone_core_iterate(marie->lc);
|
||||
linphone_core_iterate(pauline->lc);
|
||||
ms_usleep(100000);
|
||||
}
|
||||
|
||||
CU_ASSERT_TRUE(success);
|
||||
|
||||
/*just to sleep*/
|
||||
linphone_core_terminate_all_calls(pauline->lc);
|
||||
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1));
|
||||
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1));
|
||||
|
||||
linphone_core_manager_destroy(marie);
|
||||
linphone_core_manager_destroy(pauline);
|
||||
}
|
||||
|
||||
static void call_paused_resumed(void) {
|
||||
LinphoneCoreManager* marie = linphone_core_manager_new(liblinphone_tester_file_prefix, "marie_rc");
|
||||
LinphoneCoreManager* pauline = linphone_core_manager_new(liblinphone_tester_file_prefix, "pauline_rc");
|
||||
|
|
@ -736,7 +778,8 @@ test_t call_tests[] = {
|
|||
#endif
|
||||
{ "Simple conference", simple_conference },
|
||||
{ "Simple call transfer", simple_call_transfer },
|
||||
{ "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call }
|
||||
{ "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call },
|
||||
{ "Call with ICE", call_with_ice },
|
||||
};
|
||||
|
||||
test_suite_t call_test_suite = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue