summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-09-15 08:30:16 +0000
committerBenny Prijono <bennylp@teluu.com>2007-09-15 08:30:16 +0000
commit229e150c7b96a344f371fe02262d363ed0b88898 (patch)
treebd8b4b253ceb3ba011088a91559cf0626dfcf6bc
parent560a0d9b22efac7c63b45566f8e69ac592421da1 (diff)
Ticket #370: Implemented callback notification to application when ICE negotiation fails (via on_call_media_state callback)
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1435 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/include/pjmedia/transport_ice.h18
-rw-r--r--pjmedia/src/pjmedia/transport_ice.c44
-rw-r--r--pjnath/include/pjnath/ice_session.h1
-rw-r--r--pjnath/src/pjnath/ice_session.c30
-rw-r--r--pjsip-apps/src/pjsua/pjsua_app.c8
-rw-r--r--pjsip/include/pjsua-lib/pjsua.h3
-rw-r--r--pjsip/src/pjsua-lib/pjsua_media.c42
7 files changed, 126 insertions, 20 deletions
diff --git a/pjmedia/include/pjmedia/transport_ice.h b/pjmedia/include/pjmedia/transport_ice.h
index cf72886d..2a51ae76 100644
--- a/pjmedia/include/pjmedia/transport_ice.h
+++ b/pjmedia/include/pjmedia/transport_ice.h
@@ -40,6 +40,22 @@ PJ_BEGIN_DECL
/**
+ * Structure containing callbacks to receive ICE notifications.
+ */
+typedef struct pjmedia_ice_cb
+{
+ /**
+ * This callback will be called when ICE negotiation completes.
+ *
+ * @param tp PJMEDIA ICE transport.
+ * @param status ICE negotiation result, PJ_SUCCESS on success.
+ */
+ void (*on_ice_complete)(pjmedia_transport *tp,
+ pj_status_t status);
+
+} pjmedia_ice_cb;
+
+/**
* Create the media transport.
*
* @param endpt The media endpoint.
@@ -47,6 +63,7 @@ PJ_BEGIN_DECL
* for logging purposes.
* @param comp_cnt Number of components to be created.
* @param stun_cfg Pointer to STUN configuration settings.
+ * @param cb Optional callbacks.
* @param p_tp Pointer to receive the media transport instance.
*
* @return PJ_SUCCESS on success, or the appropriate error code.
@@ -55,6 +72,7 @@ PJ_DECL(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
const char *name,
unsigned comp_cnt,
pj_stun_config *stun_cfg,
+ const pjmedia_ice_cb *cb,
pjmedia_transport **p_tp);
/**
diff --git a/pjmedia/src/pjmedia/transport_ice.c b/pjmedia/src/pjmedia/transport_ice.c
index 019ba04c..4fa21c29 100644
--- a/pjmedia/src/pjmedia/transport_ice.c
+++ b/pjmedia/src/pjmedia/transport_ice.c
@@ -25,6 +25,7 @@ struct transport_ice
{
pjmedia_transport base;
pj_ice_strans *ice_st;
+ pjmedia_ice_cb cb;
pj_time_val start_ice;
@@ -95,6 +96,7 @@ PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
const char *name,
unsigned comp_cnt,
pj_stun_config *stun_cfg,
+ const pjmedia_ice_cb *cb,
pjmedia_transport **p_tp)
{
pj_ice_strans *ice_st;
@@ -123,6 +125,9 @@ PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
tp_ice->base.op = &tp_ice_op;
tp_ice->base.type = PJMEDIA_TRANSPORT_TYPE_ICE;
+ if (cb)
+ pj_memcpy(&tp_ice->cb, cb, sizeof(pjmedia_ice_cb));
+
ice_st->user_data = (void*)tp_ice;
/* Done */
@@ -686,7 +691,7 @@ static void ice_on_rx_data(pj_ice_strans *ice_st, unsigned comp_id,
static void ice_on_ice_complete(pj_ice_strans *ice_st,
- pj_status_t status)
+ pj_status_t result)
{
struct transport_ice *tp_ice = (struct transport_ice*) ice_st->user_data;
pj_time_val end_ice;
@@ -698,30 +703,33 @@ static void ice_on_ice_complete(pj_ice_strans *ice_st,
pj_gettimeofday(&end_ice);
PJ_TIME_VAL_SUB(end_ice, tp_ice->start_ice);
- if (status != PJ_SUCCESS) {
+ if (result != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
- pj_strerror(status, errmsg, sizeof(errmsg));
+ pj_strerror(result, errmsg, sizeof(errmsg));
PJ_LOG(1,(ice_st->obj_name,
"ICE negotiation failed after %d:%03ds: %s",
(int)end_ice.sec, (int)end_ice.msec,
errmsg));
- return;
+ } else {
+ check = &ice_st->ice->valid_list.checks[0];
+
+ lcand = check->lcand;
+ rcand = check->rcand;
+
+ pj_ansi_strcpy(src_addr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
+ pj_ansi_strcpy(dst_addr, pj_inet_ntoa(rcand->addr.ipv4.sin_addr));
+
+ PJ_LOG(4,(ice_st->obj_name,
+ "ICE negotiation completed in %d.%03ds. Sending from "
+ "%s:%d to %s:%d",
+ (int)end_ice.sec, (int)end_ice.msec,
+ src_addr, pj_ntohs(lcand->addr.ipv4.sin_port),
+ dst_addr, pj_ntohs(rcand->addr.ipv4.sin_port)));
}
- check = &ice_st->ice->valid_list.checks[0];
-
- lcand = check->lcand;
- rcand = check->rcand;
-
- pj_ansi_strcpy(src_addr, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
- pj_ansi_strcpy(dst_addr, pj_inet_ntoa(rcand->addr.ipv4.sin_addr));
-
- PJ_LOG(3,(ice_st->obj_name,
- "ICE negotiation completed in %d.%03ds. Sending from "
- "%s:%d to %s:%d",
- (int)end_ice.sec, (int)end_ice.msec,
- src_addr, pj_ntohs(lcand->addr.ipv4.sin_port),
- dst_addr, pj_ntohs(rcand->addr.ipv4.sin_port)));
+ /* Notify application */
+ if (tp_ice->cb.on_ice_complete)
+ (*tp_ice->cb.on_ice_complete)(&tp_ice->base, result);
}
diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h
index 14dba41f..b601385c 100644
--- a/pjnath/include/pjnath/ice_session.h
+++ b/pjnath/include/pjnath/ice_session.h
@@ -464,6 +464,7 @@ struct pj_ice_sess
pj_uint8_t *prefs; /**< Type preference. */
pj_bool_t is_complete; /**< Complete? */
pj_status_t ice_status; /**< Error status. */
+ pj_timer_entry completion_timer; /**< To call callback. */
pj_ice_sess_cb cb; /**< Callback. */
pj_stun_config stun_cfg; /**< STUN settings. */
diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c
index 78422af1..27634442 100644
--- a/pjnath/src/pjnath/ice_session.c
+++ b/pjnath/src/pjnath/ice_session.c
@@ -336,6 +336,12 @@ static void destroy_ice(pj_ice_sess *ice,
LOG4((ice->obj_name, "Destroying ICE session"));
}
+ if (ice->completion_timer.id) {
+ pj_timer_heap_cancel(ice->stun_cfg.timer_heap,
+ &ice->completion_timer);
+ ice->completion_timer.id = PJ_FALSE;
+ }
+
for (i=0; i<ice->comp_cnt; ++i) {
if (ice->comp[i].stun_sess) {
pj_stun_session_destroy(ice->comp[i].stun_sess);
@@ -945,6 +951,20 @@ static pj_status_t prune_checklist(pj_ice_sess *ice,
return PJ_SUCCESS;
}
+/* Timer callback to call on_ice_complete() callback */
+static void on_completion_timer(pj_timer_heap_t *th,
+ pj_timer_entry *te)
+{
+ pj_ice_sess *ice = (pj_ice_sess*) te->user_data;
+
+ PJ_UNUSED_ARG(th);
+
+ te->id = PJ_FALSE;
+
+ if (ice->cb.on_ice_complete)
+ (*ice->cb.on_ice_complete)(ice, ice->ice_status);
+}
+
/* This function is called when ICE processing completes */
static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
{
@@ -962,7 +982,15 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status)
/* Call callback */
if (ice->cb.on_ice_complete) {
- (*ice->cb.on_ice_complete)(ice, status);
+ pj_time_val delay = {0, 0};
+
+ ice->completion_timer.cb = &on_completion_timer;
+ ice->completion_timer.user_data = (void*) ice;
+ ice->completion_timer.id = PJ_TRUE;
+
+ pj_timer_heap_schedule(ice->stun_cfg.timer_heap,
+ &ice->completion_timer,
+ &delay);
}
}
}
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c
index a586b4dd..13f1dbd2 100644
--- a/pjsip-apps/src/pjsua/pjsua_app.c
+++ b/pjsip-apps/src/pjsua/pjsua_app.c
@@ -1675,6 +1675,14 @@ static void on_call_media_state(pjsua_call_id call_id)
PJ_LOG(3,(THIS_FILE,
"Media for call %d is suspended (hold) by remote",
call_id));
+ } else if (call_info.media_status == PJSUA_CALL_MEDIA_ERROR) {
+ pj_str_t reason = pj_str("ICE negotiation failed");
+
+ PJ_LOG(1,(THIS_FILE,
+ "Media has reported error, disconnecting call"));
+
+ pjsua_call_hangup(call_id, 500, &reason, NULL);
+
} else {
PJ_LOG(3,(THIS_FILE,
"Media for call %d is inactive",
diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index a82141b5..f493de5d 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -2375,6 +2375,9 @@ typedef enum pjsua_call_media_status
/** The media is currently put on hold by remote endpoint */
PJSUA_CALL_MEDIA_REMOTE_HOLD,
+ /** The media has reported error (e.g. ICE negotiation) */
+ PJSUA_CALL_MEDIA_ERROR
+
} pjsua_call_media_status;
diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c
index 8700bd59..0e58d100 100644
--- a/pjsip/src/pjsua-lib/pjsua_media.c
+++ b/pjsip/src/pjsua-lib/pjsua_media.c
@@ -537,6 +537,42 @@ on_error:
}
+/* This callback is called when ICE negotiation completes */
+static void on_ice_complete(pjmedia_transport *tp, pj_status_t result)
+{
+ unsigned id, c;
+ pj_bool_t found = PJ_FALSE;
+
+ /* We're only interested with failure case */
+ if (result == PJ_SUCCESS)
+ return;
+
+ /* Find call which has this media transport */
+
+ PJSUA_LOCK();
+
+ for (id=0, c=0; id<PJSUA_MAX_CALLS && c<pjsua_var.call_cnt; ++id) {
+ pjsua_call *call = &pjsua_var.calls[id];
+ if (call->inv) {
+ ++c;
+
+ if (call->med_tp == tp) {
+ call->media_st = PJSUA_CALL_MEDIA_ERROR;
+ call->media_dir = PJMEDIA_DIR_NONE;
+ found = PJ_TRUE;
+ break;
+ }
+ }
+ }
+
+ PJSUA_UNLOCK();
+
+ if (found && pjsua_var.ua_cfg.cb.on_call_media_state) {
+ pjsua_var.ua_cfg.cb.on_call_media_state(id);
+ }
+}
+
+
/* Create ICE media transports (when ice is enabled) */
static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
{
@@ -556,6 +592,7 @@ static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
/* Create each media transport */
for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
pj_ice_strans_comp comp;
+ pjmedia_ice_cb ice_cb;
int next_port;
#if PJMEDIA_ADVERTISE_RTCP
enum { COMP_CNT=2 };
@@ -563,8 +600,11 @@ static pj_status_t create_ice_media_transports(pjsua_transport_config *cfg)
enum { COMP_CNT=1 };
#endif
+ pj_bzero(&ice_cb, sizeof(pjmedia_ice_cb));
+ ice_cb.on_ice_complete = &on_ice_complete;
+
status = pjmedia_ice_create(pjsua_var.med_endpt, NULL, COMP_CNT,
- &pjsua_var.stun_cfg,
+ &pjsua_var.stun_cfg, &ice_cb,
&pjsua_var.calls[i].med_tp);
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to create ICE media transport",