summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-03-23 00:42:47 +0000
committerBenny Prijono <bennylp@teluu.com>2007-03-23 00:42:47 +0000
commit05e7998ba4cbd7fb0b02b7f82c5b328cf203fbc9 (patch)
tree1455c2739bef6d65706be32f0ddadcf2d8063f2f
parentf8d17a0d196e42dd886bcdd908085c810b3bba8d (diff)
ICE (work in progress): implemented ICE media transport
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1097 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/build/pjmedia.dsp12
-rw-r--r--pjmedia/include/pjmedia/transport.h13
-rw-r--r--pjmedia/include/pjmedia/transport_ice.h78
-rw-r--r--pjmedia/src/pjmedia/transport_ice.c549
-rw-r--r--pjmedia/src/pjmedia/transport_udp.c29
-rw-r--r--pjnath/include/pjnath/errno.h13
-rw-r--r--pjnath/src/pjnath/ice.c1
-rw-r--r--pjproject.dsw15
8 files changed, 697 insertions, 13 deletions
diff --git a/pjmedia/build/pjmedia.dsp b/pjmedia/build/pjmedia.dsp
index db649fdf..2e2e9617 100644
--- a/pjmedia/build/pjmedia.dsp
+++ b/pjmedia/build/pjmedia.dsp
@@ -41,7 +41,7 @@ RSC=rc.exe
# PROP Intermediate_Dir ".\output\pjmedia-i386-win32-vc6-release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD CPP /nologo /MD /W4 /GX /Zi /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /I "../src/pjmedia-codec" /D "NDEBUG" /D "PA_NO_ASIO" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
+# ADD CPP /nologo /MD /W4 /GX /Zi /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /I "../src/pjmedia-codec" /I "../../pjnath/include" /D "NDEBUG" /D "PA_NO_ASIO" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
@@ -65,7 +65,7 @@ LIB32=link.exe -lib
# PROP Intermediate_Dir ".\output\pjmedia-i386-win32-vc6-debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /I "../src/pjmedia-codec" /D "_DEBUG" /D "PA_NO_ASIO" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../src/pjmedia/portaudio" /I "../src/pjmedia-codec" /I "../../pjnath/include" /D "_DEBUG" /D "PA_NO_ASIO" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
@@ -244,6 +244,10 @@ SOURCE=..\src\pjmedia\tonegen.c
# End Source File
# Begin Source File
+SOURCE=..\src\pjmedia\transport_ice.c
+# End Source File
+# Begin Source File
+
SOURCE=..\src\pjmedia\transport_udp.c
# End Source File
# Begin Source File
@@ -400,6 +404,10 @@ SOURCE=..\include\pjmedia\transport.h
# End Source File
# Begin Source File
+SOURCE=..\include\pjmedia\transport_ice.h
+# End Source File
+# Begin Source File
+
SOURCE=..\include\pjmedia\transport_udp.h
# End Source File
# Begin Source File
diff --git a/pjmedia/include/pjmedia/transport.h b/pjmedia/include/pjmedia/transport.h
index ce509f03..4b2450bc 100644
--- a/pjmedia/include/pjmedia/transport.h
+++ b/pjmedia/include/pjmedia/transport.h
@@ -26,6 +26,7 @@
*/
#include <pjmedia/types.h>
+#include <pjmedia/errno.h>
/**
* @defgroup PJMEDIA_TRANSPORT Media Transports
@@ -177,6 +178,9 @@ typedef struct pjmedia_transport pjmedia_transport;
*/
struct pjmedia_transport_op
{
+ pj_status_t (*get_info)(pjmedia_transport *tp,
+ pjmedia_sock_info *info);
+
/**
* This function is called by the stream when the transport is about
* to be used by the stream for the first time, and it tells the transport
@@ -265,6 +269,15 @@ struct pjmedia_transport
};
+PJ_INLINE(pj_status_t) pjmedia_transport_get_info(pjmedia_transport *tp,
+ pjmedia_sock_info *info)
+{
+ if (tp->op->get_info)
+ return (*tp->op->get_info)(tp, info);
+ else
+ return PJ_ENOTSUP;
+}
+
/**
* Attach callbacks to be called on receipt of incoming RTP/RTCP packets.
diff --git a/pjmedia/include/pjmedia/transport_ice.h b/pjmedia/include/pjmedia/transport_ice.h
new file mode 100644
index 00000000..fa4deebb
--- /dev/null
+++ b/pjmedia/include/pjmedia/transport_ice.h
@@ -0,0 +1,78 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __pjmedia_ice_H__
+#define __pjmedia_ice_H__
+
+
+/**
+ * @file transport_ice.h
+ * @brief Stream transport with ICE.
+ */
+
+#include <pjmedia/stream.h>
+#include <pjnath/ice_stream_transport.h>
+
+
+/**
+ * @defgroup PJMEDIA_TRANSPORT_ICE ICE Socket Transport
+ * @ingroup PJMEDIA_TRANSPORT_H
+ * @brief Implementation of media transport with ICE.
+ * @{
+ */
+
+PJ_BEGIN_DECL
+
+
+PJ_DECL(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
+ const char *name,
+ pj_stun_config *stun_cfg,
+ pj_dns_resolver *resolver,
+ pj_bool_t enable_relay,
+ const pj_str_t *stun_name,
+ pjmedia_transport **p_tp);
+PJ_DECL(pj_status_t) pjmedia_ice_destroy(pjmedia_transport *tp);
+
+
+PJ_DECL(pj_status_t) pjmedia_ice_init_ice(pjmedia_transport *tp,
+ pj_ice_role role,
+ const pj_str_t *local_ufrag,
+ const pj_str_t *local_passwd);
+PJ_DECL(pj_status_t) pjmedia_ice_build_sdp(pjmedia_transport *tp,
+ pj_pool_t *pool,
+ pjmedia_sdp_session *sdp);
+PJ_DECL(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp,
+ pj_pool_t *pool,
+ pjmedia_sdp_session *rem_sdp);
+PJ_DECL(pj_status_t) pjmedia_ice_stop_ice(pjmedia_transport *tp);
+
+
+
+
+
+PJ_END_DECL
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __pjmedia_ice_H__ */
+
+
diff --git a/pjmedia/src/pjmedia/transport_ice.c b/pjmedia/src/pjmedia/transport_ice.c
new file mode 100644
index 00000000..98e89fbc
--- /dev/null
+++ b/pjmedia/src/pjmedia/transport_ice.c
@@ -0,0 +1,549 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <pjmedia/transport_ice.h>
+#include <pjnath/errno.h>
+#include <pj/assert.h>
+
+struct transport_ice
+{
+ pjmedia_transport base;
+ pj_ice_st *ice_st;
+
+ void *user_data;
+ void (*rtp_cb)(void*,
+ const void*,
+ pj_ssize_t);
+ void (*rtcp_cb)(void*,
+ const void*,
+ pj_ssize_t);
+};
+
+
+/*
+ * These are media transport operations.
+ */
+static pj_status_t tp_get_info(pjmedia_transport *tp,
+ pjmedia_sock_info *info);
+static pj_status_t tp_attach( pjmedia_transport *tp,
+ void *user_data,
+ const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
+ unsigned addr_len,
+ void (*rtp_cb)(void*,
+ const void*,
+ pj_ssize_t),
+ void (*rtcp_cb)(void*,
+ const void*,
+ pj_ssize_t));
+static void tp_detach( pjmedia_transport *tp,
+ void *strm);
+static pj_status_t tp_send_rtp( pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size);
+static pj_status_t tp_send_rtcp( pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size);
+
+/*
+ * And these are ICE callbacks.
+ */
+static void ice_on_rx_data(pj_ice_st *ice_st,
+ unsigned comp_id, unsigned cand_id,
+ void *pkt, pj_size_t size,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len);
+static void ice_on_stun_srv_resolved(pj_ice_st *ice_st,
+ pj_status_t status);
+static void ice_on_interface_status(pj_ice_st *ice_st,
+ void *notify_data,
+ pj_status_t status,
+ int itf_id);
+static void ice_on_ice_complete(pj_ice_st *ice_st,
+ pj_status_t status);
+
+
+static pjmedia_transport_op tp_ice_op =
+{
+ &tp_get_info,
+ &tp_attach,
+ &tp_detach,
+ &tp_send_rtp,
+ &tp_send_rtcp,
+ &pjmedia_ice_destroy
+};
+
+
+
+PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
+ const char *name,
+ pj_stun_config *stun_cfg,
+ pj_dns_resolver *resolver,
+ pj_bool_t enable_relay,
+ const pj_str_t *stun_name,
+ pjmedia_transport **p_tp)
+{
+ pj_ice_st *ice_st;
+ pj_ice_st_cb ice_st_cb;
+ struct transport_ice *tp_ice;
+ pj_status_t status;
+
+ PJ_UNUSED_ARG(endpt);
+
+ /* Configure ICE callbacks */
+ pj_bzero(&ice_st_cb, sizeof(ice_st_cb));
+ ice_st_cb.on_ice_complete = &ice_on_ice_complete;
+ ice_st_cb.on_interface_status = &ice_on_interface_status;
+ ice_st_cb.on_rx_data = &ice_on_rx_data;
+ ice_st_cb.on_stun_srv_resolved = &ice_on_stun_srv_resolved;
+
+ /* Create ICE */
+ status = pj_ice_st_create(stun_cfg, name, NULL, &ice_st_cb, &ice_st);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Add component 1 (RTP) */
+ status = pj_ice_st_add_comp(ice_st, 1);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Add host candidates. */
+ status = pj_ice_st_add_all_host_interfaces(ice_st, 1, 0, PJ_FALSE, NULL);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Configure STUN server for ICE */
+ if (stun_name) {
+ status = pj_ice_st_set_stun(ice_st, resolver, enable_relay, stun_name);
+ if (status != PJ_SUCCESS)
+ goto on_error;
+
+ /* Add STUN candidates */
+ status = pj_ice_st_add_stun_interface(ice_st, 1, 0, PJ_FALSE, NULL);
+ }
+
+ /* Create transport instance and attach to ICE */
+ tp_ice = PJ_POOL_ZALLOC_T(ice_st->pool, struct transport_ice);
+ tp_ice->ice_st = ice_st;
+ pj_ansi_strcpy(tp_ice->base.name, ice_st->obj_name);
+ tp_ice->base.op = &tp_ice_op;
+
+ ice_st->user_data = (void*)tp_ice;
+
+ /* Done */
+ if (p_tp)
+ *p_tp = &tp_ice->base;
+
+ return PJ_SUCCESS;
+
+on_error:
+ pj_ice_st_destroy(ice_st);
+ return status;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_ice_close(pjmedia_transport *tp)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+
+ if (tp_ice->ice_st) {
+ pj_ice_st_destroy(tp_ice->ice_st);
+ tp_ice->ice_st = NULL;
+ }
+
+ return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_ice_init_ice(pjmedia_transport *tp,
+ pj_ice_role role,
+ const pj_str_t *local_ufrag,
+ const pj_str_t *local_passwd)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ return pj_ice_st_init_ice(tp_ice->ice_st, role, local_ufrag, local_passwd);
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_ice_build_sdp(pjmedia_transport *tp,
+ pj_pool_t *pool,
+ pjmedia_sdp_session *sdp)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ enum { MAXLEN = 256 };
+ char *buffer;
+ pjmedia_sdp_attr *attr;
+ unsigned i, cand_cnt;
+
+ buffer = pj_pool_alloc(pool, MAXLEN);
+
+ /* Create ice-ufrag attribute */
+ attr = pjmedia_sdp_attr_create(pool, "ice-ufrag",
+ &tp_ice->ice_st->ice->rx_ufrag);
+ sdp->attr[sdp->attr_count++] = attr;
+
+ /* Create ice-pwd attribute */
+ attr = pjmedia_sdp_attr_create(pool, "ice-pwd",
+ &tp_ice->ice_st->ice->rx_pass);
+ sdp->attr[sdp->attr_count++] = attr;
+
+ /* Add all candidates */
+ cand_cnt = pj_ice_get_cand_cnt(tp_ice->ice_st->ice);
+ for (i=0; i<cand_cnt; ++i) {
+ pj_ice_cand *cand;
+ pj_str_t value;
+ int len;
+
+ pj_ice_get_cand(tp_ice->ice_st->ice, i, &cand);
+
+ len = pj_ansi_snprintf( buffer, MAXLEN,
+ "%.*s %d UDP %u %s %d typ ",
+ (int)cand->foundation.slen,
+ cand->foundation.ptr,
+ cand->comp_id,
+ cand->prio,
+ pj_inet_ntoa(cand->addr.ipv4.sin_addr),
+ (int)pj_ntohs(cand->addr.ipv4.sin_port));
+ if (len < 1 || len >= MAXLEN)
+ return PJ_ENAMETOOLONG;
+
+ switch (cand->type) {
+ case PJ_ICE_CAND_TYPE_HOST:
+ len = pj_ansi_snprintf(buffer+len, MAXLEN-len,
+ "host");
+ break;
+ case PJ_ICE_CAND_TYPE_SRFLX:
+ len = pj_ansi_snprintf(buffer+len, MAXLEN-len,
+ "srflx raddr %s rport %d",
+ pj_inet_ntoa(cand->base_addr.ipv4.sin_addr),
+ (int)pj_ntohs(cand->base_addr.ipv4.sin_port));
+ break;
+ case PJ_ICE_CAND_TYPE_RELAYED:
+ PJ_TODO(RELATED_ADDR_FOR_RELAYED_ADDR);
+ len = pj_ansi_snprintf(buffer+len, MAXLEN-len,
+ "srflx raddr %s rport %d",
+ pj_inet_ntoa(cand->base_addr.ipv4.sin_addr),
+ (int)pj_ntohs(cand->base_addr.ipv4.sin_port));
+ break;
+ case PJ_ICE_CAND_TYPE_PRFLX:
+ len = pj_ansi_snprintf(buffer+len, MAXLEN-len,
+ "prflx raddr %s rport %d",
+ pj_inet_ntoa(cand->base_addr.ipv4.sin_addr),
+ (int)pj_ntohs(cand->base_addr.ipv4.sin_port));
+ break;
+ default:
+ pj_assert(!"Invalid candidate type");
+ break;
+ }
+ if (len < 1 || len >= MAXLEN)
+ return PJ_ENAMETOOLONG;
+
+ value = pj_str(buffer);
+ attr = pjmedia_sdp_attr_create(pool, "candidate", &value);
+ sdp->attr[sdp->attr_count++] = attr;
+ }
+
+ /* Done */
+ return PJ_SUCCESS;
+
+}
+
+
+static pj_status_t parse_cand(pj_pool_t *pool,
+ const pj_str_t *orig_input,
+ pj_ice_cand *cand)
+{
+ pj_str_t input;
+ char *token, *host;
+ pj_str_t s;
+ pj_status_t status = PJ_EICEINCANDSDP;
+
+ pj_bzero(cand, sizeof(*cand));
+ pj_strdup_with_null(pool, &input, orig_input);
+
+ /* Foundation */
+ token = strtok(input.ptr, " ");
+ if (!token)
+ goto on_return;
+ pj_strdup2(pool, &cand->foundation, token);
+
+ /* Component ID */
+ token = strtok(NULL, " ");
+ if (!token)
+ goto on_return;
+ cand->comp_id = atoi(token);
+
+ /* Transport */
+ token = strtok(NULL, " ");
+ if (!token)
+ goto on_return;
+ if (strcmp(token, "UDP") != 0)
+ goto on_return;
+
+ /* Priority */
+ token = strtok(NULL, " ");
+ if (!token)
+ goto on_return;
+ cand->prio = atoi(token);
+
+ /* Host */
+ host = strtok(NULL, " ");
+ if (!host)
+ goto on_return;
+ if (pj_sockaddr_in_init(&cand->addr.ipv4, pj_cstr(&s, host), 0))
+ goto on_return;
+
+ /* Port */
+ token = strtok(NULL, " ");
+ if (!token)
+ goto on_return;
+ cand->addr.ipv4.sin_port = pj_htons((pj_uint16_t)atoi(token));
+
+ /* typ */
+ token = strtok(NULL, " ");
+ if (!token)
+ goto on_return;
+ if (strcmp(token, "typ") != 0)
+ goto on_return;
+
+ /* candidate type */
+ token = strtok(NULL, " ");
+ if (!token)
+ goto on_return;
+
+ if (strcmp(token, "host") == 0) {
+ cand->type = PJ_ICE_CAND_TYPE_HOST;
+
+ } else if (strcmp(token, "srflx") == 0) {
+ cand->type = PJ_ICE_CAND_TYPE_SRFLX;
+
+ } else if (strcmp(token, "relay") == 0) {
+ cand->type = PJ_ICE_CAND_TYPE_RELAYED;
+
+ } else if (strcmp(token, "prflx") == 0) {
+ cand->type = PJ_ICE_CAND_TYPE_PRFLX;
+
+ } else {
+ goto on_return;
+ }
+
+
+ status = PJ_SUCCESS;
+
+on_return:
+ return status;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp,
+ pj_pool_t *pool,
+ pjmedia_sdp_session *rem_sdp)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ pjmedia_sdp_attr *attr;
+ unsigned i, cand_cnt;
+ pj_ice_cand cand[PJ_ICE_MAX_CAND];
+ pj_str_t uname, pass;
+ pj_status_t status;
+
+ /* Find ice-ufrag attribute */
+ attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr,
+ "ice-ufrag", NULL);
+ if (attr == NULL)
+ return PJ_EICEMISSINGSDP;
+ uname = attr->value;
+
+ /* Find ice-pwd attribute */
+ attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr,
+ "ice-pwd", NULL);
+ if (attr == NULL)
+ return PJ_EICEMISSINGSDP;
+ pass = attr->value;
+
+ /* Get all candidates */
+ cand_cnt = 0;
+ for (i=0; i<rem_sdp->attr_count; ++i) {
+ pjmedia_sdp_attr *attr;
+
+ attr = rem_sdp->attr[i];
+ if (pj_strcmp2(&attr->name, "candidate")!=0)
+ continue;
+
+ status = parse_cand(pool, &attr->value, &cand[cand_cnt]);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ cand_cnt++;
+ }
+
+ /* Start ICE */
+ return pj_ice_st_start_ice(tp_ice->ice_st, &uname, &pass, cand_cnt, cand);
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_ice_stop_ice(pjmedia_transport *tp)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ return pj_ice_st_stop_ice(tp_ice->ice_st);
+}
+
+
+static pj_status_t tp_get_info(pjmedia_transport *tp,
+ pjmedia_sock_info *info)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ int rel_idx = -1, srflx_idx = -1, host_idx = -1, idx = -1;
+ unsigned i;
+
+ pj_bzero(info, sizeof(*info));
+ info->rtp_sock = info->rtcp_sock = PJ_INVALID_SOCKET;
+
+ for (i=0; i<tp_ice->ice_st->itf_cnt; ++i) {
+ pj_ice_st_interface *itf = tp_ice->ice_st->itfs[i];
+
+ if (itf->type == PJ_ICE_CAND_TYPE_HOST && host_idx == -1)
+ host_idx = i;
+ else if (itf->type == PJ_ICE_CAND_TYPE_RELAYED && rel_idx == -1)
+ rel_idx = i;
+ else if (itf->type == PJ_ICE_CAND_TYPE_SRFLX && srflx_idx == -1)
+ srflx_idx = i;
+ }
+
+ if (idx == -1 && srflx_idx != -1)
+ idx = srflx_idx;
+ else if (idx == -1 && rel_idx != -1)
+ idx = rel_idx;
+ else if (idx == -1 && host_idx != -1)
+ idx = host_idx;
+
+ PJ_ASSERT_RETURN(idx != -1, PJ_EBUG);
+
+ pj_memcpy(&info->rtp_addr_name, &tp_ice->ice_st->itfs[idx]->addr,
+ sizeof(pj_sockaddr_in));
+
+ return PJ_SUCCESS;
+}
+
+
+static pj_status_t tp_attach( pjmedia_transport *tp,
+ void *user_data,
+ const pj_sockaddr_t *rem_addr,
+ const pj_sockaddr_t *rem_rtcp,
+ unsigned addr_len,
+ void (*rtp_cb)(void*,
+ const void*,
+ pj_ssize_t),
+ void (*rtcp_cb)(void*,
+ const void*,
+ pj_ssize_t))
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+
+ tp_ice->user_data = user_data;
+ tp_ice->rtp_cb = rtp_cb;
+ tp_ice->rtcp_cb = rtcp_cb;
+
+ PJ_UNUSED_ARG(rem_addr);
+ PJ_UNUSED_ARG(rem_rtcp);
+ PJ_UNUSED_ARG(addr_len);
+
+ return PJ_SUCCESS;
+}
+
+
+static void tp_detach(pjmedia_transport *tp,
+ void *strm)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+
+ tp_ice->rtp_cb = NULL;
+ tp_ice->rtcp_cb = NULL;
+ tp_ice->user_data = NULL;
+
+ PJ_UNUSED_ARG(strm);
+}
+
+
+static pj_status_t tp_send_rtp(pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ return pj_ice_st_send_data(tp_ice->ice_st, 1, pkt, size);
+}
+
+
+static pj_status_t tp_send_rtcp(pjmedia_transport *tp,
+ const void *pkt,
+ pj_size_t size)
+{
+#if 0
+ struct transport_ice *tp_ice = (struct transport_ice*)tp;
+ return pj_ice_st_send_data(tp_ice->ice_st, 1, pkt, size);
+#else
+ PJ_TODO(SUPPORT_RTCP);
+ PJ_UNUSED_ARG(tp);
+ PJ_UNUSED_ARG(pkt);
+ PJ_UNUSED_ARG(size);
+ return PJ_SUCCESS;
+#endif
+}
+
+
+static void ice_on_rx_data(pj_ice_st *ice_st,
+ unsigned comp_id, unsigned cand_id,
+ void *pkt, pj_size_t size,
+ const pj_sockaddr_t *src_addr,
+ unsigned src_addr_len)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*) ice_st->user_data;
+
+ if (comp_id==1 && tp_ice->rtp_cb)
+ (*tp_ice->rtp_cb)(tp_ice->user_data, pkt, size);
+ else if (comp_id==2 && tp_ice->rtcp_cb)
+ (*tp_ice->rtcp_cb)(tp_ice->user_data, pkt, size);
+
+ PJ_UNUSED_ARG(cand_id);
+ PJ_UNUSED_ARG(src_addr);
+ PJ_UNUSED_ARG(src_addr_len);
+}
+
+
+static void ice_on_stun_srv_resolved(pj_ice_st *ice_st,
+ pj_status_t status)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*) ice_st->user_data;
+}
+
+
+static void ice_on_interface_status(pj_ice_st *ice_st,
+ void *notify_data,
+ pj_status_t status,
+ int itf_id)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*) ice_st->user_data;
+}
+
+
+static void ice_on_ice_complete(pj_ice_st *ice_st,
+ pj_status_t status)
+{
+ struct transport_ice *tp_ice = (struct transport_ice*) ice_st->user_data;
+}
+
+
diff --git a/pjmedia/src/pjmedia/transport_udp.c b/pjmedia/src/pjmedia/transport_udp.c
index 4b131c0a..3325be0e 100644
--- a/pjmedia/src/pjmedia/transport_udp.c
+++ b/pjmedia/src/pjmedia/transport_udp.c
@@ -93,6 +93,8 @@ static void on_rx_rtcp(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_ssize_t bytes_read);
+static pj_status_t transport_get_info(pjmedia_transport *tp,
+ pjmedia_sock_info *info);
static pj_status_t transport_attach( pjmedia_transport *tp,
void *user_data,
const pj_sockaddr_t *rem_addr,
@@ -116,6 +118,7 @@ static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
static pjmedia_transport_op transport_udp_op =
{
+ &transport_get_info,
&transport_attach,
&transport_detach,
&transport_send_rtp,
@@ -324,15 +327,7 @@ PJ_DEF(pj_status_t)
pjmedia_transport_udp_get_info( pjmedia_transport *tp,
pjmedia_transport_udp_info *inf)
{
- struct transport_udp *udp = (struct transport_udp*)tp;
- PJ_ASSERT_RETURN(tp && inf, PJ_EINVAL);
-
- inf->skinfo.rtp_sock = udp->rtp_sock;
- inf->skinfo.rtp_addr_name = udp->rtp_addr_name;
- inf->skinfo.rtcp_sock = udp->rtcp_sock;
- inf->skinfo.rtcp_addr_name = udp->rtcp_addr_name;
-
- return PJ_SUCCESS;
+ return transport_get_info(tp, &inf->skinfo);
}
@@ -527,6 +522,22 @@ static void on_rx_rtcp(pj_ioqueue_key_t *key,
}
+/* Called to get the transport info */
+static pj_status_t transport_get_info(pjmedia_transport *tp,
+ pjmedia_sock_info *info)
+{
+ struct transport_udp *udp = (struct transport_udp*)tp;
+ PJ_ASSERT_RETURN(tp && info, PJ_EINVAL);
+
+ info->rtp_sock = udp->rtp_sock;
+ info->rtp_addr_name = udp->rtp_addr_name;
+ info->rtcp_sock = udp->rtcp_sock;
+ info->rtcp_addr_name = udp->rtcp_addr_name;
+
+ return PJ_SUCCESS;
+}
+
+
/* Called by application to initialize the transport */
static pj_status_t transport_attach( pjmedia_transport *tp,
void *user_data,
diff --git a/pjnath/include/pjnath/errno.h b/pjnath/include/pjnath/errno.h
index 3a7c591f..9f45bc86 100644
--- a/pjnath/include/pjnath/errno.h
+++ b/pjnath/include/pjnath/errno.h
@@ -163,12 +163,21 @@
* ICE session not available
*/
#define PJ_ENOICE -1
-
- /**
+/**
* @hideinitializer
* ICE check is in progress
*/
#define PJ_EICEINPROGRESS -1
+/**
+ * @hideinitializer
+ * Missing ICE SDP attribute
+ */
+#define PJ_EICEMISSINGSDP -1
+/**
+ * @hideinitializer
+ * Invalid SDP "candidate" attribute
+ */
+#define PJ_EICEINCANDSDP -1
diff --git a/pjnath/src/pjnath/ice.c b/pjnath/src/pjnath/ice.c
index 9fb59238..e21e81f9 100644
--- a/pjnath/src/pjnath/ice.c
+++ b/pjnath/src/pjnath/ice.c
@@ -25,6 +25,7 @@
#include <pj/log.h>
#include <pj/os.h>
#include <pj/pool.h>
+#include <pj/rand.h>
#include <pj/string.h>
diff --git a/pjproject.dsw b/pjproject.dsw
index 7c37cb52..f056fc4c 100644
--- a/pjproject.dsw
+++ b/pjproject.dsw
@@ -84,6 +84,18 @@ Package=<4>
###############################################################################
+Project: "pjnath"=.\pjnath\build\pjnath.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
Project: "pjsip_core"=.\pjsip\build\pjsip_core.dsp - Package Owner=<4>
Package=<5>
@@ -152,6 +164,9 @@ Package=<4>
Begin Project Dependency
Project_Dep_Name pjsua_lib
End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name pjnath
+ End Project Dependency
}}}
###############################################################################