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 2434)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound_aps.cpp	(revision 2438)
@@ -18,8 +18,9 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
+#include <pjmedia/sound.h>
 #include <pjmedia/symbian_sound_aps.h>
-#include <pjmedia/sound.h>
 #include <pjmedia/alaw_ulaw.h>
 #include <pjmedia/errno.h>
+#include <pjmedia/port.h>
 #include <pj/assert.h>
 #include <pj/log.h>
@@ -59,7 +60,4 @@
 /* App UID to open global APS queues to communicate with the APS server. */
 extern TPtrC		    APP_UID;
-
-/* Default setting */
-static pjmedia_snd_aps_setting def_setting;
 
 /* APS G.711 frame length */
@@ -88,4 +86,5 @@
     pjmedia_snd_play_cb	 play_cb;
     void                *user_data;
+    pjmedia_snd_setting  setting;
 
     // Audio engine
@@ -405,11 +404,11 @@
     // the client session.
     TTime start, now;
-    enum { APS_CLOSE_WAIT_TIME = 200 };
+    enum { APS_CLOSE_WAIT_TIME = 200 }; /* in msecs */
+    
     start.UniversalTime();
-    now.UniversalTime();
-    while (now.MicroSecondsFrom(start) < APS_CLOSE_WAIT_TIME * 1000) {
+    do {
 	pj_symbianos_poll(-1, APS_CLOSE_WAIT_TIME);
 	now.UniversalTime();
-    }
+    } while (now.MicroSecondsFrom(start) < APS_CLOSE_WAIT_TIME * 1000);
 
     iSession.Close();
@@ -618,4 +617,5 @@
     pjmedia_snd_stream *strm = (pjmedia_snd_stream*) user_data;
 
+    /* Buffer has to contain normal speech. */
     pj_assert(buf.iBuffer[0] == 1 && buf.iBuffer[1] == 0);
 
@@ -660,4 +660,5 @@
     unsigned g711_frame_len = aps_g711_frame_len;
 
+    /* Init buffer attributes and header. */
     buf.iCommand = CQueueHandler::EAPSPlayData;
     buf.iStatus = 0;
@@ -697,8 +698,115 @@
 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);
+	    
+	    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;
+    }
 }
 
 static void PlayCb(TAPSCommBuffer &buf, void *user_data)
 {
+    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. */
+    buf.iCommand = CQueueHandler::EAPSPlayData;
+    buf.iStatus = 0;
+    buf.iBuffer.Zero();
+
+    switch(strm->setting.format.u32) {
+    
+    case PJMEDIA_FOURCC_G711U:
+    case PJMEDIA_FOURCC_G711A:
+	/* Add header. */
+	buf.iBuffer.Append(1);
+	buf.iBuffer.Append(0);
+
+	/* Assume frame size is 10ms if frame size hasn't been known. */
+	if (g711_frame_len == 0)
+	    g711_frame_len = 80;
+	
+	/* Call parent stream callback to get samples to play. */
+	while (samples_ready < g711_frame_len) {
+	    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);
+		
+		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)
+		    buf.iBuffer.Append((TUint8*)sf->data, sf->bitlen>>3);
+		else 
+		    buf.iBuffer.AppendFill(0, samples_cnt);
+		samples_ready += samples_cnt;
+		
+		pjmedia_frame_ext_pop_subframes(frame, 1);
+	    
+	    } else { /* PJMEDIA_FRAME_TYPE_NONE */
+		buf.iBuffer.AppendFill(0, g711_frame_len - samples_ready);
+		samples_ready = g711_frame_len;
+		frame->samples_cnt = 0;
+		frame->subframe_cnt = 0;
+	    }
+	}
+	break;
+	
+    default:
+	break;
+    }
+    
+    unsigned tes = buf.iBuffer.Length();
 }
 
@@ -709,12 +817,4 @@
 {
     snd_pool_factory = factory;
-
-    def_setting.format.u32 = PJMEDIA_FOURCC_L16;
-    def_setting.mode = 0;
-    def_setting.bitrate = 128000;
-    def_setting.plc = PJ_FALSE;
-    def_setting.vad = PJ_FALSE;
-    def_setting.cng = PJ_FALSE;
-    def_setting.loudspk = PJ_FALSE;
 
     return PJ_SUCCESS;
@@ -751,9 +851,10 @@
 			      pjmedia_snd_play_cb play_cb,
 			      void *user_data,
+			      const pjmedia_snd_setting *setting,
 			      pjmedia_snd_stream **p_snd_strm)
 {
     pj_pool_t *pool;
     pjmedia_snd_stream *strm;
-    CPjAudioSetting setting;
+    CPjAudioSetting aps_setting;
     PjAudioCallback aps_rec_cb;
     PjAudioCallback aps_play_cb;
@@ -779,43 +880,43 @@
     strm->channel_count = channel_count;
     strm->samples_per_frame = samples_per_frame;
+    strm->setting = *setting;
+
+    if (strm->setting.format.u32 == 0)
+	strm->setting.format.u32 = PJMEDIA_FOURCC_L16;
 
     /* Set audio engine settings. */
-    if (def_setting.format.u32 == PJMEDIA_FOURCC_G711U ||
-	def_setting.format.u32 == PJMEDIA_FOURCC_L16)
+    if (strm->setting.format.u32 == PJMEDIA_FOURCC_G711U ||
+	strm->setting.format.u32 == PJMEDIA_FOURCC_L16)
     {
-	setting.fourcc = TFourCC(KMCPFourCCIdG711);
+	aps_setting.fourcc = TFourCC(KMCPFourCCIdG711);
     } else {
-	setting.fourcc = TFourCC(def_setting.format.u32);
-    }
-
-    if (def_setting.format.u32 == PJMEDIA_FOURCC_AMR)
+	aps_setting.fourcc = TFourCC(strm->setting.format.u32);
+    }
+
+    if (strm->setting.format.u32 == PJMEDIA_FOURCC_AMR)
     {
-	setting.mode = (TAPSCodecMode)def_setting.bitrate;
-    } else if (def_setting.format.u32 == PJMEDIA_FOURCC_G711U ||
-	       def_setting.format.u32 == PJMEDIA_FOURCC_L16   ||
-	      (def_setting.format.u32 == PJMEDIA_FOURCC_ILBC  &&
-	       def_setting.mode == 30))
+	aps_setting.mode = (TAPSCodecMode)strm->setting.bitrate;
+    } else if (strm->setting.format.u32 == PJMEDIA_FOURCC_G711U ||
+	       strm->setting.format.u32 == PJMEDIA_FOURCC_L16   ||
+	      (strm->setting.format.u32 == PJMEDIA_FOURCC_ILBC  &&
+	       strm->setting.mode == 30))
     {
-	setting.mode = EULawOr30ms;
+	aps_setting.mode = EULawOr30ms;
     } else {
-	setting.mode = EALawOr20ms;
-    }
-
-    setting.vad = def_setting.vad;
-    setting.plc = def_setting.plc;
-    setting.cng = def_setting.cng;
-    setting.loudspk = def_setting.loudspk;
-
-    if (def_setting.format.u32 == PJMEDIA_FOURCC_AMR ||
-	def_setting.format.u32 == PJMEDIA_FOURCC_G711A ||
-	def_setting.format.u32 == PJMEDIA_FOURCC_G711U ||
-	def_setting.format.u32 == PJMEDIA_FOURCC_G729 ||
-	def_setting.format.u32 == PJMEDIA_FOURCC_ILBC)
-    {
+	aps_setting.mode = EALawOr20ms;
+    }
+
+    aps_setting.vad = strm->setting.format.u32==PJMEDIA_FOURCC_L16? 
+					EFalse : strm->setting.vad;
+    aps_setting.plc = strm->setting.plc;
+    aps_setting.cng = strm->setting.cng;
+    aps_setting.loudspk = strm->setting.loudspk;
+
+    if (strm->setting.format.u32 == PJMEDIA_FOURCC_L16) {
+	aps_play_cb = &PlayCbPcm;
+	aps_rec_cb  = &RecCbPcm;
+    } else {
 	aps_play_cb = &PlayCb;
 	aps_rec_cb  = &RecCb;
-    } else {
-	aps_play_cb = &PlayCbPcm;
-	aps_rec_cb  = &RecCbPcm;
     }
 
@@ -823,5 +924,5 @@
     TRAPD(err, strm->engine = CPjAudioEngine::NewL(strm,
 						   aps_rec_cb, aps_play_cb,
-						   strm, setting));
+						   strm, aps_setting));
     if (err != KErrNone) {
     	pj_pool_release(pool);
@@ -834,10 +935,10 @@
 
     /* play_buf size is samples per frame. */
-    strm->play_buf = (pj_int16_t*)pj_pool_alloc(pool, samples_per_frame << 1);
+    strm->play_buf = (pj_int16_t*)pj_pool_zalloc(pool, samples_per_frame << 1);
     strm->play_buf_len = 0;
     strm->play_buf_start = 0;
 
     /* rec_buf size is samples per frame. */
-    strm->rec_buf  = (pj_int16_t*)pj_pool_alloc(pool, samples_per_frame << 1);
+    strm->rec_buf  = (pj_int16_t*)pj_pool_zalloc(pool, samples_per_frame << 1);
     strm->rec_buf_len = 0;
 
@@ -861,10 +962,16 @@
 					  pjmedia_snd_stream **p_snd_strm)
 {
+    pjmedia_snd_setting setting;
+    
     if (index < 0) index = 0;
     PJ_ASSERT_RETURN(index == 0, PJ_EINVAL);
 
+    pj_bzero(&setting, sizeof(setting));
+    setting.format.u32 = PJMEDIA_FOURCC_L16;
+    setting.bitrate = 128000;
+    
     return sound_open(PJMEDIA_DIR_CAPTURE, clock_rate, channel_count,
 		      samples_per_frame, bits_per_sample, rec_cb, NULL,
-		      user_data, p_snd_strm);
+		      user_data, &setting, p_snd_strm);
 }
 
@@ -878,10 +985,16 @@
 					pjmedia_snd_stream **p_snd_strm )
 {
+    pjmedia_snd_setting setting;
+    
     if (index < 0) index = 0;
     PJ_ASSERT_RETURN(index == 0, PJ_EINVAL);
 
+    pj_bzero(&setting, sizeof(setting));
+    setting.format.u32 = PJMEDIA_FOURCC_L16;
+    setting.bitrate = 128000;
+
     return sound_open(PJMEDIA_DIR_PLAYBACK, clock_rate, channel_count,
 		      samples_per_frame, bits_per_sample, NULL, play_cb,
-		      user_data, p_snd_strm);
+		      user_data, &setting, p_snd_strm);
 }
 
@@ -897,11 +1010,39 @@
 				      pjmedia_snd_stream **p_snd_strm)
 {
+    pjmedia_snd_setting setting;
+
     if (rec_id < 0) rec_id = 0;
     if (play_id < 0) play_id = 0;
     PJ_ASSERT_RETURN(play_id == 0 && rec_id == 0, PJ_EINVAL);
 
+    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,
 		      samples_per_frame, bits_per_sample, rec_cb, play_cb,
-		      user_data, p_snd_strm);
+		      user_data, &setting, p_snd_strm);
+}
+
+PJ_DEF(pj_status_t) pjmedia_snd_open2( pjmedia_dir dir,
+				       int rec_id,
+				       int play_id,
+				       unsigned clock_rate,
+				       unsigned channel_count,
+				       unsigned samples_per_frame,
+				       unsigned bits_per_sample,
+				       pjmedia_snd_rec_cb rec_cb,
+				       pjmedia_snd_play_cb play_cb,
+				       void *user_data,
+				       const pjmedia_snd_setting *setting,
+				       pjmedia_snd_stream **p_snd_strm)
+{
+    if (rec_id < 0) rec_id = 0;
+    if (play_id < 0) play_id = 0;
+    PJ_ASSERT_RETURN(play_id == 0 && rec_id == 0, PJ_EINVAL);
+
+    return sound_open(dir, clock_rate, channel_count,
+		      samples_per_frame, bits_per_sample, rec_cb, play_cb,
+		      user_data, setting, p_snd_strm);
 }
 
@@ -994,5 +1135,4 @@
 }
 
-
 /*
  * Activate/deactivate loudspeaker.
@@ -1002,30 +1142,12 @@
 					pj_bool_t active)
 {
-    if (stream == NULL) {
-	def_setting.loudspk = active;
-    } else {
-	if (stream->engine == NULL)
-	    return PJ_EINVAL;
-
-	TInt err = stream->engine->ActivateSpeaker(active);
-	if (err != KErrNone)
-	    return PJ_RETURN_OS_ERROR(err);
-    }
+    PJ_ASSERT_RETURN(stream && stream->engine, PJ_EINVAL);
+    
+    TInt err = stream->engine->ActivateSpeaker(active);
+    if (err != KErrNone)
+	return PJ_RETURN_OS_ERROR(err);
 
     return PJ_SUCCESS;
 }
 
-/**
- * Set a codec and its settings to be used on the next sound device session.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_aps_modify_setting(
-				    const pjmedia_snd_aps_setting *setting)
-{
-    PJ_ASSERT_RETURN(setting, PJ_EINVAL);
-
-    def_setting = *setting;
-
-    return PJ_SUCCESS;
-}
-
 #endif // PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_SYMB_APS_SOUND
