X-Git-Url: http://sjero.net/git/?a=blobdiff_plain;f=coreapi%2Flinphonecore.c;h=12c8880b65a4068547ffacd35a07c984b4ab8304;hb=12a3d795131ab1b367ae000f8b70f9b8af684df6;hp=12a104e76d364ecf12d8fd08f980ea88878ffe53;hpb=33bab1941e1c37a9a3c42ea711fe19bd4bda5492;p=linphone diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 12a104e7..12c8880b 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -65,6 +65,7 @@ static void linphone_core_run_hooks(LinphoneCore *lc); static void linphone_core_free_hooks(LinphoneCore *lc); #include "enum.h" + const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc); static void toggle_video_preview(LinphoneCore *lc, bool_t val); @@ -91,12 +92,7 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){ /*prevent a gcc bug with %c*/ static size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm){ -#if !defined(_WIN32_WCE) return strftime(s, max, fmt, tm); -#else - return 0; - /*FIXME*/ -#endif /*_WIN32_WCE*/ } static void set_call_log_date(LinphoneCallLog *cl, time_t start_time){ @@ -119,7 +115,8 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *fro set_call_log_date(cl,cl->start_date_time); cl->from=from; cl->to=to; - cl->status=LinphoneCallAborted; /*default status*/ + cl->status=LinphoneCallAborted; /*default status*/ + cl->quality=-1; return cl; } @@ -202,8 +199,8 @@ static void call_logs_read_from_config_file(LinphoneCore *lc){ if (tmp) cl->refkey=ms_strdup(tmp); cl->quality=lp_config_get_float(cfg,logsection,"quality",-1); cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0); - cl->call_id=lp_config_get_string(cfg,logsection,"call_id",NULL); - if(cl->call_id) cl->call_id=ms_strdup(cl->call_id); + tmp=lp_config_get_string(cfg,logsection,"call_id",NULL); + if (tmp) cl->call_id=ms_strdup(tmp); lc->call_logs=ms_list_append(lc->call_logs,cl); }else break; } @@ -269,10 +266,20 @@ const rtp_stats_t *linphone_call_log_get_remote_stats(const LinphoneCallLog *cl) return &cl->remote_stats; } +const char *linphone_call_log_get_call_id(const LinphoneCallLog *cl){ + return cl->call_id; +} + +/** + * Assign a user pointer to the call log. +**/ void linphone_call_log_set_user_pointer(LinphoneCallLog *cl, void *up){ cl->user_pointer=up; } +/** + * Returns the user pointer associated with the call log. +**/ void *linphone_call_log_get_user_pointer(const LinphoneCallLog *cl){ return cl->user_pointer; } @@ -305,13 +312,74 @@ const char *linphone_call_log_get_ref_key(const LinphoneCallLog *cl){ return cl->refkey; } +/** + * Returns origin (ie from) address of the call. +**/ +LinphoneAddress *linphone_call_log_get_from(LinphoneCallLog *cl){ + return cl->from; +} + +/** + * Returns destination address (ie to) of the call. +**/ +LinphoneAddress *linphone_call_log_get_to(LinphoneCallLog *cl){ + return cl->to; +} + +/** + * Returns remote address (that is from or to depending on call direction). +**/ +LinphoneAddress *linphone_call_log_get_remote_address(LinphoneCallLog *cl){ + return (cl->dir == LinphoneCallIncoming) ? cl->from : cl->to; +} + +/** + * Returns the direction of the call. +**/ +LinphoneCallDir linphone_call_log_get_dir(LinphoneCallLog *cl){ + return cl->dir; +} + +/** + * Returns the status of the call. +**/ +LinphoneCallStatus linphone_call_log_get_status(LinphoneCallLog *cl){ + return cl->status; +} + +/** + * Returns the start date of the call, expressed as a POSIX time_t. +**/ +time_t linphone_call_log_get_start_date(LinphoneCallLog *cl){ + return cl->start_date_time; +} + +/** + * Returns duration of the call. +**/ +int linphone_call_log_get_duration(LinphoneCallLog *cl){ + return cl->duration; +} + +/** + * Returns overall quality indication of the call. +**/ +float linphone_call_log_get_quality(LinphoneCallLog *cl){ + return cl->quality; +} +/** + * return true if video was enabled at the end of the call + */ +LinphoneCallStatus linphone_call_log_video_enabled(LinphoneCallLog *cl) { + return cl->video_enabled; +} /** @} */ void linphone_call_log_destroy(LinphoneCallLog *cl){ if (cl->from!=NULL) linphone_address_destroy(cl->from); if (cl->to!=NULL) linphone_address_destroy(cl->to); if (cl->refkey!=NULL) ms_free(cl->refkey); - if (cl->call_id) ms_free((void*)cl->call_id); + if (cl->call_id) ms_free(cl->call_id); ms_free(cl); } @@ -339,10 +407,24 @@ const LinphoneAddress *linphone_core_get_current_call_remote_address(struct _Lin return linphone_call_get_remote_address(call); } +void linphone_core_set_log_handler(OrtpLogFunc logfunc) { + ortp_set_log_handler(logfunc); +} + +void linphone_core_set_log_file(FILE *file) { + if (file == NULL) file = stdout; + ortp_set_log_file(file); +} + +void linphone_core_set_log_level(OrtpLogLevel loglevel) { + ortp_set_log_level_mask(loglevel); +} + /** * Enable logs in supplied FILE*. * * @ingroup misc + * @deprecated Use #linphone_core_set_log_file and #linphone_core_set_log_level instead. * * @param file a C FILE* where to fprintf logs. If null stdout is used. * @@ -357,6 +439,7 @@ void linphone_core_enable_logs(FILE *file){ * Enable logs through the user's supplied log callback. * * @ingroup misc + * @deprecated Use #linphone_core_set_log_handler and #linphone_core_set_log_level instead. * * @param logfunc The address of a OrtpLogFunc callback whose protoype is * typedef void (*OrtpLogFunc)(OrtpLogLevel lev, const char *fmt, va_list args); @@ -371,6 +454,7 @@ void linphone_core_enable_logs_with_cb(OrtpLogFunc logfunc){ * Entirely disable logging. * * @ingroup misc + * @deprecated Use #linphone_core_set_log_level instead. **/ void linphone_core_disable_logs(){ ortp_set_log_level_mask(ORTP_ERROR|ORTP_FATAL); @@ -396,7 +480,7 @@ static void net_config_read (LinphoneCore *lc) linphone_core_set_firewall_policy(lc,tmp); tmp=lp_config_get_int(lc->config,"net","nat_sdp_only",0); lc->net_conf.nat_sdp_only=tmp; - tmp=lp_config_get_int(lc->config,"net","mtu",0); + tmp=lp_config_get_int(lc->config,"net","mtu",1300); linphone_core_set_mtu(lc,tmp); tmp=lp_config_get_int(lc->config,"net","download_ptime",0); linphone_core_set_download_ptime(lc,tmp); @@ -485,11 +569,11 @@ static void sound_config_read(LinphoneCore *lc) check_sound_device(lc); lc->sound_conf.latency=0; #ifndef __ios - tmp=TRUE; + tmp=TRUE; #else - tmp=FALSE; /* on iOS we have builtin echo cancellation.*/ + tmp=FALSE; /* on iOS we have builtin echo cancellation.*/ #endif - tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp); + tmp=lp_config_get_int(lc->config,"sound","echocancellation",tmp); linphone_core_enable_echo_cancellation(lc,tmp); linphone_core_enable_echo_limiter(lc, lp_config_get_int(lc->config,"sound","echolimiter",0)); @@ -514,9 +598,6 @@ static void sip_config_read(LinphoneCore *lc) int ipv6; int random_port; - tmp=lp_config_get_int(lc->config,"sip","use_info",0); - linphone_core_set_use_info_for_dtmf(lc,tmp); - if (lp_config_get_int(lc->config,"sip","use_session_timers",0)==1){ sal_use_session_timers(lc->sal,200); } @@ -526,9 +607,6 @@ static void sip_config_read(LinphoneCore *lc) sal_reuse_authorization(lc->sal, lp_config_get_int(lc->config,"sip","reuse_authorization",0)); sal_expire_old_registration_contacts(lc->sal,lp_config_get_int(lc->config,"sip","expire_old_registration_contacts",0)); - tmp=lp_config_get_int(lc->config,"sip","use_rfc2833",1); - linphone_core_set_use_rfc2833_for_dtmf(lc,tmp); - ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1); if (ipv6==-1){ ipv6=0; @@ -565,6 +643,7 @@ static void sip_config_read(LinphoneCore *lc) sal_set_root_ca(lc->sal, lp_config_get_string(lc->config,"sip","root_ca", ROOT_CA_FILE)); #endif linphone_core_verify_server_certificates(lc,lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); + linphone_core_verify_server_cn(lc,lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); /*setting the dscp must be done before starting the transports, otherwise it is not taken into effect*/ sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc)); /*start listening on ports*/ @@ -598,6 +677,9 @@ static void sip_config_read(LinphoneCore *lc) tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0); linphone_core_set_in_call_timeout(lc,tmp); + + tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4); + linphone_core_set_delayed_timeout(lc,tmp); /* get proxies config */ for(i=0;; i++){ @@ -629,10 +711,13 @@ static void sip_config_read(LinphoneCore *lc) lc->sip_conf.sdp_200_ack=lp_config_get_int(lc->config,"sip","sdp_200_ack",0); lc->sip_conf.register_only_when_network_is_up= lp_config_get_int(lc->config,"sip","register_only_when_network_is_up",1); + lc->sip_conf.register_only_when_upnp_is_ok= + lp_config_get_int(lc->config,"sip","register_only_when_upnp_is_ok",1); lc->sip_conf.ping_with_options=lp_config_get_int(lc->config,"sip","ping_with_options",1); lc->sip_conf.auto_net_state_mon=lp_config_get_int(lc->config,"sip","auto_net_state_mon",1); lc->sip_conf.keepalive_period=lp_config_get_int(lc->config,"sip","keepalive_period",10000); - sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period); + lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0); + linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0)); sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1)); sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0)); @@ -677,6 +762,7 @@ static void rtp_config_read(LinphoneCore *lc) linphone_core_enable_audio_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled); adaptive_jitt_comp_enabled = lp_config_get_int(lc->config, "rtp", "video_adaptive_jitt_comp_enabled", TRUE); linphone_core_enable_video_adaptive_jittcomp(lc, adaptive_jitt_comp_enabled); + lc->rtp_conf.disable_upnp = lp_config_get_int(lc->config, "rtp", "disable_upnp", FALSE); } static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int clock_rate, int channels, const char *recv_fmtp){ @@ -706,11 +792,12 @@ static PayloadType * find_payload(RtpProfile *prof, const char *mime_type, int c return candidate; } -static bool_t get_codec(LpConfig *config, const char* type, int index, PayloadType **ret){ +static bool_t get_codec(LinphoneCore *lc, const char* type, int index, PayloadType **ret){ char codeckey[50]; const char *mime,*fmtp; int rate,channels,enabled; PayloadType *pt; + LpConfig *config=lc->config; *ret=NULL; snprintf(codeckey,50,"%s_%i",type,index); @@ -721,7 +808,7 @@ static bool_t get_codec(LpConfig *config, const char* type, int index, PayloadTy fmtp=lp_config_get_string(config,codeckey,"recv_fmtp",NULL); channels=lp_config_get_int(config,codeckey,"channels",0); enabled=lp_config_get_int(config,codeckey,"enabled",1); - pt=find_payload(&av_profile,mime,rate,channels,fmtp); + pt=find_payload(lc->default_profile,mime,rate,channels,fmtp); if (pt && enabled ) pt->flags|=PAYLOAD_TYPE_ENABLED; //ms_message("Found codec %s/%i",pt->mime_type,pt->clock_rate); if (pt==NULL) ms_warning("Ignoring codec config %s/%i with fmtp=%s because unsupported", @@ -767,10 +854,10 @@ static int codec_compare(const PayloadType *a, const PayloadType *b){ return 0; } -static MSList *add_missing_codecs(SalStreamType mtype, MSList *l){ +static MSList *add_missing_codecs(LinphoneCore *lc, SalStreamType mtype, MSList *l){ int i; for(i=0;idefault_profile,i); if (pt){ if (mtype==SalVideo && pt->type!=PAYLOAD_VIDEO) pt=NULL; @@ -811,22 +898,22 @@ static void codecs_config_read(LinphoneCore *lc) PayloadType *pt; MSList *audio_codecs=NULL; MSList *video_codecs=NULL; - for (i=0;get_codec(lc->config,"audio_codec",i,&pt);i++){ + for (i=0;get_codec(lc,"audio_codec",i,&pt);i++){ if (pt){ if (!ms_filter_codec_supported(pt->mime_type)){ ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); }else audio_codecs=codec_append_if_new(audio_codecs,pt); } } - audio_codecs=add_missing_codecs(SalAudio,audio_codecs); - for (i=0;get_codec(lc->config,"video_codec",i,&pt);i++){ + audio_codecs=add_missing_codecs(lc,SalAudio,audio_codecs); + for (i=0;get_codec(lc,"video_codec",i,&pt);i++){ if (pt){ if (!ms_filter_codec_supported(pt->mime_type)){ ms_warning("Codec %s is not supported by mediastreamer2, removed.",pt->mime_type); }else video_codecs=codec_append_if_new(video_codecs,(void *)pt); } } - video_codecs=add_missing_codecs(SalVideo,video_codecs); + video_codecs=add_missing_codecs(lc,SalVideo,video_codecs); linphone_core_set_audio_codecs(lc,audio_codecs); linphone_core_set_video_codecs(lc,video_codecs); linphone_core_update_allocated_audio_bandwidth(lc); @@ -917,11 +1004,14 @@ bool_t linphone_core_tunnel_available(void){ } /** - * Enable adaptive rate control (experimental feature, audio-only). + * Enable adaptive rate control. + * + * @ingroup media_parameters * * Adaptive rate control consists in using RTCP feedback provided information to dynamically - * control the output bitrate of the encoders, so that we can adapt to the network conditions and - * available bandwidth. + * control the output bitrate of the audio and video encoders, so that we can adapt to the network conditions and + * available bandwidth. Control of the audio encoder is done in case of audio-only call, and control of the video encoder is done for audio & video calls. + * Adaptive rate control feature is enabled by default. **/ void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled){ lp_config_set_int(lc->config,"net","adaptive_rate_control",(int)enabled); @@ -929,6 +1019,8 @@ void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled /** * Returns whether adaptive rate control is enabled. + * + * @ingroup media_parameters * * See linphone_core_enable_adaptive_rate_control(). **/ @@ -1001,14 +1093,18 @@ int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){ return lc->net_conf.upload_bw; } /** - * Set audio packetization time linphone expects to receive from peer + * Set audio packetization time linphone expects to receive from peer. + * A value of zero means that ptime is not specified. + * @ingroup media_parameters */ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) { lp_config_set_int(lc->config,"rtp","download_ptime",ptime); } /** - * Get audio packetization time linphone expects to receive from peer + * Get audio packetization time linphone expects to receive from peer. + * A value of zero means that ptime is not specified. + * @ingroup media_parameters */ int linphone_core_get_download_ptime(LinphoneCore *lc) { return lp_config_get_int(lc->config,"rtp","download_ptime",0); @@ -1018,6 +1114,7 @@ int linphone_core_get_download_ptime(LinphoneCore *lc) { * Set audio packetization time linphone will send (in absence of requirement from peer) * A value of 0 stands for the current codec default packetization time. * + * @ingroup media_parameters **/ void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){ lp_config_set_int(lc->config,"rtp","upload_ptime",ptime); @@ -1027,6 +1124,8 @@ void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){ * Set audio packetization time linphone will send (in absence of requirement from peer) * A value of 0 stands for the current codec default packetization time. * + * + * @ingroup media_parameters **/ int linphone_core_get_upload_ptime(LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","upload_ptime",0); @@ -1073,7 +1172,7 @@ static void linphone_core_assign_payload_type(LinphoneCore *lc, PayloadType *con ms_message("assigning %s/%i payload type number %i",pt->mime_type,pt->clock_rate,number); payload_type_set_number(pt,number); if (recv_fmtp!=NULL) payload_type_set_recv_fmtp(pt,recv_fmtp); - rtp_profile_set_payload(&av_profile,number,pt); + rtp_profile_set_payload(lc->default_profile,number,pt); lc->payload_types=ms_list_append(lc->payload_types,pt); } @@ -1091,6 +1190,8 @@ static void linphone_core_handle_static_payloads(LinphoneCore *lc){ } static void linphone_core_free_payload_types(LinphoneCore *lc){ + rtp_profile_clear_all(lc->default_profile); + rtp_profile_destroy(lc->default_profile); ms_list_for_each(lc->payload_types,(void (*)(void*))payload_type_destroy); ms_list_free(lc->payload_types); lc->payload_types=NULL; @@ -1104,18 +1205,18 @@ void linphone_core_set_state(LinphoneCore *lc, LinphoneGlobalState gstate, const } static void misc_config_read (LinphoneCore *lc) { LpConfig *config=lc->config; - lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",15); - lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS); + lc->max_call_logs=lp_config_get_int(config,"misc","history_max_size",15); + lc->max_calls=lp_config_get_int(config,"misc","max_calls",NB_MAX_CALLS); } -static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, - const char *factory_config_path, void * userdata) +static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, LpConfig *config, void * userdata) { ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); memset (lc, 0, sizeof (LinphoneCore)); + lc->config=config; lc->data=userdata; lc->ringstream_autorelease=TRUE; @@ -1124,6 +1225,7 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_set_state(lc,LinphoneGlobalStartup,"Starting up"); ortp_init(); lc->dyn_pt=96; + lc->default_profile=rtp_profile_new("default profile"); linphone_core_assign_payload_type(lc,&payload_type_pcmu8000,0,NULL); linphone_core_assign_payload_type(lc,&payload_type_gsm,3,NULL); linphone_core_assign_payload_type(lc,&payload_type_pcma8000,8,NULL); @@ -1183,6 +1285,8 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta linphone_core_assign_payload_type(lc,&payload_type_silk_wb,-1,NULL); linphone_core_assign_payload_type(lc,&payload_type_silk_swb,-1,NULL); linphone_core_assign_payload_type(lc,&payload_type_g729,18,"annexb=no"); + linphone_core_assign_payload_type(lc,&payload_type_aaceld_22k,-1,"config=F8EE2000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); + linphone_core_assign_payload_type(lc,&payload_type_aaceld_44k,-1,"config=F8E82000; constantDuration=512; indexDeltaLength=3; indexLength=3; mode=AAC-hbr; profile-level-id=76; sizeLength=13; streamType=5"); linphone_core_handle_static_payloads(lc); ms_init(); @@ -1191,10 +1295,6 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->msevq=ms_event_queue_new(); ms_set_global_event_queue(lc->msevq); - lc->config=lp_config_new(config_path); - if (factory_config_path) - lp_config_read_file(lc->config,factory_config_path); - lc->sal=sal_init(); sal_set_user_pointer(lc->sal,lc); sal_set_callbacks(lc->sal,&linphone_sal_callbacks); @@ -1217,9 +1317,6 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta lc->tunnel=linphone_core_tunnel_new(lc); if (lc->tunnel) linphone_tunnel_configure(lc->tunnel); #endif -#ifdef BUILD_UPNP - lc->upnp = upnp_context_new(lc); -#endif //BUILD_UPNP if (lc->vtable.display_status) lc->vtable.display_status(lc,_("Ready")); lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon; @@ -1243,13 +1340,19 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta * It is OPTIONAL, use NULL if unneeded. * @param userdata an opaque user pointer that can be retrieved at any time (for example in * callbacks) using linphone_core_get_user_data(). - * + * @see linphone_core_new_with_config **/ LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config_path, void * userdata) { - LinphoneCore *core=ms_new(LinphoneCore,1); - linphone_core_init(core,vtable,config_path, factory_config_path, userdata); + LpConfig *config = lp_config_new_with_factory(config_path, factory_config_path); + return linphone_core_new_with_config(vtable, config, userdata); +} + +LinphoneCore *linphone_core_new_with_config(const LinphoneCoreVTable *vtable, struct _LpConfig *config, void *userdata) +{ + LinphoneCore *core = ms_new(LinphoneCore, 1); + linphone_core_init(core, vtable, config, userdata); return core; } @@ -1260,6 +1363,7 @@ LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable, * structure holding the codec information. * It is possible to make copy of the list with ms_list_copy() in order to modify it * (such as the order of codecs). + * @ingroup media_parameters **/ const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc) { @@ -1273,6 +1377,7 @@ const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc) * structure holding the codec information. * It is possible to make copy of the list with ms_list_copy() in order to modify it * (such as the order of codecs). + * @ingroup media_parameters **/ const MSList *linphone_core_get_video_codecs(const LinphoneCore *lc) { @@ -1315,12 +1420,12 @@ void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result } #ifdef BUILD_UPNP else if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && - upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { - ip = upnp_context_get_external_ipaddress(lc->upnp); + linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { + ip = linphone_upnp_context_get_external_ipaddress(lc->upnp); strncpy(result,ip,LINPHONE_IPADDR_SIZE); return; } -#endif //BUILD_UPNP +#endif //BUILD_UPNP if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,dest,result)==0) return; /*else fallback to SAL routine that will attempt to find the most realistic interface */ @@ -1570,6 +1675,7 @@ void linphone_core_set_audio_port(LinphoneCore *lc, int port) /** * Sets the UDP port range from which to randomly select the port used for audio streaming. + * @ingroup media_parameters */ void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port) { @@ -1588,6 +1694,7 @@ void linphone_core_set_video_port(LinphoneCore *lc, int port){ /** * Sets the UDP port range from which to randomly select the port used for video streaming. + * @ingroup media_parameters */ void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port) { @@ -1612,7 +1719,7 @@ void linphone_core_set_nortp_timeout(LinphoneCore *lc, int nortp_timeout){ **/ bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc) { - return lc->sip_conf.use_info; + return lp_config_get_int(lc->config, "sip", "use_info", 0); } /** @@ -1622,7 +1729,9 @@ bool_t linphone_core_get_use_info_for_dtmf(LinphoneCore *lc) **/ void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info) { - lc->sip_conf.use_info=use_info; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config, "sip", "use_info", use_info); + } } /** @@ -1632,7 +1741,7 @@ void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc,bool_t use_info) **/ bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc) { - return lc->sip_conf.use_rfc2833; + return lp_config_get_int(lc->config, "sip", "use_rfc2833", 1); } /** @@ -1642,7 +1751,9 @@ bool_t linphone_core_get_use_rfc2833_for_dtmf(LinphoneCore *lc) **/ void linphone_core_set_use_rfc2833_for_dtmf(LinphoneCore *lc,bool_t use_rfc2833) { - lc->sip_conf.use_rfc2833=use_rfc2833; + if (linphone_core_ready(lc)) { + lp_config_set_int(lc->config, "sip", "use_rfc2833", use_rfc2833); + } } /** @@ -1963,9 +2074,11 @@ void linphone_core_iterate(LinphoneCore *lc){ lc->ecc->cb(lc,ecs,lc->ecc->delay,lc->ecc->cb_data); if (ecs==LinphoneEcCalibratorDone){ int len=lp_config_get_int(lc->config,"sound","ec_tail_len",0); - lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-(len/2),0)); + int margin=len/2; + + lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-margin,0)); } else if (ecs == LinphoneEcCalibratorFailed) { - lp_config_set_int(lc->config, "sound", "ec_delay", LP_CONFIG_DEFAULT_INT(lc->config, "ec_delay", 250)); + lp_config_set_int(lc->config, "sound", "ec_delay", -1);/*use default value from soundcard*/ } else if (ecs == LinphoneEcCalibratorDoneNoEcho) { linphone_core_enable_echo_cancellation(lc, FALSE); } @@ -2004,7 +2117,7 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_start_invite() */ calls=calls->next; linphone_call_background_tasks(call,one_second_elapsed); - if (call->state==LinphoneCallOutgoingInit && (curtime-call->start_time>=2)){ + if (call->state==LinphoneCallOutgoingInit && (elapsed>=lc->sip_conf.delayed_timeout)){ /*start the call even if the OPTIONS reply did not arrive*/ if (call->ice_session != NULL) { ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway." @@ -2012,19 +2125,23 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_call_delete_ice_session(call); linphone_call_stop_media_streams_for_ice_gathering(call); } +#ifdef BUILD_UPNP if (call->upnp_session != NULL) { ms_warning("uPnP mapping has not finished yet, proceeded with the call without uPnP anyway."); linphone_call_delete_upnp_session(call); } +#endif //BUILD_UPNP linphone_core_start_invite(lc,call); } if (call->state==LinphoneCallIncomingReceived){ ms_message("incoming call ringing for %i seconds",elapsed); if (elapsed>lc->sip_conf.inc_timeout){ + LinphoneReason decline_reason; ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); + decline_reason=lc->current_call ? LinphoneReasonBusy : LinphoneReasonDeclined; call->log->status=LinphoneCallMissed; call->reason=LinphoneReasonNotAnswered; - linphone_core_terminate_call(lc,call); + linphone_core_decline_call(lc,call,decline_reason); } } if (lc->sip_conf.in_call_timeout > 0 && elapsed>lc->sip_conf.in_call_timeout) { @@ -2053,14 +2170,18 @@ void linphone_core_iterate(LinphoneCore *lc){ lc->initial_subscribes_sent=TRUE; } - if (one_second_elapsed && lp_config_needs_commit(lc->config)){ - lp_config_sync(lc->config); + if (one_second_elapsed) { + if (lp_config_needs_commit(lc->config)) { + lp_config_sync(lc->config); + } } } /** * Interpret a call destination as supplied by the user, and returns a fully qualified * LinphoneAddress. + * + * @ingroup call_control * * A sip address should look like DisplayName . * Basically this function performs the following tasks @@ -2279,10 +2400,12 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c } #ifdef BUILD_UPNP if (call->upnp_session != NULL) { - if (upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE; + if (linphone_upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE; } else { upnp_ready = TRUE; } +#else + upnp_ready=TRUE; #endif //BUILD_UPNP if (call->ping_op != NULL) { if (call->ping_replied == TRUE) ping_ready = TRUE; @@ -2508,15 +2631,23 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const } if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){ - /*defer the start of the call after the OPTIONS ping*/ - call->ping_replied=FALSE; - call->ping_op=sal_op_new(lc->sal); - sal_ping(call->ping_op,from,real_url); - sal_op_set_user_pointer(call->ping_op,call); - call->start_time=time(NULL); - }else{ - if (defer==FALSE) linphone_core_start_invite(lc,call); +#ifdef BUILD_UPNP + if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp && + linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) { +#else //BUILD_UPNP + { +#endif //BUILD_UPNP + /*defer the start of the call after the OPTIONS ping*/ + call->ping_replied=FALSE; + call->ping_op=sal_op_new(lc->sal); + sal_ping(call->ping_op,from,real_url); + sal_op_set_user_pointer(call->ping_op,call); + call->start_time=time(NULL); + defer = TRUE; + } } + + if (defer==FALSE) linphone_core_start_invite(lc,call); if (real_url!=NULL) ms_free(real_url); return call; @@ -2525,6 +2656,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const /** * Performs a simple call transfer to the specified destination. * + * @ingroup call_control * The remote endpoint is expected to issue a new call to the specified destination. * The current call remains active and thus can be later paused or terminated. **/ @@ -2555,6 +2687,8 @@ int linphone_core_transfer_call(LinphoneCore *lc, LinphoneCall *call, const char * @param lc linphone core object * @param call a running call you want to transfer * @param dest a running call whose remote person will receive the transfer + * + * @ingroup call_control * * The transfered call is supposed to be in paused state, so that it is able to accept the transfer immediately. * The destination call is a call previously established to introduce the transfered person. @@ -2579,6 +2713,19 @@ bool_t linphone_core_inc_invite_pending(LinphoneCore*lc){ return FALSE; } +bool_t linphone_core_incompatible_security(LinphoneCore *lc, SalMediaDescription *md){ + if (linphone_core_is_media_encryption_mandatory(lc) && linphone_core_get_media_encryption(lc)==LinphoneMediaEncryptionSRTP){ + int i; + for(i=0;in_active_streams;i++){ + SalStreamDescription *sd=&md->streams[i]; + if (sd->proto!=SalProtoRtpSavp){ + return TRUE; + } + } + } + return FALSE; +} + void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ char *barmesg; char *tmp; @@ -2590,10 +2737,12 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ linphone_call_make_local_media_description(lc,call); sal_call_set_local_media_description(call->op,call->localdesc); md=sal_call_get_final_media_description(call->op); - if (md && sal_media_description_empty(md)){ - sal_call_decline(call->op,SalReasonMedia,NULL); - linphone_call_unref(call); - return; + if (md){ + if (sal_media_description_empty(md) || linphone_core_incompatible_security(lc,md)){ + sal_call_decline(call->op,SalReasonMedia,NULL); + linphone_call_unref(call); + return; + } } from_parsed=linphone_address_new(sal_op_get_from(call->op)); @@ -2628,7 +2777,7 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){ }else{ /* else play a tone within the context of the current call */ call->ringing_beep=TRUE; - linphone_core_play_tone(lc); + linphone_core_play_named_tone(lc,LinphoneToneCallWaiting); } linphone_call_set_state(call,LinphoneCallIncomingReceived,"Incoming call"); @@ -2693,14 +2842,27 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho linphone_call_set_state(call,LinphoneCallUpdating,"Updating call"); #ifdef VIDEO_ENABLED bool_t has_video = call->params.has_video; - if(call->videostream != NULL && !params->has_video) { - if ((call->ice_session != NULL)) { - ice_session_remove_check_list(call->ice_session, call->videostream->ice_check_list); - call->videostream->ice_check_list = NULL; + + // Video removing + if((call->videostream != NULL) && !params->has_video) { + if (call->ice_session != NULL) { + ice_session_remove_check_list(call->ice_session, call->videostream->ms.ice_check_list); + call->videostream->ms.ice_check_list = NULL; + } +#ifdef BUILD_UPNP + if(call->upnp_session != NULL) { + if (linphone_core_update_upnp(lc, call)<0) { + /* uPnP port mappings failed, proceed with the call anyway. */ + linphone_call_delete_upnp_session(call); + } } +#endif //BUILD_UPNP } - call->params = *params; + + _linphone_call_params_copy(&call->params,params); linphone_call_make_local_media_description(lc, call); + + // Video adding if (!has_video && call->params.has_video) { if (call->ice_session != NULL) { /* Defer call update until the ICE candidates gathering process has finished. */ @@ -2781,6 +2943,7 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session); } #endif //BUILD_UPNP + linphone_call_update_remote_session_id_and_ver(call); sal_call_set_local_media_description(call->op,call->localdesc); sal_call_accept(call->op); md=sal_call_get_final_media_description(call->op); @@ -2810,6 +2973,8 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call) * @return 0 if sucessful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state). **/ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ + SalMediaDescription *remote_desc; + bool_t keep_sdp_version; #ifdef VIDEO_ENABLED bool_t old_has_video = call->params.has_video; #endif @@ -2818,6 +2983,15 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const linphone_call_state_to_string(call->state)); return -1; } + remote_desc = sal_call_get_remote_media_description(call->op); + keep_sdp_version = lp_config_get_int(lc->config, "sip", "keep_sdp_version", 0); + if (keep_sdp_version &&(remote_desc->session_id == call->remote_session_id) && (remote_desc->session_ver == call->remote_session_ver)) { + /* Remote has sent an INVITE with the same SDP as before, so send a 200 OK with the same SDP as before. */ + ms_warning("SDP version has not changed, send same SDP as before."); + sal_call_accept(call->op); + linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)"); + return 0; + } if (params==NULL){ call->params.has_video=lc->video_policy.automatically_accept || call->current_params.has_video; }else @@ -2831,11 +3005,11 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const ms_warning("Video isn't supported in conference"); call->params.has_video = FALSE; } - call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(call->op)); + call->params.has_video &= linphone_core_media_description_contains_video_stream(remote_desc); call->camera_active=call->params.has_video; linphone_call_make_local_media_description(lc,call); if (call->ice_session != NULL) { - linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(call->op)); + 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->params.has_video) && (call->params.has_video != old_has_video)) { @@ -2847,19 +3021,22 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const } else return 0; } } -#endif +#endif //VIDEO_ENABLED } -#if BUILD_UPNP +#ifdef BUILD_UPNP if(call->upnp_session != NULL) { + 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_from_remote_media_description(call, sal_call_get_remote_media_description(call->op))<0) { + if (linphone_core_update_upnp(lc, call)<0) { /* uPnP update failed, proceed with the call anyway. */ linphone_call_delete_upnp_session(call); } else return 0; } +#endif //VIDEO_ENABLED } #endif //BUILD_UPNP @@ -2961,7 +3138,7 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, if (params){ const SalMediaDescription *md = sal_call_get_remote_media_description(call->op); - call->params=*params; + _linphone_call_params_copy(&call->params,params); // There might not be a md if the INVITE was lacking an SDP // In this case we use the parameters as is. if (md) call->params.has_video &= linphone_core_media_description_contains_video_stream(md); @@ -2972,10 +3149,11 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, if (call->audiostream==NULL) linphone_call_init_media_streams(call); - if (!was_ringing && call->audiostream->ticker==NULL){ + if (!was_ringing && call->audiostream->ms.ticker==NULL){ audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard); } + linphone_call_update_remote_session_id_and_ver(call); sal_call_accept(call->op); if (lc->vtable.display_status!=NULL) lc->vtable.display_status(lc,_("Connected.")); @@ -3076,6 +3254,9 @@ int linphone_core_terminate_call(LinphoneCore *lc, LinphoneCall *the_call) /** * Decline a pending incoming call, with a reason. + * + * @ingroup call_control + * * @param lc the linphone core * @param call the LinphoneCall, must be in the IncomingReceived state. * @param reason the reason for rejecting the call: LinphoneReasonDeclined or LinphoneReasonBusy @@ -3147,8 +3328,7 @@ bool_t linphone_core_in_call(const LinphoneCore *lc){ * * @ingroup call_control **/ -LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc) -{ +LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc){ return lc->current_call; } @@ -3158,7 +3338,14 @@ LinphoneCall *linphone_core_get_current_call(const LinphoneCore *lc) * * @ingroup call_control **/ -int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) +int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call){ + int err=_linphone_core_pause_call(lc,call); + if (err==0) call->paused_by_app=TRUE; + return err; +} + +/* Internal version that does not play tone indication*/ +int _linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) { const char *subject=NULL; @@ -3196,11 +3383,13 @@ int linphone_core_pause_call(LinphoneCore *lc, LinphoneCall *call) lc->vtable.display_status(lc,_("Pausing the current call...")); if (call->audiostream || call->videostream) linphone_call_stop_media_streams (call); + call->paused_by_app=FALSE; return 0; } /** * Pause all currently running calls. + * @ingroup call_control **/ int linphone_core_pause_all_calls(LinphoneCore *lc){ const MSList *elem; @@ -3208,7 +3397,7 @@ int linphone_core_pause_all_calls(LinphoneCore *lc){ LinphoneCall *call=(LinphoneCall *)elem->data; LinphoneCallState cs=linphone_call_get_state(call); if (cs==LinphoneCallStreamsRunning || cs==LinphoneCallPausedByRemote){ - linphone_core_pause_call(lc,call); + _linphone_core_pause_call(lc,call); } } return 0; @@ -3223,7 +3412,11 @@ void linphone_core_preempt_sound_resources(LinphoneCore *lc){ current_call=linphone_core_get_current_call(lc); if(current_call != NULL){ ms_message("Pausing automatically the current call."); - linphone_core_pause_call(lc,current_call); + _linphone_core_pause_call(lc,current_call); + } + if (lc->ringstream){ + ring_stop(lc->ringstream); + lc->ringstream=NULL; } } @@ -3283,6 +3476,8 @@ static int remote_address_compare(LinphoneCall *call, const LinphoneAddress *rad * @param lc * @param remote_address * @return the LinphoneCall of the call if found + * + * @ingroup call_control */ LinphoneCall *linphone_core_get_call_by_remote_address(LinphoneCore *lc, const char *remote_address){ LinphoneAddress *raddr=linphone_address_new(remote_address); @@ -3346,6 +3541,26 @@ int linphone_core_get_in_call_timeout(LinphoneCore *lc){ return lc->sip_conf.in_call_timeout; } +/** + * Returns the delayed timeout + * + * @ingroup call_control + * See linphone_core_set_delayed_timeout() for details. +**/ +int linphone_core_get_delayed_timeout(LinphoneCore *lc){ + return lc->sip_conf.delayed_timeout; +} + +/** + * Set the in delayed timeout in seconds. + * + * @ingroup call_control + * After this timeout period, a delayed call (internal call initialisation or resolution) is resumed. +**/ +void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds){ + lc->sip_conf.delayed_timeout=seconds; +} + void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away, const char *contact, LinphoneOnlineStatus presence_mode) @@ -3756,18 +3971,18 @@ const char *linphone_core_get_ring(const LinphoneCore *lc){ * @param path * @param lc The LinphoneCore object * - * @ingroup media_parameters + * @ingroup initializing **/ void linphone_core_set_root_ca(LinphoneCore *lc,const char *path){ sal_set_root_ca(lc->sal, path); } /** - * Gets the path to a file or folder containing trusted root CAs (PEM format) + * Gets the path to a file or folder containing the trusted root CAs (PEM format) * * @param lc The LinphoneCore object * - * @ingroup media_parameters + * @ingroup initializing **/ const char *linphone_core_get_root_ca(LinphoneCore *lc){ return sal_get_root_ca(lc->sal); @@ -3775,11 +3990,21 @@ const char *linphone_core_get_root_ca(LinphoneCore *lc){ /** * Specify whether the tls server certificate must be verified when connecting to a SIP/TLS server. + * + * @ingroup initializing **/ void linphone_core_verify_server_certificates(LinphoneCore *lc, bool_t yesno){ sal_verify_server_certificates(lc->sal,yesno); } +/** + * Specify whether the tls server certificate common name must be verified when connecting to a SIP/TLS server. + * @ingroup initializing +**/ +void linphone_core_verify_server_cn(LinphoneCore *lc, bool_t yesno){ + sal_verify_server_cn(lc->sal,yesno); +} + static void notify_end_of_ring(void *ud, MSFilter *f, unsigned int event, void *arg){ LinphoneCore *lc=(LinphoneCore*)ud; lc->preview_finished=1; @@ -3965,6 +4190,31 @@ const char * linphone_core_get_stun_server(const LinphoneCore *lc){ return lc->net_conf.stun_server; } +bool_t linphone_core_upnp_available(const LinphoneCore *lc){ +#ifdef BUILD_UPNP + return TRUE; +#else + return FALSE; +#endif //BUILD_UPNP +} + +LinphoneUpnpState linphone_core_get_upnp_state(const LinphoneCore *lc){ +#ifdef BUILD_UPNP + return linphone_upnp_context_get_state(lc->upnp); +#else + return LinphoneUpnpStateNotAvailable; +#endif //BUILD_UPNP +} + +const char * linphone_core_get_upnp_external_ipaddress(const LinphoneCore *lc){ +#ifdef BUILD_UPNP + return linphone_upnp_context_get_external_ipaddress(lc->upnp); +#else + return NULL; +#endif //BUILD_UPNP +} + + const char * linphone_core_get_relay_addr(const LinphoneCore *lc){ return lc->net_conf.relay; } @@ -4021,7 +4271,26 @@ const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc) } void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy pol){ +#ifndef BUILD_UPNP + if(pol == LinphonePolicyUseUpnp) { + ms_warning("UPNP is not available, reset firewall policy to no firewall"); + pol = LinphonePolicyNoFirewall; + } +#endif //BUILD_UPNP lc->net_conf.firewall_policy=pol; +#ifdef BUILD_UPNP + if(pol == LinphonePolicyUseUpnp) { + if(lc->upnp == NULL) { + lc->upnp = linphone_upnp_context_new(lc); + } + } else { + if(lc->upnp != NULL) { + linphone_upnp_context_destroy(lc->upnp); + lc->upnp = NULL; + } + } + linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0)); +#endif //BUILD_UPNP if (lc->sip_conf.contact) update_primary_contact(lc); if (linphone_core_ready(lc)) lp_config_set_int(lc->config,"net","firewall_policy",pol); @@ -4458,7 +4727,7 @@ int linphone_core_get_device_rotation(LinphoneCore *lc ) { * **/ void linphone_core_set_device_rotation(LinphoneCore *lc, int rotation) { -ms_message("%s : rotation=%d\n", __FUNCTION__, rotation); + ms_message("%s : rotation=%d\n", __FUNCTION__, rotation); lc->device_rotation = rotation; #ifdef VIDEO_ENABLED LinphoneCall *call=linphone_core_get_current_call(lc); @@ -4585,7 +4854,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->ticker) + if (call && call->audiostream && call->audiostream->ms.ticker) audio_stream_play(call->audiostream,file); } } @@ -4595,7 +4864,8 @@ void linphone_core_set_play_file(LinphoneCore *lc, const char *file){ * Sets a wav file where incoming stream is to be recorded, * when files are used instead of soundcards (see linphone_core_use_files()). * - * The file must be a 16 bit linear wav file. + * This feature is different from call recording (linphone_call_params_set_record_file()) + * The file will be a 16 bit linear wav file. **/ void linphone_core_set_record_file(LinphoneCore *lc, const char *file){ LinphoneCall *call=linphone_core_get_current_call(lc); @@ -4657,23 +4927,44 @@ void linphone_core_play_dtmf(LinphoneCore *lc, char dtmf, int duration_ms){ else ms_filter_call_method(f, MS_DTMF_GEN_START, &dtmf); } -/** - * @ingroup media_parameters - * Plays a repeated tone to the local user until next further call to #linphone_core_stop_dtmf() - * @param lc #LinphoneCore -**/ -void linphone_core_play_tone(LinphoneCore *lc){ - MSFilter *f=get_dtmf_gen(lc); - MSDtmfGenCustomTone def; - if (f==NULL){ - ms_error("No dtmf generator at this time !"); - return; +void linphone_core_play_named_tone(LinphoneCore *lc, LinphoneToneID toneid){ + if (linphone_core_tone_indications_enabled(lc)){ + MSFilter *f=get_dtmf_gen(lc); + MSDtmfGenCustomTone def; + if (f==NULL){ + ms_error("No dtmf generator at this time !"); + return; + } + memset(&def,0,sizeof(def)); + def.amplitude=1; + /*these are french tones, excepted the failed one, which is USA congestion tone (does not exist in France)*/ + switch(toneid){ + case LinphoneToneCallOnHold: + case LinphoneToneCallWaiting: + def.duration=300; + def.frequencies[0]=440; + def.interval=2000; + break; + case LinphoneToneBusy: + def.duration=500; + def.frequencies[0]=440; + def.interval=500; + def.repeat_count=3; + break; + case LinphoneToneCallFailed: + def.duration=250; + def.frequencies[0]=480; + def.frequencies[0]=620; + def.interval=250; + def.repeat_count=3; + + break; + default: + ms_warning("Unhandled tone id."); + } + if (def.duration>0) + ms_filter_call_method(f, MS_DTMF_GEN_PLAY_CUSTOM,&def); } - def.duration=300; - def.frequency=500; - def.amplitude=1; - def.interval=2000; - ms_filter_call_method(f, MS_DTMF_GEN_PLAY_CUSTOM,&def); } /** @@ -4698,6 +4989,12 @@ void *linphone_core_get_user_data(LinphoneCore *lc){ return lc->data; } + +/** + * Associate a user pointer to the linphone core. + * + * @ingroup initializing +**/ void linphone_core_set_user_data(LinphoneCore *lc, void *userdata){ lc->data=userdata; } @@ -4706,6 +5003,13 @@ int linphone_core_get_mtu(const LinphoneCore *lc){ return lc->net_conf.mtu; } +/** + * Sets the maximum transmission unit size in bytes. + * This information is useful for sending RTP packets. + * Default value is 1500. + * + * @ingroup media_parameters +**/ void linphone_core_set_mtu(LinphoneCore *lc, int mtu){ lc->net_conf.mtu=mtu; if (mtu>0){ @@ -4801,11 +5105,10 @@ void sip_config_uninit(LinphoneCore *lc) lp_config_set_string(lc->config,"sip","contact",config->contact); lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout); lp_config_set_int(lc->config,"sip","in_call_timeout",config->in_call_timeout); - lp_config_set_int(lc->config,"sip","use_info",config->use_info); - lp_config_set_int(lc->config,"sip","use_rfc2833",config->use_rfc2833); + lp_config_set_int(lc->config,"sip","delayed_timeout",config->delayed_timeout); lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled); lp_config_set_int(lc->config,"sip","register_only_when_network_is_up",config->register_only_when_network_is_up); - + lp_config_set_int(lc->config,"sip","register_only_when_upnp_is_ok",config->register_only_when_upnp_is_ok); @@ -4859,8 +5162,8 @@ void rtp_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp); lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->video_jitt_comp); lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout); - lp_config_set_int(lc->config,"rtp","audio_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled); - lp_config_set_int(lc->config,"rtp","video_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled); + lp_config_set_int(lc->config,"rtp","audio_adaptive_jitt_comp_enabled",config->audio_adaptive_jitt_comp_enabled); + lp_config_set_int(lc->config,"rtp","video_adaptive_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled); } static void sound_config_uninit(LinphoneCore *lc) @@ -4963,11 +5266,12 @@ static void linphone_core_uninit(LinphoneCore *lc) usleep(50000); #endif } - #ifdef BUILD_UPNP - upnp_context_destroy(lc->upnp); - lc->upnp = NULL; -#endif //BUILD_UPNP + if(lc->upnp != NULL) { + linphone_upnp_context_destroy(lc->upnp); + lc->upnp = NULL; + } +#endif //BUILD_UPNP if (lc->friends) ms_list_for_each(lc->friends,(void (*)(void *))linphone_friend_close_subscriptions); @@ -4999,8 +5303,21 @@ static void linphone_core_uninit(LinphoneCore *lc) ms_list_for_each(lc->last_recv_msg_ids,ms_free); lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids); + + // Free struct variable + if(lc->zrtp_secrets_cache != NULL) { + ms_free(lc->zrtp_secrets_cache); + } + if(lc->play_file!=NULL){ + ms_free(lc->play_file); + } + if(lc->rec_file!=NULL){ + ms_free(lc->rec_file); + } linphone_core_free_payload_types(lc); + + linphone_core_message_storage_close(lc); ortp_exit(); linphone_core_set_state(lc,LinphoneGlobalOff,"Off"); #ifdef TUNNEL_ENABLED @@ -5024,9 +5341,22 @@ static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t cu } lc->netup_time=curtime; lc->network_reachable=isReachable; + if(!isReachable) { sal_reset_transports(lc->sal); } +#ifdef BUILD_UPNP + if(lc->upnp == NULL) { + if(isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { + lc->upnp = linphone_upnp_context_new(lc); + } + } else { + if(!isReachable && lc->net_conf.firewall_policy == LinphonePolicyUseUpnp) { + linphone_upnp_context_destroy(lc->upnp); + lc->upnp = NULL; + } + } +#endif } void linphone_core_refresh_registers(LinphoneCore* lc) { @@ -5233,7 +5563,13 @@ const char *linphone_error_to_string(LinphoneReason err){ * Enables signaling keep alive */ void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) { +#ifdef BUILD_UPNP + if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp) { + enable = FALSE; + } +#endif //BUILD_UPNP if (enable > 0) { + sal_use_tcp_tls_keepalive(lc->sal,lc->sip_conf.tcp_tls_keepalive); sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period); } else { sal_set_keepalive_period(lc->sal,0); @@ -5300,7 +5636,7 @@ void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook for(elem=lc->hooks;elem!=NULL;elem=elem->next){ Hook *h=(Hook*)elem->data; if (h->fun==hook && h->data==hook_data){ - ms_list_remove_link(lc->hooks,elem); + lc->hooks = ms_list_remove_link(lc->hooks,elem); ms_free(h); return; } @@ -5432,8 +5768,6 @@ void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *para params->in_conference=FALSE; } - - void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) { if (lc->device_id) ms_free(lc->device_id); lc->device_id=ms_strdup(device_id); @@ -5514,3 +5848,24 @@ void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp){ int linphone_core_get_video_dscp(const LinphoneCore *lc){ return lp_config_get_int(lc->config,"rtp","video_dscp",0x2e); } + + +/** + * Sets the database filename where chat messages will be stored. + * If the file does not exist, it will be created. + * @ingroup initializing + * @param lc the linphone core + * @param path filesystem path +**/ +void linphone_core_set_chat_database_path(LinphoneCore *lc, const char *path){ + if (lc->chat_db_file){ + ms_free(lc->chat_db_file); + lc->chat_db_file=NULL; + } + if (path) { + lc->chat_db_file=ms_strdup(path); + linphone_core_message_storage_init(lc); + } +} + +