allow usage of system-choosen random ports.

Implies a lot of refactoring in streams management.
This commit is contained in:
Simon Morlat 2014-04-07 17:36:51 +02:00
parent affd021540
commit 7bd50e004f
9 changed files with 230 additions and 165 deletions

View file

@ -58,14 +58,14 @@ void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *c
rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr;
rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr;
ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
rtp_session_set_remote_addr_full(call->audiostream->ms.session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
rtp_session_set_remote_addr_full(call->audiostream->ms.sessions.rtp_session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port);
}
#ifdef VIDEO_ENABLED
if (call->videostream && new_videodesc) {
rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr;
rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr;
ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
rtp_session_set_remote_addr_full(call->videostream->ms.session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
rtp_session_set_remote_addr_full(call->videostream->ms.sessions.rtp_session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port);
}
#else
(void)new_videodesc;
@ -97,7 +97,7 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
sal_media_description_ref(new_md);
call->expect_media_in_ack=FALSE;
call->resultdesc=new_md;
if ((call->audiostream && call->audiostream->ms.ticker) || (call->videostream && call->videostream->ms.ticker)){
if ((call->audiostream && call->audiostream->ms.state==MSStreamStarted) || (call->videostream && call->videostream->ms.state==MSStreamStarted)){
/* we already started media: check if we really need to restart it*/
if (oldmd){
int md_changed = media_parameters_changed(call, oldmd, new_md);
@ -671,7 +671,6 @@ static void call_failure(SalOp *op){
!linphone_core_is_media_encryption_mandatory(lc)) {
int i;
ms_message("Outgoing call [%p] failed with SRTP (SAVP) enabled",call);
linphone_call_stop_media_streams(call);
if (call->state==LinphoneCallOutgoingInit
|| call->state==LinphoneCallOutgoingProgress
|| call->state==LinphoneCallOutgoingRinging /*push case*/

View file

@ -191,13 +191,13 @@ void linphone_call_set_authentication_token_verified(LinphoneCall *call, bool_t
if (call->audiostream==NULL){
ms_error("linphone_call_set_authentication_token_verified(): No audio stream");
}
if (call->audiostream->ms.zrtp_context==NULL){
if (call->audiostream->ms.sessions.zrtp_context==NULL){
ms_error("linphone_call_set_authentication_token_verified(): No zrtp context.");
}
if (!call->auth_token_verified && verified){
ortp_zrtp_sas_verified(call->audiostream->ms.zrtp_context);
ortp_zrtp_sas_verified(call->audiostream->ms.sessions.zrtp_context);
}else if (call->auth_token_verified && !verified){
ortp_zrtp_sas_reset_verified(call->audiostream->ms.zrtp_context);
ortp_zrtp_sas_reset_verified(call->audiostream->ms.sessions.zrtp_context);
}
call->auth_token_verified=verified;
propagate_encryption_changed(call);
@ -333,8 +333,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
strncpy(md->streams[0].rtp_addr,local_ip,sizeof(md->streams[0].rtp_addr));
strncpy(md->streams[0].rtcp_addr,local_ip,sizeof(md->streams[0].rtcp_addr));
strncpy(md->streams[0].name,"Audio",sizeof(md->streams[0].name)-1);
md->streams[0].rtp_port=call->audio_port;
md->streams[0].rtcp_port=call->audio_port+1;
md->streams[0].rtp_port=call->media_ports[0].rtp_port;
md->streams[0].rtcp_port=call->media_ports[0].rtcp_port;
md->streams[0].proto=(call->params.media_encryption == LinphoneMediaEncryptionSRTP) ?
SalProtoRtpSavp : SalProtoRtpAvp;
md->streams[0].type=SalAudio;
@ -350,8 +350,8 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
if (call->params.has_video){
md->n_active_streams++;
strncpy(md->streams[0].name,"Video",sizeof(md->streams[0].name)-1);
md->streams[1].rtp_port=call->video_port;
md->streams[1].rtcp_port=call->video_port+1;
md->streams[1].rtp_port=call->media_ports[1].rtp_port;
md->streams[1].rtcp_port=call->media_ports[1].rtcp_port;
md->streams[1].proto=md->streams[0].proto;
md->streams[1].type=SalVideo;
l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
@ -393,34 +393,19 @@ void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *
}
}
static int find_port_offset(LinphoneCore *lc, SalStreamType type){
static int find_port_offset(LinphoneCore *lc, int stream_index, int base_port){
int offset;
MSList *elem;
int tried_port;
int existing_port;
bool_t already_used=FALSE;
for(offset=0;offset<100;offset+=2){
switch (type) {
default:
case SalAudio:
tried_port=linphone_core_get_audio_port (lc)+offset;
break;
case SalVideo:
tried_port=linphone_core_get_video_port (lc)+offset;
break;
}
tried_port=base_port+offset;
already_used=FALSE;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
switch (type) {
default:
case SalAudio:
existing_port = call->audio_port;
break;
case SalVideo:
existing_port = call->video_port;
break;
}
existing_port=call->media_ports[stream_index].rtp_port;
if (existing_port==tried_port) {
already_used=TRUE;
break;
@ -435,37 +420,19 @@ static int find_port_offset(LinphoneCore *lc, SalStreamType type){
return offset;
}
static int select_random_port(LinphoneCore *lc, SalStreamType type) {
static int select_random_port(LinphoneCore *lc, int stream_index, int min_port, int max_port) {
MSList *elem;
int nb_tries;
int tried_port = 0;
int existing_port = 0;
int min_port = 0, max_port = 0;
bool_t already_used = FALSE;
switch (type) {
default:
case SalAudio:
linphone_core_get_audio_port_range(lc, &min_port, &max_port);
break;
case SalVideo:
linphone_core_get_video_port_range(lc, &min_port, &max_port);
break;
}
tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
if (tried_port < min_port) tried_port = min_port + 2;
for (nb_tries = 0; nb_tries < 100; nb_tries++) {
for (elem = lc->calls; elem != NULL; elem = elem->next) {
LinphoneCall *call = (LinphoneCall *)elem->data;
switch (type) {
default:
case SalAudio:
existing_port = call->audio_port;
break;
case SalVideo:
existing_port = call->video_port;
break;
}
existing_port=call->media_ports[stream_index].rtp_port;
if (existing_port == tried_port) {
already_used = TRUE;
break;
@ -480,8 +447,31 @@ static int select_random_port(LinphoneCore *lc, SalStreamType type) {
return tried_port;
}
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
static void port_config_set_random(LinphoneCall *call, int stream_index){
call->media_ports[stream_index].rtp_port=-1;
call->media_ports[stream_index].rtcp_port=-1;
}
static void port_config_set(LinphoneCall *call, int stream_index, int min_port, int max_port){
int port_offset;
if (min_port>0 && max_port>0){
if (min_port == max_port) {
/* Used fixed RTP audio port. */
port_offset=find_port_offset(call->core, stream_index, min_port);
if (port_offset==-1) {
port_config_set_random(call, stream_index);
return;
}
call->media_ports[stream_index].rtp_port=min_port+port_offset;
} else {
/* Select random RTP audio port in the specified range. */
call->media_ports[stream_index].rtp_port = select_random_port(call->core, stream_index, min_port, max_port);
}
call->media_ports[stream_index].rtcp_port=call->media_ports[stream_index].rtp_port+1;
}else port_config_set_random(call,stream_index);
}
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
int min_port, max_port;
call->magic=linphone_call_magic;
@ -494,25 +484,11 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
call->camera_enabled=TRUE;
linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
if (min_port == max_port) {
/* Used fixed RTP audio port. */
port_offset=find_port_offset (call->core, SalAudio);
if (port_offset==-1) return;
call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
} else {
/* Select random RTP audio port in the specified range. */
call->audio_port = select_random_port(call->core, SalAudio);
}
port_config_set(call,0,min_port,max_port);
linphone_core_get_video_port_range(call->core, &min_port, &max_port);
if (min_port == max_port) {
/* Used fixed RTP video port. */
port_offset=find_port_offset (call->core, SalVideo);
if (port_offset==-1) return;
call->video_port=linphone_core_get_video_port(call->core)+port_offset;
} else {
/* Select random RTP video port in the specified range. */
call->video_port = select_random_port(call->core, SalVideo);
}
port_config_set(call,1,min_port,max_port);
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
}
@ -663,20 +639,22 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
// In this case WE chose the media parameters according to policy.
call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
}
/*create the ice session now if ICE is required*/
if (linphone_core_get_firewall_policy(call->core)==LinphonePolicyUseIce){
call->ice_session = ice_session_new();
ice_session_set_role(call->ice_session, IR_Controlled);
}
/*reserve the sockets immediately*/
linphone_call_init_media_streams(call);
switch (linphone_core_get_firewall_policy(call->core)) {
case LinphonePolicyUseIce:
call->ice_session = ice_session_new();
ice_session_set_role(call->ice_session, IR_Controlled);
/*start ICE gathering*/
linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
if (call->ice_session != NULL) {
linphone_call_init_media_streams(call);
linphone_call_start_media_streams_for_ice_gathering(call);
if (linphone_core_gather_ice_candidates(call->core,call)<0) {
/* Ice candidates gathering failed, proceed with the call anyway. */
linphone_call_delete_ice_session(call);
linphone_call_stop_media_streams_for_ice_gathering(call);
}
linphone_call_start_media_streams_for_ice_gathering(call);
if (linphone_core_gather_ice_candidates(call->core,call)<0) {
/* Ice candidates gathering failed, proceed with the call anyway. */
linphone_call_delete_ice_session(call);
linphone_call_stop_media_streams_for_ice_gathering(call);
}
break;
case LinphonePolicyUseStun:
@ -688,7 +666,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
if(!lc->rtp_conf.disable_upnp) {
call->upnp_session = linphone_upnp_session_new(call);
if (call->upnp_session != NULL) {
linphone_call_init_media_streams(call);
if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
linphone_call_delete_upnp_session(call);
@ -714,6 +691,11 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
static void linphone_call_set_terminated(LinphoneCall *call){
LinphoneCore *lc=call->core;
linphone_call_stop_media_streams(call);
ms_media_stream_sessions_uninit(&call->sessions[0]);
ms_media_stream_sessions_uninit(&call->sessions[1]);
linphone_call_delete_upnp_session(call);
linphone_call_delete_ice_session(call);
linphone_core_update_allocated_audio_bandwidth(lc);
call->owns_call_log=FALSE;
@ -856,11 +838,6 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
static void linphone_call_destroy(LinphoneCall *obj)
{
ms_message("Call [%p] freed.",obj);
linphone_call_stop_media_streams(obj);
#ifdef BUILD_UPNP
linphone_call_delete_upnp_session(obj);
#endif //BUILD_UPNP
linphone_call_delete_ice_session(obj);
if (obj->op!=NULL) {
sal_op_release(obj->op);
obj->op=NULL;
@ -1444,17 +1421,31 @@ void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, Lin
call->nextVideoFrameDecoded._func = cb;
call->nextVideoFrameDecoded._user_data = user_data;
#ifdef VIDEO_ENABLED
ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
if (call->videostream && call->videostream->ms.decoder)
ms_filter_call_method_noarg(call->videostream->ms.decoder, MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION);
#endif
}
static void port_config_set_random_choosed(LinphoneCall *call, int stream_index, RtpSession *session){
call->media_ports[stream_index].rtp_port=rtp_session_get_local_port(session);
call->media_ports[stream_index].rtcp_port=rtp_session_get_local_rtcp_port(session);
}
void linphone_call_init_audio_stream(LinphoneCall *call){
LinphoneCore *lc=call->core;
AudioStream *audiostream;
int dscp;
if (call->audiostream != NULL) return;
call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,call->af==AF_INET6);
if (call->sessions[0].rtp_session==NULL){
call->audiostream=audiostream=audio_stream_new(call->media_ports[0].rtp_port,call->media_ports[0].rtcp_port,call->af==AF_INET6);
}else{
call->audiostream=audio_stream_new_with_sessions(&call->sessions[0]);
}
audiostream=call->audiostream;
if (call->media_ports[0].rtp_port==-1){
port_config_set_random_choosed(call,0,audiostream->ms.sessions.rtp_session);
}
dscp=linphone_core_get_audio_dscp(lc);
if (dscp!=-1)
audio_stream_set_dscp(audiostream,dscp);
@ -1486,69 +1477,73 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
audio_stream_set_features(audiostream,linphone_core_get_audio_features(lc));
if (lc->rtptf){
RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->audio_port);
RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->audio_port+1);
rtp_session_set_transports(audiostream->ms.session,artp,artcp);
RtpTransport *artp=lc->rtptf->audio_rtp_func(lc->rtptf->audio_rtp_func_data, call->media_ports[0].rtp_port);
RtpTransport *artcp=lc->rtptf->audio_rtcp_func(lc->rtptf->audio_rtcp_func_data, call->media_ports[0].rtcp_port);
rtp_session_set_transports(audiostream->ms.sessions.rtp_session,artp,artcp);
}
if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
rtp_session_set_pktinfo(audiostream->ms.session, TRUE);
rtp_session_set_symmetric_rtp(audiostream->ms.session, FALSE);
rtp_session_set_pktinfo(audiostream->ms.sessions.rtp_session, TRUE);
rtp_session_set_symmetric_rtp(audiostream->ms.sessions.rtp_session, FALSE);
if (ice_session_check_list(call->ice_session, 0) == NULL) {
ice_session_add_check_list(call->ice_session, ice_check_list_new());
}
audiostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 0);
ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.session);
ice_check_list_set_rtp_session(audiostream->ms.ice_check_list, audiostream->ms.sessions.rtp_session);
}
call->audiostream_app_evq = ortp_ev_queue_new();
rtp_session_register_event_queue(audiostream->ms.session,call->audiostream_app_evq);
rtp_session_register_event_queue(audiostream->ms.sessions.rtp_session,call->audiostream_app_evq);
}
void linphone_call_init_video_stream(LinphoneCall *call){
#ifdef VIDEO_ENABLED
LinphoneCore *lc=call->core;
if (!call->params.has_video) {
linphone_call_stop_video_stream(call);
return;
}
if (call->videostream != NULL) return;
if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
if (call->videostream == NULL){
int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
int dscp=linphone_core_get_video_dscp(lc);
const char *display_filter=linphone_core_get_video_display_filter(lc);
call->videostream=video_stream_new(call->video_port,call->video_port+1,call->af==AF_INET6);
if (call->sessions[1].rtp_session==NULL){
call->videostream=video_stream_new(call->media_ports[1].rtp_port,call->media_ports[1].rtcp_port, call->af==AF_INET6);
}else{
call->videostream=video_stream_new_with_sessions(&call->sessions[1]);
}
if (call->media_ports[1].rtp_port==-1){
port_config_set_random_choosed(call,1,call->videostream->ms.sessions.rtp_session);
}
if (dscp!=-1)
video_stream_set_dscp(call->videostream,dscp);
video_stream_enable_display_filter_auto_rotate(call->videostream, lp_config_get_int(lc->config,"video","display_filter_auto_rotate",0));
if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.session,video_recv_buf_size);
if (video_recv_buf_size>0) rtp_session_set_recv_buf_size(call->videostream->ms.sessions.rtp_session,video_recv_buf_size);
if (display_filter != NULL)
video_stream_set_display_filter_name(call->videostream,display_filter);
video_stream_set_event_callback(call->videostream,video_stream_event_cb, call);
if (lc->rtptf){
RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->video_port);
RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
rtp_session_set_transports(call->videostream->ms.session,vrtp,vrtcp);
RtpTransport *vrtp=lc->rtptf->video_rtp_func(lc->rtptf->video_rtp_func_data, call->media_ports[1].rtp_port);
RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->media_ports[1].rtcp_port);
rtp_session_set_transports(call->videostream->ms.sessions.rtp_session,vrtp,vrtcp);
}
if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
rtp_session_set_pktinfo(call->videostream->ms.session, TRUE);
rtp_session_set_symmetric_rtp(call->videostream->ms.session, FALSE);
if (ice_session_check_list(call->ice_session, 1) == NULL) {
ice_session_add_check_list(call->ice_session, ice_check_list_new());
}
call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.session);
ms_message ("creating new ice video check list [%p] for session [%p]",call->videostream->ms.ice_check_list,call->videostream->ms.session);
}
call->videostream_app_evq = ortp_ev_queue_new();
rtp_session_register_event_queue(call->videostream->ms.session,call->videostream_app_evq);
call->videostream_app_evq = ortp_ev_queue_new();
rtp_session_register_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq);
#ifdef TEST_EXT_RENDERER
video_stream_set_render_callback(call->videostream,rendercb,NULL);
#endif
}
/*eventually re-create the ICE check list that may have been destroyed if the stream wasn't used recently*/
if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
rtp_session_set_pktinfo(call->videostream->ms.sessions.rtp_session, TRUE);
rtp_session_set_symmetric_rtp(call->videostream->ms.sessions.rtp_session, FALSE);
if (ice_session_check_list(call->ice_session, 1) == NULL) {
ice_session_add_check_list(call->ice_session, ice_check_list_new());
}
call->videostream->ms.ice_check_list = ice_session_check_list(call->ice_session, 1);
ice_check_list_set_rtp_session(call->videostream->ms.ice_check_list, call->videostream->ms.sessions.rtp_session);
ms_message ("creating new ice video check list [%p] for session [%p]",call->videostream->ms.ice_check_list,call->videostream->ms.sessions.rtp_session);
}
#else
call->videostream=NULL;
#endif
@ -1779,9 +1774,9 @@ static void configure_rtp_session_for_rtcp_xr(LinphoneCore *lc, LinphoneCall *ca
memcpy(&currentconfig, remoteconfig, sizeof(currentconfig));
}
if (type == SalAudio) {
session = call->audiostream->ms.session;
session = call->audiostream->ms.sessions.rtp_session;
} else {
session = call->videostream->ms.session;
session = call->videostream->ms.sessions.rtp_session;
}
rtp_session_configure_rtcp_xr(session, &currentconfig);
if (currentconfig.rcvr_rtt_mode != OrtpRtcpXrRcvrRttNone) {
@ -2166,14 +2161,16 @@ void linphone_call_delete_ice_session(LinphoneCall *call){
}
}
#ifdef BUILD_UPNP
void linphone_call_delete_upnp_session(LinphoneCall *call){
#ifdef BUILD_UPNP
if(call->upnp_session!=NULL) {
linphone_upnp_session_destroy(call->upnp_session);
call->upnp_session=NULL;
}
}
#endif //BUILD_UPNP
}
static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
float quality=media_stream_get_average_quality_rating(st);
@ -2186,7 +2183,8 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, MediaStream *st){
void linphone_call_stop_audio_stream(LinphoneCall *call) {
if (call->audiostream!=NULL) {
rtp_session_unregister_event_queue(call->audiostream->ms.session,call->audiostream_app_evq);
media_stream_reclaim_sessions(&call->audiostream->ms,&call->sessions[0]);
rtp_session_unregister_event_queue(call->audiostream->ms.sessions.rtp_session,call->audiostream_app_evq);
ortp_ev_queue_flush(call->audiostream_app_evq);
ortp_ev_queue_destroy(call->audiostream_app_evq);
call->audiostream_app_evq=NULL;
@ -2213,7 +2211,8 @@ void linphone_call_stop_audio_stream(LinphoneCall *call) {
void linphone_call_stop_video_stream(LinphoneCall *call) {
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL){
rtp_session_unregister_event_queue(call->videostream->ms.session,call->videostream_app_evq);
media_stream_reclaim_sessions(&call->videostream->ms,&call->sessions[1]);
rtp_session_unregister_event_queue(call->videostream->ms.sessions.rtp_session,call->videostream_app_evq);
ortp_ev_queue_flush(call->videostream_app_evq);
ortp_ev_queue_destroy(call->videostream_app_evq);
call->videostream_app_evq=NULL;
@ -2684,12 +2683,12 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
if ((call->state==LinphoneCallStreamsRunning || call->state==LinphoneCallOutgoingEarlyMedia || call->state==LinphoneCallIncomingEarlyMedia) && one_second_elapsed){
float audio_load=0, video_load=0;
if (call->audiostream!=NULL){
if (call->audiostream->ms.ticker)
audio_load=ms_ticker_get_average_load(call->audiostream->ms.ticker);
if (call->audiostream->ms.sessions.ticker)
audio_load=ms_ticker_get_average_load(call->audiostream->ms.sessions.ticker);
}
if (call->videostream!=NULL){
if (call->videostream->ms.ticker)
video_load=ms_ticker_get_average_load(call->videostream->ms.ticker);
if (call->videostream->ms.sessions.ticker)
video_load=ms_ticker_get_average_load(call->videostream->ms.sessions.ticker);
}
report_bandwidth(call,(MediaStream*)call->audiostream,(MediaStream*)call->videostream);
ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
@ -2716,7 +2715,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
} else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.session);
call->stats[LINPHONE_CALL_STATS_VIDEO].round_trip_delay = rtp_session_get_round_trip_propagation(call->videostream->ms.sessions.rtp_session);
if(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp != NULL)
freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp);
call->stats[LINPHONE_CALL_STATS_VIDEO].received_rtcp = evd->packet;
@ -2726,7 +2725,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
if (lc->vtable.call_stats_updated)
lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_VIDEO]);
} else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.session), sizeof(jitter_stats_t));
memcpy(&call->stats[LINPHONE_CALL_STATS_VIDEO].jitter_stats, rtp_session_get_jitter_stats(call->videostream->ms.sessions.rtp_session), sizeof(jitter_stats_t));
if(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp != NULL)
freemsg(call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp);
call->stats[LINPHONE_CALL_STATS_VIDEO].sent_rtcp = evd->packet;
@ -2761,7 +2760,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
} else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
} else if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.session);
call->stats[LINPHONE_CALL_STATS_AUDIO].round_trip_delay = rtp_session_get_round_trip_propagation(call->audiostream->ms.sessions.rtp_session);
if(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp != NULL)
freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp);
call->stats[LINPHONE_CALL_STATS_AUDIO].received_rtcp = evd->packet;
@ -2771,7 +2770,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
if (lc->vtable.call_stats_updated)
lc->vtable.call_stats_updated(lc, call, &call->stats[LINPHONE_CALL_STATS_AUDIO]);
} else if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.session), sizeof(jitter_stats_t));
memcpy(&call->stats[LINPHONE_CALL_STATS_AUDIO].jitter_stats, rtp_session_get_jitter_stats(call->audiostream->ms.sessions.rtp_session), sizeof(jitter_stats_t));
if(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp != NULL)
freemsg(call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp);
call->stats[LINPHONE_CALL_STATS_AUDIO].sent_rtcp = evd->packet;

View file

@ -1755,6 +1755,8 @@ void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc,bool_t rtp_no_
/**
* Sets the UDP port used for audio streaming.
* A value if -1 will request the system to allocate the local port randomly.
* This is recommended in order to avoid firewall warnings.
*
* @ingroup network_parameters
**/
@ -1775,6 +1777,8 @@ void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_
/**
* Sets the UDP port used for video streaming.
* A value if -1 will request the system to allocate the local port randomly.
* This is recommended in order to avoid firewall warnings.
*
* @ingroup network_parameters
**/
@ -2604,6 +2608,10 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c
int linphone_core_restart_invite(LinphoneCore *lc, LinphoneCall *call){
linphone_call_create_op(call);
linphone_call_stop_media_streams(call);
ms_media_stream_sessions_uninit(&call->sessions[0]);
ms_media_stream_sessions_uninit(&call->sessions[1]);
linphone_call_init_media_streams(call);
return linphone_core_start_invite(lc,call, NULL);
}
@ -2615,7 +2623,6 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, const Linph
linphone_call_set_contact_op(call);
linphone_core_stop_dtmf_stream(lc);
linphone_call_init_media_streams(call);
linphone_call_make_local_media_description(lc,call);
if (lc->ringstream==NULL) {
@ -2826,9 +2833,9 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
/* this call becomes now the current one*/
lc->current_call=call;
linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call");
linphone_call_init_media_streams(call);
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) {
/* Defer the start of the call after the ICE gathering process. */
linphone_call_init_media_streams(call);
linphone_call_start_media_streams_for_ice_gathering(call);
call->log->start_date_time=time(NULL);
if (linphone_core_gather_ice_candidates(lc,call)<0) {
@ -2841,7 +2848,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
}
else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
#ifdef BUILD_UPNP
linphone_call_init_media_streams(call);
call->log->start_date_time=time(NULL);
if (linphone_core_update_upnp(lc,call)<0) {
/* uPnP port mappings failed, proceed with the call anyway. */
@ -3280,6 +3286,7 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const
}
return _linphone_core_accept_call_update(lc, call, params);
}
int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
SalMediaDescription *remote_desc;
bool_t keep_sdp_version;
@ -3310,13 +3317,13 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons
call->params.has_video = FALSE;
}
call->params.has_video &= linphone_core_media_description_contains_video_stream(remote_desc);
linphone_call_init_media_streams(call); /*so that video stream is initialized if necessary*/
linphone_call_make_local_media_description(lc,call);
if (call->ice_session != NULL) {
linphone_core_update_ice_from_remote_media_description(call, remote_desc);
#ifdef VIDEO_ENABLED
if ((call->ice_session != NULL) &&!ice_session_candidates_gathered(call->ice_session)) {
if ((call->ice_session != NULL) && !ice_session_candidates_gathered(call->ice_session)) {
if ((call->params.has_video) && (call->params.has_video != old_has_video)) {
linphone_call_init_video_stream(call);
video_stream_prepare_video(call->videostream);
if (linphone_core_gather_ice_candidates(lc,call)<0) {
/* Ice candidates gathering failed, proceed with the call anyway. */
@ -3332,7 +3339,6 @@ int _linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, cons
linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(call->op));
#ifdef VIDEO_ENABLED
if ((call->params.has_video) && (call->params.has_video != old_has_video)) {
linphone_call_init_video_stream(call);
video_stream_prepare_video(call->videostream);
if (linphone_core_update_upnp(lc, call)<0) {
/* uPnP update failed, proceed with the call anyway. */
@ -3435,9 +3441,6 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
sal_op_set_sent_custom_header(call->op,params->custom_headers);
}
if (call->audiostream==NULL)
linphone_call_init_media_streams(call);
/*give a chance a set card prefered sampling frequency*/
if (call->localdesc->streams[0].max_rate>0) {
ms_message ("configuring prefered card sampling rate to [%i]",call->localdesc->streams[0].max_rate);
@ -3447,7 +3450,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
ms_snd_card_set_preferred_sample_rate(lc->sound_conf.capt_sndcard, call->localdesc->streams[0].max_rate);
}
if (!was_ringing && call->audiostream->ms.ticker==NULL){
if (!was_ringing && call->audiostream->ms.state==MSStreamInitialized){
audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
}
@ -5366,7 +5369,7 @@ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){
}
if (file!=NULL) {
lc->play_file=ms_strdup(file);
if (call && call->audiostream && call->audiostream->ms.ticker)
if (call && call->audiostream && call->audiostream->ms.state==MSStreamStarted)
audio_stream_play(call->audiostream,file);
}
}

View file

@ -375,6 +375,10 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
ms_warning("stun support is not implemented for ipv6");
return -1;
}
if (call->media_ports[0].rtp_port==-1){
ms_warning("Stun-only support not available for system random port");
return -1;
}
if (server!=NULL){
const struct addrinfo *ai=linphone_core_get_stun_server_addrinfo(lc);
ortp_socket_t sock1=-1, sock2=-1;
@ -394,10 +398,10 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
lc->vtable.display_status(lc,_("Stun lookup in progress..."));
/*create the two audio and video RTP sockets, and send STUN message to our stun server */
sock1=create_socket(call->audio_port);
sock1=create_socket(call->media_ports[0].rtp_port);
if (sock1==-1) return -1;
if (video_enabled){
sock2=create_socket(call->video_port);
sock2=create_socket(call->media_ports[1].rtp_port);
if (sock2==-1) return -1;
}
got_audio=FALSE;
@ -581,14 +585,14 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
return -1;
}
if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) {
ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtp_port, 1, NULL);
ice_add_local_candidate(audio_check_list, "host", local_addr, call->media_ports[0].rtcp_port, 2, NULL);
call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
}
if (call->params.has_video && (video_check_list != NULL)
if (linphone_core_video_enabled(lc) && (video_check_list != NULL)
&& (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) {
ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtp_port, 1, NULL);
ice_add_local_candidate(video_check_list, "host", local_addr, call->media_ports[1].rtcp_port, 2, NULL);
call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
}
@ -883,7 +887,12 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
}
}
for (i = ice_session_nb_check_lists(call->ice_session); i > md->n_active_streams; i--) {
ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
IceCheckList *removed=ice_session_check_list(call->ice_session, i - 1);
ice_session_remove_check_list(call->ice_session, removed);
if (call->audiostream && call->audiostream->ms.ice_check_list==removed)
call->audiostream->ms.ice_check_list=NULL;
if (call->videostream && call->videostream->ms.ice_check_list==removed)
call->videostream->ms.ice_check_list=NULL;
}
ice_session_check_mismatch(call->ice_session);
} else {

View file

@ -155,6 +155,11 @@ typedef struct StunCandidate{
}StunCandidate;
typedef struct _PortConfig{
int rtp_port;
int rtcp_port;
}PortConfig;
struct _LinphoneCall
{
int magic; /*used to distinguish from proxy config*/
@ -178,8 +183,8 @@ struct _LinphoneCall
LinphoneProxyConfig *dest_proxy;
int refcnt;
void * user_pointer;
int audio_port;
int video_port;
PortConfig media_ports[2];
MSMediaStreamSessions sessions[2]; /*the rtp, srtp, zrtp contexts for each stream*/
StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/
struct _AudioStream *audiostream; /**/
struct _VideoStream *videostream;

@ -1 +1 @@
Subproject commit 7111661bd810352ed7a4ecc9c30c7754d3006a92
Subproject commit da5d1de606699162f48751f006d9219321069545

2
oRTP

@ -1 +1 @@
Subproject commit 393857c0e8e5cab10a8d647cc89c8390355745a7
Subproject commit 5008a70e077b3706de4a48374f162f93071b4d08

View file

@ -519,7 +519,7 @@ static bool_t check_ice(LinphoneCoreManager* caller, LinphoneCoreManager* callee
return success;
}
static void call_with_ice(void) {
static void _call_with_ice(bool_t random_ports) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
@ -527,6 +527,13 @@ static void call_with_ice(void) {
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");
if (random_ports){
linphone_core_set_audio_port(marie->lc,-1);
linphone_core_set_video_port(marie->lc,-1);
linphone_core_set_audio_port(pauline->lc,-1);
linphone_core_set_video_port(pauline->lc,-1);
}
CU_ASSERT_TRUE(call(pauline,marie));
@ -536,8 +543,6 @@ static void call_with_ice(void) {
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2));
liblinphone_tester_check_rtcp(marie,pauline);
/*then close the call*/
linphone_core_terminate_all_calls(pauline->lc);
CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1));
@ -547,6 +552,14 @@ static void call_with_ice(void) {
linphone_core_manager_destroy(pauline);
}
static void call_with_ice(void){
_call_with_ice(FALSE);
}
static void call_with_ice_random_ports(void){
_call_with_ice(TRUE);
}
static void call_with_custom_headers(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
@ -718,6 +731,7 @@ static bool_t add_video(LinphoneCoreManager* caller,LinphoneCoreManager* callee)
return wait_for(caller->lc,callee->lc,&callee->stat.number_of_IframeDecoded,initial_callee_stat.number_of_IframeDecoded+1);
} else return 0;
}
static void call_with_video_added(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
@ -733,7 +747,26 @@ static void call_with_video_added(void) {
linphone_core_manager_destroy(pauline);
}
static void call_with_video_added_random_ports(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
linphone_core_set_audio_port(marie->lc,-1);
linphone_core_set_video_port(marie->lc,-1);
linphone_core_set_audio_port(pauline->lc,-1);
linphone_core_set_video_port(pauline->lc,-1);
CU_ASSERT_TRUE(call(pauline,marie));
CU_ASSERT_TRUE(add_video(pauline,marie));
/*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_with_declined_video(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
@ -808,19 +841,26 @@ static void video_call(void) {
}
#endif /*VIDEO_ENABLED*/
static void call_with_media_relay(void) {
static void _call_with_media_relay(bool_t random_ports) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
linphone_core_set_user_agent(marie->lc,"Natted Linphone",NULL);
linphone_core_set_user_agent(pauline->lc,"Natted Linphone",NULL);
if (random_ports){
linphone_core_set_audio_port(marie->lc,-1);
linphone_core_set_video_port(marie->lc,-1);
linphone_core_set_audio_port(pauline->lc,-1);
linphone_core_set_video_port(pauline->lc,-1);
}
CU_ASSERT_TRUE(call(pauline,marie));
liblinphone_tester_check_rtcp(pauline,marie);
#ifdef VIDEO_ENABLED
CU_ASSERT_TRUE(add_video(pauline,marie));
liblinphone_tester_check_rtcp(pauline,marie);
#endif
/*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));
@ -828,7 +868,14 @@ static void call_with_media_relay(void) {
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
}
static void call_with_media_relay(void) {
_call_with_media_relay(FALSE);
}
static void call_with_media_relay_random_ports(void) {
_call_with_media_relay(TRUE);
}
static void call_with_privacy(void) {
@ -1839,6 +1886,7 @@ test_t call_tests[] = {
{ "Call failed because of codecs", call_failed_because_of_codecs },
{ "Simple call", simple_call },
{ "Call with media relay", call_with_media_relay},
{ "Call with media relay (random ports)", call_with_media_relay_random_ports},
{ "Simple call compatibility mode", simple_call_compatibility_mode },
{ "Early-media call", early_media_call },
{ "Early-media call with ringing", early_media_call_with_ringing },
@ -1855,6 +1903,7 @@ test_t call_tests[] = {
{ "Simple video call",video_call},
{ "SRTP ice video call", srtp_video_ice_call },
{ "Call with video added", call_with_video_added },
{ "Call with video added (random ports)", call_with_video_added_random_ports },
{ "Call with video declined",call_with_declined_video},
#else
{ "SRTP ice call", srtp_ice_call },
@ -1872,6 +1921,7 @@ test_t call_tests[] = {
{ "Unattended call transfer with error", unattended_call_transfer_with_error },
{ "Call transfer existing call outgoing call", call_transfer_existing_call_outgoing_call },
{ "Call with ICE", call_with_ice },
{ "Call with ICE (random ports)", call_with_ice_random_ports },
{ "Call with custom headers",call_with_custom_headers},
{ "Call established with rejected INFO",call_established_with_rejected_info},
{ "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite},

View file

@ -73,8 +73,8 @@ static void linphone_stun_test_grab_ip()
int tmp=0;
memset(&dummy_call, 0, sizeof(LinphoneCall));
dummy_call.audio_port = 7078;
dummy_call.audio_port = 9078;
dummy_call.media_ports[0].rtp_port = 7078;
dummy_call.media_ports[1].rtp_port = 9078;
linphone_core_set_stun_server(lc_stun->lc, stun_address);
CU_ASSERT_STRING_EQUAL(stun_address, linphone_core_get_stun_server(lc_stun->lc));