diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index cb88095c7..efd17aab6 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -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*/ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index e4cac3a33..c5f3ef3f2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -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(¤tconfig, 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, ¤tconfig); 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; diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 8fccd7561..6c609d037 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -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); } } diff --git a/coreapi/misc.c b/coreapi/misc.c index 4c9834053..37198490e 100644 --- a/coreapi/misc.c +++ b/coreapi/misc.c @@ -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 { diff --git a/coreapi/private.h b/coreapi/private.h index 6f421e95e..9fa89dd3a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -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; diff --git a/mediastreamer2 b/mediastreamer2 index 7111661bd..da5d1de60 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 7111661bd810352ed7a4ecc9c30c7754d3006a92 +Subproject commit da5d1de606699162f48751f006d9219321069545 diff --git a/oRTP b/oRTP index 393857c0e..5008a70e0 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit 393857c0e8e5cab10a8d647cc89c8390355745a7 +Subproject commit 5008a70e077b3706de4a48374f162f93071b4d08 diff --git a/tester/call_tester.c b/tester/call_tester.c index 419def8cc..be60fd8af 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -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}, diff --git a/tester/stun_tester.c b/tester/stun_tester.c index e416fa02c..d19650f06 100644 --- a/tester/stun_tester.c +++ b/tester/stun_tester.c @@ -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));