Index: pjproject/branches/projects/2.0-dev/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- pjproject/branches/projects/2.0-dev/pjsip-apps/src/pjsua/pjsua_app.c	(revision 3656)
+++ pjproject/branches/projects/2.0-dev/pjsip-apps/src/pjsua/pjsua_app.c	(revision 3657)
@@ -3324,9 +3324,9 @@
     puts("|                                                                             |");
     puts("| vid help                  Show this help screen                             |");
-    puts("| vid call rx on|off        Enable/disable incoming video for current call    |");
-    puts("| vid call tx on|off        Enable/disable video tx for current call          |");
+    puts("| vid call rx on|off N      Enable/disable video rx for stream N in curr call |");
+    puts("| vid call tx on|off N      Enable/disable video tx for stream N in curr call |");
     puts("| vid call add              Add video stream for current call                 |");
-    puts("| vid call enable/disable N Enable/disable stream #N for current call         |");
-    puts("| vid call set-cap N ID     Set capture dev ID for stream #N for current call |");
+    puts("| vid call enable/disable N Enable/disable stream #N in current call          |");
+    puts("| vid call set-cap N ID     Set capture dev ID for stream #N in current call  |");
     puts("| vid dev list              List all video devices                            |");
     puts("| vid dev refresh           Refresh video device list                         |");
@@ -3769,28 +3769,45 @@
 	pjsua_call_vid_strm_op_param param;
 
-	if (argc == 4 && strcmp(argv[2], "rx")==0) {
+	if (argc == 5 && strcmp(argv[2], "rx")==0) {
+	    pjsua_stream_info si;
 	    pj_bool_t on = (strcmp(argv[3], "on") == 0);
-	    PJ_TODO(vid_enable_disable_video_RX_on_call);
-	    PJ_LOG(1,(THIS_FILE, "Not implemented"));
+
+	    param.med_idx = atoi(argv[4]);
+	    if (pjsua_call_get_stream_info(current_call, param.med_idx, &si) ||
+		si.type != PJMEDIA_TYPE_VIDEO)
+	    {
+		PJ_PERROR(1,(THIS_FILE, PJ_EINVAL, "Invalid stream"));
+		return;
+	    }
+
+	    if (on) param.dir = (si.info.vid.dir | PJMEDIA_DIR_DECODING);
+	    else param.dir = (si.info.vid.dir & PJMEDIA_DIR_ENCODING);
+
+	    pjsua_call_set_vid_strm(current_call, PJSUA_CALL_VID_STRM_CHANGE_DIR, &param);
 	}
-	else if (argc == 4 && strcmp(argv[2], "tx")==0) {
+	else if (argc == 5 && strcmp(argv[2], "tx")==0) {
 	    pj_bool_t on = (strcmp(argv[3], "on") == 0);
 	    pjsua_call_vid_strm_op op = on? PJSUA_CALL_VID_STRM_START_TRANSMIT :
 					    PJSUA_CALL_VID_STRM_STOP_TRANSMIT;
-	    pjsua_call_set_vid_strm(current_call, op, NULL);
+
+	    param.med_idx = atoi(argv[4]);
+
+	    pjsua_call_set_vid_strm(current_call, op, &param);
 	}
 	else if (argc == 3 && strcmp(argv[2], "add")==0) {
 	    pjsua_call_set_vid_strm(current_call, PJSUA_CALL_VID_STRM_ADD, NULL);
 	}
-	else if (argc == 4 && 
+	else if (argc >= 3 && 
 		 (strcmp(argv[2], "disable")==0 || strcmp(argv[2], "enable")==0))
 	{
 	    pj_bool_t enable = (strcmp(argv[2], "enable") == 0);
-	    pjsua_call_vid_strm_op op = enable? PJSUA_CALL_VID_STRM_ENABLE :
-						PJSUA_CALL_VID_STRM_DISABLE;
+	    pjsua_call_vid_strm_op op = enable? PJSUA_CALL_VID_STRM_CHANGE_DIR :
+						PJSUA_CALL_VID_STRM_REMOVE;
+
 	    param.med_idx = argc >= 4? atoi(argv[3]) : -1;
+	    param.dir = PJMEDIA_DIR_ENCODING_DECODING;
 	    pjsua_call_set_vid_strm(current_call, op, &param);
 	}
-	else if (argc == 5 && strcmp(argv[2], "set-cap")==0) {
+	else if (argc >= 3 && strcmp(argv[2], "set-cap")==0) {
 	    param.med_idx = argc >= 4? atoi(argv[3]) : -1;
 	    param.cap_dev = argc >= 5? atoi(argv[4]) : PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
@@ -3798,5 +3815,5 @@
 	} else
 	    goto on_error;
-    } else if (strcmp(argv[1], "dev")==0) {
+    } else if (argc >= 3 && strcmp(argv[1], "dev")==0) {
 	if (strcmp(argv[2], "list")==0) {
 	    vid_list_devs();
Index: pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h	(revision 3656)
+++ pjproject/branches/projects/2.0-dev/pjsip/include/pjsua-lib/pjsua.h	(revision 3657)
@@ -382,15 +382,15 @@
 
     /**
-     * Disable/remove an existing video stream.
-     */
-    PJSUA_CALL_VID_STRM_DISABLE,
-
-    /**
-     * Enable video stream.
-     */
-    PJSUA_CALL_VID_STRM_ENABLE,
-
-    /**
-     * Changing capture device of a video stream.
+     * Remove/disable an existing video stream.
+     */
+    PJSUA_CALL_VID_STRM_REMOVE,
+
+    /**
+     * Change direction of a video stream.
+     */
+    PJSUA_CALL_VID_STRM_CHANGE_DIR,
+
+    /**
+     * Change capture device of a video stream.
      */
     PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV,
@@ -421,6 +421,19 @@
      * This field is valid for all video stream operations, except
      * PJSUA_CALL_VID_STRM_ADD.
+     *
+     * Default: -1 (first active video stream, or any first video stream
+     *              if none is active)
      */
     int med_idx;
+ 
+    /**
+     * Specify the media stream direction.
+     *
+     * This field is valid for the following video stream operations:
+     * PJSUA_CALL_VID_STRM_ADD and PJSUA_CALL_VID_STRM_CHANGE_DIR.
+     *
+     * Default: PJMEDIA_DIR_ENCODING_DECODING
+     */
+    pjmedia_dir dir;
  
     /**
@@ -430,6 +443,7 @@
      *
      * This field is valid for the following video stream operations:
-     * PJSUA_CALL_VID_STRM_ADD, PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV, and
-     * PJSUA_CALL_VID_STRM_START_TRANSMIT.
+     * PJSUA_CALL_VID_STRM_ADD and PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV.
+     *
+     * Default: capture device configured in account.
      */
     pjmedia_vid_dev_index cap_dev;
@@ -3773,5 +3787,7 @@
  * @param op		The video stream operation to be performed,
  *			possible values are #pjsua_call_vid_strm_op.
- * @param param		The parameters for the video stream operation.
+ * @param param		The parameters for the video stream operation,
+ *			or NULL for the default parameter values
+ *			(see #pjsua_call_vid_strm_op_param).
  *
  * @return		PJ_SUCCESS on success or the appropriate error.
Index: pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_vid.c
===================================================================
--- pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 3656)
+++ pjproject/branches/projects/2.0-dev/pjsip/src/pjsua-lib/pjsua_vid.c	(revision 3657)
@@ -777,5 +777,7 @@
     pjmedia_event_unsubscribe(&call_med->esub_cap);
 
-    if (call_med->strm.v.cap_win_id != PJSUA_INVALID_ID) {
+    if (call_med->dir & PJMEDIA_DIR_ENCODING &&
+	call_med->strm.v.cap_win_id != PJSUA_INVALID_ID)
+    {
 	pjmedia_port *media_port;
 	pjsua_vid_win *w =
@@ -794,5 +796,7 @@
     }
 
-    if (call_med->strm.v.rdr_win_id != PJSUA_INVALID_ID) {
+    if (call_med->dir & PJMEDIA_DIR_DECODING &&
+	call_med->strm.v.rdr_win_id != PJSUA_INVALID_ID)
+    {
 	dec_vid_win(call_med->strm.v.rdr_win_id);
     }
@@ -1137,5 +1141,6 @@
 /* Add a new video stream into a call */
 static pj_status_t call_add_video(pjsua_call *call,
-				  pjmedia_vid_dev_index cap_dev)
+				  pjmedia_vid_dev_index cap_dev,
+				  pjmedia_dir dir)
 {
     pj_pool_t *pool = call->inv->pool_prov;
@@ -1193,4 +1198,21 @@
     sdp->media[sdp->media_count++] = sdp_m;
 
+    /* Update media direction, if it is not 'sendrecv' */
+    if (dir != PJMEDIA_DIR_ENCODING_DECODING) {
+	pjmedia_sdp_attr *a;
+
+	/* Remove sendrecv direction attribute, if any */
+	pjmedia_sdp_media_remove_all_attr(sdp_m, "sendrecv");
+
+	if (dir == PJMEDIA_DIR_ENCODING)
+	    a = pjmedia_sdp_attr_create(pool, "sendonly", NULL);
+	else if (dir == PJMEDIA_DIR_DECODING)
+	    a = pjmedia_sdp_attr_create(pool, "recvonly", NULL);
+	else
+	    a = pjmedia_sdp_attr_create(pool, "inactive", NULL);
+
+	pjmedia_sdp_media_add_attr(sdp_m, a);
+    }
+
     /* Update SDP media line by media transport */
     status = pjmedia_transport_encode_sdp(call_med->tp, pool,
@@ -1215,8 +1237,11 @@
 
 
-/* Modify a video stream from a call, i.e: enable/disable */
+/* Modify a video stream from a call, i.e: update direction,
+ * remove/disable.
+ */
 static pj_status_t call_modify_video(pjsua_call *call,
 				     int med_idx,
-				     pj_bool_t enable)
+				     pjmedia_dir dir,
+				     pj_bool_t remove)
 {
     pjsua_call_media *call_med;
@@ -1241,8 +1266,11 @@
 	return PJ_EINVAL;
 
-    /* Verify if the stream already enabled/disabled */
-    if (( enable && call_med->dir != PJMEDIA_DIR_NONE) ||
-	(!enable && call_med->dir == PJMEDIA_DIR_NONE))
+    /* Verify if the stream dir is not changed */
+    if ((!remove && call_med->dir == dir) ||
+	( remove && (call_med->tp_st == PJSUA_MED_TP_DISABLED ||
+		     call_med->tp == NULL)))
+    {
 	return PJ_SUCCESS;
+    }
 
     /* Get active local SDP */
@@ -1253,9 +1281,8 @@
     pj_assert(med_idx < (int)sdp->media_count);
 
-    if (enable) {
+    if (!remove) {
 	pjsua_acc_config *acc_cfg = &pjsua_var.acc[call->acc_id].cfg;
 	pj_pool_t *pool = call->inv->pool_prov;
 	pjmedia_sdp_media *sdp_m;
-	pjmedia_transport_info tpinfo;
 
 	status = pjsua_call_media_init(call_med, PJMEDIA_TYPE_VIDEO,
@@ -1266,18 +1293,48 @@
 
 	/* Init transport media */
-	status = pjmedia_transport_media_create(call_med->tp, pool, 0,
-						NULL, call_med->idx);
-	if (status != PJ_SUCCESS)
-	    goto on_error;
-
-	/* Get transport address info */
-	pjmedia_transport_info_init(&tpinfo);
-	pjmedia_transport_get_info(call_med->tp, &tpinfo);
-
-	/* Create SDP media line */
-	status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool,
-						&tpinfo.sock_info, 0, &sdp_m);
-	if (status != PJ_SUCCESS)
-	    goto on_error;
+	if (call_med->tp && call_med->tp_st == PJSUA_MED_TP_IDLE) {
+	    status = pjmedia_transport_media_create(call_med->tp, pool, 0,
+						    NULL, call_med->idx);
+	    if (status != PJ_SUCCESS)
+		goto on_error;
+	}
+
+	sdp_m = sdp->media[med_idx];
+
+	/* Create new SDP media line if the stream is disabled */
+	if (sdp->media[med_idx]->desc.port == 0) {
+	    pjmedia_transport_info tpinfo;
+
+	    /* Get transport address info */
+	    pjmedia_transport_info_init(&tpinfo);
+	    pjmedia_transport_get_info(call_med->tp, &tpinfo);
+
+	    status = pjmedia_endpt_create_video_sdp(pjsua_var.med_endpt, pool,
+						    &tpinfo.sock_info, 0, &sdp_m);
+	    if (status != PJ_SUCCESS)
+		goto on_error;
+	}
+
+	{
+	    pjmedia_sdp_attr *a;
+
+	    /* Remove any direction attributes */
+	    pjmedia_sdp_media_remove_all_attr(sdp_m, "sendrecv");
+	    pjmedia_sdp_media_remove_all_attr(sdp_m, "sendonly");
+	    pjmedia_sdp_media_remove_all_attr(sdp_m, "recvonly");
+	    pjmedia_sdp_media_remove_all_attr(sdp_m, "inactive");
+
+	    /* Update media direction */
+	    if (dir == PJMEDIA_DIR_ENCODING_DECODING)
+		a = pjmedia_sdp_attr_create(pool, "sendrecv", NULL);
+	    else if (dir == PJMEDIA_DIR_ENCODING)
+		a = pjmedia_sdp_attr_create(pool, "sendonly", NULL);
+	    else if (dir == PJMEDIA_DIR_DECODING)
+		a = pjmedia_sdp_attr_create(pool, "recvonly", NULL);
+	    else
+		a = pjmedia_sdp_attr_create(pool, "inactive", NULL);
+
+	    pjmedia_sdp_media_add_attr(sdp_m, a);
+	}
 
 	sdp->media[med_idx] = sdp_m;
@@ -1291,11 +1348,11 @@
 on_error:
 	if (status != PJ_SUCCESS) {
-	    if (call_med->tp) {
-		pjmedia_transport_close(call_med->tp);
-		call_med->tp = call_med->tp_orig = NULL;
-	    }
 	    return status;
 	}
+    
     } else {
+
+	pj_pool_t *pool = call->inv->pool_prov;
+
 	/* Mark media transport to disabled */
 	// Don't close this here, as SDP negotiation has not been
@@ -1303,6 +1360,7 @@
 	call_med->tp_st = PJSUA_MED_TP_DISABLED;
 
-	/* Disable the stream in SDP by setting port to 0 */
-	sdp->media[med_idx]->desc.port = 0;
+	/* Deactivate the stream */
+	pjmedia_sdp_media_deactivate(pool, sdp->media[med_idx]);
+
     }
 
@@ -1445,8 +1503,8 @@
 
 
-/* Start transmitting video stream in a call */
-static pj_status_t call_start_tx_video(pjsua_call *call,
-				       int med_idx,
-				       pjmedia_vid_dev_index cap_dev)
+/* Start/stop transmitting video stream in a call */
+static pj_status_t call_set_tx_video(pjsua_call *call,
+				     int med_idx,
+				     pj_bool_t enable)
 {
     pjsua_call_media *call_med;
@@ -1468,58 +1526,20 @@
     /* Verify if the stream is transmitting video */
     if (call_med->type != PJMEDIA_TYPE_VIDEO || 
-	(call_med->dir & PJMEDIA_DIR_ENCODING) == 0)
+	(enable && (call_med->dir & PJMEDIA_DIR_ENCODING) == 0))
     {
 	return PJ_EINVAL;
     }
 
-    /* Apply the capture device, it may be changed! */
-    status = call_change_cap_dev(call, med_idx, cap_dev);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Start stream in encoding direction */
-    status = pjmedia_vid_stream_resume(call_med->strm.v.stream,
-				       PJMEDIA_DIR_ENCODING);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    return PJ_SUCCESS;
-}
-
-
-/* Stop transmitting video stream in a call */
-static pj_status_t call_stop_tx_video(pjsua_call *call,
-				      int med_idx)
-{
-    pjsua_call_media *call_med;
-    pj_status_t status;
-
-    /* Verify and normalize media index */
-    if (med_idx == -1) {
-	int first_active;
-	
-	call_get_vid_strm_info(call, &first_active, NULL, NULL, NULL);
-	if (first_active == -1)
-	    return PJ_ENOTFOUND;
-
-	med_idx = first_active;
-    }
-
-    call_med = &call->media[med_idx];
-
-    /* Verify if the stream is transmitting video */
-    if (call_med->type != PJMEDIA_TYPE_VIDEO || 
-	(call_med->dir & PJMEDIA_DIR_ENCODING) == 0)
-    {
-	return PJ_EINVAL;
-    }
-
-    /* Pause stream in encoding direction */
-    status = pjmedia_vid_stream_pause( call_med->strm.v.stream,
-				       PJMEDIA_DIR_ENCODING);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    return PJ_SUCCESS;
+    if (enable) {
+	/* Start stream in encoding direction */
+	status = pjmedia_vid_stream_resume(call_med->strm.v.stream,
+					   PJMEDIA_DIR_ENCODING);
+    } else {
+	/* Pause stream in encoding direction */
+	status = pjmedia_vid_stream_pause( call_med->strm.v.stream,
+					   PJMEDIA_DIR_ENCODING);
+    }
+
+    return status;
 }
 
@@ -1549,4 +1569,5 @@
 	param_.med_idx = -1;
 	param_.cap_dev = PJMEDIA_VID_DEFAULT_CAPTURE_DEV;
+	param_.dir = PJMEDIA_DIR_ENCODING_DECODING;
     }
 
@@ -1572,11 +1593,12 @@
     switch (op) {
     case PJSUA_CALL_VID_STRM_ADD:
-	status = call_add_video(call, param_.cap_dev);
+	status = call_add_video(call, param_.cap_dev, param_.dir);
 	break;
-    case PJSUA_CALL_VID_STRM_ENABLE:
-	status = call_modify_video(call, param_.med_idx, PJ_TRUE);
+    case PJSUA_CALL_VID_STRM_REMOVE:
+	status = call_modify_video(call, param_.med_idx, PJMEDIA_DIR_NONE,
+				   PJ_TRUE);
 	break;
-    case PJSUA_CALL_VID_STRM_DISABLE:
-	status = call_modify_video(call, param_.med_idx, PJ_FALSE);
+    case PJSUA_CALL_VID_STRM_CHANGE_DIR:
+	status = call_modify_video(call, param_.med_idx, param_.dir, PJ_FALSE);
 	break;
     case PJSUA_CALL_VID_STRM_CHANGE_CAP_DEV:
@@ -1584,8 +1606,8 @@
 	break;
     case PJSUA_CALL_VID_STRM_START_TRANSMIT:
-	status = call_start_tx_video(call, param_.med_idx, param_.cap_dev);
+	status = call_set_tx_video(call, param_.med_idx, PJ_TRUE);
 	break;
     case PJSUA_CALL_VID_STRM_STOP_TRANSMIT:
-	status = call_stop_tx_video(call, param_.med_idx);
+	status = call_set_tx_video(call, param_.med_idx, PJ_FALSE);
 	break;
     default:
