Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3373)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 3374)
@@ -96,4 +96,5 @@
 	pj_uint32_t	 sdp_ver;    /**< SDP version of the bad answer     */
 	int		 retry_cnt;  /**< Retry count.			    */
+        pj_bool_t        pending;    /**< Pending until CONFIRMED state     */
     } lock_codec;		     /**< Data for codec locking when answer
 					  contains multiple codecs.	    */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 3373)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 3374)
@@ -124,4 +124,5 @@
     call->rem_srtp_use = PJMEDIA_SRTP_DISABLED;
     call->local_hold = PJ_FALSE;
+    pj_bzero(&call->lock_codec, sizeof(call->lock_codec));
 }
 
@@ -3061,5 +3062,5 @@
     const pj_str_t STR_UPDATE = {"UPDATE", 6};
     const pjmedia_sdp_session *local_sdp = NULL, *new_sdp;
-    const pjmedia_sdp_media *rem_m;
+    const pjmedia_sdp_media *ref_m;
     pjmedia_sdp_media *m;
     unsigned i, codec_cnt = 0;
@@ -3077,5 +3078,5 @@
 	pjmedia_sdp_neg_get_state(call->inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE)
     {
-	return PJ_SUCCESS;
+	return PJMEDIA_SDPNEG_EINSTATE;
     }
 
@@ -3084,5 +3085,5 @@
 	call->inv->cause >= 200)
     {
-	return PJ_SUCCESS;
+	return PJ_EINVALIDOP;
     }
 
@@ -3096,4 +3097,12 @@
 	return PJMEDIA_SDP_EINVER;
 
+    /* Verify if media is deactivated */
+    if (call->media_st == PJSUA_CALL_MEDIA_NONE ||
+        call->media_st == PJSUA_CALL_MEDIA_ERROR ||
+        call->media_dir == PJMEDIA_DIR_NONE)
+    {
+        return PJ_EINVALIDOP;
+    }
+
     PJ_LOG(3, (THIS_FILE, "Updating media session to use only one codec.."));
 
@@ -3103,6 +3112,7 @@
      */
     new_sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, local_sdp);
-    rem_m = local_sdp->media[call->audio_idx];
     m = new_sdp->media[call->audio_idx];
+    ref_m = local_sdp->media[call->audio_idx];
+    pj_assert(ref_m->desc.port);
     codec_cnt = 0;
     i = 0;
@@ -3126,13 +3136,10 @@
     }
 
-    /* Last check if SDP trully needs to be udpated. It is possible that OA
-     * negotiations have completed and SDP has changed but remote didn't
-     * increase it's SDP version.
+    /* Last check if SDP trully needs to be updated. It is possible that OA
+     * negotiations have completed and SDP has changed but we didn't
+     * increase the SDP version (should not happen!).
      */
-    if (rem_m->desc.fmt_count == m->desc.fmt_count ||
-	rem_m->desc.port == 0 || m->desc.port == 0)
-    {
+    if (ref_m->desc.fmt_count == m->desc.fmt_count)
 	return PJ_SUCCESS;
-    }
 
     /* Send UPDATE or re-INVITE */
@@ -3180,47 +3187,10 @@
 {
     pjsip_inv_session *inv = call->inv;
-    const pjmedia_sdp_session *local_sdp;
-    const pjmedia_sdp_session *remote_sdp;
-    const pjmedia_sdp_media *rem_m;
+    const pjmedia_sdp_session *local_sdp, *remote_sdp;
+    const pjmedia_sdp_media *rem_m, *loc_m;
     unsigned codec_cnt=0, i;
     pj_time_val delay = {0, 0};
+    const pj_str_t st_update = {"UPDATE", 6};
     pj_status_t status;
-
-    if (!pjmedia_sdp_neg_was_answer_remote(inv->neg))
-	return PJ_SUCCESS;
-
-    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
-    if (status != PJ_SUCCESS)
-	return status;
-    status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    PJ_ASSERT_RETURN(call->audio_idx>=0 &&
-		     call->audio_idx < (int)remote_sdp->media_count,
-		     PJ_EINVALIDOP);
-
-    rem_m = remote_sdp->media[call->audio_idx];
-
-    /* Check if media is disabled or only one format in the answer. */
-    if (rem_m->desc.port==0 || rem_m->desc.fmt_count==1)
-	return PJ_SUCCESS;
-
-    /* Count the formats in the answer. */
-    for (i=0; i<rem_m->desc.fmt_count && codec_cnt <= 1; ++i) {
-	if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[i]))
-	    ++codec_cnt;
-    }
-
-    if (codec_cnt <= 1) {
-	/* Answer contains single codec. */
-	return PJ_SUCCESS;
-    }
-
-    PJ_LOG(3, (THIS_FILE, "Got answer with multiple codecs, scheduling "
-			  "updating media session to use only one codec.."));
-
-    call->lock_codec.sdp_ver = local_sdp->origin.version;
-    call->lock_codec.retry_cnt = 0;
 
     /* Stop lock codec timer, if it is active */
@@ -3230,4 +3200,71 @@
 	call->lock_codec.reinv_timer.id = PJ_FALSE;
     }
+
+    /* Skip this if we are the answerer */
+    if (!inv->neg || !pjmedia_sdp_neg_was_answer_remote(inv->neg)) {
+        return PJ_SUCCESS;
+    }
+
+    /* Skip this if the media is inactive or error */
+    if (call->media_st == PJSUA_CALL_MEDIA_NONE ||
+        call->media_st == PJSUA_CALL_MEDIA_ERROR ||
+        call->media_dir == PJMEDIA_DIR_NONE)
+    {
+        return PJ_SUCCESS;
+    }
+
+    /* Delay this when the SDP negotiation done in call state EARLY and
+     * remote does not support UPDATE method.
+     */
+    if (inv->state == PJSIP_INV_STATE_EARLY && 
+	pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &st_update)!=
+	PJSIP_DIALOG_CAP_SUPPORTED)
+    {
+        call->lock_codec.pending = PJ_TRUE;
+        return PJ_SUCCESS;
+    }
+
+    status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
+    if (status != PJ_SUCCESS)
+	return status;
+    status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    PJ_ASSERT_RETURN(call->audio_idx>=0 &&
+		     call->audio_idx < (int)remote_sdp->media_count,
+		     PJ_EINVALIDOP);
+
+    rem_m = remote_sdp->media[call->audio_idx];
+    loc_m = local_sdp->media[call->audio_idx];
+
+    /* Verify that media must be active. */
+    pj_assert(loc_m->desc.port && rem_m->desc.port);
+
+    /* Count the formats in the answer. */
+    if (rem_m->desc.fmt_count==1) {
+        codec_cnt = 1;
+    } else {
+        for (i=0; i<rem_m->desc.fmt_count && codec_cnt <= 1; ++i) {
+	    if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[i]))
+	        ++codec_cnt;
+        }
+    }
+    if (codec_cnt <= 1) {
+	/* Answer contains single codec. */
+        call->lock_codec.retry_cnt = 0;
+	return PJ_SUCCESS;
+    }
+
+    /* Remote keeps answering with multiple codecs, let's just give up
+     * locking codec to avoid infinite retry loop.
+     */
+    if (++call->lock_codec.retry_cnt > LOCK_CODEC_MAX_RETRY)
+        return PJ_SUCCESS;
+
+    PJ_LOG(3, (THIS_FILE, "Got answer with multiple codecs, scheduling "
+			  "updating media session to use only one codec.."));
+
+    call->lock_codec.sdp_ver = local_sdp->origin.version;
 
     /* Can't send UPDATE or re-INVITE now, so just schedule it immediately.
@@ -3277,13 +3314,15 @@
 	    pj_gettimeofday(&call->conn_time);
 
-	    /* Ticket #476, locking a codec in the media session. */
-	    {
+            /* See if lock codec was pended as media update was done in the
+             * EARLY state and remote does not support UPDATE.
+             */
+            if (call->lock_codec.pending) {
 		pj_status_t status;
 		status = lock_codec(call);
 		if (status != PJ_SUCCESS) {
 		    pjsua_perror(THIS_FILE, "Unable to lock codec", status);
-		}
+                }
+                call->lock_codec.pending = PJ_FALSE;
 	    }
-
 	    break;
 	case PJSIP_INV_STATE_DISCONNECTED:
@@ -3516,5 +3555,5 @@
     const pjmedia_sdp_session *local_sdp;
     const pjmedia_sdp_session *remote_sdp;
-    const pj_str_t st_update = {"UPDATE", 6};
+    //const pj_str_t st_update = {"UPDATE", 6};
 
     PJSUA_LOCK();
@@ -3588,22 +3627,8 @@
     }
 
-    /* Ticket #476, handle the case of early media and remote support UPDATE */
-    if (inv->state == PJSIP_INV_STATE_EARLY && 
-	pjmedia_sdp_neg_was_answer_remote(inv->neg) &&
-	pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &st_update)==
-	PJSIP_DIALOG_CAP_SUPPORTED)
-    {
-	status = lock_codec(call);
-	if (status != PJ_SUCCESS) {
-	    pjsua_perror(THIS_FILE, "Unable to lock codec", status);
-	}
-    } else if (inv->state == PJSIP_INV_STATE_CONFIRMED &&
-	       call->media_st == PJSUA_CALL_MEDIA_ACTIVE)
-    {
-	/* https://trac.pjsip.org/repos/ticket/1149 */
-	status = lock_codec(call);
-	if (status != PJ_SUCCESS) {
-	    pjsua_perror(THIS_FILE, "Unable to lock codec", status);
-	}
+    /* Ticket #476: make sure only one codec is specified in the answer. */
+    status = lock_codec(call);
+    if (status != PJ_SUCCESS) {
+        pjsua_perror(THIS_FILE, "Unable to lock codec", status);
     }
 
