Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5961)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5962)
@@ -411,6 +411,4 @@
     pj_bool_t			 preview_running;/**< Preview is started*/
     pj_bool_t			 is_native; 	/**< Preview is by dev  */
-    pj_bool_t			 cap_started;	/**< Has the capture
-    						     been started?	*/
 } pjsua_vid_win;
 
@@ -877,5 +875,5 @@
 
 #if PJSUA_HAS_VIDEO
-PJ_DECL(void) pjsua_vid_win_reset(pjsua_vid_win_id wid);
+void pjsua_vid_win_reset(pjsua_vid_win_id wid);
 #else
 #  define pjsua_vid_win_reset(wid)
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 5961)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 5962)
@@ -250,6 +250,8 @@
 {
     pj_status_t status = PJ_SUCCESS;
-    pjsua_vid_win_id wid = vid_preview_get_win(id, PJ_FALSE);
+    pjsua_vid_win_id wid;
     
+    PJSUA_LOCK();
+    wid = vid_preview_get_win(id, PJ_FALSE);
     if (wid != PJSUA_INVALID_ID) {
         pjsua_vid_win *w;
@@ -260,9 +262,12 @@
 
     	status = pjmedia_vid_dev_stream_set_cap(cap_dev, cap, pval);
-	if (status != PJ_SUCCESS)
+	if (status != PJ_SUCCESS) {
+	    PJSUA_UNLOCK();
 	    return status;
+	}
     } else {
 	status = PJ_ENOTFOUND;
     }
+    PJSUA_UNLOCK();
 
     if (keep) {
@@ -293,6 +298,8 @@
 {
     pj_status_t status = PJ_SUCCESS;
-    pjsua_vid_win_id wid = vid_preview_get_win(id, PJ_FALSE);
+    pjsua_vid_win_id wid;
     
+    PJSUA_LOCK();
+    wid = vid_preview_get_win(id, PJ_FALSE);    
     if (wid != PJSUA_INVALID_ID) {
         pjsua_vid_win *w;
@@ -303,7 +310,11 @@
 
     	status = pjmedia_vid_dev_stream_get_cap(cap_dev, cap, pval);
+    	
+    	PJSUA_UNLOCK();
     } else {
 	pjmedia_vid_dev_info info;
-	    
+	
+	PJSUA_UNLOCK();
+
 	status = pjmedia_vid_dev_get_info(id, &info);
 	if (status != PJ_SUCCESS)
@@ -535,15 +546,19 @@
     pjsua_vid_win_id wid;
     pjsua_vid_win *w;
-
+    pjsua_conf_port_id conf_id = PJSUA_INVALID_ID;
+
+    PJSUA_LOCK();
     wid = vid_preview_get_win(id, PJ_TRUE);
-    if (wid == PJSUA_INVALID_ID)
-	return PJSUA_INVALID_ID;
-
-    w = &pjsua_var.win[wid];
-    return w->cap_slot;
-}
-
-
-PJ_DEF(void) pjsua_vid_win_reset(pjsua_vid_win_id wid)
+    if (wid != PJSUA_INVALID_ID) {
+    	w = &pjsua_var.win[wid];
+    	conf_id = w->cap_slot;
+    }
+    PJSUA_UNLOCK();
+    
+    return conf_id;
+}
+
+
+void pjsua_vid_win_reset(pjsua_vid_win_id wid)
 {
     pjsua_vid_win *w = &pjsua_var.win[wid];
@@ -896,4 +911,77 @@
 }
 
+static pj_status_t setup_vid_capture(pjsua_call_media *call_med)
+{
+    pjsua_acc *acc_enc = &pjsua_var.acc[call_med->call->acc_id];
+    pjmedia_port *media_port;
+    pjsua_vid_win *w;
+    pjsua_vid_win_id wid;
+    pj_bool_t just_created = PJ_FALSE;
+    pj_status_t status;
+
+    /* Retrieve stream encoding port */
+    status = pjmedia_vid_stream_get_port(call_med->strm.v.stream,
+					 PJMEDIA_DIR_ENCODING,
+					 &media_port);
+    if (status != PJ_SUCCESS)
+    	return status;
+
+    PJSUA_LOCK();
+
+    /* Note: calling pjsua_vid_preview_get_win() even though
+     * create_vid_win() will automatically create the window
+     * if it doesn't exist, because create_vid_win() will modify
+     * existing window SHOW/HIDE value.
+     */
+    wid = vid_preview_get_win(call_med->strm.v.cap_dev, PJ_FALSE);
+    if (wid == PJSUA_INVALID_ID) {
+    	/* Create preview video window */
+    	status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,
+			    	&media_port->info.fmt,
+				call_med->strm.v.rdr_dev,
+				call_med->strm.v.cap_dev,
+				PJSUA_HIDE_WINDOW,
+                                acc_enc->cfg.vid_wnd_flags,
+                                NULL,
+				&wid);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+
+	just_created = PJ_TRUE;
+    }
+
+    w = &pjsua_var.win[wid];
+#if ENABLE_EVENT
+    pjmedia_event_subscribe(NULL, &call_media_on_event,
+                            call_med, w->vp_cap);
+#endif
+
+    /* Connect capturer to stream encoding (via conf) */
+    status = pjsua_vid_conf_connect(w->cap_slot,
+				    call_med->strm.v.strm_enc_slot,
+				    NULL);
+    if (status != PJ_SUCCESS)
+    	goto on_error;
+
+    /* Start capturer */
+    if (just_created) {
+	status = pjmedia_vid_port_start(w->vp_cap);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+    }
+
+    /* Done */
+    inc_vid_win(wid);
+    call_med->strm.v.cap_win_id = wid;
+
+    PJSUA_UNLOCK();
+
+    return PJ_SUCCESS;
+
+on_error:
+    PJSUA_UNLOCK();
+    return status;
+}
+
 /* Internal function: update video channel after SDP negotiation.
  * Warning: do not use temporary/flip-flop pool, e.g: inv->pool_prov,
@@ -1021,4 +1109,5 @@
 
 	    /* Create stream video window */
+	    PJSUA_LOCK();
 	    status = create_vid_win(PJSUA_WND_TYPE_STREAM,
 				    &media_port->info.fmt,
@@ -1031,4 +1120,5 @@
 				    &wid);
 	    if (status != PJ_SUCCESS) {
+	        PJSUA_UNLOCK();
 		pj_log_pop_indent();
 		goto on_error;
@@ -1052,4 +1142,5 @@
 					     &call_med->strm.v.strm_dec_slot);
 	    if (status != PJ_SUCCESS) {
+	        PJSUA_UNLOCK();
 		pj_log_pop_indent();
 		goto on_error;
@@ -1060,4 +1151,5 @@
 					    w->rend_slot, NULL);
 	    if (status != PJ_SUCCESS) {
+		PJSUA_UNLOCK();
 		pj_log_pop_indent();
 		goto on_error;
@@ -1067,4 +1159,5 @@
 	    status = pjmedia_vid_port_start(w->vp_rend);
 	    if (status != PJ_SUCCESS) {
+	        PJSUA_UNLOCK();
 		pj_log_pop_indent();
 		goto on_error;
@@ -1074,15 +1167,10 @@
 	    inc_vid_win(wid);
 	    call_med->strm.v.rdr_win_id = wid;
+	    PJSUA_UNLOCK();
 	    pj_log_pop_indent();
 	}
 
 	/* Setup encoding direction */
-	if (si->dir & PJMEDIA_DIR_ENCODING && !call->local_hold)
-	{
-            pjsua_acc *acc_enc = &pjsua_var.acc[call_med->call->acc_id];
-	    pjsua_vid_win *w;
-	    pjsua_vid_win_id wid;
-	    pj_bool_t just_created = PJ_FALSE;
-
+	if (si->dir & PJMEDIA_DIR_ENCODING) {
 	    PJ_LOG(4,(THIS_FILE, "Setting up TX.."));
 	    pj_log_push_indent();
@@ -1092,38 +1180,7 @@
 						 PJMEDIA_DIR_ENCODING,
 						 &media_port);
-	    if (status != PJ_SUCCESS) {
-		pj_log_pop_indent();
+	    if (status != PJ_SUCCESS)
 		goto on_error;
-	    }
-
-	    /* Note: calling pjsua_vid_preview_get_win() even though
-	     * create_vid_win() will automatically create the window
-	     * if it doesn't exist, because create_vid_win() will modify
-	     * existing window SHOW/HIDE value.
-	     */
-	    wid = vid_preview_get_win(call_med->strm.v.cap_dev, PJ_FALSE);
-	    if (wid == PJSUA_INVALID_ID) {
-		/* Create preview video window */
-		status = create_vid_win(PJSUA_WND_TYPE_PREVIEW,
-					&media_port->info.fmt,
-					call_med->strm.v.rdr_dev,
-					call_med->strm.v.cap_dev,
-					PJSUA_HIDE_WINDOW,
-                                        acc_enc->cfg.vid_wnd_flags,
-                                        NULL,
-					&wid);
-		if (status != PJ_SUCCESS) {
-		pj_log_pop_indent();
-		    return status;
-		}
-		just_created = PJ_TRUE;
-	    }
-
-	    w = &pjsua_var.win[wid];
-#if ENABLE_EVENT
-            pjmedia_event_subscribe(NULL, &call_media_on_event,
-                                    call_med, w->vp_cap);
-#endif
-	    
+
 	    /* Register stream encoding to conf, using tmp_pool should be fine
 	     * as bridge will create its own pool (using tmp_pool factory).
@@ -1131,53 +1188,15 @@
 	    status = pjsua_vid_conf_add_port(tmp_pool, media_port, NULL,
 					     &call_med->strm.v.strm_enc_slot);
-	    if (status != PJ_SUCCESS) {
-		pj_log_pop_indent();
-		goto on_error;
-	    }
-
-	    /* Connect capturer to stream encoding (via conf) */
-	    status = pjsua_vid_conf_connect(w->cap_slot,
-					    call_med->strm.v.strm_enc_slot,
-					    NULL);
-	    if (status != PJ_SUCCESS) {
-		pj_log_pop_indent();
-		goto on_error;
-	    }
-
-	    /* Start capturer */
-	    if (just_created && acc->cfg.vid_out_auto_transmit) {
-		status = pjmedia_vid_port_start(w->vp_cap);
-		if (status != PJ_SUCCESS) {
-		    pj_log_pop_indent();
-		    goto on_error;
-		}
-		w->cap_started = PJ_TRUE;
-	    }
-
-	    /* Done */
-	    inc_vid_win(wid);
-	    call_med->strm.v.cap_win_id = wid;
-	    pj_log_pop_indent();
-
-	} else if (si->dir & PJMEDIA_DIR_ENCODING && call->local_hold) {
-	    /* This is similar as above, but we are on local hold. So
-	     * we just get the stream encoding port and add it to the
-	     * video conference, in order for the stream to be able to
-	     * keep sending keep-alive.
-	     */
-	    PJ_LOG(4,(THIS_FILE, "Setting up TX.."));
-
-	    status = pjmedia_vid_stream_get_port(call_med->strm.v.stream,
-						 PJMEDIA_DIR_ENCODING,
-						 &media_port);
 	    if (status != PJ_SUCCESS)
 		goto on_error;
 
-	    status = pjsua_vid_conf_add_port(tmp_pool, media_port, NULL,
-					     &call_med->strm.v.strm_enc_slot);
-	    if (status != PJ_SUCCESS)
-		goto on_error;
-	}
-
+	    if (!call->local_hold && acc->cfg.vid_out_auto_transmit) {
+	    	status = setup_vid_capture(call_med);
+	    	if (status != PJ_SUCCESS)
+	    	    goto on_error;
+	    }
+
+	    pj_log_pop_indent();
+	}
     }
 
@@ -1224,4 +1243,5 @@
     pjmedia_vid_stream_send_rtcp_bye(strm);
 
+    PJSUA_LOCK();
     if (call_med->strm.v.cap_win_id != PJSUA_INVALID_ID) {
 	pjsua_vid_win *w = &pjsua_var.win[call_med->strm.v.cap_win_id];
@@ -1248,4 +1268,5 @@
 	call_med->strm.v.rdr_win_id = PJSUA_INVALID_ID;
     }
+    PJSUA_UNLOCK();
 
     if ((call_med->dir & PJMEDIA_DIR_ENCODING) &&
@@ -2103,5 +2124,5 @@
 
     /* == Apply the new capture device == */
-
+    PJSUA_LOCK();
     wid = call_med->strm.v.cap_win_id;
     w = &pjsua_var.win[wid];
@@ -2118,4 +2139,6 @@
 	w->preview_cap_id = cap_dev;
 	call_med->strm.v.cap_dev = cap_dev;
+
+	PJSUA_UNLOCK();
 	/* Yay, change capturer done! */
 	return PJ_SUCCESS;
@@ -2127,6 +2150,8 @@
     status = pjmedia_vid_stream_get_port(call_med->strm.v.stream,
 					 PJMEDIA_DIR_ENCODING, &media_port);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	PJSUA_UNLOCK();
 	return status;
+    }
 
     pjmedia_event_unsubscribe(NULL, &call_media_on_event, call_med,
@@ -2136,6 +2161,8 @@
     status = pjsua_vid_conf_disconnect(w->cap_slot,
 				       call_med->strm.v.strm_enc_slot);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	PJSUA_UNLOCK();
 	return status;
+    }
 
 
@@ -2197,4 +2224,6 @@
     call_med->strm.v.cap_win_id = new_wid;
     dec_vid_win(wid);
+    
+    PJSUA_UNLOCK();
 
     return PJ_SUCCESS;
@@ -2217,6 +2246,8 @@
     status = pjsua_vid_conf_connect(w->cap_slot,
 				    call_med->strm.v.strm_enc_slot, NULL);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+        PJSUA_UNLOCK();
 	return status;
+    }
 
 #if ENABLE_EVENT
@@ -2225,4 +2256,6 @@
                             call_med, w->vp_cap);
 #endif
+
+    PJSUA_UNLOCK();
 
     return status;
@@ -2259,18 +2292,9 @@
 
     if (enable) {
-	pjsua_vid_win *w;
-	pjsua_vid_win_id wid;
-
-	wid = vid_preview_get_win(call_med->strm.v.cap_dev, PJ_FALSE);
-	pj_assert(wid != PJSUA_INVALID_ID);
-
-	w = &pjsua_var.win[wid];
-
-	if (!w->cap_started) {
-	    /* Start the video capture first */
-	    status = pjmedia_vid_port_start(w->vp_cap);
+	if (call_med->strm.v.cap_win_id == PJSUA_INVALID_ID) {
+	    /* Setup the video capture first */
+	    status = setup_vid_capture(call_med);
 	    if (status != PJ_SUCCESS)
 	        return status;
-	    w->cap_started = PJ_TRUE;
 	}
 	
@@ -2279,7 +2303,31 @@
 					   PJMEDIA_DIR_ENCODING);
     } else {
+        pjsua_vid_win_id wid;
+    	pjsua_vid_win *w;
+
 	/* Pause stream in encoding direction */
 	status = pjmedia_vid_stream_pause( call_med->strm.v.stream,
 					   PJMEDIA_DIR_ENCODING);
+	
+	PJSUA_LOCK();
+	
+	wid = vid_preview_get_win(call_med->strm.v.cap_dev, PJ_FALSE);
+    	if (wid != PJSUA_INVALID_ID) {
+    	    w = &pjsua_var.win[wid];
+
+	    /* Unsubscribe event */
+	    pjmedia_event_unsubscribe(NULL, &call_media_on_event, call_med,
+                                      w->vp_cap);
+
+	    /* Disconnect from video conference */
+    	    pjsua_vid_conf_disconnect(w->cap_slot,
+				      call_med->strm.v.strm_enc_slot);
+
+	    /* Decrement ref count of the video window */
+	    dec_vid_win(call_med->strm.v.cap_win_id);
+	    call_med->strm.v.cap_win_id = PJSUA_INVALID_ID;
+    	}
+    	
+    	PJSUA_UNLOCK();
     }
 
