Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/conference.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/conference.h	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/conference.h	(revision 2460)
@@ -62,4 +62,5 @@
     unsigned		listener_cnt;	    /**< Number of listeners.	    */
     unsigned	       *listener_slots;	    /**< Array of listeners.	    */
+    unsigned		transmitter_cnt;    /**< Number of transmitter.	    */
     unsigned		clock_rate;	    /**< Clock rate of the port.    */
     unsigned		channel_count;	    /**< Number of channels.	    */
Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound.h	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound.h	(revision 2460)
@@ -117,5 +117,4 @@
     pjmedia_format	format;	  /**< Format.			    */ 
     pj_bool_t		plc;	  /**< PLC enabled/disabled.	    */
-    pj_bool_t		cng;	  /**< CNG enabled/disabled.	    */
     pjmedia_snd_route	route;	  /**< Audio routing.		    */
 } pjmedia_snd_setting;
Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/types.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/types.h	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/types.h	(revision 2460)
@@ -205,5 +205,5 @@
 {
     /** Format ID */
-    pjmedia_format_id	fmt_id;
+    pjmedia_format_id	id;
 
     /** Bitrate. */
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2460)
@@ -588,8 +588,22 @@
     dst_port = conf->ports[sink_slot];
 
-    /* Source and sink format must match. */
-    if (src_port->info->format.fmt_id != dst_port->info->format.fmt_id) {
+    /* Format must match. */
+    if (src_port->info->format.id != dst_port->info->format.id ||
+	src_port->info->format.bitrate != dst_port->info->format.bitrate) 
+    {
 	pj_mutex_unlock(conf->mutex);
 	return PJMEDIA_ENOTCOMPATIBLE;
+    }
+
+    /* Clock rate must match. */
+    if (src_port->info->clock_rate != dst_port->info->clock_rate) {
+	pj_mutex_unlock(conf->mutex);
+	return PJMEDIA_ENCCLOCKRATE;
+    }
+
+    /* Channel count must match. */
+    if (src_port->info->channel_count != dst_port->info->channel_count) {
+	pj_mutex_unlock(conf->mutex);
+	return PJMEDIA_ENCCLOCKRATE;
     }
 
@@ -866,4 +880,5 @@
     info->listener_cnt = conf_port->listener_cnt;
     info->listener_slots = conf_port->listener_slots;
+    info->transmitter_cnt = conf_port->transmitter_cnt;
     info->clock_rate = conf_port->info->clock_rate;
     info->channel_count = conf_port->info->channel_count;
@@ -952,5 +967,5 @@
 
     /* Level adjustment is applicable only for ports that work with raw PCM. */
-    PJ_ASSERT_RETURN(conf_port->info->format.fmt_id == PJMEDIA_FORMAT_L16,
+    PJ_ASSERT_RETURN(conf_port->info->format.id == PJMEDIA_FORMAT_L16,
 		     PJ_EIGNORED);
 
@@ -986,5 +1001,5 @@
 
     /* Level adjustment is applicable only for ports that work with raw PCM. */
-    PJ_ASSERT_RETURN(conf_port->info->format.fmt_id == PJMEDIA_FORMAT_L16,
+    PJ_ASSERT_RETURN(conf_port->info->format.id == PJMEDIA_FORMAT_L16,
 		     PJ_EIGNORED);
 
@@ -1050,4 +1065,5 @@
 	f_start = (pj_int16_t*)frm_src->buf;
 	f_end   = f_start + (frm_src->size >> 1);
+
 	while (f_start < f_end) {
 	    unsigned nsamples_to_copy, nsamples_req;
@@ -1111,5 +1127,5 @@
 	/* Check port format. */
 	if (cport_dst->port &&
-	    cport_dst->port->info.format.fmt_id == PJMEDIA_FORMAT_L16)
+	    cport_dst->port->info.format.id == PJMEDIA_FORMAT_L16)
 	{
 	    /* When there is already some samples in listener's TX buffer, 
@@ -1210,4 +1226,6 @@
 	{
 	    cport->rx_level = 0;
+	    pj_add_timestamp32(&cport->ts_rx, 
+			       conf->master_port->info.samples_per_frame);
 	    continue;
 	}
@@ -1226,5 +1244,5 @@
 	    
 	    f->buf = &conf->buf[sizeof(pjmedia_frame)];
-	    f->size = BUFFER_SIZE - sizeof(pjmedia_frame);
+	    f->size = cport->info->samples_per_frame<<1;
 
 	    /* Get frame from port. */
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conference.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conference.c	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conference.c	(revision 2460)
@@ -1172,4 +1172,5 @@
     info->listener_cnt = conf_port->listener_cnt;
     info->listener_slots = conf_port->listener_slots;
+    info->transmitter_cnt = conf_port->transmitter_cnt;
     info->clock_rate = conf_port->clock_rate;
     info->channel_count = conf_port->channel_count;
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c	(revision 2460)
@@ -290,5 +290,5 @@
 	unsigned i, size_decoded;
 
-	switch (snd_port->setting.format.fmt_id) {
+	switch (snd_port->setting.format.id) {
 	case PJMEDIA_FORMAT_PCMA:
 	    decoder = &pjmedia_alaw_decode;
@@ -299,5 +299,5 @@
 	default:
 	    PJ_LOG(1,(THIS_FILE, "Unsupported format %d", 
-		      snd_port->setting.format.fmt_id));
+		      snd_port->setting.format.id));
 	    goto no_frame;
 	}
@@ -392,5 +392,5 @@
     fx->base.timestamp.u32.lo = timestamp;
 
-    switch (snd_port->setting.format.fmt_id) {
+    switch (snd_port->setting.format.id) {
     case PJMEDIA_FORMAT_PCMA:
 	encoder = &pjmedia_alaw_encode;
@@ -401,5 +401,5 @@
     default:
 	PJ_LOG(1,(THIS_FILE, "Unsupported format %d", 
-		  snd_port->setting.format.fmt_id));
+		  snd_port->setting.format.id));
 	return PJ_SUCCESS;
     }
@@ -435,5 +435,5 @@
 		     PJ_EBUG);
 
-    if (snd_port->setting.format.fmt_id == PJMEDIA_FORMAT_L16) {
+    if (snd_port->setting.format.id == PJMEDIA_FORMAT_L16) {
 	snd_rec_cb = &rec_cb;
 	snd_play_cb = &play_cb;
@@ -716,5 +716,5 @@
 #if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || PJMEDIA_SND_SUPPORT_OPEN2==0
     /* For devices that doesn't support open2(), enable simulation */
-    if (snd_port->setting.format.fmt_id != PJMEDIA_FORMAT_L16) {
+    if (snd_port->setting.format.id != PJMEDIA_FORMAT_L16) {
 	snd_port->frm_buf_size = sizeof(pjmedia_frame_ext) + 
 				 (samples_per_frame << 1) +
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/stream.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/stream.c	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/stream.c	(revision 2460)
@@ -868,5 +868,5 @@
     } else if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO &&
 	       frame->buf == NULL &&
-	       stream->port.info.format.fmt_id == PJMEDIA_FORMAT_L16 &&
+	       stream->port.info.format.id == PJMEDIA_FORMAT_L16 &&
 	       (stream->dir & PJMEDIA_DIR_ENCODING) &&
 	       stream->codec_param.info.frm_ptime *
@@ -1606,12 +1606,13 @@
     stream->port.info.clock_rate = info->fmt.clock_rate;
     stream->port.info.channel_count = info->fmt.channel_cnt;
-    stream->port.info.format.fmt_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.info.format.id = info->param->info.fmt_id;
     stream->port.port_data.pdata = stream;
-    if (stream->port.info.format.fmt_id == PJMEDIA_FORMAT_L16) {
+    if (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.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;
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 2459)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound_aps.cpp	(revision 2460)
@@ -708,5 +708,5 @@
     pjmedia_frame_ext *frame = (pjmedia_frame_ext*) strm->rec_buf;
     
-    switch(strm->setting.format.u32) {
+    switch(strm->setting.format.id) {
     case PJMEDIA_FORMAT_AMR:
 	{
@@ -757,5 +757,5 @@
 	    unsigned samples_got;
 	    
-	    samples_got = strm->setting.mode == 30? 240 : 160;
+	    samples_got = strm->setting.format.bitrate == 15200? 160 : 240;
 	    
 	    /* Check if we got a normal frame. */
@@ -836,5 +836,5 @@
     buf.iBuffer.Zero();
 
-    switch(strm->setting.format.u32) {
+    switch(strm->setting.format.id) {
     case PJMEDIA_FORMAT_AMR:
 	{
@@ -949,6 +949,9 @@
 		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));
+		
+		pj_assert((strm->setting.format.bitrate == 15200 && 
+			   samples_cnt == 160) ||
+			  (strm->setting.format.bitrate != 15200 &&
+			   samples_cnt == 240));
 		
 		if (sf->data && sf->bitlen) {
@@ -1006,5 +1009,5 @@
 		    } else {
 			pj_uint8_t silc;
-			silc = (strm->setting.format.u32==PJMEDIA_FORMAT_PCMU)?
+			silc = (strm->setting.format.id==PJMEDIA_FORMAT_PCMU)?
 				pjmedia_linear2ulaw(0) : pjmedia_linear2alaw(0);
 			buf.iBuffer.AppendFill(silc, samples_cnt);
@@ -1017,5 +1020,5 @@
 		    pj_uint8_t silc;
 		    
-		    silc = (strm->setting.format.u32==PJMEDIA_FORMAT_PCMU)?
+		    silc = (strm->setting.format.id==PJMEDIA_FORMAT_PCMU)?
 			    pjmedia_linear2ulaw(0) : pjmedia_linear2alaw(0);
 		    buf.iBuffer.AppendFill(silc, samples_req - samples_ready);
@@ -1106,28 +1109,39 @@
 
     /* Set audio engine fourcc. */
-    if (strm->setting.format.u32 == PJMEDIA_FORMAT_PCMU ||
-	strm->setting.format.u32 == PJMEDIA_FORMAT_PCMA ||
-	strm->setting.format.u32 == PJMEDIA_FORMAT_L16)
+    switch(strm->setting.format.id) {
+    case PJMEDIA_FORMAT_L16:
+    case PJMEDIA_FORMAT_PCMU:
+    case PJMEDIA_FORMAT_PCMA:
+	aps_setting.fourcc = TFourCC(KMCPFourCCIdG711);
+	break;
+    case PJMEDIA_FORMAT_AMR:
+	aps_setting.fourcc = TFourCC(KMCPFourCCIdAMRNB);
+	break;
+    case PJMEDIA_FORMAT_G729:
+	aps_setting.fourcc = TFourCC(KMCPFourCCIdG729);
+	break;
+    case PJMEDIA_FORMAT_ILBC:
+	aps_setting.fourcc = TFourCC(KMCPFourCCIdILBC);
+	break;
+    default:
+	aps_setting.fourcc = 0;
+	break;
+    }
+
+    /* Set audio engine mode. */
+    if (strm->setting.format.id == PJMEDIA_FORMAT_AMR)
     {
-	aps_setting.fourcc = TFourCC(KMCPFourCCIdG711);
-    } else {
-	aps_setting.fourcc = TFourCC(strm->setting.format.u32);
-    }
-
-    /* Set audio engine mode. */
-    if (strm->setting.format.u32 == PJMEDIA_FORMAT_AMR)
-    {
-	aps_setting.mode = (TAPSCodecMode)strm->setting.bitrate;
+	aps_setting.mode = (TAPSCodecMode)strm->setting.format.bitrate;
     } 
-    else if (strm->setting.format.u32 == PJMEDIA_FORMAT_PCMU ||
-	     strm->setting.format.u32 == PJMEDIA_FORMAT_L16 ||
-	    (strm->setting.format.u32 == PJMEDIA_FORMAT_ILBC  &&
-	     strm->setting.mode == 30))
+    else if (strm->setting.format.id == PJMEDIA_FORMAT_PCMU ||
+	     strm->setting.format.id == PJMEDIA_FORMAT_L16 ||
+	    (strm->setting.format.id == PJMEDIA_FORMAT_ILBC  &&
+	     strm->setting.format.bitrate != 15200))
     {
 	aps_setting.mode = EULawOr30ms;
     } 
-    else if (strm->setting.format.u32 == PJMEDIA_FORMAT_PCMA ||
-	    (strm->setting.format.u32 == PJMEDIA_FORMAT_ILBC &&
-	     strm->setting.mode == 20))
+    else if (strm->setting.format.id == PJMEDIA_FORMAT_PCMA ||
+	    (strm->setting.format.id == PJMEDIA_FORMAT_ILBC &&
+	     strm->setting.format.bitrate == 15200))
     {
 	aps_setting.mode = EALawOr20ms;
@@ -1135,20 +1149,20 @@
 
     /* Disable VAD on L16 and G711. */
-    if (strm->setting.format.u32 == PJMEDIA_FORMAT_PCMU ||
-	strm->setting.format.u32 == PJMEDIA_FORMAT_PCMA ||
-	strm->setting.format.u32 == PJMEDIA_FORMAT_L16)
+    if (strm->setting.format.id == PJMEDIA_FORMAT_PCMU ||
+	strm->setting.format.id == PJMEDIA_FORMAT_PCMA ||
+	strm->setting.format.id == PJMEDIA_FORMAT_L16)
     {
 	aps_setting.vad = EFalse;
     } else {
-	aps_setting.vad = strm->setting.vad;
+	aps_setting.vad = strm->setting.format.vad;
     }
     
     /* Set other audio engine attributes. */
     aps_setting.plc = strm->setting.plc;
-    aps_setting.cng = strm->setting.cng;
-    aps_setting.loudspk = strm->setting.loudspk;
+    aps_setting.cng = aps_setting.vad;
+    aps_setting.loudspk = strm->setting.route == PJMEDIA_SND_ROUTE_LOUDSPEAKER;
 
     /* Set audio engine callbacks. */
-    if (strm->setting.format.u32 == PJMEDIA_FORMAT_L16) {
+    if (strm->setting.format.id == PJMEDIA_FORMAT_L16) {
 	aps_play_cb = &PlayCbPcm;
 	aps_rec_cb  = &RecCbPcm;
@@ -1180,5 +1194,5 @@
     strm->rec_buf_len = 0;
 
-    if (strm->setting.format.u32 == PJMEDIA_FORMAT_G729) {
+    if (strm->setting.format.id == PJMEDIA_FORMAT_G729) {
 	TBitStream *g729_bitstream = new TBitStream;
 	
@@ -1212,5 +1226,5 @@
 
     pj_bzero(&setting, sizeof(setting));
-    setting.format.u32 = PJMEDIA_FORMAT_L16;
+    setting.format.id = PJMEDIA_FORMAT_L16;
     
     return sound_open(PJMEDIA_DIR_CAPTURE, clock_rate, channel_count,
@@ -1234,5 +1248,5 @@
 
     pj_bzero(&setting, sizeof(setting));
-    setting.format.u32 = PJMEDIA_FORMAT_L16;
+    setting.format.id = PJMEDIA_FORMAT_L16;
 
     return sound_open(PJMEDIA_DIR_PLAYBACK, clock_rate, channel_count,
@@ -1259,5 +1273,5 @@
 
     pj_bzero(&setting, sizeof(setting));
-    setting.format.u32 = PJMEDIA_FORMAT_L16;
+    setting.format.id = PJMEDIA_FORMAT_L16;
 
     return sound_open(PJMEDIA_DIR_CAPTURE_PLAYBACK, clock_rate, channel_count,
@@ -1347,5 +1361,5 @@
     stream->engine = NULL;
 
-    if (stream->setting.format.u32 == PJMEDIA_FORMAT_G729) {
+    if (stream->setting.format.id == PJMEDIA_FORMAT_G729) {
 	TBitStream *g729_bitstream = (TBitStream*)stream->strm_data;
 	stream->strm_data = NULL;
Index: pjproject/branches/projects/aps-direct/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjsip-apps/src/pjsua/pjsua_app.c	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjsip-apps/src/pjsua/pjsua_app.c	(revision 2460)
@@ -2402,108 +2402,4 @@
 }
 
-#ifdef PJSUA_SIMULATE_APS_DIRECT
-/* To simulate APS direct, add these to config_site.h:
-#define PJSUA_SIMULATE_APS_DIRECT
-#ifdef PJSUA_SIMULATE_APS_DIRECT
-    #define PJMEDIA_CONF_USE_SWITCH_BOARD	1
-    #define PJMEDIA_HAS_PASSTHROUGH_CODECS	1
-
-    #define PJMEDIA_HAS_L16_CODEC		0
-    #define PJMEDIA_HAS_GSM_CODEC		0
-    #define PJMEDIA_HAS_SPEEX_CODEC		0
-    #define PJMEDIA_HAS_ILBC_CODEC		0
-    #define PJMEDIA_HAS_G722_CODEC		0
-    #define PJMEDIA_HAS_INTEL_IPP		0
-
-    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR   0
-    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_G729  0
-    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC  0
-#endif
-*/
-
-/* Global sound port. */
-static pjmedia_snd_port *g_snd_port;
-
-
-/* Reopen sound device on on_stream_created() pjsua callback. */
-static void on_call_stream_created(pjsua_call_id call_id, 
-				   pjmedia_session *sess,
-				   unsigned stream_idx, 
-				   pjmedia_port **p_port)
-{
-    pjmedia_port *conf;
-    pjmedia_session_info sess_info;
-    pjmedia_port *port;
-    pjmedia_stream_info *strm_info;
-    pjmedia_snd_setting setting;
-    unsigned samples_per_frame;
-    pj_status_t status;
-
-    PJ_UNUSED_ARG(call_id);
-    PJ_UNUSED_ARG(p_port);
-
-    /* Get active format for this stream, based on SDP negotiation result. */    
-    pjmedia_session_get_info(sess, &sess_info);
-    strm_info = &sess_info.stream_info[stream_idx];
-
-    pjmedia_session_get_port(sess, stream_idx, &port);
-
-    /* Init sound device setting based on stream info. */
-    pj_bzero(&setting, sizeof(setting));
-    setting.format = port->info.format;
-    setting.cng = strm_info->param->setting.cng;
-    setting.plc = strm_info->param->setting.plc;
-
-    /* Close sound device and get the conference port. */
-    conf = pjsua_set_no_snd_dev();
-    
-    samples_per_frame = strm_info->param->info.clock_rate *
-			strm_info->param->info.frm_ptime *
-			strm_info->param->setting.frm_per_pkt *
-			strm_info->param->info.channel_cnt /
-			1000;
-
-    /* Reset conference port attributes. */
-    conf->info.samples_per_frame = samples_per_frame;
-    conf->info.clock_rate = strm_info->param->info.clock_rate;
-    conf->info.channel_count = 1;
-    conf->info.bits_per_sample = 16;
-
-    /* Reopen sound device. */
-    status = pjmedia_snd_port_create2(app_config.pool, 
-				      PJMEDIA_DIR_CAPTURE_PLAYBACK,
-				      -1,
-				      -1,
-				      strm_info->param->info.clock_rate,
-				      strm_info->param->info.channel_cnt,
-				      samples_per_frame,
-				      16,
-				      &setting,
-				      &g_snd_port);
-    if (status != PJ_SUCCESS) {
-	pjsua_perror(THIS_FILE, "Error opening sound device", status);
-	return;
-    }
-
-    /* Connect sound to conference port. */
-    pjmedia_snd_port_connect(g_snd_port, conf);
-}
-
-static void on_call_stream_destroyed(pjsua_call_id call_id,
-				     pjmedia_session *sess, 
-				     unsigned stream_idx)
-{
-    PJ_UNUSED_ARG(call_id);
-    PJ_UNUSED_ARG(sess);
-    PJ_UNUSED_ARG(stream_idx);
-
-    if (g_snd_port) {
-    	pjmedia_snd_port_destroy(g_snd_port);
-    	g_snd_port = NULL;
-    }
-}
-
-#endif
-
 /*
  * DTMF callback.
@@ -4151,8 +4047,4 @@
     app_config.cfg.cb.on_call_state = &on_call_state;
     app_config.cfg.cb.on_call_media_state = &on_call_media_state;
-#ifdef PJSUA_SIMULATE_APS_DIRECT
-    app_config.cfg.cb.on_stream_created = &on_call_stream_created;
-    app_config.cfg.cb.on_stream_destroyed = &on_call_stream_destroyed;
-#endif
     app_config.cfg.cb.on_incoming_call = &on_incoming_call;
     app_config.cfg.cb.on_call_tsx_state = &on_call_tsx_state;
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 2459)
+++ pjproject/branches/projects/aps-direct/pjsip-apps/src/symbian_ua/ua.cpp	(revision 2460)
@@ -92,7 +92,4 @@
 static pjsua_buddy_id g_buddy_id = PJSUA_INVALID_ID;
 
-static pj_pool_t *app_pool;
-static pjmedia_snd_port *g_snd_port;
-
 
 /* Callback called by the library upon receiving incoming call */
@@ -254,107 +251,4 @@
 }
 
-/* Notification that stream is created. */
-static void on_stream_created(pjsua_call_id call_id, 
-			      pjmedia_session *sess,
-			      unsigned stream_idx, 
-			      pjmedia_port **p_port)
-{
-    pjmedia_port *conf;
-    pjmedia_session_info sess_info;
-    pjmedia_stream_info *strm_info;
-    pjmedia_snd_setting setting;
-    unsigned samples_per_frame;
-    pj_status_t status;
-    
-    PJ_UNUSED_ARG(call_id);
-    PJ_UNUSED_ARG(p_port);
-    
-    status = pjmedia_session_get_info(sess, &sess_info);
-    if (status != PJ_SUCCESS) {
-	PJ_LOG(1,(THIS_FILE, "on_stream_created() failed to get session info, "
-			     "status=%d", status));
-	return;
-    }
-    
-    strm_info = &sess_info.stream_info[stream_idx];
-    if (strm_info->type != PJMEDIA_TYPE_AUDIO)
-	return;
-
-    /* Init sound device setting based on stream info. */
-    pj_bzero(&setting, sizeof(setting));
-    setting.format = strm_info->param->info.format;
-    setting.bitrate = strm_info->param->info.avg_bps;
-    setting.cng = strm_info->param->setting.cng;
-    setting.vad = strm_info->param->setting.vad;
-    setting.plc = strm_info->param->setting.plc;
-    if (setting.format.u32 == PJMEDIA_FORMAT_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 = strm_info->param->info.clock_rate;
-    conf->info.channel_count = strm_info->param->info.channel_cnt;
-    conf->info.bits_per_sample = 16;
-    conf->info.format = strm_info->param->info.format;
-
-    /* Reopen sound device. */
-    status = pjmedia_snd_port_create2(app_pool, 
-				      PJMEDIA_DIR_CAPTURE_PLAYBACK,
-				      0,
-				      0,
-				      strm_info->param->info.clock_rate,
-				      strm_info->param->info.channel_cnt,
-				      samples_per_frame,
-				      16,
-				      &setting,
-				      &g_snd_port);
-    if (status != PJ_SUCCESS) {
-	PJ_LOG(1,(THIS_FILE, "on_stream_created() failed to reopen sound "
-			     "device, status=%d", status));
-	return;
-    }
-    
-    status = pjmedia_snd_port_connect(g_snd_port, conf);
-    if (status != PJ_SUCCESS) {
-	PJ_LOG(1,(THIS_FILE, "on_stream_created() failed to connect sound "
-			     "device to conference, status=%d", status));
-	return;
-    }
-}
-
-static void on_stream_destroyed(pjsua_call_id call_id,
-				pjmedia_session *sess, 
-				unsigned stream_idx)
-{
-    PJ_UNUSED_ARG(call_id);
-    PJ_UNUSED_ARG(sess);
-    PJ_UNUSED_ARG(stream_idx);
-
-    if (g_snd_port) {
-    	pjmedia_snd_port_destroy(g_snd_port);
-    	g_snd_port = NULL;
-    }
-}
 
 //#include<e32debug.h>
@@ -397,7 +291,4 @@
     }
 
-    /* Create pool for application */
-    app_pool = pjsua_pool_create("pjsua-app", 1000, 1000);
-    
     /* Init pjsua */
     pjsua_config cfg;
@@ -420,6 +311,4 @@
     cfg.cb.on_call_replaced = &on_call_replaced;
     cfg.cb.on_nat_detect = &on_nat_detect;
-    cfg.cb.on_stream_created = &on_stream_created;
-    cfg.cb.on_stream_destroyed = &on_stream_destroyed;
     
     if (SIP_PROXY) {
@@ -636,14 +525,15 @@
 #   if PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_SYMB_APS_SOUND
     case 't':
-	if (g_snd_port) {
-	    static pj_bool_t act_loudspk = PJ_TRUE;
-	    pjmedia_snd_stream *strm;
+	do {
+	    static pjmedia_snd_route route = PJMEDIA_SND_ROUTE_LOUDSPEAKER;
 	    
-	    strm = pjmedia_snd_port_get_snd_stream(g_snd_port);
-	    pjmedia_snd_aps_activate_loudspeaker(strm, act_loudspk);
-	    act_loudspk = !act_loudspk;
-	} else {
-	    PJ_LOG(3,(THIS_FILE, "Sound device is not active."));
-	}
+	    pjsua_set_snd_route(route);
+	    
+	    if (route == PJMEDIA_SND_ROUTE_LOUDSPEAKER)
+		route = PJMEDIA_SND_ROUTE_EARPIECE;
+	    else
+		route = PJMEDIA_SND_ROUTE_LOUDSPEAKER;
+		
+	} while(0);
 	break;
 #   endif
@@ -1013,15 +903,4 @@
 #endif
 	
-    if (g_snd_port) {
-	pjmedia_snd_port_destroy(g_snd_port);
-	g_snd_port = NULL;
-    }
-
-    // Release application pool
-    if (app_pool) {
-	pj_pool_release(app_pool);
-	app_pool = NULL;
-    }
-    
     // Shutdown pjsua
     pjsua_destroy();
Index: pjproject/branches/projects/aps-direct/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjsip/include/pjsua-lib/pjsua.h	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjsip/include/pjsua-lib/pjsua.h	(revision 2460)
@@ -4913,4 +4913,13 @@
 
 
+/**
+ * Set sound device route.
+ *
+ * @param route		Sound device route to be set.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_set_snd_route(pjmedia_snd_route route);
+
 
 /*****************************************************************************
Index: pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2459)
+++ pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2460)
@@ -1510,4 +1510,136 @@
 }
 
+#if PJMEDIA_CONF_USE_SWITCH_BOARD
+
+/*
+ * Open sound device with extended setting.
+ */
+static pj_status_t open_snd_dev_ext( int capture_dev,
+				     int playback_dev,
+				     unsigned clock_rate,
+				     unsigned channel_count,
+				     unsigned samples_per_frame,
+				     const pjmedia_snd_setting *setting)
+{
+    pjmedia_port *conf_port;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(setting, PJ_EINVAL);
+
+    /* Check if NULL sound device is used */
+    if (NULL_SND_DEV_ID == capture_dev || NULL_SND_DEV_ID == playback_dev) {
+	return pjsua_set_null_snd_dev();
+    }
+
+    /* Close existing sound port */
+    close_snd_dev();
+
+    /* Create memory pool for sound device. */
+    pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000);
+    PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM);
+
+
+    /* Get the port0 of the conference bridge. */
+    conf_port = pjmedia_conf_get_master_port(pjsua_var.mconf);
+    pj_assert(conf_port != NULL);
+
+    PJ_LOG(4,(THIS_FILE, "Opening sound device @%d/%d/%s",
+	      clock_rate, channel_count,
+	      (setting->format.id==PJMEDIA_FORMAT_L16?"raw":"encoded")));
+
+    status = pjmedia_snd_port_create2( pjsua_var.snd_pool, 
+				       PJMEDIA_DIR_CAPTURE_PLAYBACK,
+				       capture_dev,
+				       playback_dev, 
+				       clock_rate, 
+				       channel_count,
+				       samples_per_frame,
+				       16, 
+				       setting, 
+				       &pjsua_var.snd_port);
+
+    /* Update port 0 info when sound dev opened successfully. */
+    if (status == PJ_SUCCESS) {
+	conf_port->info.format = setting->format;
+	conf_port->info.clock_rate = clock_rate;
+	conf_port->info.samples_per_frame = samples_per_frame;
+	conf_port->info.channel_count = channel_count;
+	conf_port->info.bits_per_sample = 16;
+    } else {
+	pjsua_perror(THIS_FILE, "Unable to open sound device", status);
+	return status;
+    }
+
+    /* Connect sound port to the bridge */
+    status = pjmedia_snd_port_connect(pjsua_var.snd_port, 	 
+				      conf_port ); 	 
+    if (status != PJ_SUCCESS) { 	 
+	pjsua_perror(THIS_FILE, "Unable to connect conference port to "
+			        "sound device", status); 	 
+	pjmedia_snd_port_destroy(pjsua_var.snd_port); 	 
+	pjsua_var.snd_port = NULL; 	 
+	return status; 	 
+    }
+
+    /* Save the device IDs */
+    pjsua_var.cap_dev = capture_dev;
+    pjsua_var.play_dev = playback_dev;
+
+    /* Update sound device name. */
+    do {
+	const pjmedia_snd_dev_info *play_info;
+	pjmedia_snd_stream *strm;
+	pjmedia_snd_stream_info si;
+        pj_str_t tmp;
+
+	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
+	pjmedia_snd_stream_get_info(strm, &si);
+	play_info = pjmedia_snd_get_dev_info(si.rec_id);
+
+	pjmedia_conf_set_port0_name(pjsua_var.mconf, 
+				    pj_cstr(&tmp, play_info->name));
+    } while(0);
+
+    return PJ_SUCCESS;
+}
+
+#endif
+
+
+/* Close existing sound device */
+static void close_snd_dev(void)
+{
+    /* Close sound device */
+    if (pjsua_var.snd_port) {
+	pjmedia_snd_dev_info cap_info, play_info;
+	pjmedia_snd_stream *strm;
+	pjmedia_snd_stream_info si;
+
+	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
+	pjmedia_snd_stream_get_info(strm, &si);
+	cap_info = *(pjmedia_snd_get_dev_info(si.rec_id));
+	play_info = *(pjmedia_snd_get_dev_info(si.play_id));
+
+	PJ_LOG(4,(THIS_FILE, "Closing %s sound playback device and "
+			     "%s sound capture device",
+			     play_info.name, cap_info.name));
+
+	pjmedia_snd_port_disconnect(pjsua_var.snd_port);
+	pjmedia_snd_port_destroy(pjsua_var.snd_port);
+	pjsua_var.snd_port = NULL;
+    }
+
+    /* Close null sound device */
+    if (pjsua_var.null_snd) {
+	PJ_LOG(4,(THIS_FILE, "Closing null sound device.."));
+	pjmedia_master_port_destroy(pjsua_var.null_snd, PJ_FALSE);
+	pjsua_var.null_snd = NULL;
+    }
+
+    if (pjsua_var.snd_pool) 
+	pj_pool_release(pjsua_var.snd_pool);
+    pjsua_var.snd_pool = NULL;
+}
+
 
 /*
@@ -1625,4 +1757,65 @@
     }
 
+#if PJMEDIA_CONF_USE_SWITCH_BOARD
+
+    /* Check if sound device need to be reopened, i.e: its attributes
+     * (format, clock rate, channel count) must match to peer's. 
+     * Note that sound device can be reopened only if it doesn't have
+     * any connection.
+     */
+    do {
+	pjmedia_conf_port_info port0_info;
+	pjmedia_conf_port_info peer_info;
+	unsigned peer_id;
+	pj_bool_t need_reopen = PJ_FALSE;
+	pj_status_t status;
+
+	peer_id = (source!=0)? source : sink;
+	status = pjmedia_conf_get_port_info(pjsua_var.mconf, peer_id, 
+					    &peer_info);
+	pj_assert(status == PJ_SUCCESS);
+
+	status = pjmedia_conf_get_port_info(pjsua_var.mconf, 0, &port0_info);
+	pj_assert(status == PJ_SUCCESS);
+
+	/* Check if sound device is instantiated. */
+	need_reopen = (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && 
+		      !pjsua_var.no_snd);
+
+	/* Check if sound device need to reopen because it needs to modify 
+	 * settings to match its peer. Sound device must be idle in this case 
+	 * though.
+	 */
+	if (!need_reopen && 
+	    port0_info.listener_cnt==0 && port0_info.transmitter_cnt==0) 
+	{
+	    need_reopen = (peer_info.format.id != port0_info.format.id ||
+			   peer_info.format.bitrate != port0_info.format.bitrate ||
+			   peer_info.clock_rate != port0_info.clock_rate ||
+			   peer_info.channel_count != port0_info.channel_count);
+	}
+
+	if (need_reopen) {
+	    pjmedia_snd_setting setting;
+
+	    pj_bzero(&setting, sizeof(setting));
+	    setting.format = peer_info.format;
+	    setting.plc = PJ_FALSE;
+	    setting.route = PJMEDIA_SND_ROUTE_DEFAULT;
+	    
+	    status = open_snd_dev_ext(pjsua_var.cap_dev, pjsua_var.play_dev,
+				      peer_info.clock_rate,
+				      peer_info.channel_count,
+				      peer_info.samples_per_frame,
+				      &setting);
+	    if (status != PJ_SUCCESS) {
+		pjsua_perror(THIS_FILE, "Error opening sound device", status);
+		return status;
+	    }
+	}
+    } while(0);
+
+#else
+
     /* Create sound port if none is instantiated */
     if (pjsua_var.snd_port==NULL && pjsua_var.null_snd==NULL && 
@@ -1637,4 +1830,6 @@
 	}
     }
+
+#endif
 
     return pjmedia_conf_connect_port(pjsua_var.mconf, source, sink, 0);
@@ -2132,37 +2327,4 @@
     return PJ_SUCCESS;
 }
-
-
-/* Close existing sound device */
-static void close_snd_dev(void)
-{
-    /* Close sound device */
-    if (pjsua_var.snd_port) {
-	const pjmedia_snd_dev_info *cap_info, *play_info;
-
-	cap_info = pjmedia_snd_get_dev_info(pjsua_var.cap_dev);
-	play_info = pjmedia_snd_get_dev_info(pjsua_var.play_dev);
-
-	PJ_LOG(4,(THIS_FILE, "Closing %s sound playback device and "
-			     "%s sound capture device",
-			     play_info->name, cap_info->name));
-
-	pjmedia_snd_port_disconnect(pjsua_var.snd_port);
-	pjmedia_snd_port_destroy(pjsua_var.snd_port);
-	pjsua_var.snd_port = NULL;
-    }
-
-    /* Close null sound device */
-    if (pjsua_var.null_snd) {
-	PJ_LOG(4,(THIS_FILE, "Closing null sound device.."));
-	pjmedia_master_port_destroy(pjsua_var.null_snd, PJ_FALSE);
-	pjsua_var.null_snd = NULL;
-    }
-
-    if (pjsua_var.snd_pool) 
-	pj_pool_release(pjsua_var.snd_pool);
-    pjsua_var.snd_pool = NULL;
-}
-
 /*
  * Select or change sound device. Application may call this function at
@@ -2419,4 +2581,15 @@
 
 
+/*
+ * Set sound device route.
+ */
+PJ_DEF(pj_status_t) pjsua_set_snd_route(pjmedia_snd_route route)
+{
+    PJ_UNUSED_ARG(route);
+
+    PJ_TODO(IMPLEMENT_SETTING_AUDIO_ROUTE);
+    return PJ_ENOTSUP;
+}
+
 /*****************************************************************************
  * Codecs.
