AM_CONDITIONAL(BUILD_TESTS,test x$build_tests != xno)
dnl Initialize libtool
LT_INIT([win32-dll shared disable-static])
+dnl Enable library dependencies linking
+AC_ARG_ENABLE(deplibs-link,
+ [AS_HELP_STRING([--disable-deplibs-link ], [Disable library dependencies linking (might break builds)])],
+ [enable_deplibs_linking="$enableval"],
+ [enable_deplibs_linking="yes"])
+AC_MSG_NOTICE([Enable library dependencies linking: $enable_interlib_deps])
+if test "${enable_deplibs_linking}" == "yes"; then
+ link_all_deplibs=yes
+ link_all_deplibs_CXX=yes
+else
+ link_all_deplibs=no
+ link_all_deplibs_CXX=no
+fi
AC_CONFIG_COMMANDS([libtool-hacking],[
if test "$mingw_found" = "yes" ; then
*) AC_MSG_ERROR(bad value ${enableval} for --enable-tools) ;;
esac],[build_tools=check])
+ dnl check for installed version of libupnp
+ AC_ARG_ENABLE(upnp,
+ [AS_HELP_STRING([--disable-upnp], [Disable uPnP support])],
+ [case "${enableval}" in
+ yes) build_upnp=true ;;
+ no) build_upnp=false ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --disable-upnp) ;;
+ esac],[build_upnp=auto])
+
+ if test "$build_upnp" != "false" ; then
+ PKG_CHECK_MODULES([LIBUPNP], [libupnp], [build_upnp=true],
+ [
+ if test "$build_upnp" == "true" ; then
+ AC_MSG_ERROR([libupnp not found.])
+ else
+ build_upnp=false
+ fi
+ ])
+
+ fi
+
+ AM_CONDITIONAL(BUILD_UPNP, test x$build_upnp != xfalse)
+ if test "$build_upnp" != "false" ; then
+ AC_DEFINE(BUILD_UPNP, 1, [Define if upnp enabled])
+ fi
+
dnl check libxml2 (needed for tools)
if test "$build_tools" != "false" ; then
PKG_CHECK_MODULES(LIBXML2, [libxml-2.0],[],
char *rtp_addr, *rtcp_addr;
int i;
- for (i = 0; i < old_md->nstreams; i++) {
+ for (i = 0; i < old_md->n_active_streams; i++) {
if (old_md->streams[i].type == SalAudio) {
old_audiodesc = &old_md->streams[i];
} else if (old_md->streams[i].type == SalVideo) {
old_videodesc = &old_md->streams[i];
}
}
- for (i = 0; i < new_md->nstreams; i++) {
+ for (i = 0; i < new_md->n_active_streams; i++) {
if (new_md->streams[i].type == SalAudio) {
new_audiodesc = &new_md->streams[i];
} else if (new_md->streams[i].type == SalVideo) {
ms_message("Defer ringing to gather ICE candidates");
return;
}
+ #ifdef BUILD_UPNP
+ if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseUpnp) && (call->upnp_session != NULL)) {
+ /* Defer ringing until the end of the ICE candidates gathering process. */
+ ms_message("Defer ringing to gather uPnP candidates");
+ return;
+ }
+ #endif //BUILD_UPNP
linphone_core_notify_incoming_call(lc,call);
}
if (call->ice_session != NULL) {
linphone_core_update_ice_from_remote_media_description(call, sal_call_get_remote_media_description(op));
}
+ #ifdef BUILD_UPNP
+ if (call->upnp_session != NULL) {
+ linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op));
+ }
+ #endif //BUILD_UPNP
md=sal_call_get_final_media_description(op);
call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
if (call->referer) linphone_core_notify_refer_state(lc,call->referer,call);
}
if (md && !sal_media_description_empty(md) && !linphone_core_incompatible_security(lc,md)){
+ linphone_call_update_remote_session_id_and_ver(call);
if (sal_media_description_has_dir(md,SalStreamSendOnly) ||
sal_media_description_has_dir(md,SalStreamInactive)){
if (lc->vtable.display_status){
linphone_core_update_ice_from_remote_media_description(call,rmd);
linphone_core_update_local_media_description_from_ice(call->localdesc,call->ice_session);
}
+ #ifdef BUILD_UPNP
+ if(call->upnp_session != NULL) {
+ linphone_core_update_upnp_from_remote_media_description(call, rmd);
+ 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_accept(call->op);
md=sal_call_get_final_media_description(call->op);
if (md && !sal_media_description_empty(md))
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Call terminated."));
+ #ifdef BUILD_UPNP
+ linphone_call_delete_upnp_session(call);
+ #endif //BUILD_UPNP
+
linphone_call_set_state(call, LinphoneCallEnd,"Call ended");
}
if (call->state==LinphoneCallOutgoingInit || call->state==LinphoneCallOutgoingProgress){
/* clear SRTP local params */
call->params.media_encryption = LinphoneMediaEncryptionNone;
- for(i=0; i<call->localdesc->nstreams; i++) {
+ for(i=0; i<call->localdesc->n_active_streams; i++) {
call->localdesc->streams[i].proto = SalProtoRtpAvp;
memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
}
/*resume to the call that send us the refer automatically*/
linphone_core_resume_call(lc,call->referer);
}
+
+ #ifdef BUILD_UPNP
+ linphone_call_delete_upnp_session(call);
+ #endif //BUILD_UPNP
+
if (sr == SalReasonDeclined) {
call->reason=LinphoneReasonDeclined;
linphone_call_set_state(call,LinphoneCallEnd,"Call declined.");
propagate_encryption_changed(call);
}
-static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate){
+static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandwidth_limit,int* max_sample_rate, int nb_codecs_limit){
MSList *l=NULL;
const MSList *it;
+ int nb = 0;
if (max_sample_rate) *max_sample_rate=0;
for(it=codecs;it!=NULL;it=it->next){
PayloadType *pt=(PayloadType*)it->data;
}
if (linphone_core_check_payload_type_usability(lc,pt)){
l=ms_list_append(l,payload_type_clone(pt));
+ nb++;
if (max_sample_rate && payload_type_get_rate(pt)>*max_sample_rate) *max_sample_rate=payload_type_get_rate(pt);
}
}
+ if ((nb_codecs_limit > 0) && (nb >= nb_codecs_limit)) break;
}
return l;
}
static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
- if (ac->port!=0){
- strcpy(md->streams[0].rtp_addr,ac->addr);
- md->streams[0].rtp_port=ac->port;
- if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){
- strcpy(md->addr,ac->addr);
+ int i;
+ for (i = 0; i < md->n_active_streams; i++) {
+ if ((md->streams[i].type == SalAudio) && (ac->port != 0)) {
+ strcpy(md->streams[0].rtp_addr,ac->addr);
+ md->streams[0].rtp_port=ac->port;
+ if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->n_active_streams==1){
+ strcpy(md->addr,ac->addr);
+ }
+ }
+ if ((md->streams[i].type == SalVideo) && (vc->port != 0)) {
+ strcpy(md->streams[1].rtp_addr,vc->addr);
+ md->streams[1].rtp_port=vc->port;
}
}
- if (vc->port!=0){
- strcpy(md->streams[1].rtp_addr,vc->addr);
- md->streams[1].rtp_port=vc->port;
- }
-
}
void linphone_call_make_local_media_description(LinphoneCore *lc, LinphoneCall *call){
const char *username=linphone_address_get_username (addr);
SalMediaDescription *md=sal_media_description_new();
bool_t keep_srtp_keys=lp_config_get_int(lc->config,"sip","keep_srtp_keys",0);
-
+
linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
md->session_id=(old_md ? old_md->session_id : (rand() & 0xfff));
md->session_ver=(old_md ? (old_md->session_ver+1) : (rand() & 0xfff));
- md->nstreams=1;
+ md->n_total_streams=(old_md ? old_md->n_total_streams : 1);
+ md->n_active_streams=1;
strncpy(md->addr,call->localip,sizeof(md->addr));
strncpy(md->username,username,sizeof(md->username));
md->streams[0].ptime=call->params.down_ptime;
else
md->streams[0].ptime=linphone_core_get_download_ptime(lc);
- l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate);
+ l=make_codec_list(lc,lc->codecs_conf.audio_codecs,call->params.audio_bw,&md->streams[0].max_rate,-1);
pt=payload_type_clone(rtp_profile_get_payload_from_mime(lc->default_profile,"telephone-event"));
l=ms_list_append(l,pt);
md->streams[0].payloads=l;
if (call->params.has_video){
- md->nstreams++;
+ md->n_active_streams++;
md->streams[1].rtp_port=call->video_port;
md->streams[1].rtcp_port=call->video_port+1;
md->streams[1].proto=md->streams[0].proto;
md->streams[1].type=SalVideo;
- l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL);
+ l=make_codec_list(lc,lc->codecs_conf.video_codecs,0,NULL,-1);
md->streams[1].payloads=l;
}
-
- for(i=0; i<md->nstreams; i++) {
+ if (md->n_total_streams < md->n_active_streams)
+ md->n_total_streams = md->n_active_streams;
+
+ /* Deactivate inactive streams. */
+ for (i = md->n_active_streams; i < md->n_total_streams; i++) {
+ md->streams[i].rtp_port = 0;
+ md->streams[i].rtcp_port = 0;
+ md->streams[i].proto = SalProtoRtpAvp;
+ md->streams[i].type = old_md->streams[i].type;
+ md->streams[i].dir = SalStreamInactive;
+ l = make_codec_list(lc, lc->codecs_conf.video_codecs, 0, NULL, 1);
+ md->streams[i].payloads = l;
+ }
+
+ for(i=0; i<md->n_active_streams; i++) {
if (md->streams[i].proto == SalProtoRtpSavp) {
if (keep_srtp_keys && old_md && old_md->streams[i].proto==SalProtoRtpSavp){
int j;
linphone_core_update_local_media_description_from_ice(md, call->ice_session);
linphone_core_update_ice_state_in_call_stats(call);
}
+ #ifdef BUILD_UPNP
+ if(call->upnp_session != NULL) {
+ linphone_core_update_local_media_description_from_upnp(md, call->upnp_session);
+ linphone_core_update_upnp_state_in_call_stats(call);
+ }
+ #endif //BUILD_UPNP
linphone_address_destroy(addr);
call->localdesc=md;
if (old_md) sal_media_description_unref(old_md);
stats->received_rtcp = NULL;
stats->sent_rtcp = NULL;
stats->ice_state = LinphoneIceStateNotActivated;
+ #ifdef BUILD_UPNP
+ stats->upnp_state = LinphoneUpnpStateIdle;
+ #else
+ stats->upnp_state = LinphoneUpnpStateNotAvailable;
+ #endif //BUILD_UPNP
}
if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
call->ping_time=linphone_core_run_stun_tests(call->core,call);
}
+ #ifdef BUILD_UPNP
+ if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
+ call->upnp_session = linphone_upnp_session_new(call);
+ }
+ #endif //BUILD_UPNP
call->camera_active=params->has_video;
discover_mtu(lc,linphone_address_get_domain (to));
case LinphonePolicyUseStun:
call->ping_time=linphone_core_run_stun_tests(call->core,call);
/* No break to also destroy ice session in this case. */
+ break;
+ case LinphonePolicyUseUpnp:
+ #ifdef BUILD_UPNP
+ call->upnp_session = linphone_upnp_session_new(call);
+ if (call->upnp_session != NULL) {
+ linphone_call_init_media_streams(call);
+ if (linphone_core_update_upnp_from_remote_media_description(call, sal_call_get_remote_media_description(op))<0) {
+ /* uPnP port mappings failed, proceed with the call anyway. */
+ linphone_call_delete_upnp_session(call);
+ }
+ }
+ #endif //BUILD_UPNP
+ break;
default:
break;
}
static void linphone_call_destroy(LinphoneCall *obj)
{
+ #ifdef BUILD_UPNP
+ linphone_call_delete_upnp_session(obj);
+ #endif //BUILD_UPNP
linphone_call_delete_ice_session(obj);
if (obj->op!=NULL) {
sal_op_release(obj->op);
new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalAudio);
if (old_stream && new_stream) {
const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalAudio);
- int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
- if (crypto_idx >= 0) {
- audio_stream_enable_srtp(call->audiostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key);
- call->audiostream_encrypted = TRUE;
- } else {
- ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
- call->audiostream_encrypted = FALSE;
- }
- for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
- old_stream->crypto[i].tag = new_stream->crypto[i].tag;
- old_stream->crypto[i].algo = new_stream->crypto[i].algo;
- strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
+ if (local_st_desc) {
+ int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
+ if (crypto_idx >= 0) {
+ audio_stream_enable_srtp(call->audiostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key);
+ call->audiostream_encrypted = TRUE;
+ } else {
+ ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
+ call->audiostream_encrypted = FALSE;
+ }
+ for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
+ old_stream->crypto[i].tag = new_stream->crypto[i].tag;
+ old_stream->crypto[i].algo = new_stream->crypto[i].algo;
+ strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
+ }
}
}
new_stream = sal_media_description_find_stream(new_md, SalProtoRtpSavp, SalVideo);
if (old_stream && new_stream) {
const SalStreamDescription *local_st_desc = sal_media_description_find_stream(call->localdesc, SalProtoRtpSavp, SalVideo);
- int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
- if (crypto_idx >= 0) {
- video_stream_enable_strp(call->videostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key);
- call->videostream_encrypted = TRUE;
- } else {
- ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
- call->videostream_encrypted = FALSE;
- }
- for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
- old_stream->crypto[i].tag = new_stream->crypto[i].tag;
- old_stream->crypto[i].algo = new_stream->crypto[i].algo;
- strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
+ if (local_st_desc) {
+ int crypto_idx = find_crypto_index_from_tag(local_st_desc->crypto, new_stream->crypto_local_tag);
+ if (crypto_idx >= 0) {
+ video_stream_enable_strp(call->videostream, new_stream->crypto[0].algo, local_st_desc->crypto[crypto_idx].master_key, new_stream->crypto[0].master_key);
+ call->videostream_encrypted = TRUE;
+ } else {
+ ms_warning("Failed to find local crypto algo with tag: %d", new_stream->crypto_local_tag);
+ call->videostream_encrypted = FALSE;
+ }
+ for (i = 0; i < SAL_CRYPTO_ALGO_MAX; i++) {
+ old_stream->crypto[i].tag = new_stream->crypto[i].tag;
+ old_stream->crypto[i].algo = new_stream->crypto[i].algo;
+ strncpy(old_stream->crypto[i].master_key, new_stream->crypto[i].master_key, sizeof(old_stream->crypto[i].master_key) - 1);
+ }
}
}
#endif
}
+void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call) {
+ SalMediaDescription *remote_desc = sal_call_get_remote_media_description(call->op);
+ if (remote_desc) {
+ call->remote_session_id = remote_desc->session_id;
+ call->remote_session_ver = remote_desc->session_ver;
+ }
+}
+
void linphone_call_delete_ice_session(LinphoneCall *call){
if (call->ice_session != NULL) {
ice_session_destroy(call->ice_session);
}
}
+ #ifdef BUILD_UPNP
+ void linphone_call_delete_upnp_session(LinphoneCall *call){
+ if(call->upnp_session!=NULL) {
+ linphone_upnp_session_destroy(call->upnp_session);
+ call->upnp_session=NULL;
+ }
+ }
+ #endif //BUILD_UPNP
+
static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
audio_stream_get_local_rtp_stats (st,&log->local_stats);
log->quality=audio_stream_get_average_quality_rating(st);
report_bandwidth(call,as,vs);
ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
}
+
+ #ifdef BUILD_UPNP
+ linphone_upnp_call_process(call);
+ #endif //BUILD_UPNP
+
#ifdef VIDEO_ENABLED
if (call->videostream!=NULL) {
OrtpEvent *ev;
#include "enum.h"
const char *linphone_core_get_nat_address_resolved(LinphoneCore *lc);
- void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result);
static void toggle_video_preview(LinphoneCore *lc, bool_t val);
/* relative path where is stored local ring*/
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));
}
/**
- * 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);
/**
* Returns whether adaptive rate control is enabled.
+ *
+ * @ingroup media_parameters
*
* See linphone_core_enable_adaptive_rate_control().
**/
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);
* 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);
* 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);
lc->tunnel=linphone_core_tunnel_new(lc);
if (lc->tunnel) linphone_tunnel_configure(lc->tunnel);
#endif
+ #ifdef BUILD_UPNP
+ lc->upnp = linphone_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;
* 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)
{
* 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)
{
strncpy(result,ip,LINPHONE_IPADDR_SIZE);
return;
}
+ #ifdef BUILD_UPNP
+ else if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
+ 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
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 */
/**
* 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)
{
/**
* 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)
{
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){
/**
* 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 <sip:username@domain:port> .
* Basically this function performs the following tasks
int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){
bool_t ice_ready = FALSE;
+ bool_t upnp_ready = FALSE;
bool_t ping_ready = FALSE;
if (call->ice_session != NULL) {
} else {
ice_ready = TRUE;
}
+ #ifdef BUILD_UPNP
+ if (call->upnp_session != NULL) {
+ if (linphone_upnp_session_get_state(call->upnp_session) == LinphoneUpnpStateOk) upnp_ready = TRUE;
+ } else {
+ upnp_ready = TRUE;
+ }
+ #endif //BUILD_UPNP
if (call->ping_op != NULL) {
if (call->ping_replied == TRUE) ping_ready = TRUE;
} else {
ping_ready = TRUE;
}
- if ((ice_ready == TRUE) && (ping_ready == TRUE)) {
+ if ((ice_ready == TRUE) && (upnp_ready == TRUE) && (ping_ready == TRUE)) {
return linphone_core_start_invite(lc, call);
}
return 0;
LinphoneAddress *parsed_url2=NULL;
char *real_url=NULL;
LinphoneCall *call;
- bool_t use_ice = FALSE;
+ bool_t defer = FALSE;
linphone_core_preempt_sound_resources(lc);
linphone_call_delete_ice_session(call);
linphone_call_stop_media_streams_for_ice_gathering(call);
} else {
- use_ice = TRUE;
+ defer = TRUE;
}
}
+ else if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseUpnp) {
+ #ifdef BUILD_UPNP
+ linphone_call_init_media_streams(call);
+ call->start_time=time(NULL);
+ if (linphone_core_update_upnp(lc,call)<0) {
+ /* uPnP port mappings failed, proceed with the call anyway. */
+ linphone_call_delete_upnp_session(call);
+ } else {
+ defer = TRUE;
+ }
+ #endif //BUILD_UPNP
+ }
if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){
/*defer the start of the call after the OPTIONS ping*/
sal_op_set_user_pointer(call->ping_op,call);
call->start_time=time(NULL);
}else{
- if (use_ice==FALSE) linphone_core_start_invite(lc,call);
+ if (defer==FALSE) linphone_core_start_invite(lc,call);
}
if (real_url!=NULL) ms_free(real_url);
/**
* 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.
**/
* @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.
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;i<md->nstreams;i++){
+ for(i=0;i<md->n_active_streams;i++){
SalStreamDescription *sd=&md->streams[i];
if (sd->proto!=SalProtoRtpSavp){
return TRUE;
int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
const char *subject;
call->camera_active=call->params.has_video;
- if (call->ice_session != NULL)
+ if (call->ice_session != NULL) {
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
-
+ }
+ #ifdef BUILD_UPNP
+ if(call->upnp_session != NULL) {
+ linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
+ }
+ #endif //BUILD_UPNP
if (call->params.in_conference){
subject="Conference";
}else{
linphone_call_set_state(call,LinphoneCallUpdating,"Updating call");
#ifdef VIDEO_ENABLED
bool_t has_video = call->params.has_video;
- if ((call->ice_session != NULL) && (call->videostream != NULL) && !params->has_video) {
- ice_session_remove_check_list(call->ice_session, call->videostream->ms.ice_check_list);
- call->videostream->ms.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_make_local_media_description(lc, call);
- if ((call->ice_session != NULL) && !has_video && call->params.has_video) {
- /* Defer call update until the ICE candidates gathering process has finished. */
- ms_message("Defer call update to gather ICE candidates");
- linphone_call_init_video_stream(call);
- video_stream_prepare_video(call->videostream);
- if (linphone_core_gather_ice_candidates(lc,call)<0) {
- /* Ice candidates gathering failed, proceed with the call anyway. */
- linphone_call_delete_ice_session(call);
- } else return err;
+
+ // 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. */
+ ms_message("Defer call update to gather ICE candidates");
+ linphone_call_init_video_stream(call);
+ video_stream_prepare_video(call->videostream);
+ if (linphone_core_gather_ice_candidates(lc,call)<0) {
+ /* Ice candidates gathering failed, proceed with the call anyway. */
+ linphone_call_delete_ice_session(call);
+ } else {
+ return err;
+ }
+ }
+ #ifdef BUILD_UPNP
+ if(call->upnp_session != NULL) {
+ ms_message("Defer call update to add uPnP port mappings");
+ linphone_call_init_video_stream(call);
+ video_stream_prepare_video(call->videostream);
+ if (linphone_core_update_upnp(lc, call)<0) {
+ /* uPnP port mappings failed, proceed with the call anyway. */
+ linphone_call_delete_upnp_session(call);
+ } else {
+ return err;
+ }
+ }
+ #endif //BUILD_UPNP
}
#endif
err = linphone_core_start_update_call(lc, call);
}
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
}
+ #ifdef BUILD_UPNP
+ if(call->upnp_session != NULL) {
+ 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);
* @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
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
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)) {
} else return 0;
}
}
- #endif
+ #endif //VIDEO_ENABLED
}
+
+ #if 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(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
+
linphone_core_start_accept_call_update(lc, call);
return 0;
}
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."));
lc->ringstream=NULL;
}
linphone_call_stop_media_streams(call);
+
+ #ifdef BUILD_UPNP
+ linphone_call_delete_upnp_session(call);
+ #endif //BUILD_UPNP
+
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Call aborted") );
linphone_call_set_state(call,LinphoneCallError,error);
}
linphone_call_stop_media_streams(call);
+
+ #ifdef BUILD_UPNP
+ linphone_call_delete_upnp_session(call);
+ #endif //BUILD_UPNP
+
if (lc->vtable.display_status!=NULL)
lc->vtable.display_status(lc,_("Call ended") );
linphone_call_set_state(call,LinphoneCallEnd,"Call terminated");
/**
* 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
return -1;
}
linphone_call_make_local_media_description(lc,call);
- if (call->ice_session != NULL)
+ if (call->ice_session != NULL) {
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
+ }
+ #ifdef BUILD_UPNP
+ if(call->upnp_session != NULL) {
+ linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
+ }
+ #endif //BUILD_UPNP
if (sal_media_description_has_dir(call->resultdesc,SalStreamSendRecv)){
sal_media_description_set_dir(call->localdesc,SalStreamSendOnly);
subject="Call on hold";
/**
* Pause all currently running calls.
+ * @ingroup call_control
**/
int linphone_core_pause_all_calls(LinphoneCore *lc){
const MSList *elem;
if (call->audiostream) audio_stream_play(call->audiostream, NULL);
linphone_call_make_local_media_description(lc,the_call);
- if (call->ice_session != NULL)
+ if (call->ice_session != NULL) {
linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
+ }
+ #ifdef BUILD_UPNP
+ if(call->upnp_session != NULL) {
+ linphone_core_update_local_media_description_from_upnp(call->localdesc, call->upnp_session);
+ }
+ #endif //BUILD_UPNP
sal_call_set_local_media_description(call->op,call->localdesc);
sal_media_description_set_dir(call->localdesc,SalStreamSendRecv);
if (call->params.in_conference && !call->current_params.in_conference) subject="Conference";
* @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);
* @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);
/**
* 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);
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;
}
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){
usleep(50000);
#endif
}
+
+ #ifdef BUILD_UPNP
+ 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);
linphone_core_set_state(lc,LinphoneGlobalShutdown,"Shutting down");
*/
void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) {
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);
**/
typedef enum _LinphoneIceState LinphoneIceState;
+ /**
+ * Enum describing uPnP states.
+ * @ingroup initializing
+ **/
+ enum _LinphoneUpnpState{
+ LinphoneUpnpStateIdle, /**< uPnP is not activate */
+ LinphoneUpnpStatePending, /**< uPnP process is in progress */
+ LinphoneUpnpStateAdding, /**< Internal use: Only used by port binding */
+ LinphoneUpnpStateRemoving, /**< Internal use: Only used by port binding */
+ LinphoneUpnpStateNotAvailable, /**< uPnP is not available */
+ LinphoneUpnpStateOk, /**< uPnP is enabled */
+ LinphoneUpnpStateKo, /**< uPnP processing has failed */
+ };
+
+ /**
+ * Enum describing uPnP states.
+ * @ingroup initializing
+ **/
+ typedef enum _LinphoneUpnpState LinphoneUpnpState;
+
+
/**
* The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams.
*
mblk_t* sent_rtcp;/**<Last RTCP packet sent, as a mblk_t structure. See oRTP documentation for details how to extract information from it*/
float round_trip_delay; /**<Round trip propagation time in seconds if known, -1 if unknown.*/
LinphoneIceState ice_state; /**< State of ICE processing. */
+ LinphoneUpnpState upnp_state; /**< State of uPnP processing. */
float download_bandwidth; /**<Download bandwidth measurement of received stream, expressed in kbit/s, including IP/UDP/RTP headers*/
float upload_bandwidth; /**<Download bandwidth measurement of sent stream, expressed in kbit/s, including IP/UDP/RTP headers*/
};
LinphonePolicyNoFirewall,
LinphonePolicyUseNatAddress,
LinphonePolicyUseStun,
- LinphonePolicyUseIce
+ LinphonePolicyUseIce,
+ LinphonePolicyUseUpnp,
} LinphoneFirewallPolicy;
typedef enum _LinphoneWaitingState{
void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled);
bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc);
-/**
- * set audio packetization time linphone expect to receive from peer
- * @ingroup media_parameters
- *
- */
+
void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime);
-/**
- * get audio packetization time linphone expect to receive from peer, 0 means unspecified
- * @ingroup media_parameters
- */
int linphone_core_get_download_ptime(LinphoneCore *lc);
void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime);
*/
#define LINPHONE_FIND_PAYLOAD_IGNORE_CHANNELS -1
/**
- * Get payload type from mime type and clock rate
+ * Get payload type from mime type and clock rate
* @ingroup media_parameters
* This function searches in audio and video codecs for the given payload type name and clockrate.
* @param lc #LinphoneCore object
}
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;
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)) {
}
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')) {
}
/* 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) {
}
}
}
- 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);
{
int i;
- for (i = 0; i < md->nstreams; i++) {
- if ((md->streams[i].type == SalVideo) && (md->streams[i].rtp_port != 0))
+ for (i = 0; i < md->n_active_streams; i++) {
+ if (md->streams[i].type == SalVideo)
return TRUE;
}
return FALSE;
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;
+ }
}
}
}
}
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
extern "C" {
#endif
#include "linphonecore.h"
+ #include "linphonefriend.h"
#include "linphone_tunnel.h"
#include "linphonecore_utils.h"
#include "sal.h"
+ #include "sipsetup.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "mediastreamer2/ice.h"
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msconference.h"
+ #ifdef BUILD_UPNP
+ #include "upnp.h"
+ #endif //BUILD_UPNP
#ifndef LIBLINPHONE_VERSION
#define LIBLINPHONE_VERSION LINPHONE_VERSION
OrtpEvQueue *videostream_app_evq;
CallCallbackObj nextVideoFrameDecoded;
LinphoneCallStats stats[2];
+ #ifdef BUILD_UPNP
+ UpnpSession *upnp_session;
+ #endif //BUILD_UPNP
IceSession *ice_session;
LinphoneChatMessage* pending_message;
int ping_time;
+ unsigned int remote_session_id;
+ unsigned int remote_session_ver;
bool_t refer_pending;
bool_t media_pending;
bool_t audio_muted;
void linphone_call_stop_video_stream(LinphoneCall *call);
void linphone_call_stop_media_streams(LinphoneCall *call);
void linphone_call_delete_ice_session(LinphoneCall *call);
+ void linphone_call_delete_upnp_session(LinphoneCall *call);
void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call);
void linphone_call_update_crypto_parameters(LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md);
+void linphone_call_update_remote_session_id_and_ver(LinphoneCall *call);
const char * linphone_core_get_identity(LinphoneCore *lc);
const char * linphone_core_get_route(LinphoneCore *lc);
bool_t register_only_when_network_is_up;
bool_t ping_with_options;
bool_t auto_net_state_mon;
+ bool_t tcp_tls_keepalive;
} sip_config_t;
typedef struct rtp_config
bool_t network_reachable;
bool_t use_preview_window;
- time_t network_last_check;
- bool_t network_last_status;
+ time_t network_last_check;
+ bool_t network_last_status;
bool_t ringstream_autorelease;
bool_t pad[3];
LinphoneTunnel *tunnel;
char* device_id;
MSList *last_recv_msg_ids;
+ #ifdef BUILD_UPNP
+ UpnpContext *upnp;
+ #endif //BUILD_UPNP
};
LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc);
void linphone_tunnel_destroy(LinphoneTunnel *tunnel);
void linphone_tunnel_configure(LinphoneTunnel *tunnel);
void linphone_tunnel_enable_logs_with_handler(LinphoneTunnel *tunnel, bool_t enabled, OrtpLogFunc logHandler);
-
+
bool_t linphone_core_can_we_add_call(LinphoneCore *lc);
int linphone_core_add_call( LinphoneCore *lc, LinphoneCall *call);
int linphone_core_del_call( LinphoneCore *lc, LinphoneCall *call);
int linphone_core_get_edge_bw(LinphoneCore *lc);
int linphone_core_get_edge_ptime(LinphoneCore *lc);
+ int linphone_upnp_init(LinphoneCore *lc);
+ void linphone_upnp_destroy(LinphoneCore *lc);
+
#ifdef __cplusplus
}
#endif
- Subproject commit 3a231efb89305d775ab39a6866ee981a891aed7e
-Subproject commit b21f304297319e15fbe0beb3509592022eb8e88a
++Subproject commit 2e0ef7e31e919b524cfbe1ff4ffbc409fce3599c