Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c	(revision 2438)
+++ 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
