Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 4886)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 4887)
@@ -1884,22 +1884,9 @@
 
 /**
- * Register a thread to poll for events. This function should be
- * called by an external worker thread, and it will block polling
- * for events until the library is destroyed.
- *
- * @return 		PJ_SUCCESS if things are working correctly
- * 			or an error polling cannot be done for some
- * 			reason.
- */
-PJ_DECL(pj_status_t) pjsua_register_worker_thread(const char *name);
-
-
-/**
  * Signal all worker threads to quit. This will only wait until internal
- * threads are done. For external threads, application must perform
- * its own waiting for the external threads to quit from
- * pjsua_register_worker_thread() function.
+ * threads are done.
  */
 PJ_DECL(void) pjsua_stop_worker_threads(void);
+
 
 /**
Index: /pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp	(revision 4886)
+++ /pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp	(revision 4887)
@@ -28,4 +28,5 @@
 #include <pjsua2/siptypes.hpp>
 #include <list>
+#include <map>
 
 /** PJSUA2 API is inside pj namespace */
@@ -722,9 +723,19 @@
 
     /**
-     * Register a thread to poll for events. This function should be
-     * called by an external worker thread, and it will block polling
-     * for events until the library is destroyed.
-     */
-    void libRegisterWorkerThread(const string &name) throw(Error);
+     * Register a thread that was created by external or native API to the
+     * library. Note that each time this function is called, it will allocate
+     * some memory to store the thread description, which will only be freed
+     * when the library is destroyed.
+     *
+     * @param name	The optional name to be assigned to the thread.
+     */
+    void libRegisterThread(const string &name) throw(Error);
+
+    /**
+     * Check if this thread has been registered to the library. Note that
+     * this function is only applicable for library main & worker threads and
+     * external/native threads registered using libRegisterThread().
+     */
+    bool libIsThreadRegistered();
 
     /**
@@ -1173,4 +1184,5 @@
     AudDevManager		 audioDevMgr;
     CodecInfoVector		 codecInfoList;
+    std::map<pj_thread_t*, pj_thread_desc*> threadDescMap;
 
     /* Pending logging */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 4886)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 4887)
@@ -700,27 +700,4 @@
 }
 
-PJ_DEF(pj_status_t) pjsua_register_worker_thread(const char *name)
-{
-    pj_thread_desc desc;
-    pj_thread_t *thread;
-    pj_status_t status;
-
-    if (pjsua_var.thread_quit_flag)
-	return PJ_EGONE;
-
-    status = pj_thread_register(NULL, desc, &thread);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    if (name)
-	PJ_LOG(4,(THIS_FILE, "Worker thread %s started", name));
-
-    worker_thread(NULL);
-
-    if (name)
-	PJ_LOG(4,(THIS_FILE, "Worker thread %s stopped", name));
-
-    return PJ_SUCCESS;
-}
 
 PJ_DEF(void) pjsua_stop_worker_threads(void)
Index: /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 4886)
+++ /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 4887)
@@ -27,6 +27,5 @@
 using namespace std;
 
-#include <pjsua2/account.hpp>
-#include <pjsua2/call.hpp>
+#include <pjsua-lib/pjsua_internal.h>   /* For retrieving pjsua threads */
 
 #define THIS_FILE		"endpoint.cpp"
@@ -1218,4 +1217,7 @@
     PJSUA2_CHECK_EXPR( pjsua_create() );
     mainThread = pj_thread_this();
+    
+    /* Register library main thread */
+    threadDescMap[pj_thread_this()] = NULL;
 }
 
@@ -1278,4 +1280,21 @@
     /* Init! */
     PJSUA2_CHECK_EXPR( pjsua_init(&ua_cfg, &log_cfg, &med_cfg) );
+
+    /* Register worker threads */
+    int i = pjsua_var.ua_cfg.thread_cnt;
+    while (i) {
+	pj_thread_t *t = pjsua_var.thread[--i];
+	if (t)
+	    threadDescMap[t] = NULL;
+    }
+
+    /* Register media endpoint worker thread */
+    pjmedia_endpt *medept = pjsua_get_pjmedia_endpt();
+    i = pjmedia_endpt_get_thread_count(medept);
+    while (i) {
+	pj_thread_t *t = pjmedia_endpt_get_thread(medept, --i);
+	if (t)
+	    threadDescMap[t] = NULL;
+    }
 }
 
@@ -1285,7 +1304,28 @@
 }
 
-void Endpoint::libRegisterWorkerThread(const string &name) throw(Error)
-{
-    PJSUA2_CHECK_EXPR(pjsua_register_worker_thread(name.c_str()));
+void Endpoint::libRegisterThread(const string &name) throw(Error)
+{
+    pj_thread_t *thread;
+    pj_thread_desc *desc;
+    pj_status_t status;
+
+    desc = (pj_thread_desc*)malloc(sizeof(pj_thread_desc));
+    status = pj_thread_register(name.c_str(), *desc, &thread);
+    if (status == PJ_SUCCESS) {
+	threadDescMap[thread] = desc;
+    } else {
+	free(desc);
+	PJSUA2_RAISE_ERROR(status);
+    }
+}
+
+bool Endpoint::libIsThreadRegistered()
+{
+    if (pj_thread_is_registered()) {
+	/* Recheck again if it exists in the thread description map */
+	return (threadDescMap.find(pj_thread_this()) != threadDescMap.end());
+    }
+
+    return false;
 }
 
@@ -1315,4 +1355,13 @@
     }
 #endif
+
+    /* Clean up thread descriptors */
+    std::map<pj_thread_t*, pj_thread_desc*>::iterator i;
+    for (i = threadDescMap.begin(); i != threadDescMap.end(); ++i) {
+	pj_thread_desc* d = (*i).second;
+	if (d != NULL)
+	    free(d);
+    }
+    threadDescMap.clear();
 
     PJSUA2_CHECK_RAISE_ERROR(status);
