Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 3937)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 3938)
@@ -1997,5 +1997,5 @@
  *
  * @param entry		Timer heap entry.
- * @param delay     The interval to expire.
+ * @param delay         The interval to expire.
  *
  * @return		PJ_SUCCESS on success, or the appropriate error code.
@@ -2006,4 +2006,18 @@
 					  const pj_time_val *delay);
 
+/**
+ * Schedule a callback function to be called after a specified time interval.
+ * Note that the callback may be executed by different thread, depending on
+ * whether worker thread is enabled or not.
+ *
+ * @param cb		The callback function.
+ * @param user_data     The user data.
+ * @param msec_delay    The time interval in msec.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_schedule_timer2(void (*cb)(void *user_data),
+                                           void *user_data,
+                                           unsigned msec_delay);
 
 /**
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3937)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3938)
@@ -77,4 +77,5 @@
     pjmedia_transport	*tp;        /**< Current media transport (can be 0) */
     pj_status_t		 tp_ready;  /**< Media transport status.	    */
+    pj_status_t		 tp_result; /**< Media transport creation result.   */
     pjmedia_transport	*tp_orig;   /**< Original media transport	    */
     pj_bool_t		 tp_auto_del; /**< May delete media transport       */
@@ -457,4 +458,14 @@
     pjsua_vid_win	 win[PJSUA_MAX_VID_WINS]; /**< Array of windows	*/
 #endif
+
+    /* Timer entry list */
+    struct timer_list
+    {
+        PJ_DECL_LIST_MEMBER(struct timer_list);
+        pj_timer_entry          entry;
+        void                  (*cb)(void *user_data);
+        void                   *user_data;
+    } timer_list;
+    pj_mutex_t          *timer_mutex;
 };
 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3937)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 3938)
@@ -713,4 +713,16 @@
     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
 
+    /* Init timer entry list */
+    pj_list_init(&pjsua_var.timer_list);
+
+    /* Create timer mutex */
+    status = pj_mutex_create_recursive(pjsua_var.pool, "pjsua_timer", 
+				       &pjsua_var.timer_mutex);
+    if (status != PJ_SUCCESS) {
+	pj_log_pop_indent();
+	pjsua_perror(THIS_FILE, "Unable to create mutex", status);
+	return status;
+    }
+
     pjsua_set_state(PJSUA_STATE_CREATED);
     pj_log_pop_indent();
@@ -2604,4 +2616,57 @@
 }
 
+/* Timer callback */
+static void timer_cb( pj_timer_heap_t *th,
+		      pj_timer_entry *entry)
+{
+    struct timer_list *tmr = (struct timer_list *)entry->user_data;
+    void (*cb)(void *user_data) = tmr->cb;
+    void *user_data = tmr->user_data;
+
+    PJ_UNUSED_ARG(th);
+
+    pj_mutex_lock(pjsua_var.timer_mutex);
+    pj_list_push_back(&pjsua_var.timer_list, tmr);
+    pj_mutex_unlock(pjsua_var.timer_mutex);
+
+    if (cb)
+        (*cb)(user_data);
+}
+
+/*
+ * Schedule a timer callback. 
+ */
+PJ_DEF(pj_status_t) pjsua_schedule_timer2( void (*cb)(void *user_data),
+                                           void *user_data,
+                                           unsigned msec_delay)
+{
+    struct timer_list *tmr = NULL;
+    pj_status_t status;
+    pj_time_val delay;
+
+    pj_mutex_lock(pjsua_var.timer_mutex);
+
+    if (pj_list_empty(&pjsua_var.timer_list)) {
+        tmr = PJ_POOL_ALLOC_T(pjsua_var.pool, struct timer_list);
+    } else {
+        tmr = pjsua_var.timer_list.next;
+        pj_list_erase(tmr);
+    }
+    pj_timer_entry_init(&tmr->entry, 0, tmr, timer_cb);
+    tmr->cb = cb;
+    tmr->user_data = user_data;
+    delay.sec = 0;
+    delay.msec = msec_delay;
+
+    status = pjsip_endpt_schedule_timer(pjsua_var.endpt, &tmr->entry, &delay);
+    if (status != PJ_SUCCESS) {
+        pj_list_push_back(&pjsua_var.timer_list, tmr);
+    }
+
+    pj_mutex_unlock(pjsua_var.timer_mutex);
+
+    return status;
+}
+
 /*
  * Cancel the previously scheduled timer.
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 3937)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 3938)
@@ -767,4 +767,18 @@
 #endif
 
+static void med_tp_timer_cb(void *user_data)
+{
+    pjsua_call_media *call_med = (pjsua_call_media*)user_data;
+
+    PJSUA_LOCK();
+
+    call_med->tp_ready = call_med->tp_result;
+    if (call_med->med_create_cb)
+        (*call_med->med_create_cb)(call_med, call_med->tp_ready,
+                                   call_med->call->secure_level, NULL);
+
+    PJSUA_UNLOCK();
+}
+
 /* This callback is called when ICE negotiation completes */
 static void on_ice_complete(pjmedia_transport *tp, 
@@ -779,10 +793,6 @@
     switch (op) {
     case PJ_ICE_STRANS_OP_INIT:
-        PJSUA_LOCK();
-        call_med->tp_ready = result;
-        if (call_med->med_create_cb)
-            (*call_med->med_create_cb)(call_med, result,
-                                       call_med->call->secure_level, NULL);
-        PJSUA_UNLOCK();
+        call_med->tp_result = result;
+        pjsua_schedule_timer2(&med_tp_timer_cb, call_med, 1);
 	break;
     case PJ_ICE_STRANS_OP_NEGOTIATION:
@@ -1539,7 +1549,5 @@
             pjsua_call_media *call_med = &call->media[mi];
 
-            if (call_med->med_init_cb ||
-                call_med->tp_st == PJSUA_MED_TP_NULL)
-            {
+            if (call_med->med_init_cb) {
                 pj_mutex_unlock(call->med_ch_mutex);
                 return PJ_SUCCESS;
