Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-codec/amr_helper.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-codec/amr_helper.h	(revision 2443)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-codec/amr_helper.h	(revision 2444)
@@ -633,5 +633,4 @@
  * @return	    AMR mode.
  */
-
 PJ_INLINE(pj_int8_t) pjmedia_codec_amr_get_mode(unsigned bitrate)
 {
@@ -679,4 +678,33 @@
 
 /**
+ * Get AMR mode based on frame length.
+ *
+ * @param amrnb	    Set to PJ_TRUE for AMR-NB domain or PJ_FALSE for AMR-WB.
+ * @param frame_len The frame length.
+ *
+ * @return	    AMR mode.
+ */
+
+PJ_INLINE(pj_int8_t) pjmedia_codec_amr_get_mode2(pj_bool_t amrnb,
+						 unsigned frame_len)
+{
+    unsigned i;
+
+    if (amrnb) {
+	for (i = 0; i < 9; ++i)
+	    if (frame_len == pjmedia_codec_amrnb_framelen[i])
+		return i;
+    } else {
+	for (i = 0; i < 10; ++i) {
+	    if (frame_len == pjmedia_codec_amrwb_framelen[i])
+		return i;
+	}
+    }
+    
+    pj_assert(!"Invalid AMR frame length");
+    return -1;
+}
+
+/**
  * Prepare a frame before pass it to decoder. This function will do:
  * - reorder AMR bitstream from descending sensitivity order into 
Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2443)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2444)
@@ -311,11 +311,12 @@
 	pjmedia_frame_ext_subframe *fsub;
 	fsub = (pjmedia_frame_ext_subframe*) p;
-	p += sizeof(fsub->bitlen) + fsub->bitlen / 8;
-	if (fsub->bitlen % 8)
+	p += sizeof(fsub->bitlen) + (fsub->bitlen >> 3);
+	if (fsub->bitlen & 0x07)
 	    ++p;
     }
 
-    tmp = bitlen / 8;
-    if (bitlen % 8) ++tmp;
+    tmp = bitlen >> 3;
+    if (bitlen & 0x07)
+	++tmp;
 
     pj_memcpy(p, &bitlen, sizeof(bitlen));
@@ -348,6 +349,6 @@
 	for (i = 0; i < n; ++i) {	
 	    sf = (pjmedia_frame_ext_subframe*) p;
-	    p += sizeof(sf->bitlen) + sf->bitlen / 8;
-	    if (sf->bitlen % 8)
+	    p += sizeof(sf->bitlen) + (sf->bitlen >> 3);
+	    if (sf->bitlen & 0x07)
 		++p;
 	}
@@ -382,6 +383,7 @@
     move_src = (pj_uint8_t*)pjmedia_frame_ext_get_subframe(frm, n);
     sf = pjmedia_frame_ext_get_subframe(frm, frm->subframe_cnt-1);
-    move_len = (pj_uint8_t*)sf - move_src + sizeof(sf->bitlen) + sf->bitlen/8;
-    if (sf->bitlen % 8 != 0)
+    move_len = (pj_uint8_t*)sf - move_src + sizeof(sf->bitlen) + 
+	       (sf->bitlen >> 3);
+    if (sf->bitlen & 0x07)
 	++move_len;
     pj_memmove((pj_uint8_t*)frm+sizeof(pjmedia_frame_ext), 
Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/types.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/types.h	(revision 2443)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/types.h	(revision 2444)
@@ -201,5 +201,5 @@
 #define PJMEDIA_FOURCC_AMR	PJMEDIA_FOURCC_PACK(' ', 'A', 'M', 'R')
 #define PJMEDIA_FOURCC_G729	PJMEDIA_FOURCC_PACK('G', '7', '2', '9')
-#define PJMEDIA_FOURCC_ILBC	PJMEDIA_FOURCC_PACK('i', 'L', 'B', 'C')
+#define PJMEDIA_FOURCC_ILBC	PJMEDIA_FOURCC_PACK('I', 'L', 'B', 'C')
 
 
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-codec/passthrough.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-codec/passthrough.c	(revision 2443)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-codec/passthrough.c	(revision 2444)
@@ -171,7 +171,7 @@
 {
 #   if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
-    {1, "AMR",	    PJMEDIA_RTP_PT_AMR,       PJMEDIA_FOURCC_AMR,
+    {1, "AMR",	    PJMEDIA_RTP_PT_AMR,       {PJMEDIA_FOURCC_AMR},
 		    8000, 1, 160, 
-		    5900, 12200, 4,
+		    12200, 12200, 2,
 		    &parse_amr, &pack_amr
 		    /*, {1, {{{"octet-align", 11}, {"1", 1}}} } */
@@ -180,14 +180,14 @@
 
 #   if PJMEDIA_HAS_PASSTHROUGH_CODEC_G729
-    {1, "G729",	    PJMEDIA_RTP_PT_G729,      PJMEDIA_FOURCC_G729,
+    {1, "G729",	    PJMEDIA_RTP_PT_G729,      {PJMEDIA_FOURCC_G729},
 		    8000, 1,  80,
-		    8000, 11800, 2
+		    8000, 8000, 2
     },
 #   endif
 
 #   if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
-    {1, "iLBC",	    PJMEDIA_RTP_PT_ILBC,      PJMEDIA_FOURCC_ILBC,
-		    8000, 1,  80,
-		    8000, 11800, 2,
+    {1, "iLBC",	    PJMEDIA_RTP_PT_ILBC,      {PJMEDIA_FOURCC_ILBC},
+		    8000, 1,  240,
+		    13333, 15200, 2,
 		    NULL, NULL,
 		    {1, {{{"mode", 4}, {"30", 2}}} }
@@ -196,5 +196,5 @@
 
 #   if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMU
-    {1, "PCMU",	    PJMEDIA_RTP_PT_PCMU,      PJMEDIA_FOURCC_G711U,
+    {1, "PCMU",	    PJMEDIA_RTP_PT_PCMU,      {PJMEDIA_FOURCC_G711U},
 		    8000, 1,  80,
 		    64000, 64000, 2
@@ -203,5 +203,5 @@
 
 #   if PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMA
-    {1, "PCMA",	    PJMEDIA_RTP_PT_PCMA,      PJMEDIA_FOURCC_G711A,
+    {1, "PCMA",	    PJMEDIA_RTP_PT_PCMA,      {PJMEDIA_FOURCC_G711A},
 		    8000, 1,  80,
 		    64000, 64000, 2
@@ -210,4 +210,5 @@
 };
 
+
 #if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
 
@@ -227,59 +228,43 @@
 			      struct pjmedia_frame *output)
 {
-    enum {MAX_FRAMES_PER_PACKET = 16};
+    enum {MAX_FRAMES_PER_PACKET = 8};
 
     pjmedia_frame frames[MAX_FRAMES_PER_PACKET];
-    unsigned nframes = 0;
-    pjmedia_codec_amr_bit_info *info;
-
-    PJ_TODO(DEFINE_AMR_FRAME_INFO_FOR_PJMEDIA_FRAME_EXT);
-
-#if 0
-
-    pj_uint8_t *r; /* Read cursor */
+    amr_settings_t* setting = (amr_settings_t*)codec_data->codec_setting;
+    pjmedia_codec_amr_pack_setting *enc_setting = &setting->enc_setting;
     pj_uint8_t SID_FT;
-    pjmedia_codec_amr_pack_setting *setting;
-
-    setting = &((amr_settings_t*)codec_data->codec_setting)->enc_setting;
-
-    SID_FT = (pj_uint8_t)(setting->amr_nb? 8 : 9);
-
-    /* Align pkt buf right */
-    r = (pj_uint8_t*)pkt + max_pkt_size - *pkt_size;
-    pj_memmove(r, pkt, *pkt_size);
+    unsigned i;
+
+    pj_assert(input->subframe_cnt <= MAX_FRAMES_PER_PACKET);
+
+    SID_FT = (pj_uint8_t)(enc_setting->amr_nb? 8 : 9);
 
     /* Get frames */
-    for (;;) {
-	pj_bool_t eof;
-	pj_uint16_t info_;
-
-	info_ = *((pj_uint16_t*)r);
-	eof = ((info_ & 0x40) != 0);
-
-	info = (pjmedia_codec_amr_bit_info*) &frames[nframes].bit_info;
+    for (i = 0; i < input->subframe_cnt; ++i) {
+	pjmedia_frame_ext_subframe *sf;
+	pjmedia_codec_amr_bit_info *info;
+	unsigned len;
+	
+	sf = pjmedia_frame_ext_get_subframe(input, i);
+	
+	len = sf->bitlen >> 3;
+	if (sf->bitlen & 0x07)
+	    ++len;
+	
+	info = (pjmedia_codec_amr_bit_info*) &frames[i].bit_info;
 	pj_bzero(info, sizeof(*info));
-	info->frame_type = (pj_uint8_t)(info_ & 0x0F);
+	info->frame_type = pjmedia_codec_amr_get_mode2(enc_setting->amr_nb, 
+						       len);
 	info->good_quality = 1;
-	info->mode = (pj_int8_t) ((info_ >> 8) & 0x0F);
-
-	frames[nframes].buf = r + 2;
-	frames[nframes].size = info->frame_type <= SID_FT ?
-			       pjmedia_codec_amrnb_framelen[info->frame_type] :
-			       0;
-
-	r += frames[nframes].size + 2;
-
-	/* Last frame */
-	if (++nframes >= MAX_FRAMES_PER_PACKET || eof)
-	    break;
-    }
-
-    /* Pack */
-    *pkt_size = max_pkt_size;
-
-    return pjmedia_codec_amr_pack(frames, nframes, setting, pkt, pkt_size);
-#endif
-
-    return PJ_ENOTSUP;
+	info->mode = setting->enc_mode;
+
+	frames[i].buf = sf->data;
+	frames[i].size = len;
+    }
+
+    output->size = output_buf_len;
+
+    return pjmedia_codec_amr_pack(frames, input->subframe_cnt, enc_setting, 
+				  output->buf, &output->size);
 }
 
@@ -302,8 +287,9 @@
 	return status;
 
+    // CMR is not supported for now. 
     /* Check Change Mode Request. */
-    if ((setting->amr_nb && cmr <= 7) || (!setting->amr_nb && cmr <= 8)) {
-	s->enc_mode = cmr;
-    }
+    //if ((setting->amr_nb && cmr <= 7) || (!setting->amr_nb && cmr <= 8)) {
+    //	s->enc_mode = cmr;
+    //}
 
     return PJ_SUCCESS;
@@ -800,5 +786,5 @@
     pjmedia_frame_ext *output_ = (pjmedia_frame_ext*) output;
 
-    pj_assert(input && input->size > 0);
+    pj_assert(input);
 
 #if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
@@ -807,21 +793,21 @@
      * into encoder bits order.
      */
-    if (desc->pt == PJMEDIA_RTP_PT_AMR) {
-	pjmedia_frame frame;
+    if (desc->pt == PJMEDIA_RTP_PT_AMR || desc->pt == PJMEDIA_RTP_PT_AMRWB) {
+	pjmedia_frame input_;
 	pjmedia_codec_amr_pack_setting *setting;
 
 	setting = &((amr_settings_t*)codec_data->codec_setting)->dec_setting;
 
-	frame = *input;
-	pjmedia_codec_amr_predecode(input, setting, &frame);
+	input_ = *input;
+	pjmedia_codec_amr_predecode(input, setting, &input_);
+	
+	pjmedia_frame_ext_append_subframe(output_, input_.buf, 
+					  (pj_uint16_t)(input_.size << 3),
+					  (pj_uint16_t)desc->samples_per_frame);
+	
+	return PJ_SUCCESS;
     }
 #endif
-    /*
-    PJ_ASSERT_RETURN(output_buf_len >= sizeof(pjmedia_frame_ext) +
-				       sizeof(pjmedia_frame_ext_subframe) +
-				       input->size,
-		     PJMEDIA_CODEC_EFRMTOOSHORT);
-     */
-
+    
     pjmedia_frame_ext_append_subframe(output_, input->buf, 
 				      (pj_uint16_t)(input->size << 3),
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2443)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2444)
@@ -68,4 +68,5 @@
 struct conf_port
 {
+    SLOT_TYPE		 slot;		/**< Array of listeners.	    */
     pj_str_t		 name;		/**< Port name.			    */
     pjmedia_port	*port;		/**< get_frame() and put_frame()    */
@@ -77,7 +78,5 @@
 
     /* Shortcut for port info. */
-    unsigned		 clock_rate;	/**< Port's clock rate.		    */
-    unsigned		 samples_per_frame; /**< Port's samples per frame.  */
-    unsigned		 channel_count;	/**< Port's channel count.	    */
+    pjmedia_port_info	*info;
 
     /* Calculated signal levels: */
@@ -118,8 +117,4 @@
     pj_mutex_t		 *mutex;	/**< Conference mutex.		    */
     struct conf_port	**ports;	/**< Array of ports.		    */
-    unsigned		  clock_rate;	/**< Sampling rate.		    */
-    unsigned		  channel_count;/**< Number of channels (1=mono).   */
-    unsigned		  samples_per_frame;	/**< Samples per frame.	    */
-    unsigned		  bits_per_sample;	/**< Bits per sample.	    */
     pj_uint8_t		  buf[BUFFER_SIZE];	/**< Common buffer.	    */
 };
@@ -146,4 +141,6 @@
     pjmedia_frame *f;
 
+    PJ_ASSERT_RETURN(pool && conf && port && name && p_conf_port, PJ_EINVAL);
+
     /* Create port. */
     conf_port = PJ_POOL_ZALLOC_T(pool, struct conf_port);
@@ -163,15 +160,6 @@
 
     /* Save some port's infos, for convenience. */
-    if (port) {
-	conf_port->port = port;
-	conf_port->clock_rate = port->info.clock_rate;
-	conf_port->samples_per_frame = port->info.samples_per_frame;
-	conf_port->channel_count = port->info.channel_count;
-    } else {
-	conf_port->port = NULL;
-	conf_port->clock_rate = conf->clock_rate;
-	conf_port->samples_per_frame = conf->samples_per_frame;
-	conf_port->channel_count = conf->channel_count;
-    }
+    conf_port->port = port;
+    conf_port->info = &port->info;
 
     /* Init pjmedia_frame structure in the TX buffer. */
@@ -196,5 +184,5 @@
 
 
-    status = create_conf_port(pool, conf, NULL, &name, &conf_port);
+    status = create_conf_port(pool, conf, conf->master_port, &name, &conf_port);
     if (status != PJ_SUCCESS)
 	return status;
@@ -206,4 +194,6 @@
 	pjmedia_snd_stream *strm;
 	pjmedia_snd_stream_info si;
+	pjmedia_port_info *master_port_info = (pjmedia_port_info*)
+					      &conf->master_port->info;
 
 	/*
@@ -212,19 +202,22 @@
 	 */
 	if (conf->options & PJMEDIA_CONF_NO_MIC)  {
-	    status = pjmedia_snd_port_create_player(pool, -1, conf->clock_rate,
-						    conf->channel_count,
-						    conf->samples_per_frame,
-						    conf->bits_per_sample, 
-						    0,	/* options */
-						    &conf->snd_dev_port);
+	    status = pjmedia_snd_port_create_player(
+					pool, -1, 
+					master_port_info->clock_rate,
+					master_port_info->channel_count,
+					master_port_info->samples_per_frame,
+					master_port_info->bits_per_sample, 
+					0,	/* options */
+					&conf->snd_dev_port);
 
 	} else {
-	    status = pjmedia_snd_port_create( pool, -1, -1, conf->clock_rate, 
-					      conf->channel_count, 
-					      conf->samples_per_frame,
-					      conf->bits_per_sample,
-					      0,    /* Options */
-					      &conf->snd_dev_port);
-
+	    status = pjmedia_snd_port_create( 
+					pool, -1, -1, 
+					master_port_info->clock_rate, 
+					master_port_info->channel_count, 
+					master_port_info->samples_per_frame,
+					master_port_info->bits_per_sample,
+					0,    /* Options */
+					&conf->snd_dev_port);
 	}
 
@@ -246,4 +239,5 @@
 
      /* Add the port to the bridge */
+    conf_port->slot = 0;
     conf->ports[0] = conf_port;
     conf->port_cnt++;
@@ -286,9 +280,4 @@
     conf->options = options;
     conf->max_ports = max_ports;
-    conf->clock_rate = clock_rate;
-    conf->channel_count = channel_count;
-    conf->samples_per_frame = samples_per_frame;
-    conf->bits_per_sample = bits_per_sample;
-
     
     /* Create and initialize the master port interface. */
@@ -425,6 +414,5 @@
     conf->ports[0]->name.slen = len;
 
-    if (conf->master_port)
-	conf->master_port->info.name = conf->ports[0]->name;
+    conf->master_port->info.name = conf->ports[0]->name;
 
     return PJ_SUCCESS;
@@ -445,4 +433,5 @@
 
     PJ_ASSERT_RETURN(conf && pool && strm_port, PJ_EINVAL);
+    /*
     PJ_ASSERT_RETURN(conf->clock_rate == strm_port->info.clock_rate, 
 		     PJMEDIA_ENCCLOCKRATE);
@@ -451,8 +440,11 @@
     PJ_ASSERT_RETURN(conf->bits_per_sample == strm_port->info.bits_per_sample,
 		     PJMEDIA_ENCBITS);
+    */
 
     /* Port's samples per frame should be equal to or multiplication of 
      * conference's samples per frame.
      */
+    /*
+    Not sure if this is needed!
     PJ_ASSERT_RETURN((conf->samples_per_frame %
 		     strm_port->info.samples_per_frame==0) ||
@@ -460,4 +452,5 @@
 		     conf->samples_per_frame==0),
 		     PJMEDIA_ENCSAMPLESPFRAME);
+    */
 
     /* If port_name is not specified, use the port's name */
@@ -489,4 +482,5 @@
 
     /* Put the port. */
+    conf_port->slot = index;
     conf->ports[index] = conf_port;
     conf->port_cnt++;
@@ -589,4 +583,14 @@
     dst_port = conf->ports[sink_slot];
 
+    /* Source and sink ptime must be equal or a multiplication factor. */
+    if ((src_port->info->samples_per_frame % 
+	 dst_port->info->samples_per_frame != 0) &&
+        (dst_port->info->samples_per_frame % 
+         src_port->info->samples_per_frame != 0))
+    {
+	pj_mutex_unlock(conf->mutex);
+	return PJMEDIA_ENCSAMPLESPFRAME;
+    }
+    
     /* Check if source and sink has compatible format */
     if (src_slot != 0 && sink_slot != 0 && 
@@ -678,4 +682,7 @@
 	--src_port->listener_cnt;
 	--dst_port->transmitter_cnt;
+	
+	/* Clean up sink TX buffer. */
+	pj_bzero(dst_port->tx_buf, sizeof(pjmedia_frame_ext));
 
 	PJ_LOG(4,(THIS_FILE,
@@ -777,4 +784,7 @@
 	pj_assert(conf->connect_cnt > 0);
 	--conf->connect_cnt;
+
+	/* Clean up TX buffer. */
+	pj_bzero(dst_port->tx_buf, sizeof(pjmedia_frame_ext));
     }
 
@@ -842,10 +852,9 @@
     info->listener_cnt = conf_port->listener_cnt;
     info->listener_slots = conf_port->listener_slots;
-    info->clock_rate = conf_port->clock_rate;
-    info->channel_count = conf_port->channel_count;
-    info->samples_per_frame = conf_port->samples_per_frame;
-    info->bits_per_sample = conf->bits_per_sample;
-    info->format = slot? conf_port->port->info.format : 
-			 conf->master_port->info.format;
+    info->clock_rate = conf_port->info->clock_rate;
+    info->channel_count = conf_port->info->channel_count;
+    info->samples_per_frame = conf_port->info->samples_per_frame;
+    info->bits_per_sample = conf_port->info->bits_per_sample;
+    info->format = conf_port->port->info.format;
 
     return PJ_SUCCESS;
@@ -991,7 +1000,7 @@
 	     * samples per frame.
 	     */
-	    if (f_dst->samples_cnt == cport_dst->samples_per_frame)
+	    if (f_dst->samples_cnt == cport_dst->info->samples_per_frame)
 	    {
-		if (cport_dst->port) {
+		if (cport_dst->slot) {
 		    pjmedia_port_put_frame(cport_dst->port, 
 					   (pjmedia_frame*)f_dst);
@@ -1004,6 +1013,5 @@
 		/* Update TX timestamp. */
 		pj_add_timestamp32(&cport_dst->ts_tx, 
-				   cport_dst->samples_per_frame);
-
+				   cport_dst->info->samples_per_frame);
 	    }
 	}
@@ -1020,7 +1028,9 @@
 	    /* Copy frame to listener's TX buffer. */
 	    nsamples_to_copy = f_end - f_start;
-	    nsamples_req = cport_dst->samples_per_frame - (frm_dst->size>>1);
+	    nsamples_req = cport_dst->info->samples_per_frame - 
+			  (frm_dst->size>>1);
 	    if (nsamples_to_copy > nsamples_req)
 		nsamples_to_copy = nsamples_req;
+
 	    pjmedia_copy_samples((pj_int16_t*)frm_dst->buf + (frm_dst->size>>1),
 				 f_start, 
@@ -1033,7 +1043,7 @@
 	     * samples per frame.
 	     */
-	    if ((frm_dst->size >> 1) == cport_dst->samples_per_frame)
+	    if ((frm_dst->size >> 1) == cport_dst->info->samples_per_frame)
 	    {
-		if (cport_dst->port) {
+		if (cport_dst->slot) {
 		    pjmedia_port_put_frame(cport_dst->port, frm_dst);
 
@@ -1044,5 +1054,5 @@
 		/* Update TX timestamp. */
 		pj_add_timestamp32(&cport_dst->ts_tx, 
-				   cport_dst->samples_per_frame);
+				   cport_dst->info->samples_per_frame);
 	    }
 	}
@@ -1059,10 +1069,10 @@
 	    if (frm_dst->size != 0) {
 		pjmedia_zero_samples((pj_int16_t*)frm_dst->buf,
-				     cport_dst->samples_per_frame - 
+				     cport_dst->info->samples_per_frame - 
 				     (frm_dst->size>>1));
 
 		frm_dst->type = PJMEDIA_FRAME_TYPE_AUDIO;
-		frm_dst->size = cport_dst->samples_per_frame << 1;
-		if (cport_dst->port) {
+		frm_dst->size = cport_dst->info->samples_per_frame << 1;
+		if (cport_dst->slot) {
 		    pjmedia_port_put_frame(cport_dst->port, frm_dst);
 
@@ -1073,5 +1083,5 @@
 		/* Update TX timestamp. */
 		pj_add_timestamp32(&cport_dst->ts_tx, 
-				   cport_dst->samples_per_frame);
+				   cport_dst->info->samples_per_frame);
 	    }
 	} else {
@@ -1081,7 +1091,6 @@
 		frm_dst->type = PJMEDIA_FRAME_TYPE_EXTENDED;
 		pjmedia_frame_ext_append_subframe(f_dst, NULL, 0, (pj_uint16_t)
-						  (cport_dst->samples_per_frame-
-						   f_dst->samples_cnt));
-		if (cport_dst->port) {
+		    (cport_dst->info->samples_per_frame - f_dst->samples_cnt));
+		if (cport_dst->slot) {
 		    pjmedia_port_put_frame(cport_dst->port, frm_dst);
 
@@ -1093,5 +1102,5 @@
 		/* Update TX timestamp. */
 		pj_add_timestamp32(&cport_dst->ts_tx, 
-				   cport_dst->samples_per_frame);
+				   cport_dst->info->samples_per_frame);
 	    }
 	}
@@ -1103,9 +1112,9 @@
 	    frm_dst->type = PJMEDIA_FRAME_TYPE_NONE;
 	    frm_dst->timestamp = cport_dst->ts_tx;
-	    if (cport_dst->port)
+	    if (cport_dst->slot)
 		pjmedia_port_put_frame(cport_dst->port, frm_dst);
 
 	    /* Update TX timestamp. */
-	    pj_add_timestamp32(&cport_dst->ts_tx, cport_dst->samples_per_frame);
+	    pj_add_timestamp32(&cport_dst->ts_tx, cport_dst->info->samples_per_frame);
 	}
     }
@@ -1144,5 +1153,6 @@
 
 	/* Update clock of the port. */
-	pj_add_timestamp32(&cport->ts_clock, conf->samples_per_frame);
+	pj_add_timestamp32(&cport->ts_clock, 
+			   conf->master_port->info.samples_per_frame);
 
 	/* Skip if we're not allowed to receive from this port or 
@@ -1166,5 +1176,5 @@
 	    pj_int32_t level;
 
-	    pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame);
+	    pj_add_timestamp32(&cport->ts_rx, cport->info->samples_per_frame);
 	    
 	    f->buf = &conf->buf[sizeof(pjmedia_frame)];
@@ -1200,5 +1210,5 @@
 		if (listener->tx_setting == PJMEDIA_PORT_DISABLE) {
 		    pj_add_timestamp32(&listener->ts_tx, 
-				       listener->samples_per_frame);
+				       listener->info->samples_per_frame);
 		    listener->tx_level = 0;
 		    continue;
@@ -1250,5 +1260,5 @@
 
 		    pjmedia_port_put_frame(cport->port, &tmp_f);
-		    pj_add_timestamp32(&cport->ts_tx, cport->samples_per_frame);
+		    pj_add_timestamp32(&cport->ts_tx, cport->info->samples_per_frame);
 		}
 	    }
@@ -1269,5 +1279,5 @@
 	    pj_uint16_t samples_per_subframe;
 	    
-	    if (f_src_->samples_cnt < this_cport->samples_per_frame) {
+	    if (f_src_->samples_cnt < this_cport->info->samples_per_frame) {
 		pj_bzero(this_cport->tx_buf, sizeof(pjmedia_frame_ext));
 		frame->type = PJMEDIA_FRAME_TYPE_NONE;
@@ -1281,5 +1291,5 @@
 
 
-	    while (f_dst->samples_cnt < this_cport->samples_per_frame) {
+	    while (f_dst->samples_cnt < this_cport->info->samples_per_frame) {
 		sf = pjmedia_frame_ext_get_subframe(f_src_, i++);
 		pj_assert(sf);
@@ -1292,5 +1302,5 @@
 
 	} else if (f_src->type == PJMEDIA_FRAME_TYPE_AUDIO) {
-	    if ((f_src->size>>1) < this_cport->samples_per_frame) {
+	    if ((f_src->size>>1) < this_cport->info->samples_per_frame) {
 		pj_bzero(this_cport->tx_buf, sizeof(pjmedia_frame_ext));
 		frame->type = PJMEDIA_FRAME_TYPE_NONE;
@@ -1300,6 +1310,6 @@
 	    pjmedia_copy_samples((pj_int16_t*)frame->buf, 
 				 (pj_int16_t*)f_src->buf, 
-				 this_cport->samples_per_frame);
-	    frame->size = this_cport->samples_per_frame << 1;
+				 this_cport->info->samples_per_frame);
+	    frame->size = this_cport->info->samples_per_frame << 1;
 
 	    /* Shift left TX buffer. */
@@ -1308,5 +1318,5 @@
 		pjmedia_move_samples((pj_int16_t*)f_src->buf,
 				     (pj_int16_t*)f_src->buf + 
-				     this_cport->samples_per_frame,
+				     this_cport->info->samples_per_frame,
 				     f_src->size >> 1);
 	} else { /* PJMEDIA_FRAME_TYPE_NONE */
@@ -1334,5 +1344,5 @@
     pj_int32_t level;
 
-    pj_add_timestamp32(&cport->ts_rx, cport->samples_per_frame);
+    pj_add_timestamp32(&cport->ts_rx, cport->info->samples_per_frame);
     
     /* Skip if this port is muted/disabled. */
@@ -1373,5 +1383,5 @@
 	if (listener->tx_setting == PJMEDIA_PORT_DISABLE) {
 	    pj_add_timestamp32(&listener->ts_tx, 
-			       listener->samples_per_frame);
+			       listener->info->samples_per_frame);
 	    listener->tx_level = 0;
 	    continue;
@@ -1381,5 +1391,5 @@
 	if (listener == cport) {
 	    pj_add_timestamp32(&listener->ts_tx, 
-			       listener->samples_per_frame);
+			       listener->info->samples_per_frame);
 	    listener->tx_level = 0;
 	    continue;
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/s60_g729_bitstream.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/s60_g729_bitstream.h	(revision 2444)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/s60_g729_bitstream.h	(revision 2444)
@@ -0,0 +1,171 @@
+#ifndef __BITSTREAM_H_
+#define __BITSTREAM_H_
+
+#define KPackedFrameLen 10
+#define KUnpackedFrameLen 22
+
+// Below values are taken from the APS design document
+const TUint8 KG729FullPayloadBits[] = { 8, 10, 8, 1, 13, 4, 7, 5, 13, 4, 7 };
+const TUint  KNumFullFrameParams = 11;
+const TUint8 KG729SIDPayloadBits[] = { 1, 5, 4, 5 };
+const TUint  KNumSIDFrameParams = 4;
+
+/*! 
+  @class TBitStream
+  
+  @discussion Provides compression from 16-bit-word-aligned G.729 audio frames
+  (used in S60 G.729 DSP codec) to 8-bit stream, and vice versa.
+  */
+class TBitStream
+  {        
+public:
+    /*!
+      @function TBitStream
+      
+      @discussion Constructor
+      */   
+    TBitStream():iDes(iData,KUnpackedFrameLen){}
+    /*!
+      @function CompressG729Frame
+      
+      @discussion Compress either a 22-byte G.729 full rate frame to 10 bytes
+      or a 8-byte G.729 Annex.B SID frame to 2 bytes.
+      @param aSrc Reference to the uncompressed source frame data
+      @param aIsSIDFrame True if the source is a SID frame
+      @result a reference to the compressed frame
+      */
+    const TDesC8& CompressG729Frame( const TDesC8& aSrc, TBool aIsSIDFrame = EFalse );
+    
+    /*!
+      @function ExpandG729Frame
+            
+      @discussion Expand a 10-byte G.729 full rate frame to 22 bytes
+      or a 2-byte G.729 Annex.B SID frame to 8(22) bytes.
+      @param aSrc Reference to the compressed source frame data
+      @param aIsSIDFrame True if the source is a SID frame
+      @result a reference to a descriptor representing the uncompressed frame.
+      Note that SID frames are zero-padded to 22 bytes as well.
+      */
+    const TDesC8& ExpandG729Frame( const TDesC8& aSrc, TBool aIsSIDFrame = EFalse );
+
+private:
+    void Compress( TUint8 aValue, TUint8 aNumOfBits );
+    void Expand( const TUint8* aSrc, TInt aDstIdx, TUint8 aNumOfBits );
+
+private:
+    TUint8      iData[KUnpackedFrameLen];
+    TPtr8       iDes;
+    TInt        iIdx;
+    TInt        iBitOffset;
+    };
+    
+
+const TDesC8& TBitStream::CompressG729Frame( const TDesC8& aSrc, TBool aIsSIDFrame )
+    {
+    // reset data
+    iDes.FillZ(iDes.MaxLength());
+    iIdx = iBitOffset = 0;
+    
+    TInt numParams = (aIsSIDFrame) ? KNumSIDFrameParams : KNumFullFrameParams;
+    const TUint8* p = const_cast<TUint8*>(aSrc.Ptr());
+    
+    for(TInt i = 0, pIdx = 0; i < numParams; i++, pIdx += 2) 
+        {
+        TUint8 paramBits = (aIsSIDFrame) ? KG729SIDPayloadBits[i] : KG729FullPayloadBits[i];        
+        if(paramBits > 8)
+            {
+            Compress(p[pIdx+1], paramBits - 8); // msb
+            paramBits = 8;
+            }            
+        Compress(p[pIdx], paramBits); // lsb    
+        }
+
+    if( iBitOffset )
+        iIdx++;
+        
+    iDes.SetLength(iIdx);
+    return iDes;
+    }
+
+ 
+const TDesC8& TBitStream::ExpandG729Frame( const TDesC8& aSrc, TBool aIsSIDFrame )
+    {
+    // reset data
+    iDes.FillZ(iDes.MaxLength());
+    iIdx = iBitOffset = 0;
+    
+    TInt numParams = (aIsSIDFrame) ? KNumSIDFrameParams : KNumFullFrameParams;
+    const TUint8* p = const_cast<TUint8*>(aSrc.Ptr());
+    
+    for(TInt i = 0, dIdx = 0; i < numParams; i++, dIdx += 2) 
+        {
+        TUint8 paramBits = (aIsSIDFrame) ? KG729SIDPayloadBits[i] : KG729FullPayloadBits[i];
+        if(paramBits > 8)
+          {
+          Expand(p, dIdx+1, paramBits - 8); // msb
+          paramBits = 8;
+          }    
+        Expand(p, dIdx, paramBits); // lsb 
+        }
+        
+    iDes.SetLength(KUnpackedFrameLen);
+    return iDes;
+    }
+
+
+void TBitStream::Compress( TUint8 aValue, TUint8 aNumOfBits )
+  {
+    // clear bits that will be discarded
+    aValue &= (0xff >> (8 - aNumOfBits));
+    
+    // calculate required bitwise left shift
+    TInt shl = 8 - (iBitOffset + aNumOfBits);
+    
+    if (shl == 0) // no shift required
+        { 
+        iData[iIdx++] |= aValue;
+        iBitOffset = 0;
+        }
+    else if (shl > 0) // bits fit into current byte
+        { 
+        iData[iIdx] |= (aValue << shl);
+        iBitOffset += aNumOfBits;
+        }        
+    else        
+        { 
+        iBitOffset = -shl;
+        iData[iIdx] |= (aValue >> iBitOffset); // right shift
+        iData[++iIdx] |= (aValue << (8-iBitOffset)); // push remaining bits to next byte
+        }
+  }
+    
+
+void TBitStream::Expand( const TUint8* aSrc, TInt aDstIdx, TUint8 aNumOfBits )
+  {    
+    TUint8 aValue = aSrc[iIdx] & (0xff >> iBitOffset);
+       
+    // calculate required bitwise right shift
+    TInt shr = 8 - (iBitOffset + aNumOfBits);
+    
+    if (shr == 0) // no shift required
+        { 
+        iData[aDstIdx] = aValue;
+        iIdx++;
+        iBitOffset = 0;
+        }
+    else if (shr > 0) // right shift
+        { 
+        iData[aDstIdx] = (aValue >> shr);
+        iBitOffset += aNumOfBits;
+        }        
+    else // shift left and take remaining bits from the next src byte
+        {
+        iBitOffset = -shr;
+        iData[aDstIdx] = aValue << iBitOffset;                
+        iData[aDstIdx] |= aSrc[++iIdx] >> (8 - iBitOffset);
+        }
+  }
+
+#endif // __BITSTREAM_H_
+    
+// eof
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound_aps.cpp
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound_aps.cpp	(revision 2443)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound_aps.cpp	(revision 2444)
@@ -99,4 +99,5 @@
     pj_int16_t		*rec_buf;
     pj_uint16_t		 rec_buf_len;
+    void                *strm_data;
 };
 
@@ -696,40 +697,22 @@
 }
 
+/* Pack/unpack G.729 frame of S60 DSP codec, taken from:  
+ * http://wiki.forum.nokia.com/index.php/TSS000776_-_Payload_conversion_for_G.729_audio_format
+ */
+#include "s60_g729_bitstream.h"
+#include <pjmedia-codec/amr_helper.h>
+
 static void RecCb(TAPSCommBuffer &buf, void *user_data)
 {
     pjmedia_snd_stream *strm = (pjmedia_snd_stream*) user_data;
     pjmedia_frame_ext *frame = (pjmedia_frame_ext*) strm->rec_buf;
-    unsigned samples_processed = 0;
-
+    
     switch(strm->setting.format.u32) {
-    
-    case PJMEDIA_FOURCC_G711U:
-    case PJMEDIA_FOURCC_G711A:
-	pj_assert(buf.iBuffer[0] == 1 && buf.iBuffer[1] == 0);
-
-	/* Detect the recorder G.711 frame size, player frame size will follow
-	 * this recorder frame size.
-	 */
-	if (aps_g711_frame_len == 0) {
-	    aps_g711_frame_len = buf.iBuffer.Length() < 160? 80 : 160;
-	    TRACE_((THIS_FILE, "Detected APS G.711 frame size = %u samples",
-		    aps_g711_frame_len));
-	}
-	
-	/* Convert APS buffer format into pjmedia_frame_ext. Whenever 
-	 * samples count in the frame is equal to stream's samples per frame,
-	 * call parent stream callback.
-	 */
-	while (samples_processed < aps_g711_frame_len) {
-	    unsigned tmp;
-	    const pj_uint8_t *pb = (const pj_uint8_t*)buf.iBuffer.Ptr() + 2 +
-				   samples_processed;
-
-	    tmp = PJ_MIN(strm->samples_per_frame - frame->samples_cnt,
-			 aps_g711_frame_len - samples_processed);
+    case PJMEDIA_FOURCC_AMR:
+	{
+	    const pj_uint8_t *p = (const pj_uint8_t*)buf.iBuffer.Ptr() + 1;
+	    unsigned len = buf.iBuffer.Length() - 1;
 	    
-	    pjmedia_frame_ext_append_subframe(frame, pb, tmp << 3, tmp);
-	    samples_processed += tmp;
-
+	    pjmedia_frame_ext_append_subframe(frame, p, len << 3, 160);
 	    if (frame->samples_cnt == strm->samples_per_frame) {
 		frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
@@ -741,4 +724,101 @@
 	break;
 	
+    case PJMEDIA_FOURCC_G729:
+	{
+	    /* Check if we got a normal or SID frame. */
+	    if (buf.iBuffer[0] != 0 || buf.iBuffer[1] != 0) {
+		enum { NORMAL_LEN = 22, SID_LEN = 8 };
+		TBitStream *bitstream = (TBitStream*)strm->strm_data;
+		unsigned src_len = buf.iBuffer.Length()- 2;
+		
+		pj_assert(src_len == NORMAL_LEN || src_len == SID_LEN);
+
+		const TDesC8& p = bitstream->CompressG729Frame(
+					    buf.iBuffer.Right(src_len), 
+					    src_len == SID_LEN);
+		
+		pjmedia_frame_ext_append_subframe(frame, p.Ptr(), 
+						  p.Length() << 3, 80);
+	    } else { /* We got null frame. */
+		pjmedia_frame_ext_append_subframe(frame, NULL, 0, 80);
+	    }
+	    
+	    if (frame->samples_cnt == strm->samples_per_frame) {
+		frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
+		strm->rec_cb(strm->user_data, 0, strm->rec_buf, 0);
+		frame->samples_cnt = 0;
+		frame->subframe_cnt = 0;
+	    }
+	}
+	break;
+
+    case PJMEDIA_FOURCC_ILBC:
+	{
+	    unsigned samples_got;
+	    
+	    samples_got = strm->setting.mode == 30? 240 : 160;
+	    
+	    /* Check if we got a normal frame. */
+	    if (buf.iBuffer[0] == 1 && buf.iBuffer[1] == 0) {
+		const pj_uint8_t *p = (const pj_uint8_t*)buf.iBuffer.Ptr() + 2;
+		unsigned len = buf.iBuffer.Length() - 2;
+		
+		pjmedia_frame_ext_append_subframe(frame, p, len << 3,
+						  samples_got);
+	    } else { /* We got null frame. */
+		pjmedia_frame_ext_append_subframe(frame, NULL, 0, samples_got);
+	    }
+	    
+	    if (frame->samples_cnt == strm->samples_per_frame) {
+		frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
+		strm->rec_cb(strm->user_data, 0, strm->rec_buf, 0);
+		frame->samples_cnt = 0;
+		frame->subframe_cnt = 0;
+	    }
+	}
+	break;
+	
+    case PJMEDIA_FOURCC_G711U:
+    case PJMEDIA_FOURCC_G711A:
+	{
+	    unsigned samples_processed = 0;
+	    
+	    /* Make sure it is normal frame. */
+	    pj_assert(buf.iBuffer[0] == 1 && buf.iBuffer[1] == 0);
+
+	    /* Detect the recorder G.711 frame size, player frame size will 
+	     * follow this recorder frame size.
+	     */
+	    if (aps_g711_frame_len == 0) {
+		aps_g711_frame_len = buf.iBuffer.Length() < 160? 80 : 160;
+		TRACE_((THIS_FILE, "Detected APS G.711 frame size = %u samples",
+			aps_g711_frame_len));
+	    }
+	    
+	    /* Convert APS buffer format into pjmedia_frame_ext. Whenever 
+	     * samples count in the frame is equal to stream's samples per 
+	     * frame, call parent stream callback.
+	     */
+	    while (samples_processed < aps_g711_frame_len) {
+		unsigned tmp;
+		const pj_uint8_t *pb = (const pj_uint8_t*)buf.iBuffer.Ptr() +
+				       2 + samples_processed;
+    
+		tmp = PJ_MIN(strm->samples_per_frame - frame->samples_cnt,
+			     aps_g711_frame_len - samples_processed);
+		
+		pjmedia_frame_ext_append_subframe(frame, pb, tmp << 3, tmp);
+		samples_processed += tmp;
+    
+		if (frame->samples_cnt == strm->samples_per_frame) {
+		    frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
+		    strm->rec_cb(strm->user_data, 0, strm->rec_buf, 0);
+		    frame->samples_cnt = 0;
+		    frame->subframe_cnt = 0;
+		}
+	    }
+	}
+	break;
+	
     default:
 	break;
@@ -750,6 +830,4 @@
     pjmedia_snd_stream *strm = (pjmedia_snd_stream*) user_data;
     pjmedia_frame_ext *frame = (pjmedia_frame_ext*) strm->play_buf;
-    unsigned g711_frame_len = aps_g711_frame_len;
-    unsigned samples_ready = 0;
 
     /* Init buffer attributes and header. */
@@ -759,21 +837,158 @@
 
     switch(strm->setting.format.u32) {
+    case PJMEDIA_FOURCC_AMR:
+	{
+	    if (frame->samples_cnt == 0) {
+		frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
+		strm->play_cb(strm->user_data, 0, strm->play_buf, 0);
+		
+		pj_assert(frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
+			  frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
+	    }
+
+	    if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
+		pjmedia_frame_ext_subframe *sf;
+		unsigned samples_cnt;
+		
+		sf = pjmedia_frame_ext_get_subframe(frame, 0);
+		samples_cnt = frame->samples_cnt / frame->subframe_cnt;
+		
+		if (sf->data && sf->bitlen) {
+		    /* AMR header for APS is one byte, the format (may be!):
+		     * 0xxxxy00, where xxxx:frame type, y:not sure. 
+		     */
+		    unsigned len = sf->bitlen>>3;
+		    enum {SID_FT = 8 };
+		    pj_uint8_t amr_header = 4, ft = SID_FT;
+
+		    if (sf->bitlen & 0x07)
+			++len;
+
+		    if (len >= pjmedia_codec_amrnb_framelen[0])
+			ft = pjmedia_codec_amr_get_mode2(PJ_TRUE, len);
+		    
+		    amr_header |= ft << 3;
+		    buf.iBuffer.Append(amr_header);
+		    
+		    buf.iBuffer.Append((TUint8*)sf->data, len);
+		} else {
+		    buf.iBuffer.Append(0);
+		}
+
+		pjmedia_frame_ext_pop_subframes(frame, 1);
+	    
+	    } else { /* PJMEDIA_FRAME_TYPE_NONE */
+		buf.iBuffer.Append(0);
+		
+		frame->samples_cnt = 0;
+		frame->subframe_cnt = 0;
+	    }
+	}
+	break;
+	
+    case PJMEDIA_FOURCC_G729:
+	{
+	    if (frame->samples_cnt == 0) {
+		frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
+		strm->play_cb(strm->user_data, 0, strm->play_buf, 0);
+		
+		pj_assert(frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
+			  frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
+	    }
+
+	    if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
+		pjmedia_frame_ext_subframe *sf;
+		unsigned samples_cnt;
+		
+		sf = pjmedia_frame_ext_get_subframe(frame, 0);
+		samples_cnt = frame->samples_cnt / frame->subframe_cnt;
+		
+		if (sf->data && sf->bitlen) {
+		    enum { NORMAL_LEN = 10, SID_LEN = 2 };
+		    pj_bool_t sid_frame = ((sf->bitlen >> 3) == SID_LEN);
+		    TBitStream *bitstream = (TBitStream*)strm->strm_data;
+		    const TPtrC8 src(sf->data, sf->bitlen>>3);
+		    const TDesC8 &dst = bitstream->ExpandG729Frame(src,
+								   sid_frame); 
+		    if (sid_frame) {
+			buf.iBuffer.Append(0);
+			buf.iBuffer.Append(1);
+		    } else {
+			buf.iBuffer.Append(1);
+			buf.iBuffer.Append(0);
+		    }
+		    buf.iBuffer.Append(dst);
+		} else {
+		    buf.iBuffer.Append(0);
+		    buf.iBuffer.Append(0);
+		}
+
+		pjmedia_frame_ext_pop_subframes(frame, 1);
+	    
+	    } else { /* PJMEDIA_FRAME_TYPE_NONE */
+		buf.iBuffer.Append(0);
+		buf.iBuffer.Append(0);
+		
+		frame->samples_cnt = 0;
+		frame->subframe_cnt = 0;
+	    }
+	}
+	break;
+	
+    case PJMEDIA_FOURCC_ILBC:
+	{
+	    if (frame->samples_cnt == 0) {
+		frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
+		strm->play_cb(strm->user_data, 0, strm->play_buf, 0);
+		
+		pj_assert(frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
+			  frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
+	    }
+
+	    if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
+		pjmedia_frame_ext_subframe *sf;
+		unsigned samples_cnt;
+		
+		sf = pjmedia_frame_ext_get_subframe(frame, 0);
+		samples_cnt = frame->samples_cnt / frame->subframe_cnt;
+		pj_assert((strm->setting.mode == 30 && samples_cnt == 240) ||
+			  (strm->setting.mode == 20 && samples_cnt == 160));
+		
+		if (sf->data && sf->bitlen) {
+		    buf.iBuffer.Append(1);
+		    buf.iBuffer.Append(0);
+		    buf.iBuffer.Append((TUint8*)sf->data, sf->bitlen>>3);
+		} else {
+		    buf.iBuffer.Append(0);
+		    buf.iBuffer.Append(0);
+		}
+
+		pjmedia_frame_ext_pop_subframes(frame, 1);
+	    
+	    } else { /* PJMEDIA_FRAME_TYPE_NONE */
+		buf.iBuffer.Append(0);
+		buf.iBuffer.Append(0);
+		
+		frame->samples_cnt = 0;
+		frame->subframe_cnt = 0;
+	    }
+	}
+	break;
+	
     case PJMEDIA_FOURCC_G711U:
     case PJMEDIA_FOURCC_G711A:
 	{
-	    /* Add header. */
-	    buf.iBuffer.Append(1);
-	    buf.iBuffer.Append(0);
-    
+	    unsigned samples_ready = 0;
+	    unsigned samples_req = aps_g711_frame_len;
+	    
 	    /* Assume frame size is 10ms if frame size hasn't been known. */
-	    if (g711_frame_len == 0)
-		g711_frame_len = 80;
+	    if (samples_req == 0)
+		samples_req = 80;
 	    
 	    /* Call parent stream callback to get samples to play. */
-	    while (samples_ready < g711_frame_len) {
+	    while (samples_ready < samples_req) {
 		if (frame->samples_cnt == 0) {
 		    frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
-		    strm->play_cb(strm->user_data, 0, strm->play_buf,
-				  strm->samples_per_frame<<1);
+		    strm->play_cb(strm->user_data, 0, strm->play_buf, 0);
 		    
 		    pj_assert(frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
@@ -787,15 +1002,11 @@
 		    sf = pjmedia_frame_ext_get_subframe(frame, 0);
 		    samples_cnt = frame->samples_cnt / frame->subframe_cnt;
-		    if (sf->data && sf->bitlen)
+		    if (sf->data && sf->bitlen) {
+			buf.iBuffer.Append(1);
+			buf.iBuffer.Append(0);
 			buf.iBuffer.Append((TUint8*)sf->data, sf->bitlen>>3);
-		    else {
-			pj_uint8_t silence_code;
-			
-			if (strm->setting.format.u32 == PJMEDIA_FOURCC_G711U)
-			    silence_code = pjmedia_linear2ulaw(0);
-			else
-			    silence_code = pjmedia_linear2alaw(0);
-			
-			buf.iBuffer.AppendFill(silence_code, samples_cnt);
+		    } else {
+			buf.iBuffer.Append(0);
+			buf.iBuffer.Append(0);
 		    }
 		    samples_ready += samples_cnt;
@@ -804,14 +1015,8 @@
 		
 		} else { /* PJMEDIA_FRAME_TYPE_NONE */
-		    pj_uint8_t silence_code;
-		    
-		    if (strm->setting.format.u32 == PJMEDIA_FOURCC_G711U)
-			silence_code = pjmedia_linear2ulaw(0);
-		    else
-			silence_code = pjmedia_linear2alaw(0);
-		    
-		    buf.iBuffer.AppendFill(silence_code, 
-					   g711_frame_len - samples_ready);
-		    samples_ready = g711_frame_len;
+		    buf.iBuffer.Append(0);
+		    buf.iBuffer.Append(0);
+
+		    samples_ready = samples_req;
 		    frame->samples_cnt = 0;
 		    frame->subframe_cnt = 0;
@@ -922,6 +1127,14 @@
     }
 
-    aps_setting.vad = strm->setting.format.u32==PJMEDIA_FOURCC_L16? 
-					EFalse : strm->setting.vad;
+    /* Disable VAD on L16 and G711. */
+    if (strm->setting.format.u32 == PJMEDIA_FOURCC_L16 ||
+	strm->setting.format.u32 == PJMEDIA_FOURCC_G711U ||
+	strm->setting.format.u32 == PJMEDIA_FOURCC_G711A)
+    {
+	aps_setting.vad = EFalse;
+    } else {
+	aps_setting.vad = strm->setting.vad;
+    }
+    
     aps_setting.plc = strm->setting.plc;
     aps_setting.cng = strm->setting.cng;
@@ -958,4 +1171,11 @@
     strm->rec_buf_len = 0;
 
+    if (strm->setting.format.u32 == PJMEDIA_FOURCC_G729) {
+	TBitStream *g729_bitstream = new TBitStream;
+	
+	PJ_ASSERT_RETURN(g729_bitstream, PJ_ENOMEM);
+	strm->strm_data = (void*)g729_bitstream;
+    }
+	
     // Done.
     *p_snd_strm = strm;
@@ -984,5 +1204,4 @@
     pj_bzero(&setting, sizeof(setting));
     setting.format.u32 = PJMEDIA_FOURCC_L16;
-    setting.bitrate = 128000;
     
     return sound_open(PJMEDIA_DIR_CAPTURE, clock_rate, channel_count,
@@ -1007,5 +1226,4 @@
     pj_bzero(&setting, sizeof(setting));
     setting.format.u32 = PJMEDIA_FOURCC_L16;
-    setting.bitrate = 128000;
 
     return sound_open(PJMEDIA_DIR_PLAYBACK, clock_rate, channel_count,
@@ -1033,5 +1251,4 @@
     pj_bzero(&setting, sizeof(setting));
     setting.format.u32 = PJMEDIA_FOURCC_L16;
-    setting.bitrate = 128000;
 
     return sound_open(PJMEDIA_DIR_CAPTURE_PLAYBACK, clock_rate, channel_count,
@@ -1121,4 +1338,10 @@
     stream->engine = NULL;
 
+    if (stream->setting.format.u32 == PJMEDIA_FOURCC_G729) {
+	TBitStream *g729_bitstream = (TBitStream*)stream->strm_data;
+	stream->strm_data = NULL;
+	delete g729_bitstream;
+    }
+
     pool = stream->pool;
     if (pool) {
Index: pjproject/branches/projects/aps-direct/pjsip-apps/src/symbian_ua/ua.cpp
===================================================================
--- pjproject/branches/projects/aps-direct/pjsip-apps/src/symbian_ua/ua.cpp	(revision 2443)
+++ pjproject/branches/projects/aps-direct/pjsip-apps/src/symbian_ua/ua.cpp	(revision 2444)
@@ -281,4 +281,5 @@
 	return;
 
+    /* Init sound device setting based on stream info. */
     pj_bzero(&setting, sizeof(setting));
     setting.format = strm_info->param->info.format;
@@ -287,10 +288,35 @@
     setting.vad = strm_info->param->setting.vad;
     setting.plc = strm_info->param->setting.plc;
+    if (setting.format.u32 == PJMEDIA_FOURCC_ILBC) {
+	unsigned i;
+	pjmedia_codec_fmtp *fmtp = &strm_info->param->setting.dec_fmtp;
+	
+	/* Initialize mode. */
+	setting.mode = 30;
+	
+	/* Get mode. */
+	for (i = 0; i < fmtp->cnt; ++i) {
+	    if (pj_stricmp2(&fmtp->param[i].name, "mode") == 0) {
+		setting.mode = (pj_uint32_t) pj_strtoul(&fmtp->param[i].val);
+		break;
+	    }
+	}
+    }
+
+    samples_per_frame = strm_info->param->info.clock_rate *
+			strm_info->param->info.frm_ptime *
+			strm_info->param->info.channel_cnt /
+			1000;
+    
+    /* Close sound device. */
+    conf = pjsua_set_no_snd_dev();
+    
+    /* Reset conference attributes. */
+    conf->info.samples_per_frame = samples_per_frame;
+    conf->info.clock_rate = 8000;
+    conf->info.channel_count = 1;
+    conf->info.bits_per_sample = 16;
 
     /* Reopen sound device. */
-    conf = pjsua_set_no_snd_dev();
-
-    samples_per_frame = conf->info.samples_per_frame;
-    
     status = pjmedia_snd_port_create2(app_pool, 
 				      PJMEDIA_DIR_CAPTURE_PLAYBACK,
