Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 719)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 729)
@@ -384,4 +384,5 @@
 	return PJ_FALSE;
 
+    PJSUA_LOCK();
 
     /* Verify that we can handle the request. */
@@ -408,4 +409,5 @@
 	}
 
+	PJSUA_UNLOCK();
 	return PJ_TRUE;
     } 
@@ -428,4 +430,5 @@
 	PJ_LOG(2,(THIS_FILE, 
 		  "Unable to accept incoming call (too many calls)"));
+	PJSUA_UNLOCK();
 	return PJ_TRUE;
     }
@@ -446,4 +449,5 @@
 	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
 				      NULL, NULL);
+	PJSUA_UNLOCK();
 	return PJ_TRUE;
     }
@@ -463,4 +467,5 @@
 	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
 				      NULL, NULL);
+	PJSUA_UNLOCK();
 	return PJ_TRUE;
     }
@@ -472,5 +477,5 @@
 	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
 				      NULL, NULL);
-
+	PJSUA_UNLOCK();
 	return PJ_TRUE;
     }
@@ -500,4 +505,5 @@
 	pjsip_dlg_terminate(dlg);
 	 */
+	PJSUA_UNLOCK();
 	return PJ_TRUE;
     }
@@ -521,4 +527,5 @@
 	pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL);
 	pjsip_inv_terminate(inv, 500, PJ_FALSE);
+	PJSUA_UNLOCK();
 	return PJ_TRUE;
 
@@ -537,4 +544,5 @@
 
     /* This INVITE request has been handled. */
+    PJSUA_UNLOCK();
     return PJ_TRUE;
 }
@@ -566,4 +574,64 @@
 
 
+/* Acquire lock to the specified call_id */
+static pj_status_t acquire_call(const char *title,
+				pjsua_call_id call_id,
+				pjsua_call **p_call)
+{
+    enum { MAX_RETRY=50 };
+    unsigned retry;
+    pjsua_call *call;
+    pj_bool_t has_pjsua_lock;
+    pj_status_t status;
+
+    for (retry=0; retry<MAX_RETRY; ++retry) {
+	
+	has_pjsua_lock = PJ_FALSE;
+
+	status = PJSUA_TRY_LOCK();
+	if (status != PJ_SUCCESS) {
+	    pj_thread_sleep(retry/10);
+	    continue;
+	}
+
+	has_pjsua_lock = PJ_TRUE;
+	call = &pjsua_var.calls[call_id];
+
+	if (call->inv == NULL) {
+	    PJSUA_UNLOCK();
+	    PJ_LOG(3,(THIS_FILE, "Invalid call_id %d in %s", call_id, title));
+	    return PJSIP_ESESSIONTERMINATED;
+	}
+
+	status = pjsip_dlg_try_inc_lock(call->inv->dlg);
+	if (status != PJ_SUCCESS) {
+	    PJSUA_UNLOCK();
+	    pj_thread_sleep(retry/10);
+	    continue;
+	}
+
+	PJSUA_UNLOCK();
+
+	break;
+    }
+
+    if (status != PJ_SUCCESS) {
+	if (has_pjsua_lock == PJ_FALSE)
+	    PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire PJSUA mutex "
+				 "(possibly system has deadlocked) in %s",
+				 title));
+	else
+	    PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire dialog mutex "
+				 "(possibly system has deadlocked) in %s",
+				 title));
+	return PJ_ETIMEDOUT;
+    }
+    
+    *p_call = call;
+
+    return PJ_SUCCESS;
+}
+
+
 /*
  * Get the conference port identification associated with the call.
@@ -571,8 +639,22 @@
 PJ_DEF(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id)
 {
+    pjsua_call *call;
+    pjsua_conf_port_id port_id;
+    pj_status_t status;
+
     PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, 
 		     PJ_EINVAL);
-    return pjsua_var.calls[call_id].conf_slot;
-}
+
+    status = acquire_call("pjsua_call_get_conf_port()", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return -1;
+
+    port_id = call->conf_slot;
+
+    pjsip_dlg_dec_lock(call->inv->dlg);
+
+    return port_id;
+}
+
 
 
@@ -584,4 +666,5 @@
 {
     pjsua_call *call;
+    pj_status_t status;
 
     PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
@@ -590,15 +673,8 @@
     pj_bzero(info, sizeof(*info));
 
-    PJSUA_LOCK();
-
-    call = &pjsua_var.calls[call_id];
-
-    if (call->inv == NULL) {
-	PJSUA_UNLOCK();
-	return PJ_SUCCESS;
-    }
-
-    pjsip_dlg_inc_lock(call->inv->dlg);
-
+    status = acquire_call("pjsua_call_get_info()", call_id, &call);
+    if (status != PJ_SUCCESS) {
+	return status;
+    }
 
     /* id and role */
@@ -697,5 +773,4 @@
 
     pjsip_dlg_dec_lock(call->inv->dlg);
-    PJSUA_UNLOCK();
 
     return PJ_SUCCESS;
@@ -743,13 +818,7 @@
 		     PJ_EINVAL);
 
-    PJSUA_LOCK();
-
-    call = &pjsua_var.calls[call_id];
-
-    if (call->inv == NULL) {
-	PJ_LOG(3,(THIS_FILE, "Call %d already disconnected", call_id));
-	PJSUA_UNLOCK();
-	return PJSIP_ESESSIONTERMINATED;
-    }
+    status = acquire_call("pjsua_call_answer()", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return status;
 
     if (call->res_time.sec == 0)
@@ -761,5 +830,5 @@
 	pjsua_perror(THIS_FILE, "Error creating response", 
 		     status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
@@ -774,5 +843,5 @@
 		     status);
 
-    PJSUA_UNLOCK();
+    pjsip_dlg_dec_lock(call->inv->dlg);
 
     return status;
@@ -794,16 +863,15 @@
 
 
+    if (call_id<0 || call_id>=(int)pjsua_var.ua_cfg.max_calls) {
+	PJ_LOG(1,(THIS_FILE, "pjsua_call_hangup(): invalid call id %d",
+			     call_id));
+    }
+    
     PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
 		     PJ_EINVAL);
 
-    PJSUA_LOCK();
-
-    call = &pjsua_var.calls[call_id];
-
-    if (!call->inv) {
-	PJ_LOG(3,(THIS_FILE,"Invalid call or call has been disconnected"));
-	PJSUA_UNLOCK();
-	return PJ_EINVAL;
-    }
+    status = acquire_call("pjsua_call_hangup()", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return status;
 
     if (code==0) {
@@ -821,5 +889,5 @@
 		     "Failed to create end session message", 
 		     status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
@@ -830,5 +898,5 @@
      */
     if (tdata == NULL) {
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return PJ_SUCCESS;
     }
@@ -843,9 +911,9 @@
 		     "Failed to send end session message", 
 		     status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
 
-    PJSUA_UNLOCK();
+    pjsip_dlg_dec_lock(call->inv->dlg);
 
     return PJ_SUCCESS;
@@ -867,17 +935,12 @@
 		     PJ_EINVAL);
 
-    PJSUA_LOCK();
-
-    call = &pjsua_var.calls[call_id];
-    
-    if (!call->inv) {
-	PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
-	PJSUA_UNLOCK();
-	return PJSIP_ESESSIONTERMINATED;
-    }
+    status = acquire_call("pjsua_call_set_hold()", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return status;
+
 
     if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
 	PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed"));
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return PJSIP_ESESSIONSTATE;
     }
@@ -885,5 +948,5 @@
     status = create_inactive_sdp(call, &sdp);
     if (status != PJ_SUCCESS) {
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
@@ -893,5 +956,5 @@
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
@@ -904,9 +967,9 @@
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
 
-    PJSUA_UNLOCK();
+    pjsip_dlg_dec_lock(call->inv->dlg);
 
     return PJ_SUCCESS;
@@ -930,18 +993,11 @@
 		     PJ_EINVAL);
 
-    PJSUA_LOCK();
-
-    call = &pjsua_var.calls[call_id];
-
-    if (!call->inv) {
-	PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
-	PJSUA_UNLOCK();
-	return PJSIP_ESESSIONTERMINATED;
-    }
-
+    status = acquire_call("pjsua_call_reinvite()", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return status;
 
     if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) {
 	PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed"));
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return PJSIP_ESESSIONSTATE;
     }
@@ -955,5 +1011,5 @@
 	pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint", 
 		     status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
@@ -963,5 +1019,5 @@
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
@@ -974,9 +1030,9 @@
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
 
-    PJSUA_UNLOCK();
+    pjsip_dlg_dec_lock(call->inv->dlg);
 
     return PJ_SUCCESS;
@@ -1000,13 +1056,9 @@
 		     PJ_EINVAL);
     
-    PJSUA_LOCK();
-
-    call = &pjsua_var.calls[call_id];
-
-    if (!call->inv) {
-	PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
-	PJSUA_UNLOCK();
-	return PJSIP_ESESSIONTERMINATED;
-    }
+    pjsip_dlg_dec_lock(call->inv->dlg);
+    status = acquire_call("pjsua_call_xfer()", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return status;
+
    
     /* Create xfer client subscription.
@@ -1017,5 +1069,5 @@
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to create xfer", status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
@@ -1027,5 +1079,5 @@
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to create REFER request", status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
@@ -1038,5 +1090,5 @@
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to send REFER request", status);
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return status;
     }
@@ -1047,5 +1099,5 @@
      */
 
-    PJSUA_UNLOCK();
+    pjsip_dlg_dec_lock(call->inv->dlg);
 
     return PJ_SUCCESS;
@@ -1066,5 +1118,7 @@
 		     PJ_EINVAL);
     
-    PJSUA_LOCK();
+    status = acquire_call("pjsua_call_dial_dtmf()", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return status;
 
     call = &pjsua_var.calls[call_id];
@@ -1072,5 +1126,5 @@
     if (!call->session) {
 	PJ_LOG(3,(THIS_FILE, "Media is not established yet!"));
-	PJSUA_UNLOCK();
+	pjsip_dlg_dec_lock(call->inv->dlg);
 	return PJ_EINVALIDOP;
     }
@@ -1078,5 +1132,5 @@
     status = pjmedia_session_dial_dtmf( call->session, 0, digits);
 
-    PJSUA_UNLOCK();
+    pjsip_dlg_dec_lock(call->inv->dlg);
 
     return status;
@@ -1104,17 +1158,8 @@
 		     PJ_EINVAL);
 
-    PJSUA_LOCK();
-
-    call = &pjsua_var.calls[call_id];
-
-    if (!call->inv) {
-	PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
-	PJSUA_UNLOCK();
-	return PJSIP_ESESSIONTERMINATED;
-    }
-
-    /* Lock dialog. */
-    pjsip_dlg_inc_lock(call->inv->dlg);
-
+    status = acquire_call("pjsua_call_send_im", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return status;
+    
     /* Set default media type if none is specified */
     if (mime_type == NULL) {
@@ -1168,5 +1213,4 @@
 on_return:
     pjsip_dlg_dec_lock(call->inv->dlg);
-    PJSUA_UNLOCK();
     return status;
 }
@@ -1184,21 +1228,11 @@
     pj_status_t status;
 
-
     PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls,
 		     PJ_EINVAL);
 
-    PJSUA_LOCK();
-
-    call = &pjsua_var.calls[call_id];
-
-    if (!call->inv) {
-	PJ_LOG(3,(THIS_FILE,"Call has been disconnected"));
-	PJSUA_UNLOCK();
-	return PJSIP_ESESSIONTERMINATED;
-    }
-
-    /* Lock dialog. */
-    pjsip_dlg_inc_lock(call->inv->dlg);
-    
+    status = acquire_call("pjsua_call_send_typing_ind", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return status;
+
     /* Create request message. */
     status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method,
@@ -1225,5 +1259,4 @@
 on_return:
     pjsip_dlg_dec_lock(call->inv->dlg);
-    PJSUA_UNLOCK();
     return status;
 }
@@ -1502,4 +1535,5 @@
     char tmp[128];
     char *p, *end;
+    pj_status_t status;
     int len;
 
@@ -1507,7 +1541,7 @@
 		     PJ_EINVAL);
 
-    PJSUA_LOCK();
-
-    call = &pjsua_var.calls[call_id];
+    status = acquire_call("pjsua_call_dump()", call_id, &call);
+    if (status != PJ_SUCCESS)
+	return status;
 
     *buffer = '\0';
@@ -1515,9 +1549,4 @@
     end = buffer + maxlen;
     len = 0;
-
-    if (call->inv == NULL) {
-	PJSUA_UNLOCK();
-	return PJ_EINVALIDOP;
-    }
 
     print_call(indent, call_id, tmp, sizeof(tmp));
@@ -1570,5 +1599,5 @@
 	dump_media_session(indent, p, end-p, call->session);
 
-    PJSUA_UNLOCK();
+    pjsip_dlg_dec_lock(call->inv->dlg);
 
     return PJ_SUCCESS;
