Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 656)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 657)
@@ -140,4 +140,5 @@
     puts  ("  --auto-answer=code  Automatically answer incoming calls with code (e.g. 200)");
     puts  ("  --max-calls=N       Maximum number of concurrent calls (default:4, max:255)");
+    puts  ("  --thread-cnt=N      Number of worker threads (default:1)");
     /*
     puts  ("  --duration=SEC      Set maximum call duration (default:no limit)");
@@ -265,5 +266,5 @@
 	   OPT_RX_DROP_PCT, OPT_TX_DROP_PCT, OPT_EC_TAIL,
 	   OPT_NEXT_ACCOUNT, OPT_NEXT_CRED, OPT_MAX_CALLS, 
-	   OPT_DURATION, OPT_NO_TCP, OPT_NO_UDP,
+	   OPT_DURATION, OPT_NO_TCP, OPT_NO_UDP, OPT_THREAD_CNT,
     };
     struct pj_getopt_option long_options[] = {
@@ -312,5 +313,6 @@
 	{ "next-cred",	0, 0, OPT_NEXT_CRED},
 	{ "max-calls",	1, 0, OPT_MAX_CALLS},
-	{ "duration",1,0, OPT_DURATION},
+	{ "duration",	1, 0, OPT_DURATION},
+	{ "thread-cnt",	1, 0, OPT_THREAD_CNT},
 	{ NULL, 0, 0, 0}
     };
@@ -612,4 +614,13 @@
 	    break;
 	*/
+
+	case OPT_THREAD_CNT:
+	    cfg->cfg.thread_cnt = my_atoi(pj_optarg);
+	    if (cfg->cfg.thread_cnt > 128) {
+		PJ_LOG(1,(THIS_FILE,
+			  "Error: invalid --thread-cnt option"));
+		return -1;
+	    }
+	    break;
 
 	case OPT_PTIME:
Index: /pjproject/trunk/pjsip-apps/src/samples/pjsip-perf.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/pjsip-perf.c	(revision 656)
+++ /pjproject/trunk/pjsip-apps/src/samples/pjsip-perf.c	(revision 657)
@@ -159,4 +159,7 @@
 
     struct {
+	pj_bool_t send_trying;
+	pj_bool_t send_ringing;
+	unsigned delay;
 	struct srv_state prev_state;
 	struct srv_state cur_state;
@@ -169,5 +172,5 @@
 {
     pjsip_inv_session	*inv;
-    pj_timer_entry	 timer;
+    pj_timer_entry	 ans_timer;
 };
 
@@ -344,4 +347,58 @@
 
 
+static pj_status_t send_response(pjsip_inv_session *inv, 
+				 pjsip_rx_data *rdata,
+				 int code,
+				 pj_bool_t *has_initial)
+{
+    pjsip_tx_data *tdata;
+    pj_status_t status;
+
+    if (*has_initial) {
+	status = pjsip_inv_answer(inv, code, NULL, NULL, &tdata);
+    } else {
+	status = pjsip_inv_initial_answer(inv, rdata, code, 
+					  NULL, NULL, &tdata);
+    }
+
+    if (status != PJ_SUCCESS) {
+	if (*has_initial) {
+	    status = pjsip_inv_answer(inv, PJSIP_SC_NOT_ACCEPTABLE, 
+				      NULL, NULL, &tdata);
+	} else {
+	    status = pjsip_inv_initial_answer(inv, rdata, 
+					      PJSIP_SC_NOT_ACCEPTABLE,
+					      NULL, NULL, &tdata);
+	}
+
+	if (status == PJ_SUCCESS) {
+	    *has_initial = PJ_TRUE;
+	    pjsip_inv_send_msg(inv, tdata); 
+	} else {
+	    pjsip_inv_terminate(inv, 500, PJ_FALSE);
+	    return -1;
+	}
+    } else {
+	*has_initial = PJ_TRUE;
+
+	status = pjsip_inv_send_msg(inv, tdata); 
+	if (status != PJ_SUCCESS) {
+	    pjsip_tx_data_dec_ref(tdata);
+	    return status;
+	}
+    }
+
+    return status;
+}
+
+static void answer_timer_cb(pj_timer_heap_t *h, pj_timer_entry *entry)
+{
+    struct call *call = entry->user_data;
+    pj_bool_t has_initial = PJ_TRUE;
+
+    entry->id = 0;
+    send_response(call->inv, NULL, 200, &has_initial);
+}
+
 static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata)
 {
@@ -353,4 +410,5 @@
     pjmedia_sdp_session *sdp;
     pjsip_tx_data *tdata;
+    pj_bool_t has_initial = PJ_FALSE;
     pj_status_t status;
 
@@ -445,24 +503,37 @@
     }
     
-
-    /* Create 200 response .*/
-    status = pjsip_inv_initial_answer(call->inv, rdata, 200, 
-				      NULL, NULL, &tdata);
-    if (status != PJ_SUCCESS) {
-	status = pjsip_inv_initial_answer(call->inv, rdata, 
-					  PJSIP_SC_NOT_ACCEPTABLE,
-					  NULL, NULL, &tdata);
-	if (status == PJ_SUCCESS)
-	    pjsip_inv_send_msg(call->inv, tdata); 
-	else
-	    pjsip_inv_terminate(call->inv, 500, PJ_FALSE);
-	return PJ_TRUE;
-    }
-
-
-    /* Send the 200 response. */  
-    status = pjsip_inv_send_msg(call->inv, tdata); 
-    PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return PJ_TRUE);
-
+    /* Send 100/Trying if needed */
+    if (app.server.send_trying) {
+	status = send_response(call->inv, rdata, 100, &has_initial);
+	if (status != PJ_SUCCESS)
+	    return PJ_TRUE;
+    }
+
+    /* Send 180/Ringing if needed */
+    if (app.server.send_ringing) {
+	status = send_response(call->inv, rdata, 180, &has_initial);
+	if (status != PJ_SUCCESS)
+	    return PJ_TRUE;
+    }
+
+    /* Simulate call processing delay */
+    if (app.server.delay) {
+	pj_time_val delay;
+
+	call->ans_timer.id = 1;
+	call->ans_timer.user_data = call;
+	call->ans_timer.cb = &answer_timer_cb;
+	
+	delay.sec = 0;
+	delay.msec = app.server.delay;
+	pj_time_val_normalize(&delay);
+
+	pjsip_endpt_schedule_timer(app.sip_endpt, &call->ans_timer, &delay);
+
+    } else {
+	/* Send the 200 response immediately . */  
+	status = pjsip_inv_send_msg(call->inv, tdata); 
+	PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return PJ_TRUE);
+    }
 
     /* Done */
@@ -1063,4 +1134,7 @@
 	"                           [default: no]\n"
 	"   --thread-count=N        Set number of worker threads [default=1]\n"
+	"   --trying                Send 100/Trying response (server, default no)\n"
+	"   --ringing               Send 180/Ringing response (server, default no)\n"
+	"   --delay=MS, -d          Delay answering call by MS (server, default no)\n"
 	"\n"
 	"Misc options:\n"
@@ -1085,5 +1159,5 @@
 static pj_status_t init_options(int argc, char *argv[])
 {
-    enum { OPT_THREAD_COUNT = 1, OPT_REAL_SDP };
+    enum { OPT_THREAD_COUNT = 1, OPT_REAL_SDP, OPT_TRYING, OPT_RINGING };
     struct pj_getopt_option long_options[] = {
 	{ "local-port",	    1, 0, 'p' },
@@ -1098,4 +1172,7 @@
 	{ "use-tcp",	    0, 0, 'T' },
 	{ "window",	    1, 0, 'w' },
+	{ "delay",	    1, 0, 'd' },
+	{ "trying",	    0, 0, OPT_TRYING},
+	{ "ringing",	    0, 0, OPT_RINGING},
 	{ NULL, 0, 0, 0 },
     };
@@ -1115,5 +1192,5 @@
     /* Parse options */
     pj_optind = 0;
-    while((c=pj_getopt_long(argc,argv, "p:c:m:t:w:hsv", 
+    while((c=pj_getopt_long(argc,argv, "p:c:m:t:w:d:hsv", 
 			    long_options, &option_index))!=-1) 
     {
@@ -1189,4 +1266,21 @@
 	case 'T':
 	    app.use_tcp = PJ_TRUE;
+	    break;
+
+	case 'd':
+	    app.server.delay = my_atoi(pj_optarg);
+	    if (app.server.delay > 3600) {
+		PJ_LOG(3,(THIS_FILE, "I think --delay %s is too long", 
+			  pj_optarg));
+		return -1;
+	    }
+	    break;
+
+	case OPT_TRYING:
+	    app.server.send_trying = 1;
+	    break;
+
+	case OPT_RINGING:
+	    app.server.send_ringing = 1;
 	    break;
 
Index: /pjproject/trunk/pjsip-apps/src/samples/siprtp.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 656)
+++ /pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 657)
@@ -1062,5 +1062,4 @@
 {
 #define POLICY	SCHED_FIFO
-    pthread_t thread;
     struct sched_param tp;
     int max_prio;
Index: /pjproject/trunk/pjsip-apps/src/samples/sndinfo.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/sndinfo.c	(revision 656)
+++ /pjproject/trunk/pjsip-apps/src/samples/sndinfo.c	(revision 657)
@@ -118,5 +118,5 @@
 
 static pj_status_t rec_cb(void *user_data, pj_uint32_t timestamp,
-			  const void *input, unsigned size)
+			  void *input, unsigned size)
 {
 
Index: /pjproject/trunk/pjsip-apps/src/samples/sndtest.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/sndtest.c	(revision 656)
+++ /pjproject/trunk/pjsip-apps/src/samples/sndtest.c	(revision 657)
@@ -199,5 +199,5 @@
 
 static pj_status_t rec_cb(void *user_data, pj_uint32_t timestamp,
-			  const void *input, unsigned size)
+			  void *input, unsigned size)
 {
 
Index: /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 656)
+++ /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 657)
@@ -257,8 +257,16 @@
     if (method->id == PJSIP_ACK_METHOD && inv) {
 
+	/* Ignore ACK if pending INVITE transaction has not finished. */
+	if (inv->invite_tsx && 
+	    inv->invite_tsx->state < PJSIP_TSX_STATE_COMPLETED)
+	{
+	    return PJ_TRUE;
+	}
+
 	/* Terminate INVITE transaction, if it's still present. */
 	if (inv->invite_tsx && 
 	    inv->invite_tsx->state <= PJSIP_TSX_STATE_COMPLETED)
 	{
+	    pj_assert(inv->invite_tsx->status_code >= 200);
 	    pjsip_tsx_terminate(inv->invite_tsx, 
 				inv->invite_tsx->status_code);
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 656)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 657)
@@ -1010,4 +1010,7 @@
     pjsip_tsx_state_e prev_state = tsx->state;
 
+    /* New state must be greater than previous state */
+    pj_assert(state >= tsx->state);
+
     PJ_LOG(5, (tsx->obj_name, "State changed from %s to %s, event=%s",
 	       state_str[tsx->state], state_str[state], 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 656)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 657)
@@ -553,4 +553,8 @@
 		goto on_error;
 	}
+	PJ_LOG(4,(THIS_FILE, "%d SIP worker threads created", 
+		  pjsua_var.ua_cfg.thread_cnt));
+    } else {
+	PJ_LOG(4,(THIS_FILE, "No SIP worker threads created"));
     }
 
