Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 2942)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 2943)
@@ -1726,4 +1726,15 @@
 
 /**
+ * Default maximum time to wait for account unregistration transactions to
+ * complete during library shutdown sequence.
+ *
+ * Default: 4000 (4 seconds)
+ */
+#ifndef PJSUA_UNREG_TIMEOUT
+#   define PJSUA_UNREG_TIMEOUT	    4000
+#endif
+
+
+/**
  * Default PUBLISH expiration
  */
@@ -1919,4 +1930,12 @@
      */
     unsigned	    reg_timeout;
+
+    /**
+     * Specify the maximum time to wait for unregistration requests to
+     * complete during library shutdown sequence.
+     *
+     * Default: PJSUA_UNREG_TIMEOUT
+     */
+    unsigned	    unreg_timeout;
 
     /** 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 2942)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 2943)
@@ -645,4 +645,12 @@
     if (dlg || tsx)
 	return PJ_FALSE;
+
+    /* Don't want to accept the call if shutdown is in progress */
+    if (pjsua_var.thread_quit_flag) {
+	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 
+				      PJSIP_SC_TEMPORARILY_UNAVAILABLE, NULL,
+				      NULL, NULL);
+	return PJ_TRUE;
+    }
 
     PJSUA_LOCK();
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 2942)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 2943)
@@ -162,4 +162,5 @@
 
     cfg->reg_timeout = PJSUA_REG_INTERVAL;
+    cfg->unreg_timeout = PJSUA_UNREG_TIMEOUT;
     pjsip_publishc_opt_default(&cfg->publish_opt);
     cfg->unpublish_max_wait_time_msec = PJSUA_UNPUBLISH_MAX_WAIT_TIME_MSEC;
@@ -304,4 +305,12 @@
     {
 	return PJ_FALSE;
+    }
+
+    /* Don't want to handle if shutdown is in progress */
+    if (pjsua_var.thread_quit_flag) {
+	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 
+				      PJSIP_SC_TEMPORARILY_UNAVAILABLE, NULL,
+				      NULL, NULL);
+	return PJ_TRUE;
     }
 
@@ -1232,4 +1241,6 @@
 	unsigned max_wait;
 
+	PJ_LOG(4,(THIS_FILE, "Shutting down..."));
+
 	/* Terminate all calls. */
 	pjsua_call_hangup_all();
@@ -1245,4 +1256,7 @@
 	/* Terminate all presence subscriptions. */
 	pjsua_pres_shutdown();
+
+	/* Destroy media (to shutdown media transports etc) */
+	pjsua_media_subsys_destroy();
 
 	/* Wait for sometime until all publish client sessions are done
@@ -1291,8 +1305,4 @@
 	    }
 	}
-    }
-
-    /* Destroy endpoint. */
-    if (pjsua_var.endpt) {
 
 	/* Terminate any pending STUN resolution */
@@ -1306,21 +1316,38 @@
 	}
 
+	/* Wait until all unregistrations are done (ticket #364) */
+	/* First stage, get the maximum wait time */
+	max_wait = 100;
+	for (i=0; i<PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+	    if (!pjsua_var.acc[i].valid)
+		continue;
+	    if (pjsua_var.acc[i].cfg.unreg_timeout > max_wait)
+		max_wait = pjsua_var.acc[i].cfg.unreg_timeout;
+	}
+	
+	/* Second stage, wait for unregistrations to complete */
+	for (i=0; i<(int)(max_wait/50); ++i) {
+	    unsigned j;
+	    for (j=0; j<PJ_ARRAY_SIZE(pjsua_var.acc); ++j) {
+		if (!pjsua_var.acc[j].valid)
+		    continue;
+
+		if (pjsua_var.acc[j].regc)
+		    break;
+	    }
+	    if (j != PJ_ARRAY_SIZE(pjsua_var.acc))
+		busy_sleep(50);
+	    else
+		break;
+	}
+	/* Note variable 'i' is used below */
+
 	/* Wait for some time to allow unregistration and ICE/TURN
 	 * transports shutdown to complete: 
-	*/
-	PJ_LOG(4,(THIS_FILE, "Shutting down..."));
-	busy_sleep(1000);
+	 */
+	if (i < 20)
+	    busy_sleep(1000 - i*50);
 
 	PJ_LOG(4,(THIS_FILE, "Destroying..."));
-
-	/* Terminate all calls again, just in case there's new call
-	 * picked up during busy_sleep()
-	 */
-	pjsua_call_hangup_all();
-
-	/* Destroy media after all polling is done, as there may be
-	 * incoming request that needs handling (e.g. OPTIONS)
-	 */
-	pjsua_media_subsys_destroy();
 
 	/* Must destroy endpoint first before destroying pools in
@@ -1347,7 +1374,4 @@
 	    }
 	}
-    } else {
-	/* Destroy media */
-	pjsua_media_subsys_destroy();
     }
 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2942)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2943)
@@ -640,4 +640,6 @@
 {
     unsigned i;
+
+    PJ_LOG(4,(THIS_FILE, "Shutting down media.."));
 
     close_snd_dev();
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c	(revision 2942)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c	(revision 2943)
@@ -683,4 +683,12 @@
     /* Incoming SUBSCRIBE: */
 
+    /* Don't want to accept the request if shutdown is in progress */
+    if (pjsua_var.thread_quit_flag) {
+	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 
+				      PJSIP_SC_TEMPORARILY_UNAVAILABLE, NULL,
+				      NULL, NULL);
+	return PJ_TRUE;
+    }
+
     PJSUA_LOCK();
 
@@ -1722,4 +1730,6 @@
     unsigned i;
 
+    PJ_LOG(4,(THIS_FILE, "Shutting down presence.."));
+
     if (pjsua_var.pres_timer.id != 0) {
 	pjsip_endpt_cancel_timer(pjsua_var.endpt, &pjsua_var.pres_timer);
