|
|
|
|
@ -21,9 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
#include "private.h"
|
|
|
|
|
#include "lpconfig.h"
|
|
|
|
|
|
|
|
|
|
#define UPNP_ADD_MAX_RETRY 4
|
|
|
|
|
#define UPNP_ADD_MAX_RETRY 4
|
|
|
|
|
#define UPNP_REMOVE_MAX_RETRY 4
|
|
|
|
|
#define UPNP_SECTION_NAME "uPnP"
|
|
|
|
|
#define UPNP_SECTION_NAME "uPnP"
|
|
|
|
|
#define UPNP_CORE_READY_CHECK 1
|
|
|
|
|
#define UPNP_CORE_RETRY_DELAY 4
|
|
|
|
|
#define UPNP_CALL_RETRY_DELAY 1
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* uPnP Definitions
|
|
|
|
|
@ -41,6 +44,7 @@ typedef struct _UpnpPortBinding {
|
|
|
|
|
int ref;
|
|
|
|
|
bool_t to_remove;
|
|
|
|
|
bool_t to_add;
|
|
|
|
|
time_t last_update;
|
|
|
|
|
} UpnpPortBinding;
|
|
|
|
|
|
|
|
|
|
typedef struct _UpnpStream {
|
|
|
|
|
@ -69,7 +73,9 @@ struct _UpnpContext {
|
|
|
|
|
|
|
|
|
|
ms_mutex_t mutex;
|
|
|
|
|
ms_cond_t empty_cond;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
time_t last_ready_check;
|
|
|
|
|
LinphoneUpnpState last_ready_state;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -77,19 +83,24 @@ bool_t linphone_core_upnp_hook(void *data);
|
|
|
|
|
void linphone_core_upnp_refresh(UpnpContext *ctx);
|
|
|
|
|
|
|
|
|
|
UpnpPortBinding *linphone_upnp_port_binding_new();
|
|
|
|
|
UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port);
|
|
|
|
|
UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port);
|
|
|
|
|
UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port);
|
|
|
|
|
bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2);
|
|
|
|
|
UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port);
|
|
|
|
|
UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port);
|
|
|
|
|
void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay);
|
|
|
|
|
void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port);
|
|
|
|
|
void linphone_upnp_port_binding_release(UpnpPortBinding *port);
|
|
|
|
|
|
|
|
|
|
// Configuration
|
|
|
|
|
MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc);
|
|
|
|
|
void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
|
|
|
|
|
void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
|
|
|
|
|
|
|
|
|
|
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port);
|
|
|
|
|
int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port);
|
|
|
|
|
// uPnP
|
|
|
|
|
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry);
|
|
|
|
|
int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -172,7 +183,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
|
|
|
|
|
mapping = (upnp_igd_port_mapping *) arg;
|
|
|
|
|
port_mapping = (UpnpPortBinding*) mapping->cookie;
|
|
|
|
|
port_mapping->external_port = -1; //Force random external port
|
|
|
|
|
if(linphone_upnp_context_send_add_port_binding(lupnp, port_mapping) != 0) {
|
|
|
|
|
if(linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, TRUE) != 0) {
|
|
|
|
|
linphone_upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -190,7 +201,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
|
|
|
|
|
case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE:
|
|
|
|
|
mapping = (upnp_igd_port_mapping *) arg;
|
|
|
|
|
port_mapping = (UpnpPortBinding*) mapping->cookie;
|
|
|
|
|
if(linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping) != 0) {
|
|
|
|
|
if(linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE) != 0) {
|
|
|
|
|
linphone_upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping);
|
|
|
|
|
linphone_upnp_config_remove_port_binding(lupnp, port_mapping);
|
|
|
|
|
}
|
|
|
|
|
@ -208,7 +219,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
|
|
|
|
|
if(port_mapping->to_remove) {
|
|
|
|
|
if(port_mapping->state == LinphoneUpnpStateOk) {
|
|
|
|
|
port_mapping->to_remove = FALSE;
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, FALSE);
|
|
|
|
|
} else if(port_mapping->state == LinphoneUpnpStateKo) {
|
|
|
|
|
port_mapping->to_remove = FALSE;
|
|
|
|
|
}
|
|
|
|
|
@ -216,7 +227,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
|
|
|
|
|
if(port_mapping->to_add) {
|
|
|
|
|
if(port_mapping->state == LinphoneUpnpStateIdle || port_mapping->state == LinphoneUpnpStateKo) {
|
|
|
|
|
port_mapping->to_add = FALSE;
|
|
|
|
|
linphone_upnp_context_send_add_port_binding(lupnp, port_mapping);
|
|
|
|
|
linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, FALSE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -239,13 +250,14 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
|
|
|
|
|
LCSipTransports transport;
|
|
|
|
|
UpnpContext *lupnp = (UpnpContext *)ms_new0(UpnpContext,1);
|
|
|
|
|
const char *ip_address;
|
|
|
|
|
|
|
|
|
|
ms_mutex_init(&lupnp->mutex, NULL);
|
|
|
|
|
ms_cond_init(&lupnp->empty_cond, NULL);
|
|
|
|
|
|
|
|
|
|
lupnp->last_ready_check = 0;
|
|
|
|
|
lupnp->last_ready_state = LinphoneUpnpStateIdle;
|
|
|
|
|
|
|
|
|
|
lupnp->lc = lc;
|
|
|
|
|
lupnp->pending_bindings = NULL;
|
|
|
|
|
lupnp->adding_configs = NULL;
|
|
|
|
|
@ -253,31 +265,10 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
|
|
|
|
|
lupnp->state = LinphoneUpnpStateIdle;
|
|
|
|
|
ms_message("uPnP IGD: New %p for core %p", lupnp, lc);
|
|
|
|
|
|
|
|
|
|
linphone_core_get_sip_transports(lc, &transport);
|
|
|
|
|
if(transport.udp_port != 0) {
|
|
|
|
|
lupnp->sip_udp = linphone_upnp_port_binding_new();
|
|
|
|
|
lupnp->sip_udp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
|
|
|
|
|
lupnp->sip_udp->local_port = transport.udp_port;
|
|
|
|
|
lupnp->sip_udp->external_port = transport.udp_port;
|
|
|
|
|
} else {
|
|
|
|
|
lupnp->sip_udp = NULL;
|
|
|
|
|
}
|
|
|
|
|
if(transport.tcp_port != 0) {
|
|
|
|
|
lupnp->sip_tcp = linphone_upnp_port_binding_new();
|
|
|
|
|
lupnp->sip_tcp->protocol = UPNP_IGD_IP_PROTOCOL_TCP;
|
|
|
|
|
lupnp->sip_tcp->local_port = transport.tcp_port;
|
|
|
|
|
lupnp->sip_tcp->external_port = transport.tcp_port;
|
|
|
|
|
} else {
|
|
|
|
|
lupnp->sip_tcp = NULL;
|
|
|
|
|
}
|
|
|
|
|
if(transport.tls_port != 0) {
|
|
|
|
|
lupnp->sip_tls = linphone_upnp_port_binding_new();
|
|
|
|
|
lupnp->sip_tls->protocol = UPNP_IGD_IP_PROTOCOL_TCP;
|
|
|
|
|
lupnp->sip_tls->local_port = transport.tls_port;
|
|
|
|
|
lupnp->sip_tls->external_port = transport.tls_port;
|
|
|
|
|
} else {
|
|
|
|
|
lupnp->sip_tls = NULL;
|
|
|
|
|
}
|
|
|
|
|
// Init ports
|
|
|
|
|
lupnp->sip_udp = NULL;
|
|
|
|
|
lupnp->sip_tcp = NULL;
|
|
|
|
|
lupnp->sip_tls = NULL;
|
|
|
|
|
|
|
|
|
|
linphone_core_add_iterate_hook(lc, linphone_core_upnp_hook, lupnp);
|
|
|
|
|
|
|
|
|
|
@ -289,17 +280,6 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ip_address = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
|
|
|
|
|
if(lupnp->sip_udp != NULL) {
|
|
|
|
|
strncpy(lupnp->sip_udp->local_addr, ip_address, sizeof(lupnp->sip_udp->local_addr));
|
|
|
|
|
}
|
|
|
|
|
if(lupnp->sip_tcp != NULL) {
|
|
|
|
|
strncpy(lupnp->sip_tcp->local_addr, ip_address, sizeof(lupnp->sip_tcp->local_addr));
|
|
|
|
|
}
|
|
|
|
|
if(lupnp->sip_tls != NULL) {
|
|
|
|
|
strncpy(lupnp->sip_tls->local_addr, ip_address, sizeof(lupnp->sip_tls->local_addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lupnp->state = LinphoneUpnpStatePending;
|
|
|
|
|
upnp_igd_start(lupnp->upnp_igd_ctxt);
|
|
|
|
|
|
|
|
|
|
@ -307,22 +287,19 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void linphone_upnp_context_destroy(UpnpContext *lupnp) {
|
|
|
|
|
/*
|
|
|
|
|
* Not need, all hooks are removed before
|
|
|
|
|
* linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc);
|
|
|
|
|
*/
|
|
|
|
|
linphone_core_remove_iterate_hook(lupnp->lc, linphone_core_upnp_hook, lupnp);
|
|
|
|
|
|
|
|
|
|
ms_mutex_lock(&lupnp->mutex);
|
|
|
|
|
|
|
|
|
|
/* Send port binding removes */
|
|
|
|
|
if(lupnp->sip_udp != NULL) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp, TRUE);
|
|
|
|
|
}
|
|
|
|
|
if(lupnp->sip_tcp != NULL) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp, TRUE);
|
|
|
|
|
}
|
|
|
|
|
if(lupnp->sip_tls != NULL) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Wait all pending bindings are done */
|
|
|
|
|
@ -368,15 +345,88 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
|
|
|
|
|
ms_free(lupnp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx) {
|
|
|
|
|
return ctx->state;
|
|
|
|
|
LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *lupnp) {
|
|
|
|
|
LinphoneUpnpState state;
|
|
|
|
|
ms_mutex_lock(&lupnp->mutex);
|
|
|
|
|
state = lupnp->state;
|
|
|
|
|
ms_mutex_unlock(&lupnp->mutex);
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx) {
|
|
|
|
|
return upnp_igd_get_external_ipaddress(ctx->upnp_igd_ctxt);
|
|
|
|
|
bool_t _linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) {
|
|
|
|
|
bool_t ready = TRUE;
|
|
|
|
|
|
|
|
|
|
// 1 Check global uPnP state
|
|
|
|
|
ready = (lupnp->state == LinphoneUpnpStateOk);
|
|
|
|
|
|
|
|
|
|
// 2 Check external ip address
|
|
|
|
|
if(ready) {
|
|
|
|
|
if (upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt) == NULL) {
|
|
|
|
|
ready = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3 Check sip ports bindings
|
|
|
|
|
if(ready) {
|
|
|
|
|
if(lupnp->sip_udp != NULL) {
|
|
|
|
|
if(lupnp->sip_udp->state != LinphoneUpnpStateOk) {
|
|
|
|
|
ready = FALSE;
|
|
|
|
|
}
|
|
|
|
|
} else if(lupnp->sip_tcp != NULL) {
|
|
|
|
|
if(lupnp->sip_tcp->state != LinphoneUpnpStateOk) {
|
|
|
|
|
ready = FALSE;
|
|
|
|
|
}
|
|
|
|
|
} else if(lupnp->sip_tls != NULL) {
|
|
|
|
|
if(lupnp->sip_tls->state != LinphoneUpnpStateOk) {
|
|
|
|
|
ready = FALSE;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ready = FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ready;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) {
|
|
|
|
|
bool_t linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) {
|
|
|
|
|
bool_t ready;
|
|
|
|
|
ms_mutex_lock(&lupnp->mutex);
|
|
|
|
|
ready = _linphone_upnp_context_is_ready_for_register(lupnp);
|
|
|
|
|
ms_mutex_unlock(&lupnp->mutex);
|
|
|
|
|
return ready;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int linphone_upnp_context_get_external_port(UpnpContext *lupnp) {
|
|
|
|
|
int port = -1;
|
|
|
|
|
ms_mutex_lock(&lupnp->mutex);
|
|
|
|
|
|
|
|
|
|
if(lupnp->sip_udp != NULL) {
|
|
|
|
|
if(lupnp->sip_udp->state == LinphoneUpnpStateOk) {
|
|
|
|
|
port = lupnp->sip_udp->external_port;
|
|
|
|
|
}
|
|
|
|
|
} else if(lupnp->sip_tcp != NULL) {
|
|
|
|
|
if(lupnp->sip_tcp->state == LinphoneUpnpStateOk) {
|
|
|
|
|
port = lupnp->sip_tcp->external_port;
|
|
|
|
|
}
|
|
|
|
|
} else if(lupnp->sip_tls != NULL) {
|
|
|
|
|
if(lupnp->sip_tls->state == LinphoneUpnpStateOk) {
|
|
|
|
|
port = lupnp->sip_tls->external_port;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ms_mutex_unlock(&lupnp->mutex);
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *lupnp) {
|
|
|
|
|
const char* addr = NULL;
|
|
|
|
|
ms_mutex_lock(&lupnp->mutex);
|
|
|
|
|
addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
|
|
|
|
|
ms_mutex_unlock(&lupnp->mutex);
|
|
|
|
|
return addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) {
|
|
|
|
|
upnp_igd_port_mapping mapping;
|
|
|
|
|
char description[128];
|
|
|
|
|
int ret;
|
|
|
|
|
@ -404,6 +454,11 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No retry if specified
|
|
|
|
|
if(port->retry != 0 && !retry) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(port->retry >= UPNP_ADD_MAX_RETRY) {
|
|
|
|
|
ret = -1;
|
|
|
|
|
@ -435,7 +490,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) {
|
|
|
|
|
int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) {
|
|
|
|
|
upnp_igd_port_mapping mapping;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
@ -461,6 +516,11 @@ int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortB
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No retry if specified
|
|
|
|
|
if(port->retry != 0 && !retry) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(port->retry >= UPNP_REMOVE_MAX_RETRY) {
|
|
|
|
|
ret = -1;
|
|
|
|
|
@ -489,68 +549,34 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
|
|
|
|
|
LinphoneCore *lc = call->core;
|
|
|
|
|
UpnpContext *lupnp = lc->upnp;
|
|
|
|
|
int ret = -1;
|
|
|
|
|
const char *local_addr, *external_addr;
|
|
|
|
|
|
|
|
|
|
if(lupnp == NULL) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ms_mutex_lock(&lupnp->mutex);
|
|
|
|
|
|
|
|
|
|
// Don't handle when the call
|
|
|
|
|
if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) {
|
|
|
|
|
ret = 0;
|
|
|
|
|
local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
|
|
|
|
|
external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Audio part
|
|
|
|
|
*/
|
|
|
|
|
strncpy(call->upnp_session->audio->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
|
|
|
|
|
strncpy(call->upnp_session->audio->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
|
|
|
|
|
call->upnp_session->audio->rtp->local_port = call->audio_port;
|
|
|
|
|
if(call->upnp_session->audio->rtp->external_port == -1) {
|
|
|
|
|
call->upnp_session->audio->rtp->external_port = call->audio_port;
|
|
|
|
|
}
|
|
|
|
|
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->rtcp->external_port == -1) {
|
|
|
|
|
call->upnp_session->audio->rtcp->external_port = call->audio_port+1;
|
|
|
|
|
}
|
|
|
|
|
if(audio) {
|
|
|
|
|
// Add audio port binding
|
|
|
|
|
linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtp);
|
|
|
|
|
linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtcp);
|
|
|
|
|
} else {
|
|
|
|
|
// Remove audio port binding
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtp);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtcp);
|
|
|
|
|
}
|
|
|
|
|
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp,
|
|
|
|
|
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port:0, UPNP_CALL_RETRY_DELAY);
|
|
|
|
|
|
|
|
|
|
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp,
|
|
|
|
|
UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port+1:0, UPNP_CALL_RETRY_DELAY);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Video part
|
|
|
|
|
*/
|
|
|
|
|
strncpy(call->upnp_session->video->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
|
|
|
|
|
strncpy(call->upnp_session->video->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
|
|
|
|
|
call->upnp_session->video->rtp->local_port = call->video_port;
|
|
|
|
|
if(call->upnp_session->video->rtp->external_port == -1) {
|
|
|
|
|
call->upnp_session->video->rtp->external_port = call->video_port;
|
|
|
|
|
}
|
|
|
|
|
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->rtcp->external_port == -1) {
|
|
|
|
|
call->upnp_session->video->rtcp->external_port = call->video_port+1;
|
|
|
|
|
}
|
|
|
|
|
if(video) {
|
|
|
|
|
// Add video port binding
|
|
|
|
|
linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtp);
|
|
|
|
|
linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtcp);
|
|
|
|
|
} else {
|
|
|
|
|
// Remove video port binding
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtp);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtcp);
|
|
|
|
|
}
|
|
|
|
|
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp,
|
|
|
|
|
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port:0, UPNP_CALL_RETRY_DELAY);
|
|
|
|
|
|
|
|
|
|
linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp,
|
|
|
|
|
UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port+1:0, UPNP_CALL_RETRY_DELAY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ms_mutex_unlock(&lupnp->mutex);
|
|
|
|
|
@ -564,6 +590,7 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) {
|
|
|
|
|
bool_t audio = FALSE;
|
|
|
|
|
bool_t video = FALSE;
|
|
|
|
|
@ -591,6 +618,23 @@ void linphone_core_update_upnp_state_in_call_stats(LinphoneCall *call) {
|
|
|
|
|
call->stats[LINPHONE_CALL_STATS_VIDEO].upnp_state = call->upnp_session->video->state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void linphone_upnp_update_stream_state(UpnpStream *stream) {
|
|
|
|
|
if((stream->rtp == NULL || stream->rtp->state == LinphoneUpnpStateOk || stream->rtp->state == LinphoneUpnpStateIdle) &&
|
|
|
|
|
(stream->rtcp == NULL || stream->rtcp->state == LinphoneUpnpStateOk || stream->rtcp->state == LinphoneUpnpStateIdle)) {
|
|
|
|
|
stream->state = LinphoneUpnpStateOk;
|
|
|
|
|
} else if((stream->rtp != NULL &&
|
|
|
|
|
(stream->rtp->state == LinphoneUpnpStateAdding || stream->rtp->state == LinphoneUpnpStateRemoving)) ||
|
|
|
|
|
(stream->rtcp != NULL &&
|
|
|
|
|
(stream->rtcp->state == LinphoneUpnpStateAdding || stream->rtcp->state == LinphoneUpnpStateRemoving))) {
|
|
|
|
|
stream->state = LinphoneUpnpStatePending;
|
|
|
|
|
} else if((stream->rtp != NULL && stream->rtp->state == LinphoneUpnpStateKo) ||
|
|
|
|
|
(stream->rtcp != NULL && stream->rtcp->state == LinphoneUpnpStateKo)) {
|
|
|
|
|
stream->state = LinphoneUpnpStateKo;
|
|
|
|
|
} else {
|
|
|
|
|
ms_error("Invalid stream %p state", stream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int linphone_upnp_call_process(LinphoneCall *call) {
|
|
|
|
|
LinphoneCore *lc = call->core;
|
|
|
|
|
UpnpContext *lupnp = lc->upnp;
|
|
|
|
|
@ -610,38 +654,12 @@ int linphone_upnp_call_process(LinphoneCall *call) {
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
linphone_upnp_update_stream_state(call->upnp_session->audio);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
} else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateAdding ||
|
|
|
|
|
call->upnp_session->video->rtp->state == LinphoneUpnpStateRemoving ||
|
|
|
|
|
call->upnp_session->video->rtcp->state == LinphoneUpnpStateAdding ||
|
|
|
|
|
call->upnp_session->video->rtcp->state == LinphoneUpnpStateRemoving) {
|
|
|
|
|
call->upnp_session->video->state = LinphoneUpnpStatePending;
|
|
|
|
|
} else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateKo ||
|
|
|
|
|
call->upnp_session->video->rtp->state == LinphoneUpnpStateKo) {
|
|
|
|
|
call->upnp_session->video->state = LinphoneUpnpStateKo;
|
|
|
|
|
} else {
|
|
|
|
|
call->upnp_session->video->state = LinphoneUpnpStateIdle;
|
|
|
|
|
}
|
|
|
|
|
linphone_upnp_update_stream_state(call->upnp_session->video);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Update session state
|
|
|
|
|
@ -709,7 +727,6 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) {
|
|
|
|
|
|
|
|
|
|
ms_message("uPnP IGD: Refresh mappings");
|
|
|
|
|
|
|
|
|
|
/* Remove context port bindings */
|
|
|
|
|
if(lupnp->sip_udp != NULL) {
|
|
|
|
|
global_list = ms_list_append(global_list, lupnp->sip_udp);
|
|
|
|
|
}
|
|
|
|
|
@ -720,26 +737,32 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) {
|
|
|
|
|
global_list = ms_list_append(global_list, lupnp->sip_tls);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Remove call port bindings */
|
|
|
|
|
list = lupnp->lc->calls;
|
|
|
|
|
while(list != NULL) {
|
|
|
|
|
call = (LinphoneCall *)list->data;
|
|
|
|
|
if(call->upnp_session != NULL) {
|
|
|
|
|
global_list = ms_list_append(global_list, call->upnp_session->audio->rtp);
|
|
|
|
|
global_list = ms_list_append(global_list, call->upnp_session->audio->rtcp);
|
|
|
|
|
global_list = ms_list_append(global_list, call->upnp_session->video->rtp);
|
|
|
|
|
global_list = ms_list_append(global_list, call->upnp_session->video->rtcp);
|
|
|
|
|
if(call->upnp_session->audio->rtp != NULL) {
|
|
|
|
|
global_list = ms_list_append(global_list, call->upnp_session->audio->rtp);
|
|
|
|
|
}
|
|
|
|
|
if(call->upnp_session->audio->rtcp != NULL) {
|
|
|
|
|
global_list = ms_list_append(global_list, call->upnp_session->audio->rtcp);
|
|
|
|
|
}
|
|
|
|
|
if(call->upnp_session->video->rtp != NULL) {
|
|
|
|
|
global_list = ms_list_append(global_list, call->upnp_session->video->rtp);
|
|
|
|
|
}
|
|
|
|
|
if(call->upnp_session->video->rtcp != NULL) {
|
|
|
|
|
global_list = ms_list_append(global_list, call->upnp_session->video->rtcp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
list = list->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove port binding configurations
|
|
|
|
|
list = linphone_upnp_config_list_port_bindings(lupnp->lc->config);
|
|
|
|
|
for(item = list;item != NULL; item = item->next) {
|
|
|
|
|
port_mapping = (UpnpPortBinding *)item->data;
|
|
|
|
|
port_mapping2 = linphone_upnp_port_binding_equivalent_in_list(global_list, port_mapping);
|
|
|
|
|
if(port_mapping2 == NULL) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE);
|
|
|
|
|
} else if(port_mapping2->state == LinphoneUpnpStateIdle){
|
|
|
|
|
/* Force to remove */
|
|
|
|
|
port_mapping2->state = LinphoneUpnpStateOk;
|
|
|
|
|
@ -753,20 +776,96 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) {
|
|
|
|
|
list = global_list;
|
|
|
|
|
while(list != NULL) {
|
|
|
|
|
port_mapping = (UpnpPortBinding *)list->data;
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
|
|
|
|
|
linphone_upnp_context_send_add_port_binding(lupnp, port_mapping);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE);
|
|
|
|
|
linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, TRUE);
|
|
|
|
|
list = list->next;
|
|
|
|
|
}
|
|
|
|
|
global_list = ms_list_free(global_list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay) {
|
|
|
|
|
const char *local_addr, *external_addr;
|
|
|
|
|
time_t now = time(NULL);
|
|
|
|
|
if(port != 0) {
|
|
|
|
|
if(*port_mapping != NULL) {
|
|
|
|
|
if(port != (*port_mapping)->local_port) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE);
|
|
|
|
|
*port_mapping = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(*port_mapping == NULL) {
|
|
|
|
|
*port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get addresses
|
|
|
|
|
local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
|
|
|
|
|
external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
|
|
|
|
|
|
|
|
|
|
// Force binding update on local address change
|
|
|
|
|
if(local_addr != NULL) {
|
|
|
|
|
if(strncmp((*port_mapping)->local_addr, local_addr, sizeof((*port_mapping)->local_addr))) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE);
|
|
|
|
|
strncpy((*port_mapping)->local_addr, local_addr, sizeof((*port_mapping)->local_addr));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(external_addr != NULL) {
|
|
|
|
|
strncpy((*port_mapping)->external_addr, external_addr, sizeof((*port_mapping)->external_addr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add (if not already done) the binding
|
|
|
|
|
if(now - (*port_mapping)->last_update >= retry_delay) {
|
|
|
|
|
(*port_mapping)->last_update = now;
|
|
|
|
|
linphone_upnp_context_send_add_port_binding(lupnp, *port_mapping, FALSE);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if(*port_mapping != NULL) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE);
|
|
|
|
|
*port_mapping = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool_t linphone_core_upnp_hook(void *data) {
|
|
|
|
|
char key[64];
|
|
|
|
|
MSList *item;
|
|
|
|
|
LCSipTransports transport;
|
|
|
|
|
const MSList *item;
|
|
|
|
|
LinphoneUpnpState ready_state;
|
|
|
|
|
time_t now = time(NULL);
|
|
|
|
|
UpnpPortBinding *port_mapping;
|
|
|
|
|
UpnpContext *lupnp = (UpnpContext *)data;
|
|
|
|
|
|
|
|
|
|
ms_mutex_lock(&lupnp->mutex);
|
|
|
|
|
|
|
|
|
|
/* Update ports */
|
|
|
|
|
if(lupnp->state == LinphoneUpnpStateOk) {
|
|
|
|
|
linphone_core_get_sip_transports(lupnp->lc, &transport);
|
|
|
|
|
linphone_upnp_update_port_binding(lupnp, &lupnp->sip_udp, UPNP_IGD_IP_PROTOCOL_UDP, transport.udp_port, UPNP_CORE_RETRY_DELAY);
|
|
|
|
|
linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tcp, UPNP_IGD_IP_PROTOCOL_TCP, transport.tcp_port, UPNP_CORE_RETRY_DELAY);
|
|
|
|
|
linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tls, UPNP_IGD_IP_PROTOCOL_TCP, transport.tls_port, UPNP_CORE_RETRY_DELAY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Refresh registers if we are ready */
|
|
|
|
|
if(now - lupnp->last_ready_check >= UPNP_CORE_READY_CHECK) {
|
|
|
|
|
lupnp->last_ready_check = now;
|
|
|
|
|
ready_state = (_linphone_upnp_context_is_ready_for_register(lupnp))? LinphoneUpnpStateOk: LinphoneUpnpStateKo;
|
|
|
|
|
if(ready_state != lupnp->last_ready_state) {
|
|
|
|
|
for(item=linphone_core_get_proxy_config_list(lupnp->lc);item!=NULL;item=item->next) {
|
|
|
|
|
LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)item->data;
|
|
|
|
|
if (linphone_proxy_config_register_enabled(cfg)) {
|
|
|
|
|
if (ready_state != LinphoneUpnpStateOk) {
|
|
|
|
|
// Only reset ithe registration if we require that upnp should be ok
|
|
|
|
|
if(lupnp->lc->sip_conf.register_only_when_upnp_is_ok) {
|
|
|
|
|
linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone, "Registration impossible (uPnP not ready)");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
cfg->commit=TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lupnp->last_ready_state = ready_state;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add configs */
|
|
|
|
|
for(item = lupnp->adding_configs;item!=NULL;item=item->next) {
|
|
|
|
|
port_mapping = (UpnpPortBinding *)item->data;
|
|
|
|
|
@ -811,11 +910,11 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *
|
|
|
|
|
upnpStream = session->video;
|
|
|
|
|
}
|
|
|
|
|
if(upnpStream != NULL) {
|
|
|
|
|
if(upnpStream->rtp->state == LinphoneUpnpStateOk) {
|
|
|
|
|
if(upnpStream->rtp != NULL && upnpStream->rtp->state == LinphoneUpnpStateOk) {
|
|
|
|
|
strncpy(stream->rtp_addr, upnpStream->rtp->external_addr, LINPHONE_IPADDR_SIZE);
|
|
|
|
|
stream->rtp_port = upnpStream->rtp->external_port;
|
|
|
|
|
}
|
|
|
|
|
if(upnpStream->rtcp->state == LinphoneUpnpStateOk) {
|
|
|
|
|
if(upnpStream->rtcp != NULL && upnpStream->rtcp->state == LinphoneUpnpStateOk) {
|
|
|
|
|
strncpy(stream->rtcp_addr, upnpStream->rtcp->external_addr, LINPHONE_IPADDR_SIZE);
|
|
|
|
|
stream->rtcp_port = upnpStream->rtcp->external_port;
|
|
|
|
|
}
|
|
|
|
|
@ -834,6 +933,7 @@ UpnpPortBinding *linphone_upnp_port_binding_new() {
|
|
|
|
|
port = ms_new0(UpnpPortBinding,1);
|
|
|
|
|
ms_mutex_init(&port->mutex, NULL);
|
|
|
|
|
port->state = LinphoneUpnpStateIdle;
|
|
|
|
|
port->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
|
|
|
|
|
port->local_addr[0] = '\0';
|
|
|
|
|
port->local_port = -1;
|
|
|
|
|
port->external_addr[0] = '\0';
|
|
|
|
|
@ -841,9 +941,30 @@ UpnpPortBinding *linphone_upnp_port_binding_new() {
|
|
|
|
|
port->to_remove = FALSE;
|
|
|
|
|
port->to_add = FALSE;
|
|
|
|
|
port->ref = 1;
|
|
|
|
|
port->last_update = 0;
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port) {
|
|
|
|
|
UpnpPortBinding *port_binding = linphone_upnp_port_binding_new();
|
|
|
|
|
port_binding->protocol = protocol;
|
|
|
|
|
port_binding->local_port = local_port;
|
|
|
|
|
port_binding->external_port = external_port;
|
|
|
|
|
return port_binding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port) {
|
|
|
|
|
UpnpPortBinding *tmp_binding;
|
|
|
|
|
UpnpPortBinding *end_binding;
|
|
|
|
|
end_binding = linphone_upnp_port_binding_new_with_parameters(protocol, local_port, external_port);
|
|
|
|
|
tmp_binding = linphone_upnp_port_binding_equivalent_in_list(list, end_binding);
|
|
|
|
|
if(tmp_binding != NULL) {
|
|
|
|
|
linphone_upnp_port_binding_release(end_binding);
|
|
|
|
|
end_binding = tmp_binding;
|
|
|
|
|
}
|
|
|
|
|
return end_binding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port) {
|
|
|
|
|
UpnpPortBinding *new_port = NULL;
|
|
|
|
|
new_port = ms_new0(UpnpPortBinding,1);
|
|
|
|
|
@ -915,18 +1036,20 @@ void linphone_upnp_port_binding_release(UpnpPortBinding *port) {
|
|
|
|
|
UpnpStream* linphone_upnp_stream_new() {
|
|
|
|
|
UpnpStream *stream = ms_new0(UpnpStream,1);
|
|
|
|
|
stream->state = LinphoneUpnpStateIdle;
|
|
|
|
|
stream->rtp = linphone_upnp_port_binding_new();
|
|
|
|
|
stream->rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
|
|
|
|
|
stream->rtcp = linphone_upnp_port_binding_new();
|
|
|
|
|
stream->rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
|
|
|
|
|
stream->rtp = NULL;
|
|
|
|
|
stream->rtcp = NULL;
|
|
|
|
|
return stream;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void linphone_upnp_stream_destroy(UpnpStream* stream) {
|
|
|
|
|
linphone_upnp_port_binding_release(stream->rtp);
|
|
|
|
|
stream->rtp = NULL;
|
|
|
|
|
linphone_upnp_port_binding_release(stream->rtcp);
|
|
|
|
|
stream->rtcp = NULL;
|
|
|
|
|
if(stream->rtp != NULL) {
|
|
|
|
|
linphone_upnp_port_binding_release(stream->rtp);
|
|
|
|
|
stream->rtp = NULL;
|
|
|
|
|
}
|
|
|
|
|
if(stream->rtcp != NULL) {
|
|
|
|
|
linphone_upnp_port_binding_release(stream->rtcp);
|
|
|
|
|
stream->rtcp = NULL;
|
|
|
|
|
}
|
|
|
|
|
ms_free(stream);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -949,10 +1072,18 @@ void linphone_upnp_session_destroy(UpnpSession *session) {
|
|
|
|
|
|
|
|
|
|
if(lc->upnp != NULL) {
|
|
|
|
|
/* Remove bindings */
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp);
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp);
|
|
|
|
|
if(session->audio->rtp != NULL) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp, TRUE);
|
|
|
|
|
}
|
|
|
|
|
if(session->audio->rtcp != NULL) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp, TRUE);
|
|
|
|
|
}
|
|
|
|
|
if(session->video->rtp != NULL) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp, TRUE);
|
|
|
|
|
}
|
|
|
|
|
if(session->video->rtcp != NULL) {
|
|
|
|
|
linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
linphone_upnp_stream_destroy(session->audio);
|
|
|
|
|
@ -964,6 +1095,7 @@ LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session) {
|
|
|
|
|
return session->state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* uPnP Config
|
|
|
|
|
*/
|
|
|
|
|
|