/*result must be an array of chars at least LINPHONE_IPADDR_SIZE */
-void linphone_core_get_public_ip(LinphoneCore *lc, const char *dest, char *result){
+void linphone_core_get_local_ip(LinphoneCore *lc, const char *dest, char *result){
const char *ip;
if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseNatAddress
&& (ip=linphone_core_get_nat_address_resolved(lc))!=NULL){
&& lc->upnp.state == LinphoneUpnpStateOk) {
ip = upnp_igd_get_external_ipaddress(lc->upnp.upnp_igd_ctxt);
strncpy(result,ip,LINPHONE_IPADDR_SIZE);
+ return;
}
#endif
if (linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,dest,result)==0)
ms_error("Could not parse identity contact !");
url=linphone_address_new("sip:unknown@unkwownhost");
}
- linphone_core_get_public_ip(lc, NULL, tmp);
+ linphone_core_get_local_ip(lc, NULL, tmp);
if (strcmp(tmp,"127.0.0.1")==0 || strcmp(tmp,"::1")==0 ){
ms_warning("Local loopback network only !");
lc->sip_conf.loopback_only=TRUE;
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 (call->upnp_session->state == 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;
#if BUILD_UPNP
if(call->upnp_session != NULL) {
+ 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) {
+ /* uPnP update failed, proceed with the call anyway. */
+ linphone_call_delete_upnp_session(call);
+ } else return 0;
+ }
}
#endif //BUILD_UPNP
lc->config = NULL; /* Mark the config as NULL to block further calls */
sip_setup_unregister_all();
+#ifdef BUILD_UPNP
+ upnp_context_uninit(lc);
+#endif
+
ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy);
lc->call_logs=ms_list_free(lc->call_logs);
#ifdef TUNNEL_ENABLED
if (lc->tunnel) linphone_tunnel_destroy(lc->tunnel);
#endif
-#ifdef BUILD_UPNP
- upnp_context_uninit(lc);
-#endif
}
static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime){
UpnpPortBinding *upnp_port_binding_copy(const UpnpPortBinding *port);
bool_t upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2);
UpnpPortBinding *upnp_port_binding_retain(UpnpPortBinding *port);
+void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port);
void upnp_port_binding_release(UpnpPortBinding *port);
MSList *upnp_config_list_port_bindings(struct _LpConfig *lpc);
int upnp_context_send_remove_port_binding(LinphoneCore *lc, UpnpPortBinding *port);
int upnp_context_send_add_port_binding(LinphoneCore *lc, UpnpPortBinding *port);
+
/**
* uPnP Callbacks
*/
ortp_level = ORTP_MESSAGE;
break;
case UPNP_IGD_WARNING:
- ortp_level = ORTP_WARNING;
+ ortp_level = ORTP_DEBUG; // Too verbose otherwise
break;
case UPNP_IGD_ERROR:
- ortp_level = ORTP_ERROR;
+ ortp_level = ORTP_DEBUG; // Too verbose otherwise
break;
default:
break;
port_mapping = (UpnpPortBinding*) mapping->cookie;
port_mapping->external_port = mapping->remote_port;
port_mapping->state = LinphoneUpnpStateOk;
- ms_message("uPnP IGD: Added port binding %s|%d->%s:%d",
- (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
- port_mapping->external_port,
- port_mapping->local_addr,
- port_mapping->local_port);
+ upnp_port_binding_log(ORTP_MESSAGE, "Added port binding", port_mapping);
upnp_config_add_port_binding(lc, port_mapping);
upnp_port_binding_release(port_mapping);
mapping = (upnp_igd_port_mapping *) arg;
port_mapping = (UpnpPortBinding*) mapping->cookie;
if(upnp_context_send_add_port_binding(lc, port_mapping) != 0) {
- ms_error("uPnP IGD: Can't add port binding %s|%d->%s:%d",
- (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
- port_mapping->external_port,
- port_mapping->local_addr,
- port_mapping->local_port);
+ upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping);
}
upnp_port_binding_release(port_mapping);
mapping = (upnp_igd_port_mapping *) arg;
port_mapping = (UpnpPortBinding*) mapping->cookie;
port_mapping->state = LinphoneUpnpStateIdle;
- ms_message("uPnP IGD: Removed port binding %s|%d->%d",
- (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
- port_mapping->external_port,
- port_mapping->local_port);
+ upnp_port_binding_log(ORTP_MESSAGE, "Removed port binding", port_mapping);
upnp_config_remove_port_binding(lc, port_mapping);
upnp_port_binding_release(port_mapping);
mapping = (upnp_igd_port_mapping *) arg;
port_mapping = (UpnpPortBinding*) mapping->cookie;
if(upnp_context_send_remove_port_binding(lc, port_mapping) != 0) {
- ms_error("uPnP IGD: Can't remove port binding %s|%d->%d",
- (port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
- port_mapping->external_port,
- port_mapping->local_port);
+ upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping);
upnp_config_remove_port_binding(lc, port_mapping);
}
UpnpContext *lupnp = &lc->upnp;
upnp_igd_port_mapping mapping;
int ret;
- if(port->state == LinphoneUpnpStateIdle) {
+ if(port->state == LinphoneUpnpStateOk) {
port->retry = 0;
port->state = LinphoneUpnpStateRemoving;
} else if(port->state != LinphoneUpnpStateRemoving) {
* uPnP Core interfaces
*/
-int upnp_call_process(LinphoneCall *call) {
+int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool_t video) {
LinphoneCore *lc = call->core;
UpnpContext *lupnp = &lc->upnp;
int ret = -1;
- UpnpState oldState;
const char *local_addr, *external_addr;
ms_mutex_lock(&lupnp->mutex);
strncpy(call->upnp_session->audio->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
strncpy(call->upnp_session->audio->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
call->upnp_session->audio->rtcp->local_port = call->audio_port+1;
- if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle && call->audiostream != NULL) {
+ if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle && audio) {
// Add audio port binding
upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtp);
- } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk && call->audiostream == NULL) {
+ } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk && !audio) {
// Remove audio port binding
upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtp);
}
- if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle && call->audiostream != NULL) {
+ if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle && audio) {
// Add audio port binding
upnp_context_send_add_port_binding(lc, call->upnp_session->audio->rtcp);
- } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk && call->audiostream == NULL) {
+ } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk && !audio) {
// Remove audio port binding
upnp_context_send_remove_port_binding(lc, call->upnp_session->audio->rtcp);
}
- if((call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle) &&
- (call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle)) {
- call->upnp_session->audio->state = LinphoneUpnpStateOk;
- } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateAdding ||
- call->upnp_session->audio->rtp->state == LinphoneUpnpStateRemoving ||
- call->upnp_session->audio->rtcp->state == LinphoneUpnpStateAdding ||
- call->upnp_session->audio->rtcp->state == LinphoneUpnpStateRemoving) {
- call->upnp_session->audio->state = LinphoneUpnpStatePending;
- } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateKo ||
- call->upnp_session->audio->rtp->state == LinphoneUpnpStateKo) {
- call->upnp_session->audio->state = LinphoneUpnpStateKo;
- } else {
- call->upnp_session->audio->state = LinphoneUpnpStateIdle;
- }
/*
* Video part
strncpy(call->upnp_session->video->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
strncpy(call->upnp_session->video->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
call->upnp_session->video->rtcp->local_port = call->video_port+1;
- if(call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle && call->videostream != NULL) {
+ if(call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle && video) {
// Add video port binding
upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtp);
- } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateOk && call->videostream == NULL) {
+ } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateOk && !video) {
// Remove video port binding
upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtp);
}
- if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle && call->videostream != NULL) {
+ if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle && video) {
// Add video port binding
upnp_context_send_add_port_binding(lc, call->upnp_session->video->rtcp);
- } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk && call->videostream == NULL) {
+ } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk && !video) {
// Remove video port binding
upnp_context_send_remove_port_binding(lc, call->upnp_session->video->rtcp);
}
+ }
+
+ ms_mutex_unlock(&lupnp->mutex);
+ return ret;
+}
+
+
+int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) {
+ bool_t audio = FALSE;
+ bool_t video = FALSE;
+ int i;
+ const SalStreamDescription *stream;
+
+ for (i = 0; i < md->nstreams; i++) {
+ stream = &md->streams[i];
+ if(stream->type == SalAudio) {
+ audio = TRUE;
+ } else if(stream->type == SalVideo) {
+ video = TRUE;
+ }
+ }
+
+ return linphone_core_update_upnp_audio_video(call, audio, video);
+}
+
+int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) {
+ return linphone_core_update_upnp_audio_video(call, call->audiostream!=NULL, call->videostream!=NULL);
+}
+
+int upnp_call_process(LinphoneCall *call) {
+ LinphoneCore *lc = call->core;
+ UpnpContext *lupnp = &lc->upnp;
+ int ret = -1;
+ UpnpState oldState;
+
+ ms_mutex_lock(&lupnp->mutex);
+
+ // Don't handle when the call
+ if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) {
+ ret = 0;
+
+ /*
+ * Update Audio state
+ */
+ if((call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle) &&
+ (call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle)) {
+ call->upnp_session->audio->state = LinphoneUpnpStateOk;
+ } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateAdding ||
+ call->upnp_session->audio->rtp->state == LinphoneUpnpStateRemoving ||
+ call->upnp_session->audio->rtcp->state == LinphoneUpnpStateAdding ||
+ call->upnp_session->audio->rtcp->state == LinphoneUpnpStateRemoving) {
+ call->upnp_session->audio->state = LinphoneUpnpStatePending;
+ } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateKo ||
+ call->upnp_session->audio->rtp->state == LinphoneUpnpStateKo) {
+ call->upnp_session->audio->state = LinphoneUpnpStateKo;
+ } else {
+ call->upnp_session->audio->state = LinphoneUpnpStateIdle;
+ }
+
+ /*
+ * Update Video state
+ */
if((call->upnp_session->video->rtp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle) &&
(call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle)) {
call->upnp_session->video->state = LinphoneUpnpStateOk;
/* When change is done proceed update */
if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo &&
(call->upnp_session->state == LinphoneUpnpStateOk || call->upnp_session->state == LinphoneUpnpStateKo)) {
+ if(call->upnp_session->state == LinphoneUpnpStateOk)
+ ms_message("uPnP IGD: uPnP for Call %p is ok", call);
+ else
+ ms_message("uPnP IGD: uPnP for Call %p is ko", call);
+
switch (call->state) {
case LinphoneCallUpdating:
- linphone_core_start_update_call(call->core, call);
+ linphone_core_start_update_call(lc, call);
break;
case LinphoneCallUpdatedByRemote:
- linphone_core_start_accept_call_update(call->core, call);
+ linphone_core_start_accept_call_update(lc, call);
break;
case LinphoneCallOutgoingInit:
- linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
+ linphone_core_proceed_with_invite_if_ready(lc, call, NULL);
break;
case LinphoneCallIdle:
- linphone_core_notify_incoming_call(call->core, call);
+ linphone_core_notify_incoming_call(lc, call);
break;
default:
break;
return ret;
}
-int linphone_core_update_upnp(LinphoneCore *lc, LinphoneCall *call) {
- return upnp_call_process(call);
-}
-
bool_t linphone_core_upnp_hook(void *data) {
char key[64];
MSList *port_bindings = NULL;
(port_mapping->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
port_mapping->external_port,
port_mapping->local_port);
- lp_config_set_string(lc->config, UPNP_SECTION_NAME, key, "");
+ lp_config_set_string(lc->config, UPNP_SECTION_NAME, key, "uPnP");
}
if(port_mapping->state == LinphoneUpnpStateRemoving) {
snprintf(key, sizeof(key), "%s-%d-%d",
return new_port;
}
+void upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port) {
+ if(strlen(port->local_addr)) {
+ ortp_log(level, "uPnP IGD: %s %s|%d->%s:%d", msg,
+ (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
+ port->external_port,
+ port->local_addr,
+ port->local_port);
+ } else {
+ ortp_log(level, "uPnP IGD: %s %s|%d->%d", msg,
+ (port->protocol == UPNP_IGD_IP_PROTOCOL_TCP)? "TCP":"UDP",
+ port->external_port,
+ port->local_port);
+ }
+}
+
bool_t upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2) {
return port1->protocol == port2->protocol && port1->local_port == port2->local_port &&
port1->external_port && port2->external_port;
ms_mutex_unlock(&port->mutex);
}
+
/*
* uPnP Stream
*/
stream->rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
stream->rtcp = upnp_port_binding_new();
stream->rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
- return NULL;
+ return stream;
}
void upnp_stream_destroy(UpnpStream* stream) {
session->state = LinphoneUpnpStateIdle;
session->audio = upnp_stream_new();
session->video = upnp_stream_new();
- return NULL;
+ return session;
}
void upnp_session_destroy(LinphoneCall* call) {
}
if(valid) {
port = upnp_port_binding_new();
+ port->state = LinphoneUpnpStateOk;
port->protocol = protocol;
port->external_port = external_port;
port->local_port = local_port;