Index: /pjproject/trunk/pjmedia/include/pjmedia-codec/passthrough.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-codec/passthrough.h	(revision 2833)
+++ /pjproject/trunk/pjmedia/include/pjmedia-codec/passthrough.h	(revision 2834)
@@ -59,4 +59,5 @@
     pjmedia_format	*fmts;		/**< Encoding formats to be 
 					     enabled.			*/
+    unsigned		 ilbc_mode;	/**< iLBC default mode.		*/
 } pjmedia_codec_passthrough_setting;
 
Index: /pjproject/trunk/pjmedia/src/pjmedia-codec/ilbc.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia-codec/ilbc.c	(revision 2833)
+++ /pjproject/trunk/pjmedia/src/pjmedia-codec/ilbc.c	(revision 2834)
@@ -377,5 +377,7 @@
     struct ilbc_codec *ilbc_codec = (struct ilbc_codec*)codec;
     pj_status_t status;
-    unsigned i, dec_fmtp_mode = 0, enc_fmtp_mode = 0;
+    unsigned i;
+    pj_uint16_t dec_fmtp_mode = DEFAULT_MODE, 
+		enc_fmtp_mode = DEFAULT_MODE;
 
     pj_assert(ilbc_codec != NULL);
@@ -387,5 +389,5 @@
 	if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0)
 	{
-	    dec_fmtp_mode = (unsigned)
+	    dec_fmtp_mode = (pj_uint16_t)
 			    pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
 	    break;
@@ -401,5 +403,5 @@
 	if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0)
 	{
-	    enc_fmtp_mode = (unsigned)
+	    enc_fmtp_mode = (pj_uint16_t)
 			    pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
 	    break;
@@ -407,22 +409,23 @@
     }
 
-    /* The enc mode must be set in the attribute 
-     * (from the mode parameter in fmtp attribute in the SDP
-     * received from remote) 
+    PJ_ASSERT_RETURN(enc_fmtp_mode==20 || enc_fmtp_mode==30, 
+		     PJMEDIA_CODEC_EINMODE);
+
+    /* Both sides of a bi-directional session MUST use the same "mode" value.
+     * In this point, possible values are only 20 or 30, so when encoder and
+     * decoder modes are not same, just use the default mode, it is 30.
      */
-    if (enc_fmtp_mode == 0)
-	enc_fmtp_mode = dec_fmtp_mode;
-
-    PJ_ASSERT_RETURN(enc_fmtp_mode==20 ||
-		     enc_fmtp_mode==30, PJMEDIA_CODEC_EINMODE);
-
-    /* Update enc_ptime in the param */
     if (enc_fmtp_mode != dec_fmtp_mode) {
-	attr->info.enc_ptime = (pj_uint16_t)enc_fmtp_mode;
-    } else {
-	attr->info.enc_ptime = 0;
-    }
-
-    /* Create enc */
+	enc_fmtp_mode = dec_fmtp_mode = DEFAULT_MODE;
+	PJ_LOG(4,(ilbc_codec->obj_name, 
+		  "Normalized iLBC encoder and decoder modes to %d", 
+		  DEFAULT_MODE));
+    }
+
+    /* Update some attributes based on negotiated mode. */
+    attr->info.avg_bps = (dec_fmtp_mode == 30? 13333 : 15200);
+    attr->info.frm_ptime = dec_fmtp_mode;
+
+    /* Create encoder */
     ilbc_codec->enc_frame_size = initEncode(&ilbc_codec->enc, enc_fmtp_mode);
     ilbc_codec->enc_samples_per_frame = CLOCK_RATE * enc_fmtp_mode / 1000;
@@ -433,12 +436,5 @@
 						   dec_fmtp_mode,
 						   attr->setting.penh);
-    if (dec_fmtp_mode == 20)
-	ilbc_codec->dec_frame_size = 38;
-    else if (dec_fmtp_mode == 30)
-	ilbc_codec->dec_frame_size = 50;
-    else {
-	pj_assert(!"Invalid iLBC mode");
-	ilbc_codec->dec_frame_size = ilbc_codec->enc_frame_size;
-    }
+    ilbc_codec->dec_frame_size = (dec_fmtp_mode == 20? 38 : 50);
     ilbc_codec->dec_ready = PJ_TRUE;
 
@@ -460,6 +456,5 @@
 
     PJ_LOG(5,(ilbc_codec->obj_name, 
-	      "iLBC codec opened, encoder mode=%d, decoder mode=%d",
-	      enc_fmtp_mode, dec_fmtp_mode));
+	      "iLBC codec opened, mode=%d", dec_fmtp_mode));
 
     return PJ_SUCCESS;
Index: /pjproject/trunk/pjmedia/src/pjmedia-codec/passthrough.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia-codec/passthrough.c	(revision 2833)
+++ /pjproject/trunk/pjmedia/src/pjmedia-codec/passthrough.c	(revision 2834)
@@ -115,4 +115,8 @@
     void		*codec_setting;	    /**< Specific codec setting.    */
     pj_uint16_t		 avg_frame_size;    /**< Average of frame size.	    */
+    unsigned		 samples_per_frame; /**< Samples per frame, for iLBC
+						 this can be 240 or 160, can
+						 only be known after codec is
+						 opened.		    */
 } codec_private_t;
 
@@ -381,4 +385,21 @@
 	    codec_desc[i].enabled = enabled;
 	}
+
+#if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
+	/* Update iLBC codec description based on default mode setting. */
+	for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
+	    if (codec_desc[i].enabled && 
+		codec_desc[i].fmt_id == PJMEDIA_FORMAT_ILBC)
+	    {
+		codec_desc[i].samples_per_frame = 
+				(setting->ilbc_mode == 20? 160 : 240);
+		codec_desc[i].def_bitrate = 
+				(setting->ilbc_mode == 20? 15200 : 13333);
+		pj_strset2(&codec_desc[i].dec_fmtp.param[0].val, 
+				(setting->ilbc_mode == 20? "20" : "30"));
+		break;
+	    }
+	}
+#endif
     }
 
@@ -646,6 +667,9 @@
     pool = codec_data->pool;
 
-    /* Get bitstream size */
-    i = attr->info.avg_bps * desc->samples_per_frame;
+    /* Cache samples per frame value */
+    codec_data->samples_per_frame = desc->samples_per_frame;
+
+    /* Calculate bitstream size */
+    i = attr->info.avg_bps * codec_data->samples_per_frame;
     j = desc->clock_rate << 3;
     codec_data->avg_frame_size = (pj_uint16_t)(i / j);
@@ -695,4 +719,61 @@
 #endif
 
+#if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
+    {
+	enum { DEFAULT_MODE = 30 };
+	static pj_str_t STR_MODE = {"mode", 4};
+	pj_uint16_t dec_fmtp_mode = DEFAULT_MODE, 
+		    enc_fmtp_mode = DEFAULT_MODE;
+
+	/* Get decoder mode */
+	for (i = 0; i < attr->setting.dec_fmtp.cnt; ++i) {
+	    if (pj_stricmp(&attr->setting.dec_fmtp.param[i].name, &STR_MODE) == 0)
+	    {
+		dec_fmtp_mode = (pj_uint16_t)
+				pj_strtoul(&attr->setting.dec_fmtp.param[i].val);
+		break;
+	    }
+	}
+
+	/* Decoder mode must be set */
+	PJ_ASSERT_RETURN(dec_fmtp_mode == 20 || dec_fmtp_mode == 30, 
+			 PJMEDIA_CODEC_EINMODE);
+
+	/* Get encoder mode */
+	for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
+	    if (pj_stricmp(&attr->setting.enc_fmtp.param[i].name, &STR_MODE) == 0)
+	    {
+		enc_fmtp_mode = (pj_uint16_t)
+				pj_strtoul(&attr->setting.enc_fmtp.param[i].val);
+		break;
+	    }
+	}
+
+	PJ_ASSERT_RETURN(enc_fmtp_mode==20 || enc_fmtp_mode==30, 
+			 PJMEDIA_CODEC_EINMODE);
+
+	/* Both sides of a bi-directional session MUST use the same "mode" value.
+	 * In this point, possible values are only 20 or 30, so when encoder and
+	 * decoder modes are not same, just use the default mode, it is 30.
+	 */
+	if (enc_fmtp_mode != dec_fmtp_mode) {
+	    enc_fmtp_mode = dec_fmtp_mode = DEFAULT_MODE;
+	    PJ_LOG(4,(pool->obj_name, 
+		      "Normalized iLBC encoder and decoder modes to %d", 
+		      DEFAULT_MODE));
+	}
+
+	/* Update some attributes based on negotiated mode. */
+	attr->info.avg_bps = (dec_fmtp_mode == 30? 13333 : 15200);
+	attr->info.frm_ptime = dec_fmtp_mode;
+
+	/* Override average frame size */
+	codec_data->avg_frame_size = (dec_fmtp_mode == 30? 50 : 38);
+
+	/* Override samples per frame */
+	codec_data->samples_per_frame = (dec_fmtp_mode == 30? 240 : 160);
+    }
+#endif
+
     return PJ_SUCCESS;
 }
@@ -746,5 +827,6 @@
 	frames[count].buf = pkt;
 	frames[count].size = codec_data->avg_frame_size;
-	frames[count].timestamp.u64 = ts->u64 + count*desc->samples_per_frame;
+	frames[count].timestamp.u64 = ts->u64 + 
+				      count * codec_data->samples_per_frame;
 
 	pkt = (pj_uint8_t*)pkt + codec_data->avg_frame_size;
@@ -758,5 +840,6 @@
 	frames[count].buf = pkt;
 	frames[count].size = pkt_size;
-	frames[count].timestamp.u64 = ts->u64 + count*desc->samples_per_frame;
+	frames[count].timestamp.u64 = ts->u64 + 
+				       count * codec_data->samples_per_frame;
 	++count;
     }
@@ -855,5 +938,5 @@
 	pjmedia_frame_ext_append_subframe(output_, input_.buf, 
 					  (pj_uint16_t)(input_.size << 3),
-					  (pj_uint16_t)desc->samples_per_frame);
+					  (pj_uint16_t)codec_data->samples_per_frame);
 	output->timestamp = input->timestamp;
 	
@@ -864,5 +947,5 @@
     pjmedia_frame_ext_append_subframe(output_, input->buf, 
 				      (pj_uint16_t)(input->size << 3),
-				      (pj_uint16_t)desc->samples_per_frame);
+				      (pj_uint16_t)codec_data->samples_per_frame);
     output->timestamp = input->timestamp;
 
@@ -884,5 +967,5 @@
 
     pjmedia_frame_ext_append_subframe(output_, NULL, 0,
-				      (pj_uint16_t)desc->samples_per_frame);
+				      (pj_uint16_t)codec_data->samples_per_frame);
 
     return PJ_SUCCESS;
Index: /pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 2833)
+++ /pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 2834)
@@ -1674,18 +1674,4 @@
     stream->port.info.channel_count = info->fmt.channel_cnt;
     stream->port.port_data.pdata = stream;
-    if (info->param==NULL || info->param->info.fmt_id == PJMEDIA_FORMAT_L16) {
-	stream->port.info.format.id = PJMEDIA_FORMAT_L16;
-
-	stream->port.put_frame = &put_frame;
-	stream->port.get_frame = &get_frame;
-    } else {
-	stream->port.info.format.id = info->param->info.fmt_id;
-	stream->port.info.format.bitrate = info->param->info.avg_bps;
-	stream->port.info.format.vad = (info->param->setting.vad != 0);
-
-	stream->port.put_frame = &put_frame;
-	stream->port.get_frame = &get_frame_ext;
-    }
-
 
     /* Init stream: */
@@ -1746,5 +1732,10 @@
 	stream->codec_param.setting.frm_per_pkt = 1;
 
-    /* Set additional info. */
+    /* Open the codec. */
+    status = stream->codec->op->open(stream->codec, &stream->codec_param);
+    if (status != PJ_SUCCESS)
+	goto err_cleanup;
+
+    /* Set additional info and callbacks. */
     stream->port.info.bits_per_sample = 16;
     stream->port.info.samples_per_frame = info->fmt.clock_rate * 
@@ -1763,9 +1754,14 @@
     }
 
-    /* Open the codec: */
-
-    status = stream->codec->op->open(stream->codec, &stream->codec_param);
-    if (status != PJ_SUCCESS)
-	goto err_cleanup;
+    stream->port.info.format.id = stream->codec_param.info.fmt_id;
+    if (stream->codec_param.info.fmt_id == PJMEDIA_FORMAT_L16) {
+	stream->port.put_frame = &put_frame;
+	stream->port.get_frame = &get_frame;
+    } else {
+	stream->port.info.format.bitrate = stream->codec_param.info.avg_bps;
+	stream->port.info.format.vad = (stream->codec_param.setting.vad != 0);
+	stream->port.put_frame = &put_frame;
+	stream->port.get_frame = &get_frame_ext;
+    }
 
     /* If encoder and decoder's ptime are asymmetric, then we need to
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2833)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2834)
@@ -238,4 +238,5 @@
 	setting.fmt_cnt = ext_fmt_cnt;
 	setting.fmts = ext_fmts;
+	setting.ilbc_mode = cfg->ilbc_mode;
 	status = pjmedia_codec_passthrough_init2(pjsua_var.med_endpt, &setting);
 	if (status != PJ_SUCCESS) {
