Fix #1235: fixed lock codec to check all active media (previously only checked one media: first active audio).




git-svn-id: https://svn.pjsip.org/repos/pjproject/branches/projects/2.0-dev@3573 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c
index 62c31c5..a7705ff 100644
--- a/pjsip/src/pjsua-lib/pjsua_call.c
+++ b/pjsip/src/pjsua-lib/pjsua_call.c
@@ -3174,11 +3174,9 @@
 {
     const pj_str_t STR_UPDATE = {"UPDATE", 6};
     const pjmedia_sdp_session *local_sdp = NULL, *new_sdp;
-    const pjmedia_sdp_media *ref_m;
-    pjmedia_sdp_media *m;
-    pjsua_call_media *call_med = &call->media[call->audio_idx];
-    unsigned i, codec_cnt = 0;
+    unsigned i;
     pj_bool_t rem_can_update;
+    pj_bool_t need_lock_codec = PJ_FALSE;
     pjsip_tx_data *tdata;
     pj_status_t status;
 
@@ -3210,14 +3208,6 @@
     if (local_sdp->origin.version > call->lock_codec.sdp_ver)
 	return PJMEDIA_SDP_EINVER;
 
-    /* Verify if media is deactivated */
-    if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
-	call_med->state == PJSUA_CALL_MEDIA_ERROR ||
-	call_med->dir == PJMEDIA_DIR_NONE)
-    {
-        return PJ_EINVALIDOP;
-    }
-
     PJ_LOG(3, (THIS_FILE, "Updating media session to use only one codec.."));
 
     /* Update the new offer so it contains only a codec. Note that formats
@@ -3225,35 +3215,54 @@
      * just directly update the offer without looking-up the answer.
      */
     new_sdp = pjmedia_sdp_session_clone(call->inv->pool_prov, local_sdp);
-    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;
-    while (i < m->desc.fmt_count) {
-	pjmedia_sdp_attr *a;
-	pj_str_t *fmt = &m->desc.fmt[i];
 
-	if (is_non_av_fmt(m, fmt) || (++codec_cnt == 1)) {
-	    ++i;
+    for (i = 0; i < call->med_cnt; ++i) {
+	unsigned j = 0, codec_cnt = 0;
+	const pjmedia_sdp_media *ref_m;
+	pjmedia_sdp_media *m;
+	pjsua_call_media *call_med = &call->media[i];
+
+	/* Verify if media is deactivated */
+	if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
+	    call_med->state == PJSUA_CALL_MEDIA_ERROR ||
+	    call_med->dir == PJMEDIA_DIR_NONE)
+	{
 	    continue;
 	}
 
-	/* Remove format */
-	a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "rtpmap", fmt);
-	if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a);
-	a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "fmtp", fmt);
-	if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a);
-	pj_array_erase(m->desc.fmt, sizeof(m->desc.fmt[0]),
-		       m->desc.fmt_count, i);
-	--m->desc.fmt_count;
+	ref_m = local_sdp->media[i];
+	m = new_sdp->media[i];
+
+	/* Verify that media must be active. */
+	pj_assert(ref_m->desc.port);
+
+	while (j < m->desc.fmt_count) {
+	    pjmedia_sdp_attr *a;
+	    pj_str_t *fmt = &m->desc.fmt[j];
+
+	    if (is_non_av_fmt(m, fmt) || (++codec_cnt == 1)) {
+		++j;
+		continue;
+	    }
+
+	    /* Remove format */
+	    a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "rtpmap", fmt);
+	    if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a);
+	    a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "fmtp", fmt);
+	    if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a);
+	    pj_array_erase(m->desc.fmt, sizeof(m->desc.fmt[0]),
+			   m->desc.fmt_count, j);
+	    --m->desc.fmt_count;
+	}
+	
+	need_lock_codec |= (ref_m->desc.fmt_count > m->desc.fmt_count);
     }
 
     /* 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 (ref_m->desc.fmt_count == m->desc.fmt_count)
+    if (!need_lock_codec)
 	return PJ_SUCCESS;
 
     /* Send UPDATE or re-INVITE */
@@ -3301,11 +3310,10 @@
 {
     pjsip_inv_session *inv = call->inv;
     const pjmedia_sdp_session *local_sdp, *remote_sdp;
-    const pjmedia_sdp_media *rem_m, *loc_m;
-    unsigned codec_cnt=0, i;
-    pjsua_call_media *call_med = &call->media[call->audio_idx];
     pj_time_val delay = {0, 0};
     const pj_str_t st_update = {"UPDATE", 6};
+    unsigned i;
+    pj_bool_t has_mult_fmt = PJ_FALSE;
     pj_status_t status;
 
     /* Stop lock codec timer, if it is active */
@@ -3320,14 +3328,6 @@
         return PJ_SUCCESS;
     }
 
-    /* Skip this if the media is inactive or error */
-    if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
-	call_med->state == PJSUA_CALL_MEDIA_ERROR ||
-	call_med->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.
      */
@@ -3346,28 +3346,50 @@
     if (status != PJ_SUCCESS)
 	return status;
 
-    PJ_ASSERT_RETURN(call->audio_idx>=0 &&
-		     call->audio_idx < (int)remote_sdp->media_count,
-		     PJ_EINVALIDOP);
+    /* Find multiple codecs answer in all media */
+    for (i = 0; i < call->med_cnt; ++i) {
+	pjsua_call_media *call_med = &call->media[i];
+	const pjmedia_sdp_media *rem_m, *loc_m;
+	unsigned codec_cnt = 0;
 
-    rem_m = remote_sdp->media[call->audio_idx];
-    loc_m = local_sdp->media[call->audio_idx];
+	/* Skip this if the media is inactive or error */
+	if (call_med->state == PJSUA_CALL_MEDIA_NONE ||
+	    call_med->state == PJSUA_CALL_MEDIA_ERROR ||
+	    call_med->dir == PJMEDIA_DIR_NONE)
+	{
+	    continue;
+	}
 
-    /* Verify that media must be active. */
-    pj_assert(loc_m->desc.port && rem_m->desc.port);
+	/* Remote may answer with less media lines. */
+	if (i >= remote_sdp->media_count)
+	    continue;
 
-    /* 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;
-        }
+	rem_m = remote_sdp->media[i];
+	loc_m = local_sdp->media[i];
+
+	/* 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 {
+	    unsigned j;
+	    for (j=0; j<rem_m->desc.fmt_count && codec_cnt <= 1; ++j) {
+		if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[j]))
+		    ++codec_cnt;
+	    }
+	}
+
+	if (codec_cnt > 1) {
+	    has_mult_fmt = PJ_TRUE;
+	    break;
+	}
     }
-    if (codec_cnt <= 1) {
-	/* Answer contains single codec. */
-        call->lock_codec.retry_cnt = 0;
+
+    /* Each media in the answer already contains single codec. */
+    if (!has_mult_fmt) {
+	call->lock_codec.retry_cnt = 0;
 	return PJ_SUCCESS;
     }