4 Copyright (C) 2000 Simon MORLAT (simon.morlat@linphone.org)
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include "mediastreamer2/mediastream.h"
26 #ifdef HAVE_SIGHANDLER_T
28 #endif /*HAVE_SIGHANDLER_T*/
31 #if !defined(_WIN32_WCE)
33 #include <sys/types.h>
40 #include <ortp/stun.h>
42 #ifdef HAVE_GETIFADDRS
50 static char lock_name[80];
51 static char lock_set=0;
52 /* put a lock file in /tmp. this is called when linphone runs as a daemon*/
57 snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
58 lockfile=fopen(lock_name,"w");
61 printf("Failed to create lock file.\n");
64 fprintf(lockfile,"%i",getpid());
70 /* looks if there is a lock file. If presents return its content (the pid of the already running linphone), if not found, returns -1*/
76 snprintf(lock_name,80,"/tmp/linphone.%i",getuid());
77 lockfile=fopen(lock_name,"r");
80 if (fscanf(lockfile,"%i",&pid)!=1){
81 ms_warning("Could not read pid in lock file.");
89 /* remove the lock file if it was set*/
90 int remove_lock_file()
95 err=unlink(lock_name);
103 char *int2str(int number)
105 char *numstr=ms_malloc(10);
106 snprintf(numstr,10,"%i",number);
110 void check_sound_device(LinphoneCore *lc)
117 char *i810_audio=NULL;
118 char *snd_pcm_oss=NULL;
119 char *snd_mixer_oss=NULL;
121 fd=open("/proc/modules",O_RDONLY);
124 /* read the entire /proc/modules file and check if sound conf seems correct */
125 /*a=fstat(fd,&statbuf);
126 if (a<0) ms_warning("Can't stat /proc/modules:%s.",strerror(errno));
128 if (len==0) ms_warning("/proc/modules has zero size!");
130 /***** fstat does not work on /proc/modules for unknown reason *****/
132 file=ms_malloc(len+1);
134 if (a<len) file=ms_realloc(file,a+1);
136 i810_audio=strstr(file,"i810_audio");
137 if (i810_audio!=NULL){
138 /* I'm sorry i put this warning in comments because
139 * i don't use yet the right driver !! */
140 /* lc->vtable.display_warning(lc,_("You are currently using the i810_audio driver.\nThis driver is buggy and so does not work with Linphone.\nWe suggest that you replace it by its equivalent ALSA driver,\neither with packages from your distribution, or by downloading\nALSA drivers at http://www.alsa-project.org."));*/
143 snd_pcm=strstr(file,"snd-pcm");
145 snd_pcm_oss=strstr(file,"snd-pcm-oss");
146 snd_mixer_oss=strstr(file,"snd-mixer-oss");
147 if (snd_pcm_oss==NULL){
148 lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the pcm oss emulation module\nis missing and linphone needs it. Please execute\n'modprobe snd-pcm-oss' as root to load it."));
150 if (snd_mixer_oss==NULL){
151 lc->vtable.display_warning(lc,_("Your computer appears to be using ALSA sound drivers.\nThis is the best choice. However the mixer oss emulation module\nis missing and linphone needs it. Please execute\n 'modprobe snd-mixer-oss' as root to load it."));
156 ms_warning("Could not open /proc/modules.");
158 /* now check general volume. Some user forget to rise it and then complain that linphone is
160 /* but some other users complain that linphone should not change levels...
161 if (lc->sound_conf.sndcard!=NULL){
162 a=snd_card_get_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL);
164 ms_warning("General level is quite low (%i). Linphone rises it up for you.",a);
165 snd_card_set_level(lc->sound_conf.sndcard,SND_CARD_LEVEL_GENERAL,80);
170 if (file!=NULL) ms_free(file);
176 #define RTP_HDR_SZ 12
177 #define IP4_HDR_SZ 20 /*20 is the minimum, but there may be some options*/
179 static void payload_type_set_enable(PayloadType *pt,int value)
181 if ((value)!=0) payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED); \
182 else payload_type_unset_flag(pt,PAYLOAD_TYPE_ENABLED);
185 static bool_t payload_type_enabled(const PayloadType *pt) {
186 return (((pt)->flags & PAYLOAD_TYPE_ENABLED)!=0);
189 bool_t linphone_core_payload_type_enabled(LinphoneCore *lc, const PayloadType *pt){
190 if (ms_list_find(lc->codecs_conf.audio_codecs, (PayloadType*) pt) || ms_list_find(lc->codecs_conf.video_codecs, (PayloadType*)pt)){
191 return payload_type_enabled(pt);
193 ms_error("Getting enablement status of codec not in audio or video list of PayloadType !");
197 int linphone_core_enable_payload_type(LinphoneCore *lc, PayloadType *pt, bool_t enabled){
198 if (ms_list_find(lc->codecs_conf.audio_codecs,pt) || ms_list_find(lc->codecs_conf.video_codecs,pt)){
199 payload_type_set_enable(pt,enabled);
200 _linphone_core_codec_config_write(lc);
203 ms_error("Enabling codec not in audio or video list of PayloadType !");
207 int linphone_core_get_payload_type_number(LinphoneCore *lc, const PayloadType *pt){
208 return payload_type_get_number(pt);
211 const char *linphone_core_get_payload_type_description(LinphoneCore *lc, PayloadType *pt){
212 if (ms_filter_codec_supported(pt->mime_type)){
213 MSFilterDesc *desc=ms_filter_get_encoder(pt->mime_type);
215 return dgettext("mediastreamer",desc->text);
224 /*this function makes a special case for speex/8000.
225 This codec is variable bitrate. The 8kbit/s mode is interesting when having a low upload bandwidth, but its quality
226 is not very good. We 'd better use its 15kbt/s mode when we have enough bandwidth*/
227 static int get_codec_bitrate(LinphoneCore *lc, const PayloadType *pt){
228 int upload_bw=linphone_core_get_upload_bandwidth(lc);
229 if (bandwidth_is_greater(upload_bw,129) || (bandwidth_is_greater(upload_bw,33) && !linphone_core_video_enabled(lc)) ) {
230 if (strcmp(pt->mime_type,"speex")==0 && pt->clock_rate==8000){
234 return pt->normal_bitrate;
237 static double get_audio_payload_bandwidth(LinphoneCore *lc, const PayloadType *pt){
241 bitrate=get_codec_bitrate(lc,pt);
242 packet_size= (((double)bitrate)/(50*8))+UDP_HDR_SZ+RTP_HDR_SZ+IP4_HDR_SZ;
243 return packet_size*8.0*npacket;
246 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt){
247 call->audio_bw=(int)(get_audio_payload_bandwidth(call->core,pt)/1000.0);
248 ms_message("Audio bandwidth for this call is %i",call->audio_bw);
251 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc){
253 PayloadType *max=NULL;
254 for(elem=linphone_core_get_audio_codecs(lc);elem!=NULL;elem=elem->next){
255 PayloadType *pt=(PayloadType*)elem->data;
256 if (payload_type_enabled(pt)){
257 int pt_bitrate=get_codec_bitrate(lc,pt);
258 if (max==NULL) max=pt;
259 else if (max->normal_bitrate<pt_bitrate){
265 lc->audio_bw=(int)(get_audio_payload_bandwidth(lc,max)/1000.0);
269 bool_t linphone_core_is_payload_type_usable_for_bandwidth(LinphoneCore *lc, PayloadType *pt, int bandwidth_limit)
275 case PAYLOAD_AUDIO_CONTINUOUS:
276 case PAYLOAD_AUDIO_PACKETIZED:
277 codec_band=get_audio_payload_bandwidth(lc,pt);
278 ret=bandwidth_is_greater(bandwidth_limit*1000,codec_band);
279 /*hack to avoid using uwb codecs when having low bitrate and video*/
280 if (bandwidth_is_greater(199,bandwidth_limit)){
281 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
285 //ms_message("Payload %s: %g",pt->mime_type,codec_band);
288 if (bandwidth_limit!=0) {/* infinite (-1) or strictly positive*/
297 /* return TRUE if codec can be used with bandwidth, FALSE else*/
298 bool_t linphone_core_check_payload_type_usability(LinphoneCore *lc, PayloadType *pt)
301 int allowed_bw,video_bw;
304 linphone_core_update_allocated_audio_bandwidth(lc);
305 allowed_bw=get_min_bandwidth(linphone_core_get_download_bandwidth(lc),
306 linphone_core_get_upload_bandwidth(lc));
309 video_bw=1500; /*around 1.5 Mbit/s*/
311 video_bw=get_video_bandwidth(allowed_bw,lc->audio_bw);
314 case PAYLOAD_AUDIO_CONTINUOUS:
315 case PAYLOAD_AUDIO_PACKETIZED:
316 codec_band=get_audio_payload_bandwidth(lc,pt);
317 ret=bandwidth_is_greater(allowed_bw*1000,codec_band);
318 /*hack to avoid using uwb codecs when having low bitrate and video*/
319 if (bandwidth_is_greater(199,allowed_bw)){
320 if (linphone_core_video_enabled(lc) && pt->clock_rate>16000){
324 //ms_message("Payload %s: %g",pt->mime_type,codec_band);
328 pt->normal_bitrate=video_bw*1000;
337 bool_t lp_spawn_command_line_sync(const char *command, char **result,int *command_ret){
338 #if !defined(_WIN32_WCE)
339 FILE *f=popen(command,"r");
342 *result=ms_malloc(4096);
343 err=fread(*result,1,4096-1,f);
345 ms_warning("Error reading command output:%s",strerror(errno));
351 if (command_ret!=NULL) *command_ret=err;
354 #endif /*_WIN32_WCE*/
358 static ortp_socket_t create_socket(int local_port){
359 struct sockaddr_in laddr;
362 sock=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
364 ms_error("Fail to create socket");
367 memset (&laddr,0,sizeof(laddr));
368 laddr.sin_family=AF_INET;
369 laddr.sin_addr.s_addr=INADDR_ANY;
370 laddr.sin_port=htons(local_port);
371 if (bind(sock,(struct sockaddr*)&laddr,sizeof(laddr))<0){
372 ms_error("Bind socket to 0.0.0.0:%i failed: %s",local_port,getSocketError());
377 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
378 (SOCKET_OPTION_VALUE)&optval, sizeof (optval))<0){
379 ms_warning("Fail to set SO_REUSEADDR");
381 set_non_blocking_socket(sock);
385 static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){
386 char buf[STUN_MAX_MESSAGE_SIZE];
387 int len = STUN_MAX_MESSAGE_SIZE;
388 StunAtrString username;
389 StunAtrString password;
392 memset(&req, 0, sizeof(StunMessage));
393 memset(&username,0,sizeof(username));
394 memset(&password,0,sizeof(password));
395 stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id);
396 len = stunEncodeMessage( &req, buf, len, &password);
398 ms_error("Fail to encode stun message.");
401 err=sendto(sock,buf,len,0,server,addrlen);
403 ms_error("sendto failed: %s",strerror(errno));
409 int parse_hostname_to_addr(const char *server, struct sockaddr_storage *ss, socklen_t *socklen){
410 struct addrinfo hints,*res=NULL;
413 char host[NI_MAXHOST];
415 host[NI_MAXHOST-1]='\0';
416 strncpy(host,server,sizeof(host)-1);
422 memset(&hints,0,sizeof(hints));
423 hints.ai_family=PF_INET;
424 hints.ai_socktype=SOCK_DGRAM;
425 hints.ai_protocol=IPPROTO_UDP;
426 ret=getaddrinfo(host,port,&hints,&res);
428 ms_error("getaddrinfo() failed for %s:%s : %s",host,port,gai_strerror(ret));
432 memcpy(ss,res->ai_addr,res->ai_addrlen);
433 *socklen=res->ai_addrlen;
438 static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id){
439 char buf[STUN_MAX_MESSAGE_SIZE];
440 int len = STUN_MAX_MESSAGE_SIZE;
442 len=recv(sock,buf,len,0);
445 stunParseMessage(buf,len, &resp );
446 *id=resp.msgHdr.tr_id.octet[0];
447 if (resp.hasXorMappedAddress){
448 *port = resp.xorMappedAddress.ipv4.port;
449 ia.s_addr=htonl(resp.xorMappedAddress.ipv4.addr);
450 }else if (resp.hasMappedAddress){
451 *port = resp.mappedAddress.ipv4.port;
452 ia.s_addr=htonl(resp.mappedAddress.ipv4.addr);
454 strncpy(ipaddr,inet_ntoa(ia),LINPHONE_IPADDR_SIZE);
459 void linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
460 const char *server=linphone_core_get_stun_server(lc);
462 if (lc->sip_conf.ipv6_enabled){
463 ms_warning("stun support is not implemented for ipv6");
467 struct sockaddr_storage ss;
469 ortp_socket_t sock1=-1, sock2=-1;
471 bool_t video_enabled=linphone_core_video_enabled(lc);
472 bool_t got_audio,got_video;
473 bool_t cone_audio=FALSE,cone_video=FALSE;
474 struct timeval init,cur;
475 SalEndpointCandidate *ac,*vc;
477 ac=&call->localdesc->streams[0].candidates[0];
478 vc=&call->localdesc->streams[1].candidates[0];
480 if (parse_hostname_to_addr(server,&ss,&ss_len)<0){
481 ms_error("Fail to parser stun server address: %s",server);
484 if (lc->vtable.display_status!=NULL)
485 lc->vtable.display_status(lc,_("Stun lookup in progress..."));
487 /*create the two audio and video RTP sockets, and send STUN message to our stun server */
488 sock1=create_socket(call->audio_port);
489 if (sock1==-1) return;
491 sock2=create_socket(call->video_port);
492 if (sock2==-1) return ;
496 gettimeofday(&init,NULL);
501 ms_message("Sending stun requests...");
502 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,11,TRUE);
503 sendStunRequest(sock1,(struct sockaddr*)&ss,ss_len,1,FALSE);
505 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,22,TRUE);
506 sendStunRequest(sock2,(struct sockaddr*)&ss,ss_len,2,FALSE);
515 if (recvStunResponse(sock1,ac->addr,
517 ms_message("STUN test result: local audio port maps to %s:%i",
524 if (recvStunResponse(sock2,vc->addr,
526 ms_message("STUN test result: local video port maps to %s:%i",
533 gettimeofday(&cur,NULL);
534 elapsed=((cur.tv_sec-init.tv_sec)*1000.0) + ((cur.tv_usec-init.tv_usec)/1000.0);
536 ms_message("Stun responses timeout, going ahead.");
540 }while(!(got_audio && (got_video||sock2==-1) ) );
542 ms_error("No stun server response for audio port.");
545 ms_message("NAT is symmetric for audio port");
550 ms_error("No stun server response for video port.");
553 ms_message("NAT is symmetric for video port.");
557 if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0)
559 strcpy(call->localdesc->addr,ac->addr);
562 if (sock2!=-1) close_socket(sock2);
566 int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
569 struct sockaddr_storage ss;
571 IceCheckList *audio_check_list;
572 IceCheckList *video_check_list;
573 const char *server = linphone_core_get_stun_server(lc);
575 if ((server == NULL) || (call->ice_session == NULL)) return -1;
576 audio_check_list = ice_session_check_list(call->ice_session, 0);
577 video_check_list = ice_session_check_list(call->ice_session, 1);
578 if (audio_check_list == NULL) return -1;
580 if (lc->sip_conf.ipv6_enabled){
581 ms_warning("stun support is not implemented for ipv6");
585 if (parse_hostname_to_addr(server, &ss, &ss_len) < 0) {
586 ms_error("Fail to parser stun server address: %s", server);
589 if (lc->vtable.display_status != NULL)
590 lc->vtable.display_status(lc, _("ICE local candidates gathering in progress..."));
592 /* Gather local host candidates. */
593 if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
594 ms_error("Fail to get local ip");
597 ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
598 ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
599 if (call->params.has_video && (video_check_list != NULL)) {
600 ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
601 ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
604 /* Gather local srflx candidates. */
605 ice_session_gather_candidates(call->ice_session, ss, ss_len);
609 void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
611 const char *rtp_addr, *rtcp_addr;
612 IceSessionState session_state = ice_session_state(session);
616 if (session_state == IS_Completed) {
617 desc->ice_completed = TRUE;
618 ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL);
619 strncpy(desc->addr, rtp_addr, sizeof(desc->addr));
622 desc->ice_completed = FALSE;
624 strncpy(desc->ice_pwd, ice_session_local_pwd(session), sizeof(desc->ice_pwd));
625 strncpy(desc->ice_ufrag, ice_session_local_ufrag(session), sizeof(desc->ice_ufrag));
626 for (i = 0; i < desc->nstreams; i++) {
627 SalStreamDescription *stream = &desc->streams[i];
628 IceCheckList *cl = ice_session_check_list(session, i);
630 if (cl == NULL) continue;
631 if (cl->state == ICL_Completed) {
632 stream->ice_completed = TRUE;
633 ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, i), &rtp_addr, &stream->rtp_port, &rtcp_addr, &stream->rtcp_port);
634 strncpy(stream->rtp_addr, rtp_addr, sizeof(stream->rtp_addr));
635 strncpy(stream->rtcp_addr, rtcp_addr, sizeof(stream->rtcp_addr));
637 stream->ice_completed = FALSE;
639 if ((strlen(ice_check_list_local_pwd(cl)) != strlen(desc->ice_pwd)) || (strcmp(ice_check_list_local_pwd(cl), desc->ice_pwd)))
640 strncpy(stream->ice_pwd, ice_check_list_local_pwd(cl), sizeof(stream->ice_pwd));
642 memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
643 if ((strlen(ice_check_list_local_ufrag(cl)) != strlen(desc->ice_ufrag)) || (strcmp(ice_check_list_local_ufrag(cl), desc->ice_ufrag)))
644 strncpy(stream->ice_ufrag, ice_check_list_local_ufrag(cl), sizeof(stream->ice_ufrag));
646 memset(stream->ice_pwd, 0, sizeof(stream->ice_pwd));
647 stream->ice_mismatch = ice_check_list_is_mismatch(cl);
648 if ((cl->state == ICL_Running) || (cl->state == ICL_Completed)) {
649 memset(stream->ice_candidates, 0, sizeof(stream->ice_candidates));
650 for (j = 0; j < MIN(ms_list_size(cl->local_candidates), SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES); j++) {
651 SalIceCandidate *sal_candidate = &stream->ice_candidates[nb_candidates];
652 IceCandidate *ice_candidate = ms_list_nth_data(cl->local_candidates, j);
653 const char *default_addr = NULL;
654 int default_port = 0;
655 if (ice_candidate->componentID == 1) {
656 default_addr = stream->rtp_addr;
657 default_port = stream->rtp_port;
658 } else if (ice_candidate->componentID == 2) {
659 default_addr = stream->rtcp_addr;
660 default_port = stream->rtcp_port;
662 if (default_addr[0] == '\0') default_addr = desc->addr;
663 /* Only include the candidates matching the default destination for each component of the stream if the state is Completed as specified in RFC5245 section 9.1.2.2. */
664 if ((cl->state == ICL_Completed)
665 && !((ice_candidate->taddr.port == default_port) && (strlen(ice_candidate->taddr.ip) == strlen(default_addr)) && (strcmp(ice_candidate->taddr.ip, default_addr) == 0)))
667 strncpy(sal_candidate->foundation, ice_candidate->foundation, sizeof(sal_candidate->foundation));
668 sal_candidate->componentID = ice_candidate->componentID;
669 sal_candidate->priority = ice_candidate->priority;
670 strncpy(sal_candidate->type, ice_candidate_type(ice_candidate), sizeof(sal_candidate->type));
671 strncpy(sal_candidate->addr, ice_candidate->taddr.ip, sizeof(sal_candidate->addr));
672 sal_candidate->port = ice_candidate->taddr.port;
673 if ((ice_candidate->base != NULL) && (ice_candidate->base != ice_candidate)) {
674 strncpy(sal_candidate->raddr, ice_candidate->base->taddr.ip, sizeof(sal_candidate->raddr));
675 sal_candidate->rport = ice_candidate->base->taddr.port;
680 if ((cl->state == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
681 int rtp_port, rtcp_port;
682 memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
683 ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
684 strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
685 stream->ice_remote_candidates[0].port = rtp_port;
686 strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
687 stream->ice_remote_candidates[1].port = rtcp_port;
692 static void get_default_addr_and_port(uint16_t componentID, const SalMediaDescription *md, const SalStreamDescription *stream, const char **addr, int *port)
694 if (componentID == 1) {
695 *addr = stream->rtp_addr;
696 *port = stream->rtp_port;
697 } else if (componentID == 2) {
698 *addr = stream->rtcp_addr;
699 *port = stream->rtcp_port;
701 if ((*addr)[0] == '\0') *addr = md->addr;
704 void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md)
706 bool_t ice_restarted = FALSE;
708 if ((md->ice_pwd[0] != '\0') && (md->ice_ufrag[0] != '\0')) {
711 /* Check for ICE restart and set remote credentials. */
712 if ((strcmp(md->addr, "0.0.0.0") == 0) || (strcmp(md->addr, "::0") == 0)) {
713 ice_session_restart(call->ice_session);
714 ice_restarted = TRUE;
716 for (i = 0; i < md->nstreams; i++) {
717 const SalStreamDescription *stream = &md->streams[i];
718 IceCheckList *cl = ice_session_check_list(call->ice_session, i);
719 if (cl && (strcmp(stream->rtp_addr, "0.0.0.0") == 0)) {
720 ice_session_restart(call->ice_session);
721 ice_restarted = TRUE;
726 if ((ice_session_remote_ufrag(call->ice_session) == NULL) && (ice_session_remote_pwd(call->ice_session) == NULL)) {
727 ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
728 } else if (ice_session_remote_credentials_changed(call->ice_session, md->ice_ufrag, md->ice_pwd)) {
729 if (ice_restarted == FALSE) {
730 ice_session_restart(call->ice_session);
731 ice_restarted = TRUE;
733 ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
735 for (i = 0; i < md->nstreams; i++) {
736 const SalStreamDescription *stream = &md->streams[i];
737 IceCheckList *cl = ice_session_check_list(call->ice_session, i);
738 if (cl && (stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0')) {
739 if (ice_check_list_remote_credentials_changed(cl, stream->ice_ufrag, stream->ice_pwd)) {
740 if (ice_restarted == FALSE) {
741 ice_session_restart(call->ice_session);
742 ice_restarted = TRUE;
744 ice_session_set_remote_credentials(call->ice_session, md->ice_ufrag, md->ice_pwd);
750 /* Create ICE check lists if needed and parse ICE attributes. */
751 for (i = 0; i < md->nstreams; i++) {
752 const SalStreamDescription *stream = &md->streams[i];
753 IceCheckList *cl = ice_session_check_list(call->ice_session, i);
755 cl = ice_check_list_new();
756 ice_session_add_check_list(call->ice_session, cl);
757 switch (stream->type) {
759 if (call->audiostream != NULL) call->audiostream->ice_check_list = cl;
762 if (call->videostream != NULL) call->videostream->ice_check_list = cl;
768 if (stream->ice_mismatch == TRUE) {
769 ice_check_list_set_state(cl, ICL_Failed);
771 if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
772 ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
773 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_CANDIDATES; j++) {
774 const SalIceCandidate *candidate = &stream->ice_candidates[j];
775 bool_t default_candidate = FALSE;
776 const char *addr = NULL;
778 if (candidate->addr[0] == '\0') break;
779 if ((candidate->componentID == 0) || (candidate->componentID > 2)) continue;
780 get_default_addr_and_port(candidate->componentID, md, stream, &addr, &port);
781 if (addr && (candidate->port == port) && (strlen(candidate->addr) == strlen(addr)) && (strcmp(candidate->addr, addr) == 0))
782 default_candidate = TRUE;
783 ice_add_remote_candidate(cl, candidate->type, candidate->addr, candidate->port, candidate->componentID,
784 candidate->priority, candidate->foundation, default_candidate);
786 if (ice_restarted == FALSE) {
787 for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
788 const SalIceRemoteCandidate *candidate = &stream->ice_remote_candidates[j];
789 const char *addr = NULL;
791 int componentID = j + 1;
792 if (candidate->addr[0] == '\0') break;
793 get_default_addr_and_port(componentID, md, stream, &addr, &port);
794 ice_add_losing_pair(ice_session_check_list(call->ice_session, i), j + 1, candidate->addr, candidate->port, addr, port);
799 for (i = ice_session_nb_check_lists(call->ice_session); i > md->nstreams; i--) {
800 ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
802 ice_session_check_mismatch(call->ice_session);
804 if ((ice_session_state(call->ice_session) == IS_Failed) || (ice_session_nb_check_lists(call->ice_session) == 0)) {
805 linphone_call_delete_ice_session(call);
809 LinphoneCall * is_a_linphone_call(void *user_pointer){
810 LinphoneCall *call=(LinphoneCall*)user_pointer;
811 if (call==NULL) return NULL;
812 return call->magic==linphone_call_magic ? call : NULL;
815 LinphoneProxyConfig * is_a_linphone_proxy_config(void *user_pointer){
816 LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)user_pointer;
817 if (cfg==NULL) return NULL;
818 return cfg->magic==linphone_proxy_config_magic ? cfg : NULL;
821 unsigned int linphone_core_get_audio_features(LinphoneCore *lc){
823 const char *features=lp_config_get_string(lc->config,"sound","features",NULL);
828 strncpy(tmp,features,sizeof(tmp)-1);
829 for(p=tmp;*p!='\0';p++){
830 if (*p==' ') continue;
834 ms_message("Found audio feature %s",name);
835 if (strcasecmp(name,"PLC")==0) ret|=AUDIO_STREAM_FEATURE_PLC;
836 else if (strcasecmp(name,"EC")==0) ret|=AUDIO_STREAM_FEATURE_EC;
837 else if (strcasecmp(name,"EQUALIZER")==0) ret|=AUDIO_STREAM_FEATURE_EQUALIZER;
838 else if (strcasecmp(name,"VOL_SND")==0) ret|=AUDIO_STREAM_FEATURE_VOL_SND;
839 else if (strcasecmp(name,"VOL_RCV")==0) ret|=AUDIO_STREAM_FEATURE_VOL_RCV;
840 else if (strcasecmp(name,"DTMF")==0) ret|=AUDIO_STREAM_FEATURE_DTMF;
841 else if (strcasecmp(name,"DTMF_ECHO")==0) ret|=AUDIO_STREAM_FEATURE_DTMF_ECHO;
842 else if (strcasecmp(name,"ALL")==0) ret|=AUDIO_STREAM_FEATURE_ALL;
843 else if (strcasecmp(name,"NONE")==0) ret=0;
844 else ms_error("Unsupported audio feature %s requested in config file.",name);
848 }else ret=AUDIO_STREAM_FEATURE_ALL;
853 #ifdef HAVE_GETIFADDRS
856 static int get_local_ip_with_getifaddrs(int type, char *address, int size)
859 struct ifaddrs *ifpstart;
862 if (getifaddrs(&ifpstart) < 0) {
866 for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
867 if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
868 && (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
870 getnameinfo(ifp->ifa_addr,
872 sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in),
873 address, size, NULL, 0, NI_NUMERICHOST);
874 if (strchr(address, '%') == NULL) { /*avoid ipv6 link-local addresses */
875 /*ms_message("getifaddrs() found %s",address);*/
881 freeifaddrs(ifpstart);
887 static int get_local_ip_for_with_connect(int type, const char *dest, char *result){
889 struct addrinfo hints;
890 struct addrinfo *res=NULL;
891 struct sockaddr_storage addr;
892 struct sockaddr *p_addr=(struct sockaddr*)&addr;
896 memset(&hints,0,sizeof(hints));
897 hints.ai_family=(type==AF_INET6) ? PF_INET6 : PF_INET;
898 hints.ai_socktype=SOCK_DGRAM;
899 /*hints.ai_flags=AI_NUMERICHOST|AI_CANONNAME;*/
900 err=getaddrinfo(dest,"5060",&hints,&res);
902 ms_error("getaddrinfo() error: %s",gai_strerror(err));
906 ms_error("bug: getaddrinfo returned nothing.");
909 sock=socket(res->ai_family,SOCK_DGRAM,0);
911 err=setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(SOCKET_OPTION_VALUE)&tmp,sizeof(int));
913 ms_warning("Error in setsockopt: %s",strerror(errno));
915 err=connect(sock,res->ai_addr,res->ai_addrlen);
917 ms_error("Error in connect: %s",strerror(errno));
925 err=getsockname(sock,(struct sockaddr*)&addr,&s);
927 ms_error("Error in getsockname: %s",strerror(errno));
931 if (p_addr->sa_family==AF_INET){
932 struct sockaddr_in *p_sin=(struct sockaddr_in*)p_addr;
933 if (p_sin->sin_addr.s_addr==0){
938 err=getnameinfo((struct sockaddr *)&addr,s,result,LINPHONE_IPADDR_SIZE,NULL,0,NI_NUMERICHOST);
940 ms_error("getnameinfo error: %s",strerror(errno));
943 ms_message("Local interface to reach %s is %s.",dest,result);
947 int linphone_core_get_local_ip_for(int type, const char *dest, char *result){
948 strcpy(result,type==AF_INET ? "127.0.0.1" : "::1");
949 #ifdef HAVE_GETIFADDRS
951 /*we use getifaddrs for lookup of default interface */
954 found_ifs=get_local_ip_with_getifaddrs(type,result,LINPHONE_IPADDR_SIZE);
957 }else if (found_ifs<=0){
958 /*absolutely no network on this machine */
963 /*else use connect to find the best local ip address */
965 dest="87.98.157.38"; /*a public IP address*/
966 else dest="2a00:1450:8002::68";
967 return get_local_ip_for_with_connect(type,dest,result);
975 void _linphone_core_configure_resolver(){
976 /*bionic declares _res but does not define nor export it !!*/
978 /*timeout and attempts are the same as retrans and retry, but are android specific names.*/
979 setenv("RES_OPTIONS","timeout:2 attempts:2 retrans:2 retry:2",1);
982 _res.retrans=2; /*retransmit every two seconds*/
983 _res.retry=2; /*only two times per DNS server*/
989 void _linphone_core_configure_resolver(){