Index: /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia.dsp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia.dsp	(revision 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia.dsp	(revision 2452)
@@ -110,4 +110,8 @@
 # Begin Source File
 
+SOURCE=..\src\pjmedia\conf_switch.c
+# End Source File
+# Begin Source File
+
 SOURCE=..\src\pjmedia\conference.c
 # End Source File
Index: /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_codec.dsp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_codec.dsp	(revision 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_codec.dsp	(revision 2452)
@@ -148,4 +148,8 @@
 # Begin Source File
 
+SOURCE="..\src\pjmedia-codec\passthrough.c"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjmedia-codec\speex_codec.c"
 
@@ -190,4 +194,8 @@
 
 SOURCE="..\include\pjmedia-codec\l16.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\include\pjmedia-codec\passthrough.h"
 # End Source File
 # Begin Source File
Index: /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_codec.vcproj
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_codec.vcproj	(revision 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_codec.vcproj	(revision 2452)
@@ -399,4 +399,8 @@
 			</File>
 			<File
+				RelativePath="..\src\pjmedia-codec\passthrough.c"
+				>
+			</File>
+			<File
 				RelativePath="..\src\pjmedia-codec\speex_codec.c"
 				>
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 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-codec/amr_helper.h	(revision 2452)
@@ -689,14 +689,14 @@
 						 unsigned frame_len)
 {
-    unsigned i;
+    int i;
 
     if (amrnb) {
 	for (i = 0; i < 9; ++i)
 	    if (frame_len == pjmedia_codec_amrnb_framelen[i])
-		return i;
+		return (pj_int8_t)i;
     } else {
 	for (i = 0; i < 10; ++i) {
 	    if (frame_len == pjmedia_codec_amrwb_framelen[i])
-		return i;
+		return (pj_int8_t)i;
 	}
     }
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/alaw_ulaw.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/alaw_ulaw.h	(revision 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/alaw_ulaw.h	(revision 2452)
@@ -145,10 +145,10 @@
  * @param dst	    Destination buffer for 8-bit U-Law data.
  * @param src	    Source, 16-bit linear PCM data.
- * @param len	    Number of samples.
+ * @param count	    Number of samples.
  */
 PJ_INLINE(void) pjmedia_ulaw_encode(pj_uint8_t *dst, const pj_int16_t *src, 
-				    pj_size_t len)
-{
-    const pj_int16_t *end = src + len;
+				    pj_size_t count)
+{
+    const pj_int16_t *end = src + count;
     
     while (src < end) {
@@ -162,10 +162,10 @@
  * @param dst	    Destination buffer for 8-bit A-Law data.
  * @param src	    Source, 16-bit linear PCM data.
- * @param len	    Number of samples.
+ * @param count	    Number of samples.
  */
 PJ_INLINE(void) pjmedia_alaw_encode(pj_uint8_t *dst, const pj_int16_t *src, 
-				    pj_size_t len)
-{
-    const pj_int16_t *end = src + len;
+				    pj_size_t count)
+{
+    const pj_int16_t *end = src + count;
     
     while (src < end) {
@@ -179,5 +179,5 @@
  * @param dst	    Destination buffer for 16-bit PCM data.
  * @param src	    Source, 8-bit U-Law data.
- * @param len	    Number of samples.
+ * @param len	    Encoded frame/source length in bytes.
  */
 PJ_INLINE(void) pjmedia_ulaw_decode(pj_int16_t *dst, const pj_uint8_t *src, 
@@ -196,5 +196,5 @@
  * @param dst	    Destination buffer for 16-bit PCM data.
  * @param src	    Source, 8-bit A-Law data.
- * @param len	    Number of samples.
+ * @param len	    Encoded frame/source length in bytes.
  */
 PJ_INLINE(void) pjmedia_alaw_decode(pj_int16_t *dst, const pj_uint8_t *src, 
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/config.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/config.h	(revision 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/config.h	(revision 2452)
@@ -108,4 +108,15 @@
 #endif
 
+/**
+ * Specify if the sound device implementation supports handling encoded
+ * frames. Setting this to zero will activate some emulation in the
+ * sound port.
+ */
+#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_SYMB_APS_SOUND || \
+    PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_SYMB_VAS_SOUND
+#   define PJMEDIA_SND_SUPPORT_OPEN2	1
+#else
+#   define PJMEDIA_SND_SUPPORT_OPEN2	0
+#endif
 
 /**
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2452)
@@ -320,5 +320,5 @@
 
     frm->subframe_cnt++;
-    frm->samples_cnt = frm->samples_cnt + (pj_uint16_t)samples_cnt;
+    frm->samples_cnt = (pj_uint16_t)(frm->samples_cnt + samples_cnt);
 }
 
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-codec/passthrough.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-codec/passthrough.c	(revision 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-codec/passthrough.c	(revision 2452)
@@ -642,5 +642,5 @@
 	    return PJMEDIA_CODEC_EINMODE;
 
-	s->enc_setting.amr_nb = desc->pt == PJMEDIA_RTP_PT_AMR;
+	s->enc_setting.amr_nb = (pj_uint8_t)(desc->pt == PJMEDIA_RTP_PT_AMR);
 	s->enc_setting.octet_aligned = octet_align;
 	s->enc_setting.reorder = PJ_FALSE; /* Note this! passthrough codec
@@ -649,5 +649,5 @@
 	s->enc_setting.cmr = 15;
 	
-	s->dec_setting.amr_nb = desc->pt == PJMEDIA_RTP_PT_AMR;
+	s->dec_setting.amr_nb = (pj_uint8_t)(desc->pt == PJMEDIA_RTP_PT_AMR);
 	s->dec_setting.octet_aligned = octet_align;
 	s->dec_setting.reorder = PJ_FALSE; /* Note this! passthrough codec
@@ -770,5 +770,4 @@
 		output->size += sf_len;
 
-#if PJMEDIA_HAS_INTEL_IPP_CODEC_G729
 		/* If there is SID or DTX frame, break the loop. */
 		if (desc->pt == PJMEDIA_RTP_PT_G729 && 
@@ -777,5 +776,4 @@
 		    break;
 		}
-#endif
 		
 	    }
@@ -799,4 +797,5 @@
 
     pj_assert(input);
+    PJ_UNUSED_ARG(output_buf_len);
 
 #if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2452)
@@ -1031,5 +1031,5 @@
 	     * samples per frame.
 	     */
-	    if (f_dst->samples_cnt == cport_dst->info->samples_per_frame)
+	    if (f_dst->samples_cnt >= cport_dst->info->samples_per_frame)
 	    {
 		if (cport_dst->slot) {
@@ -1360,5 +1360,5 @@
 	    pjmedia_frame_ext *f_dst = (pjmedia_frame_ext*)frame;
 	    pjmedia_frame_ext_subframe *sf;
-	    pj_uint16_t samples_per_subframe;
+	    unsigned samples_per_subframe;
 	    
 	    if (f_src_->samples_cnt < this_cport->info->samples_per_frame) {
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c	(revision 2451)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c	(revision 2452)
@@ -19,4 +19,5 @@
  */
 #include <pjmedia/sound_port.h>
+#include <pjmedia/alaw_ulaw.h>
 #include <pjmedia/delaybuf.h>
 #include <pjmedia/echo.h>
@@ -36,5 +37,4 @@
 //#define TEST_OVERFLOW_UNDERFLOW
 
-
 struct pjmedia_snd_port
 {
@@ -63,4 +63,11 @@
     pjmedia_delay_buf	*delay_buf;
 #endif
+
+    /* Encoded sound emulation */
+#if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || !PJMEDIA_SND_SUPPORT_OPEN2
+    unsigned		 frm_buf_size;
+    pj_uint8_t		*put_frm_buf;
+    pj_uint8_t		*get_frm_buf;
+#endif
 };
 
@@ -79,10 +86,4 @@
     pj_status_t status;
 
-    /* We're risking accessing the port without holding any mutex.
-     * It's possible that port is disconnected then destroyed while
-     * we're trying to access it.
-     * But in the name of performance, we'll try this approach until
-     * someone complains when it crashes.
-     */
     port = snd_port->port;
     if (port == NULL)
@@ -198,10 +199,4 @@
     pjmedia_frame frame;
 
-    /* We're risking accessing the port without holding any mutex.
-     * It's possible that port is disconnected then destroyed while
-     * we're trying to access it.
-     * But in the name of performance, we'll try this approach until
-     * someone complains when it crashes.
-     */
     port = snd_port->port;
     if (port == NULL)
@@ -245,4 +240,8 @@
 			       /* out */  unsigned size)
 {
+#if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0
+    /* This is the version to use when the sound device supports
+     * open2().
+     */
     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
     pjmedia_port *port;
@@ -253,10 +252,4 @@
     PJ_UNUSED_ARG(timestamp);
 
-    /* We're risking accessing the port without holding any mutex.
-     * It's possible that port is disconnected then destroyed while
-     * we're trying to access it.
-     * But in the name of performance, we'll try this approach until
-     * someone complains when it crashes.
-     */
     port = snd_port->port;
     if (port == NULL) {
@@ -268,4 +261,87 @@
 
     return status;
+#else
+    /* This is the emulation version */
+    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
+    pjmedia_port *port = snd_port->port;
+    pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->get_frm_buf;
+    pj_status_t status;
+
+    if (port==NULL) {
+	goto no_frame;
+    }
+
+    pj_bzero(fx, sizeof(*fx));
+    fx->base.type = PJMEDIA_FRAME_TYPE_NONE;
+    fx->base.buf = ((pj_uint8_t*)fx) + sizeof(*fx);
+    fx->base.size = snd_port->frm_buf_size - sizeof(*fx);
+    fx->base.timestamp.u32.hi = 0;
+    fx->base.timestamp.u32.lo = timestamp;
+
+    status = pjmedia_port_get_frame(port, &fx->base);
+    if (status != PJ_SUCCESS)
+	goto no_frame;
+
+    if (fx->base.type == PJMEDIA_FRAME_TYPE_AUDIO) {
+	pj_assert(fx->base.size == size);
+	pj_memcpy(output, fx->base.buf, size);
+    } else if (fx->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
+	void (*decoder)(pj_int16_t*, const pj_uint8_t*, pj_size_t) = NULL;
+	unsigned i, size_decoded;
+
+	switch (snd_port->setting.format.u32) {
+	case PJMEDIA_FOURCC_PCMA:
+	    decoder = &pjmedia_alaw_decode;
+	    break;
+	case PJMEDIA_FOURCC_PCMU:
+	    decoder = &pjmedia_ulaw_decode;
+	    break;
+	default:
+	    PJ_LOG(1,(THIS_FILE, "Unsupported format %d", 
+		      snd_port->setting.format.u32));
+	    goto no_frame;
+	}
+
+	if (fx->samples_cnt > size>>1) {
+	    PJ_LOG(4,(THIS_FILE, "Frame too large by %d samples", 
+		      fx->samples_cnt - (size>>1)));
+	} else if (fx->samples_cnt < size>>1) {
+	    PJ_LOG(4,(THIS_FILE, "Not enough frame by %d samples", 
+		      (size>>1) - fx->samples_cnt));
+	}
+
+	for (i=0, size_decoded=0; 
+	     i<fx->subframe_cnt && size_decoded<size; 
+	     ++i) 
+	{
+	    pjmedia_frame_ext_subframe *subfrm;
+
+	    subfrm = pjmedia_frame_ext_get_subframe(fx, i);	    
+
+	    if ((subfrm->bitlen>>3) > (int)(size-size_decoded)) {
+		subfrm->bitlen = (pj_uint16_t)((size-size_decoded) << 3);
+	    }
+
+	    (*decoder)((short*)((pj_uint8_t*)output + size_decoded),
+		       subfrm->data, subfrm->bitlen>>3);
+
+	    size_decoded += (subfrm->bitlen>>3) << 1;
+	}
+
+	if (size_decoded < size) {
+	    pj_bzero((pj_uint8_t*)output + size_decoded, size-size_decoded);
+	}
+
+    } else {
+	goto no_frame;
+    }
+
+    return PJ_SUCCESS;
+
+no_frame:
+    pj_bzero(output, size);
+    return PJ_SUCCESS;
+
+#endif	/* PJMEDIA_SND_SUPPORT_OPEN2 */
 }
 
@@ -280,4 +356,8 @@
 			      /* in*/    unsigned size)
 {
+#if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0
+    /* This is the version to use when the sound device supports
+     * open2().
+     */
     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
     pjmedia_port *port;
@@ -287,10 +367,4 @@
     PJ_UNUSED_ARG(timestamp);
 
-    /* We're risking accessing the port without holding any mutex.
-     * It's possible that port is disconnected then destroyed while
-     * we're trying to access it.
-     * But in the name of performance, we'll try this approach until
-     * someone complains when it crashes.
-     */
     port = snd_port->port;
     if (port == NULL)
@@ -300,4 +374,40 @@
 
     return PJ_SUCCESS;
+#else
+    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
+    pjmedia_port *port = snd_port->port;
+    pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->put_frm_buf;
+    void (*encoder)(pj_uint8_t*, const pj_int16_t*, pj_size_t) = NULL;
+
+    if (port==NULL)
+	return PJ_SUCCESS;
+
+    pj_bzero(fx, sizeof(*fx));
+    fx->base.buf = NULL;
+    fx->base.size = snd_port->frm_buf_size - sizeof(*fx);
+    fx->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
+    fx->base.timestamp.u32.lo = timestamp;
+
+    switch (snd_port->setting.format.u32) {
+    case PJMEDIA_FOURCC_PCMA:
+	encoder = &pjmedia_alaw_encode;
+	break;
+    case PJMEDIA_FOURCC_PCMU:
+	encoder = &pjmedia_ulaw_encode;
+	break;
+    default:
+	PJ_LOG(1,(THIS_FILE, "Unsupported format %d", 
+		  snd_port->setting.format.u32));
+	return PJ_SUCCESS;
+    }
+
+    (*encoder)((pj_uint8_t*)input, (pj_int16_t*)input, size >> 1);
+
+    pjmedia_frame_ext_append_subframe(fx, input, (size >> 1) << 3, 
+				      size >> 1);
+    pjmedia_port_put_frame(port, &fx->base);
+
+    return PJ_SUCCESS;
+#endif
 }
 
@@ -332,4 +442,5 @@
     }
 
+#if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0
     status = pjmedia_snd_open2( snd_port->dir,
 				snd_port->rec_id, 
@@ -344,4 +455,16 @@
 				&snd_port->setting,
 				&snd_port->snd_stream);
+#else
+    status = pjmedia_snd_open(  snd_port->rec_id, 
+				snd_port->play_id,
+				snd_port->clock_rate,
+				snd_port->channel_count,
+				snd_port->samples_per_frame,
+				snd_port->bits_per_sample,
+				snd_rec_cb,
+				snd_play_cb,
+				snd_port,
+				&snd_port->snd_stream);
+#endif
 
     if (status != PJ_SUCCESS)
@@ -572,5 +695,5 @@
     snd_port->samples_per_frame = samples_per_frame;
     snd_port->bits_per_sample = bits_per_sample;
-    snd_port->setting = *setting;
+    pj_memcpy(&snd_port->setting, setting, sizeof(*setting));
     
 #if PJMEDIA_SOUND_USE_DELAYBUF
@@ -589,4 +712,19 @@
 					  0, &snd_port->delay_buf);
 	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+    }
+#endif
+
+#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.u32 != 0 &&
+	snd_port->setting.format.u32 != PJMEDIA_FOURCC_L16) 
+    {
+	snd_port->frm_buf_size = sizeof(pjmedia_frame_ext) + 
+				 (samples_per_frame >> 1) +
+				 16 * sizeof(pjmedia_frame_ext_subframe);
+	snd_port->put_frm_buf = (pj_uint8_t*)
+				pj_pool_alloc(pool, snd_port->frm_buf_size);
+	snd_port->get_frm_buf = (pj_uint8_t*)
+				pj_pool_alloc(pool, snd_port->frm_buf_size);
     }
 #endif
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 2451)
+++ /pjproject/branches/projects/aps-direct/pjsip-apps/src/pjsua/pjsua_app.c	(revision 2452)
@@ -2402,4 +2402,107 @@
 }
 
+#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_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];
+
+    /* 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;
+
+    /* 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 = 8000;
+    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,
+				      8000,
+				      1,
+				      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.
@@ -4047,4 +4150,8 @@
     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;
