Index: pjproject/branches/1.x/pjlib/src/pj/os_core_symbian.cpp
===================================================================
--- pjproject/branches/1.x/pjlib/src/pj/os_core_symbian.cpp	(revision 3978)
+++ pjproject/branches/1.x/pjlib/src/pj/os_core_symbian.cpp	(revision 3986)
@@ -76,4 +76,7 @@
 };
 
+/* Flag and reference counter for PJLIB instance */
+static int initialized;
+
 /* Flags to indicate which TLS variables have been used */
 static int tls_vars[PJ_MAX_TLS];
@@ -82,6 +85,4 @@
 static unsigned atexit_count;
 static void (*atexit_func[32])(void);
-
-
 
 
@@ -336,4 +337,10 @@
     pj_status_t status;
     
+    /* Check if PJLIB have been initialized */
+    if (initialized) {
+	++initialized;
+	return PJ_SUCCESS;
+    }
+
     pj_ansi_strcpy(main_thread.obj_name, "pjthread");
 
@@ -369,4 +376,8 @@
 #endif
 
+    /* Flag PJLIB as initialized */
+    ++initialized;
+    pj_assert(initialized == 1);
+
     PJ_LOG(5,(THIS_FILE, "PJLIB initialized."));
     return PJ_SUCCESS;
@@ -391,4 +402,9 @@
 PJ_DEF(void) pj_shutdown(void)
 {
+    /* Only perform shutdown operation when 'initialized' reaches zero */
+    pj_assert(initialized > 0);
+    if (--initialized != 0)
+	return;
+
     /* Call atexit() functions */
     while (atexit_count > 0) {
Index: pjproject/branches/1.x/pjlib/src/pj/os_core_unix.c
===================================================================
--- pjproject/branches/1.x/pjlib/src/pj/os_core_unix.c	(revision 3978)
+++ pjproject/branches/1.x/pjlib/src/pj/os_core_unix.c	(revision 3986)
@@ -103,4 +103,9 @@
 
 
+/*
+ * Flag and reference counter for PJLIB instance.
+ */
+static int initialized;
+
 #if PJ_HAS_THREADS
     static pj_thread_t main_thread;
@@ -127,4 +132,10 @@
     pj_str_t guid;
     pj_status_t rc;
+
+    /* Check if PJLIB have been initialized */
+    if (initialized) {
+	++initialized;
+	return PJ_SUCCESS;
+    }
 
 #if PJ_HAS_THREADS
@@ -168,4 +179,8 @@
 #endif   
 
+    /* Flag PJLIB as initialized */
+    ++initialized;
+    pj_assert(initialized == 1);
+
     PJ_LOG(4,(THIS_FILE, "pjlib %s for POSIX initialized",
 	      PJ_VERSION));
@@ -192,4 +207,9 @@
 {
     int i;
+
+    /* Only perform shutdown operation when 'initialized' reaches zero */
+    pj_assert(initialized > 0);
+    if (--initialized != 0)
+	return;
 
     /* Call atexit() functions */
Index: pjproject/branches/1.x/pjlib/src/pj/os_core_win32.c
===================================================================
--- pjproject/branches/1.x/pjlib/src/pj/os_core_win32.c	(revision 3978)
+++ pjproject/branches/1.x/pjlib/src/pj/os_core_win32.c	(revision 3986)
@@ -118,4 +118,9 @@
 
 /*
+ * Flag and reference counter for PJLIB instance.
+ */
+static int initialized;
+
+/*
  * Static global variables.
  */
@@ -142,4 +147,10 @@
     pj_str_t guid;
     pj_status_t rc;
+
+    /* Check if PJLIB have been initialized */
+    if (initialized) {
+	++initialized;
+	return PJ_SUCCESS;
+    }
 
     /* Init Winsock.. */
@@ -188,4 +199,8 @@
 #endif   
 
+    /* Flag PJLIB as initialized */
+    ++initialized;
+    pj_assert(initialized == 1);
+
     PJ_LOG(4,(THIS_FILE, "pjlib %s for win32 initialized",
 	      PJ_VERSION));
@@ -213,4 +228,9 @@
 {
     int i;
+
+    /* Only perform shutdown operation when 'initialized' reaches zero */
+    pj_assert(initialized > 0);
+    if (--initialized != 0)
+	return;
 
     /* Display stack usage */
Index: pjproject/branches/1.x/pjmedia/include/pjmedia/endpoint.h
===================================================================
--- pjproject/branches/1.x/pjmedia/include/pjmedia/endpoint.h	(revision 3978)
+++ pjproject/branches/1.x/pjmedia/include/pjmedia/endpoint.h	(revision 3986)
@@ -58,4 +58,10 @@
 
 } pjmedia_endpt_flag;
+
+
+/**
+ * Type of callback to register to pjmedia_endpt_atexit().
+ */
+typedef void (*pjmedia_endpt_exit_callback)(pjmedia_endpt *endpt);
 
 
@@ -205,4 +211,18 @@
 
 
+/**
+ * Register cleanup function to be called by media endpoint when 
+ * #pjmedia_endpt_destroy() is called.
+ *
+ * @param endpt		The media endpoint.
+ * @param func		The function to be registered.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_endpt_atexit(pjmedia_endpt *endpt,
+					  pjmedia_endpt_exit_callback func);
+
+
+
 PJ_END_DECL
 
Index: pjproject/branches/1.x/pjmedia/include/pjmedia/transport_srtp.h
===================================================================
--- pjproject/branches/1.x/pjmedia/include/pjmedia/transport_srtp.h	(revision 3978)
+++ pjproject/branches/1.x/pjmedia/include/pjmedia/transport_srtp.h	(revision 3986)
@@ -201,6 +201,10 @@
  * library deinitialization to #pj_atexit(), so the deinitialization
  * of SRTP library will be performed automatically by PJLIB destructor.
- */
-PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(void);
+ *
+ * @param endpt	    The media endpoint instance.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt);
 
 
Index: pjproject/branches/1.x/pjmedia/src/pjmedia/endpoint.c
===================================================================
--- pjproject/branches/1.x/pjmedia/src/pjmedia/endpoint.c	(revision 3978)
+++ pjproject/branches/1.x/pjmedia/src/pjmedia/endpoint.c	(revision 3986)
@@ -24,4 +24,5 @@
 #include <pj/assert.h>
 #include <pj/ioqueue.h>
+#include <pj/lock.h>
 #include <pj/log.h>
 #include <pj/os.h>
@@ -57,4 +58,12 @@
 
 
+/* List of media endpoint exit callback. */
+typedef struct exit_cb
+{
+    PJ_DECL_LIST_MEMBER		    (struct exit_cb);
+    pjmedia_endpt_exit_callback	    func;
+} exit_cb;
+
+
 /** Concrete declaration of media endpoint. */
 struct pjmedia_endpt
@@ -86,4 +95,7 @@
     /** Is telephone-event enable */
     pj_bool_t		  has_telephone_event;
+
+    /** List of exit callback. */
+    exit_cb		  exit_cb_list;
 };
 
@@ -129,4 +141,7 @@
 	goto on_error;
 
+    /* Initialize exit callback list. */
+    pj_list_init(&endpt->exit_cb_list);
+
     /* Create ioqueue if none is specified. */
     if (endpt->ioqueue == NULL) {
@@ -189,4 +204,5 @@
 PJ_DEF(pj_status_t) pjmedia_endpt_destroy (pjmedia_endpt *endpt)
 {
+    exit_cb *ecb;
     unsigned i;
 
@@ -202,4 +218,11 @@
 	    endpt->thread[i] = NULL;
 	}
+    }
+
+    /* Call all registered exit callbacks */
+    ecb = endpt->exit_cb_list.next;
+    while (ecb != &endpt->exit_cb_list) {
+	(*ecb->func)(endpt);
+	ecb = ecb->next;
     }
 
@@ -629,2 +652,22 @@
     return PJ_SUCCESS;
 }
+
+PJ_DEF(pj_status_t) pjmedia_endpt_atexit( pjmedia_endpt *endpt,
+					  pjmedia_endpt_exit_callback func)
+{
+    exit_cb *new_cb;
+
+    PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
+
+    if (endpt->quit_flag)
+	return PJ_EINVALIDOP;
+
+    new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
+    new_cb->func = func;
+
+    pj_enter_critical_section();
+    pj_list_push_back(&endpt->exit_cb_list, new_cb);
+    pj_leave_critical_section();
+
+    return PJ_SUCCESS;
+}
Index: pjproject/branches/1.x/pjmedia/src/pjmedia/transport_srtp.c
===================================================================
--- pjproject/branches/1.x/pjmedia/src/pjmedia/transport_srtp.c	(revision 3978)
+++ pjproject/branches/1.x/pjmedia/src/pjmedia/transport_srtp.c	(revision 3986)
@@ -271,7 +271,7 @@
 
 static pj_bool_t libsrtp_initialized;
-static void pjmedia_srtp_deinit_lib(void);
-
-PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(void)
+static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt);
+
+PJ_DEF(pj_status_t) pjmedia_srtp_init_lib(pjmedia_endpt *endpt)
 {
     if (libsrtp_initialized == PJ_FALSE) {
@@ -285,5 +285,6 @@
 	}
 
-	if (pj_atexit(pjmedia_srtp_deinit_lib) != PJ_SUCCESS) {
+	if (pjmedia_endpt_atexit(endpt, pjmedia_srtp_deinit_lib) != PJ_SUCCESS)
+	{
 	    /* There will be memory leak when it fails to schedule libsrtp 
 	     * deinitialization, however the memory leak could be harmless,
@@ -300,7 +301,16 @@
 }
 
-static void pjmedia_srtp_deinit_lib(void)
+static void pjmedia_srtp_deinit_lib(pjmedia_endpt *endpt)
 {
     err_status_t err;
+
+    /* Note that currently this SRTP init/deinit is not equipped with
+     * reference counter, it should be safe as normally there is only
+     * one single instance of media endpoint and even if it isn't, the
+     * pjmedia_transport_srtp_create() will invoke SRTP init (the only
+     * drawback should be the delay described by #788).
+     */
+
+    PJ_UNUSED_ARG(endpt);
 
     err = srtp_deinit();
@@ -411,5 +421,5 @@
 
     /* Init libsrtp. */
-    status = pjmedia_srtp_init_lib();
+    status = pjmedia_srtp_init_lib(endpt);
     if (status != PJ_SUCCESS)
 	return status;
Index: pjproject/branches/1.x/pjsip/include/pjsip/sip_endpoint.h
===================================================================
--- pjproject/branches/1.x/pjsip/include/pjsip/sip_endpoint.h	(revision 3978)
+++ pjproject/branches/1.x/pjsip/include/pjsip/sip_endpoint.h	(revision 3986)
@@ -63,4 +63,11 @@
  */
 
+
+/**
+ * Type of callback to register to pjsip_endpt_atexit().
+ */
+typedef void (*pjsip_endpt_exit_callback)(pjsip_endpoint *endpt);
+
+
 /**
  * Create an instance of SIP endpoint from the specified pool factory.
@@ -512,4 +519,16 @@
 
 
+/**
+ * Register cleanup function to be called by SIP endpoint when 
+ * #pjsip_endpt_destroy() is called.
+ *
+ * @param endpt		The SIP endpoint.
+ * @param func		The function to be registered.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjsip_endpt_atexit(pjsip_endpoint *endpt,
+					pjsip_endpt_exit_callback func);
+
 
 /**
Index: pjproject/branches/1.x/pjsip/src/pjsip-ua/sip_replaces.c
===================================================================
--- pjproject/branches/1.x/pjsip/src/pjsip-ua/sip_replaces.c	(revision 3978)
+++ pjproject/branches/1.x/pjsip/src/pjsip-ua/sip_replaces.c	(revision 3986)
@@ -163,6 +163,8 @@
 
 /* Deinitialize Replaces */
-static void pjsip_replaces_deinit_module(void)
-{
+static void pjsip_replaces_deinit_module(pjsip_endpoint *endpt)
+{
+    PJ_TODO(provide_initialized_flag_for_each_endpoint);
+    PJ_UNUSED_ARG(endpt);
     is_initialized = PJ_FALSE;
 }
@@ -192,5 +194,6 @@
 
     /* Register deinit module to be executed when PJLIB shutdown */
-    if (pj_atexit(&pjsip_replaces_deinit_module) != PJ_SUCCESS) {
+    if (pjsip_endpt_atexit(endpt, &pjsip_replaces_deinit_module) != PJ_SUCCESS)
+    {
 	/* Failure to register this function may cause this module won't 
 	 * work properly when the stack is restarted (without quitting 
Index: pjproject/branches/1.x/pjsip/src/pjsip-ua/sip_timer.c
===================================================================
--- pjproject/branches/1.x/pjsip/src/pjsip-ua/sip_timer.c	(revision 3978)
+++ pjproject/branches/1.x/pjsip/src/pjsip-ua/sip_timer.c	(revision 3986)
@@ -496,6 +496,8 @@
 
 /* Deinitialize Session Timers */
-static void pjsip_timer_deinit_module(void)
-{
+static void pjsip_timer_deinit_module(pjsip_endpoint *endpt)
+{
+    PJ_TODO(provide_initialized_flag_for_each_endpoint);
+    PJ_UNUSED_ARG(endpt);
     is_initialized = PJ_FALSE;
 }
@@ -532,5 +534,5 @@
 
     /* Register deinit module to be executed when PJLIB shutdown */
-    if (pj_atexit(&pjsip_timer_deinit_module) != PJ_SUCCESS) {
+    if (pjsip_endpt_atexit(endpt, &pjsip_timer_deinit_module) != PJ_SUCCESS) {
 	/* Failure to register this function may cause this module won't 
 	 * work properly when the stack is restarted (without quitting 
Index: pjproject/branches/1.x/pjsip/src/pjsip/sip_endpoint.c
===================================================================
--- pjproject/branches/1.x/pjsip/src/pjsip/sip_endpoint.c	(revision 3978)
+++ pjproject/branches/1.x/pjsip/src/pjsip/sip_endpoint.c	(revision 3986)
@@ -41,4 +41,13 @@
 #define MAX_METHODS   32
 
+
+/* List of SIP endpoint exit callback. */
+typedef struct exit_cb
+{
+    PJ_DECL_LIST_MEMBER		    (struct exit_cb);
+    pjsip_endpt_exit_callback	    func;
+} exit_cb;
+
+
 /**
  * The SIP endpoint.
@@ -87,4 +96,7 @@
     /** Additional request headers. */
     pjsip_hdr		 req_hdr;
+
+    /** List of exit callback. */
+    exit_cb		 exit_cb_list;
 };
 
@@ -446,4 +458,7 @@
     pj_list_init(&endpt->module_list);
 
+    /* Initialize exit callback list. */
+    pj_list_init(&endpt->exit_cb_list);
+
     /* Create R/W mutex for module manipulation. */
     status = pj_rwmutex_create(endpt->pool, "ept%p", &endpt->mod_mutex);
@@ -560,6 +575,14 @@
 {
     pjsip_module *mod;
+    exit_cb *ecb;
 
     PJ_LOG(5, (THIS_FILE, "Destroying endpoing instance.."));
+
+    /* Call all registered exit callbacks */
+    ecb = endpt->exit_cb_list.next;
+    while (ecb != &endpt->exit_cb_list) {
+	(*ecb->func)(endpt);
+	ecb = ecb->next;
+    }
 
     /* Phase 1: stop all modules */
@@ -1179,2 +1202,19 @@
 }
 
+
+PJ_DEF(pj_status_t) pjsip_endpt_atexit( pjsip_endpoint *endpt,
+					pjsip_endpt_exit_callback func)
+{
+    exit_cb *new_cb;
+
+    PJ_ASSERT_RETURN(endpt && func, PJ_EINVAL);
+
+    new_cb = PJ_POOL_ZALLOC_T(endpt->pool, exit_cb);
+    new_cb->func = func;
+
+    pj_mutex_lock(endpt->mutex);
+    pj_list_push_back(&endpt->exit_cb_list, new_cb);
+    pj_mutex_unlock(endpt->mutex);
+
+    return PJ_SUCCESS;
+}
Index: pjproject/branches/1.x/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- pjproject/branches/1.x/pjsip/src/pjsua-lib/pjsua_media.c	(revision 3978)
+++ pjproject/branches/1.x/pjsip/src/pjsua-lib/pjsua_media.c	(revision 3986)
@@ -336,6 +336,6 @@
 
 #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
-    /* Initialize SRTP library. */
-    status = pjmedia_srtp_init_lib();
+    /* Initialize SRTP library (ticket #788). */
+    status = pjmedia_srtp_init_lib(pjsua_var.med_endpt);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Error initializing SRTP library", 
