]> sjero.net Git - linphone/blobdiff - coreapi/misc.c
add special case to compute aac network birate
[linphone] / coreapi / misc.c
index df65b53f47268bd2063ced4e221ae5a11ccdd27b..5d4c0ebcc2d365915ece80841e5ac2c1f1e7b858 100644 (file)
@@ -43,7 +43,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <net/if.h>
 #include <ifaddrs.h>
 #endif
-
+#include <math.h>
 
 #if !defined(WIN32)
 
@@ -234,17 +234,26 @@ static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
        return pt->normal_bitrate;
 }
 
+/*
+ *((codec-birate*ptime/8) + RTP header + UDP header + IP header)*8/ptime;
+ *ptime=1/npacket
+ */
 static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
        double npacket=50;
        double packet_size;
        int bitrate;
+       if (strcmp(payload_type_get_mime(&payload_type_aaceld_44k), payload_type_get_mime(pt))==0) {
+               /*special case of aac 44K because ptime= 10ms*/
+               npacket=100;
+       }
+               
        bitrate=get_codec_bitrate(lc,pt);
-       packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
+       packet_size= (((double)bitrate)/(npacket*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
        return packet_size*8.0*npacket;
 }
 
 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt){
-       call->audio_bw=(int)(get_audio_payload_bandwidth(call->core,pt)/1000.0);
+       call->audio_bw=(int)(ceil(get_audio_payload_bandwidth(call->core,pt)/1000.0)); /*rounding codec bandwidth should be avoid, specially for AMR*/
        ms_message("Audio bandwidth for this call is %i",call->audio_bw);
 }
 
@@ -574,21 +583,31 @@ int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
        return -1;
 }
 
+int linphone_core_get_edge_bw(LinphoneCore *lc){
+       int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20);
+       return edge_bw;
+}
+
+int linphone_core_get_edge_ptime(LinphoneCore *lc){
+       int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100);
+       return edge_ptime;
+}
+
 void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params){
-       if (lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){
+       if (ping_time_ms>0 && lp_config_get_int(lc->config,"net","activate_edge_workarounds",0)==1){
                ms_message("Stun server ping time is %i ms",ping_time_ms);
                int threshold=lp_config_get_int(lc->config,"net","edge_ping_time",500);
                
                if (ping_time_ms>threshold){
-                       int edge_ptime=lp_config_get_int(lc->config,"net","edge_ptime",100);
-                       int edge_bw=lp_config_get_int(lc->config,"net","edge_bw",20);
-                       /* we are in a 2G network*/
-                       params->up_bw=params->down_bw=edge_bw;
-                       params->up_ptime=params->down_ptime=edge_ptime;
-                       params->has_video=FALSE;
-                       
+                       /* we might be in a 2G network*/
+                       params->low_bandwidth=TRUE;
                }/*else use default settings */
        }
+       if (params->low_bandwidth){
+               params->up_bw=params->down_bw=linphone_core_get_edge_bw(lc);
+               params->up_ptime=params->down_ptime=linphone_core_get_edge_ptime(lc);
+               params->has_video=FALSE;
+       }
 }
 
 
@@ -620,14 +639,17 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
                lc->vtable.display_status(lc, _("ICE local candidates gathering in progress..."));
 
        /* Gather local host candidates. */
-       if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
+       if (linphone_core_get_local_ip_for(AF_INET, server, local_addr) < 0) {
                ms_error("Fail to get local ip");
                return -1;
        }
-       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);
-       call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
-       if (call->params.has_video && (video_check_list != NULL)) {
+       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);
+               call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
+       }
+       if (call->params.has_video && (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);
                call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
@@ -652,31 +674,44 @@ void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
 
        session_state = ice_session_state(call->ice_session);
        if ((session_state == IS_Completed) || ((session_state == IS_Failed) && (ice_session_has_completed_check_list(call->ice_session) == TRUE))) {
-               switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) {
-                       case ICT_HostCandidate:
-                               call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateHostConnection;
-                               break;
-                       case ICT_ServerReflexiveCandidate:
-                       case ICT_PeerReflexiveCandidate:
-                               call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateReflexiveConnection;
-                               break;
-                       case ICT_RelayedCandidate:
-                               call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection;
-                               break;
-               }
-               if (call->params.has_video && (video_check_list != NULL)) {
-                       switch (ice_check_list_selected_valid_candidate_type(video_check_list)) {
+               if (ice_check_list_state(audio_check_list) == ICL_Completed) {
+                       switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) {
                                case ICT_HostCandidate:
-                                       call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateHostConnection;
+                                       call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateHostConnection;
                                        break;
                                case ICT_ServerReflexiveCandidate:
                                case ICT_PeerReflexiveCandidate:
-                                       call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateReflexiveConnection;
+                                       call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateReflexiveConnection;
                                        break;
                                case ICT_RelayedCandidate:
-                                       call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection;
+                                       call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection;
                                        break;
                        }
+               } else {
+                       call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed;
+               }
+               if (call->params.has_video && (video_check_list != NULL)) {
+                       if (ice_check_list_state(video_check_list) == ICL_Completed) {
+                               switch (ice_check_list_selected_valid_candidate_type(video_check_list)) {
+                                       case ICT_HostCandidate:
+                                               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateHostConnection;
+                                               break;
+                                       case ICT_ServerReflexiveCandidate:
+                                       case ICT_PeerReflexiveCandidate:
+                                               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateReflexiveConnection;
+                                               break;
+                                       case ICT_RelayedCandidate:
+                                               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection;
+                                               break;
+                               }
+                       } else {
+                               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed;
+                       }
+               }
+       } else if (session_state == IS_Running) {
+               call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
+               if (call->params.has_video && (video_check_list != NULL)) {
+                       call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
                }
        } else {
                call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed;
@@ -708,7 +743,7 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription *
        }
        strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
        strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
-       for (i = 0; i < desc->nstreams; i++) {
+       for (i = 0; i < desc->n_active_streams; i++) {
                SalStreamDescription *stream = &desc->streams[i];
                IceCheckList *cl = ice_session_check_list(session, i);
                nb_candidates = 0;
@@ -771,11 +806,19 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription *
                if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
                        int rtp_port, rtcp_port;
                        memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
-                       ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
-                       strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
-                       stream->ice_remote_candidates[0].port = rtp_port;
-                       strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
-                       stream->ice_remote_candidates[1].port = rtcp_port;
+                       if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port) == TRUE) {
+                               strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
+                               stream->ice_remote_candidates[0].port = rtp_port;
+                               strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
+                               stream->ice_remote_candidates[1].port = rtcp_port;
+                       } else {
+                               ms_error("ice: Selected valid remote candidates should be present if the check list is in the Completed state");
+                       }
+               } else {
+                       for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
+                               stream->ice_remote_candidates[j].addr[0] = '\0';
+                               stream->ice_remote_candidates[j].port = 0;
+                       }
                }
        }
 }
@@ -804,7 +847,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
                        ice_session_restart(call->ice_session);
                        ice_restarted = TRUE;
                } else {
-                       for (i = 0; i < md->nstreams; i++) {
+                       for (i = 0; i < md->n_total_streams; i++) {
                                const SalStreamDescription *stream = &md->streams[i];
                                IceCheckList *cl = ice_session_check_list(call->ice_session, i);
                                if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) {
@@ -823,7 +866,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
                        }
                        ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
                }
-               for (i = 0; i < md->nstreams; i++) {
+               for (i = 0; i < md->n_total_streams; i++) {
                        const SalStreamDescription *stream = &md->streams[i];
                        IceCheckList *cl = ice_session_check_list(call->ice_session, i);
                        if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
@@ -839,25 +882,27 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
                }
 
                /* Create ICE check lists if needed and parse ICE attributes. */
-               for (i = 0; i < md->nstreams; i++) {
+               for (i = 0; i < md->n_total_streams; i++) {
                        const SalStreamDescription *stream = &md->streams[i];
                        IceCheckList *cl = ice_session_check_list(call->ice_session, i);
-                       if (cl == NULL) {
+                       if ((cl == NULL) && (i < md->n_active_streams)) {
                                cl = ice_check_list_new();
                                ice_session_add_check_list(call->ice_session, cl);
                                switch (stream->type) {
                                        case SalAudio:
-                                               if (call->audiostream != NULL) call->audiostream->ice_check_list = cl;
+                                               if (call->audiostream != NULL) call->audiostream->ms.ice_check_list = cl;
                                                break;
                                        case SalVideo:
-                                               if (call->videostream != NULL) call->videostream->ice_check_list = cl;
+                                               if (call->videostream != NULL) call->videostream->ms.ice_check_list = cl;
                                                break;
                                        default:
                                                break;
                                }
                        }
-                       if ((stream->ice_mismatch == TRUE) || (stream->rtp_port == 0)) {
+                       if (stream->ice_mismatch == TRUE) {
                                ice_check_list_set_state(cl, ICL_Failed);
+                       } else if (stream->rtp_port == 0) {
+                               ice_session_remove_check_list(call->ice_session, cl);
                        } else {
                                if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
                                        ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
@@ -883,6 +928,10 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
                                                int componentID = j + 1;
                                                if (candidate->addr[0] == '\0') break;
                                                get_default_addr_and_port(componentID, md, stream, &addr, &port);
+                                               if (j == 0) {
+                                                       /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */
+                                                       ice_check_list_unselect_valid_pairs(cl);
+                                               }
                                                ice_add_losing_pair(cl, j + 1, candidate->addr, candidate->port, addr, port);
                                                losing_pairs_added = TRUE;
                                        }
@@ -890,7 +939,7 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
                                }
                        }
                }
-               for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) {
+               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));
                }
                ice_session_check_mismatch(call->ice_session);
@@ -904,15 +953,15 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
        }
 }
 
-void linphone_core_deactivate_ice_for_deactivated_media_streams(LinphoneCall *call, const SalMediaDescription *md)
+bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md)
 {
        int i;
-       for (i = 0; i < md->nstreams; i++) {
-               IceCheckList *cl = ice_session_check_list(call->ice_session, i);
-               if (cl && (md->streams[i].rtp_port == 0)) {
-                       if (ice_check_list_state(cl) != ICL_Completed) ice_check_list_set_state(cl, ICL_Failed);
-               }
+
+       for (i = 0; i < md->n_active_streams; i++) {
+               if (md->streams[i].type == SalVideo)
+                       return TRUE;
        }
+       return FALSE;
 }
 
 LinphoneCall * is_a_linphone_call(void *user_pointer){
@@ -948,6 +997,7 @@ unsigned int linphone_core_get_audio_features(LinphoneCore *lc){
                        else if (strcasecmp(name,"VOL_RCV")==0) ret|=AUDIO_STREAM_FEATURE_VOL_RCV;
                        else if (strcasecmp(name,"DTMF")==0) ret|=AUDIO_STREAM_FEATURE_DTMF;
                        else if (strcasecmp(name,"DTMF_ECHO")==0) ret|=AUDIO_STREAM_FEATURE_DTMF_ECHO;
+                       else if (strcasecmp(name,"MIXED_RECORDING")==0) ret|=AUDIO_STREAM_FEATURE_MIXED_RECORDING;
                        else if (strcasecmp(name,"ALL")==0) ret|=AUDIO_STREAM_FEATURE_ALL;
                        else if (strcasecmp(name,"NONE")==0) ret=0;
                        else ms_error("Unsupported audio feature %s requested in config file.",name);
@@ -955,9 +1005,18 @@ unsigned int linphone_core_get_audio_features(LinphoneCore *lc){
                        p=n;
                }
        }else ret=AUDIO_STREAM_FEATURE_ALL;
+       
+       if (ret==AUDIO_STREAM_FEATURE_ALL){
+               /*since call recording is specified before creation of the stream in linphonecore,
+               * it will be requested on demand. It is not necessary to include it all the time*/
+               ret&=~AUDIO_STREAM_FEATURE_MIXED_RECORDING;
+       }
        return ret;
 }
 
+bool_t linphone_core_tone_indications_enabled(LinphoneCore*lc){
+       return lp_config_get_int(lc->config,"sound","tone_indications",1);
+}
 
 #ifdef HAVE_GETIFADDRS
 
@@ -981,14 +1040,15 @@ static int get_local_ip_with_getifaddrs(int type, char *address, int size)
                if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
                        && (ifp->ifa_flags & UP_FLAG) && !(ifp->ifa_flags & IFF_LOOPBACK))
                {
-                       getnameinfo(ifp->ifa_addr,
+                       if(getnameinfo(ifp->ifa_addr,
                                                (type == AF_INET6) ?
                                                sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
-                                               address, size, NULL, 0, NI_NUMERICHOST);
-                       if (strchr(address, '%') == NULL) {     /*avoid ipv6 link-local addresses */
-                               /*ms_message("getifaddrs() found %s",address);*/
-                               ret++;
-                               break;
+                                               address, size, NULL, 0, NI_NUMERICHOST) == 0) {
+                               if (strchr(address, '%') == NULL) {     /*avoid ipv6 link-local addresses */
+                                       /*ms_message("getifaddrs() found %s",address);*/
+                                       ret++;
+                                       break;
+                               }
                        }
                }
        }
@@ -1059,26 +1119,26 @@ static int get_local_ip_for_with_connect(int type, const char *dest, char *resul
 }
 
 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
-       strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
+        strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
 #ifdef HAVE_GETIFADDRS
-       if (dest==NULL) {
-               /*we use getifaddrs for lookup of default interface */
-               int found_ifs;
-       
-               found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
-               if (found_ifs==1){
-                       return 0;
-               }else if (found_ifs<=0){
-                       /*absolutely no network on this machine */
-                       return -1;
-               }
-       }
+        if (dest==NULL) {
+                /*we use getifaddrs for lookup of default interface */
+                int found_ifs;
+
+                found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
+                if (found_ifs==1){
+                        return 0;
+                }else if (found_ifs<=0){
+                        /*absolutely no network on this machine */
+                        return -1;
+                }
+        }
 #endif
-       /*else use connect to find the best local ip address */
-       if (type==AF_INET)
-               dest="87.98.157.38"; /*a public IP address*/
-       else dest="2a00:1450:8002::68";
-       return get_local_ip_for_with_connect(type,dest,result);
+        /*else use connect to find the best local ip address */
+        if (type==AF_INET)
+                dest="87.98.157.38"; /*a public IP address*/
+        else dest="2a00:1450:8002::68";
+        return get_local_ip_for_with_connect(type,dest,result);
 }
 
 #ifndef WIN32