Index: pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c	(revision 129)
+++ pjproject/trunk/pjmedia/src/pjmedia/sdp_neg.c	(revision 140)
@@ -78,5 +78,5 @@
 PJ_DEF(pj_status_t) 
 pjmedia_sdp_neg_create_w_remote_offer(pj_pool_t *pool,
-				      const pjmedia_sdp_session *local,
+				      const pjmedia_sdp_session *initial,
 				      const pjmedia_sdp_session *remote,
 				      pjmedia_sdp_neg **p_neg)
@@ -86,13 +86,12 @@
 
     /* Check arguments are valid. */
-    PJ_ASSERT_RETURN(pool && local && remote && p_neg, PJ_EINVAL);
+    PJ_ASSERT_RETURN(pool && remote && p_neg, PJ_EINVAL);
 
     *p_neg = NULL;
 
-    /* Validate remote offer and local answer */
+    /* Validate remote offer and initial answer */
     status = pjmedia_sdp_validate(remote);
     if (status != PJ_SUCCESS)
 	return status;
-    PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(local))==PJ_SUCCESS, status);
 
     /* Create and initialize negotiator. */
@@ -100,13 +99,20 @@
     PJ_ASSERT_RETURN(neg != NULL, PJ_ENOMEM);
 
-    neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO;
-    neg->initial_sdp = pjmedia_sdp_session_clone(pool, local);
-    PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(neg->initial_sdp))==PJ_SUCCESS,
-		     status);
-
-    neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local);
     neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote);
-    PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(neg->neg_remote_sdp))==PJ_SUCCESS,
-		      status);
+
+    if (initial) {
+	PJ_ASSERT_RETURN((status=pjmedia_sdp_validate(initial))==PJ_SUCCESS, 
+			 status);
+
+	neg->initial_sdp = pjmedia_sdp_session_clone(pool, initial);
+	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, initial);
+
+	neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO;
+
+    } else {
+	
+	neg->state = PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER;
+
+    }
 
     *p_neg = neg;
@@ -127,6 +133,6 @@
 
 PJ_DEF(pj_status_t) 
-pjmedia_sdp_neg_get_local( pjmedia_sdp_neg *neg,
-			   const pjmedia_sdp_session **local)
+pjmedia_sdp_neg_get_active_local( pjmedia_sdp_neg *neg,
+				  const pjmedia_sdp_session **local)
 {
     PJ_ASSERT_RETURN(neg && local, PJ_EINVAL);
@@ -139,6 +145,6 @@
 
 PJ_DEF(pj_status_t) 
-pjmedia_sdp_neg_get_remote( pjmedia_sdp_neg *neg,
-			    const pjmedia_sdp_session **remote)
+pjmedia_sdp_neg_get_active_remote( pjmedia_sdp_neg *neg,
+				   const pjmedia_sdp_session **remote)
 {
     PJ_ASSERT_RETURN(neg && remote, PJ_EINVAL);
@@ -146,4 +152,26 @@
 
     *remote = neg->active_remote_sdp;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t)
+pjmedia_sdp_neg_get_neg_remote( pjmedia_sdp_neg *neg,
+				const pjmedia_sdp_session **remote)
+{
+    PJ_ASSERT_RETURN(neg && remote, PJ_EINVAL);
+    PJ_ASSERT_RETURN(neg->neg_remote_sdp, PJMEDIA_SDPNEG_ENONEG);
+
+    *remote = neg->neg_remote_sdp;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) 
+pjmedia_sdp_neg_get_neg_local( pjmedia_sdp_neg *neg,
+			       const pjmedia_sdp_session **local)
+{
+    PJ_ASSERT_RETURN(neg && local, PJ_EINVAL);
+    PJ_ASSERT_RETURN(neg->neg_local_sdp, PJMEDIA_SDPNEG_ENONEG);
+
+    *local = neg->neg_local_sdp;
     return PJ_SUCCESS;
 }
@@ -175,7 +203,7 @@
 
 PJ_DEF(pj_status_t) 
-pjmedia_sdp_neg_tx_local_offer( pj_pool_t *pool,
-				pjmedia_sdp_neg *neg,
-				const pjmedia_sdp_session **offer)
+pjmedia_sdp_neg_send_local_offer( pj_pool_t *pool,
+				  pjmedia_sdp_neg *neg,
+				  const pjmedia_sdp_session **offer)
 {
     /* Check arguments are valid. */
@@ -211,7 +239,30 @@
 
 PJ_DEF(pj_status_t) 
-pjmedia_sdp_neg_rx_remote_offer( pj_pool_t *pool,
-				 pjmedia_sdp_neg *neg,
-				 const pjmedia_sdp_session *remote)
+pjmedia_sdp_neg_set_remote_answer( pj_pool_t *pool,
+				   pjmedia_sdp_neg *neg,
+				   const pjmedia_sdp_session *remote)
+{
+    /* Check arguments are valid. */
+    PJ_ASSERT_RETURN(pool && neg && remote, PJ_EINVAL);
+
+    /* Can only do this in STATE_LOCAL_OFFER.
+     * If we haven't provided local offer, then rx_remote_offer() should
+     * be called instead of this function.
+     */
+    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, 
+		     PJMEDIA_SDPNEG_EINSTATE);
+
+    /* We're ready to negotiate. */
+    neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO;
+    neg->has_remote_answer = 1;
+    neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote);
+ 
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) 
+pjmedia_sdp_neg_set_remote_offer( pj_pool_t *pool,
+				  pjmedia_sdp_neg *neg,
+				  const pjmedia_sdp_session *remote)
 {
     /* Check arguments are valid. */
@@ -225,6 +276,6 @@
 		     PJMEDIA_SDPNEG_EINSTATE);
 
-    /* We're ready to negotiate. */
-    neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO;
+    /* State now is STATE_REMOTE_OFFER. */
+    neg->state = PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER;
     neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote);
 
@@ -233,23 +284,27 @@
 
 PJ_DEF(pj_status_t) 
-pjmedia_sdp_neg_rx_remote_answer( pj_pool_t *pool,
+pjmedia_sdp_neg_set_local_answer( pj_pool_t *pool,
 				  pjmedia_sdp_neg *neg,
-				  const pjmedia_sdp_session *remote)
+				  const pjmedia_sdp_session *local)
 {
     /* Check arguments are valid. */
-    PJ_ASSERT_RETURN(pool && neg && remote, PJ_EINVAL);
-
-    /* Can only do this in STATE_LOCAL_OFFER.
-     * If we haven't provided local offer, then rx_remote_offer() should
+    PJ_ASSERT_RETURN(pool && neg && local, PJ_EINVAL);
+
+    /* Can only do this in STATE_REMOTE_OFFER.
+     * If we already provide local offer, then rx_remote_answer() should
      * be called instead of this function.
      */
-    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER, 
+    PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_REMOTE_OFFER, 
 		     PJMEDIA_SDPNEG_EINSTATE);
 
-    /* We're ready to negotiate. */
+    /* State now is STATE_WAIT_NEGO. */
     neg->state = PJMEDIA_SDP_NEG_STATE_WAIT_NEGO;
-    neg->has_remote_answer = 1;
-    neg->neg_remote_sdp = pjmedia_sdp_session_clone(pool, remote);
- 
+    if (local)
+	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, local);
+    else {
+	PJ_ASSERT_RETURN(neg->initial_sdp, PJMEDIA_SDPNEG_ENOINITIAL);
+	neg->neg_local_sdp = pjmedia_sdp_session_clone(pool, neg->initial_sdp);
+    }
+
     return PJ_SUCCESS;
 }
@@ -464,4 +519,5 @@
 {
     unsigned mi;
+    pj_bool_t has_active = PJ_FALSE;
     pj_status_t status;
 
@@ -479,8 +535,12 @@
 	if (status != PJ_SUCCESS)
 	    return status;
+
+	if (offer->media[mi]->desc.port != 0)
+	    has_active = PJ_TRUE;
     }
 
     *p_active = offer;
-    return PJ_SUCCESS;
+
+    return has_active ? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA;
 }
 
@@ -675,4 +735,5 @@
 {
     pj_status_t status;
+    pj_bool_t has_active = PJ_FALSE;
     pjmedia_sdp_session *answer;
     char media_used[PJSDP_MAX_MEDIA];
@@ -749,8 +810,13 @@
 	/* Add the media answer */
 	answer->media[answer->media_count++] = am;
+
+	/* Check if this media is active.*/
+	if (am->desc.port != 0)
+	    has_active = PJ_TRUE;
     }
 
     *p_answer = answer;
-    return PJ_SUCCESS;
+
+    return has_active ? PJ_SUCCESS : PJMEDIA_SDPNEG_ENOMEDIA;
 }
 
@@ -785,5 +851,5 @@
 	pjmedia_sdp_session *answer;
 
-	status = create_answer(pool, neg->initial_sdp, neg->neg_remote_sdp,
+	status = create_answer(pool, neg->neg_local_sdp, neg->neg_remote_sdp,
 			       &answer);
 	if (status == PJ_SUCCESS) {
