Index: /pjproject/branches/projects/aps-direct/pjlib/include/pj/config_site_sample.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjlib/include/pj/config_site_sample.h	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjlib/include/pj/config_site_sample.h	(revision 2489)
@@ -1,11 +1,21 @@
-
-
-//#define PJ_CONFIG_MINIMAL_SIZE
-//#define PJ_CONFIG_MAXIMUM_SPEED
-
-
-/*
- * This file (config_site_sample.h) contains various configuration
- * settings that I use for certain settings. 
+/*
+ * This file contains several sample settings especially for Windows
+ * Mobile and Symbian targets. You can include this file in your
+ * <pj/config_site.h> file.
+ *
+ * The Windows Mobile and Symbian settings will be activated
+ * automatically if you include this file.
+ *
+ * In addition, you may specify one of these macros (before including
+ * this file) to activate additional settings:
+ *
+ * #define PJ_CONFIG_NOKIA_APS_DIRECT
+ *   Use this macro to activate the APS-Direct feature. Please see
+ *   http://trac.pjsip.org/repos/wiki/Nokia_APS_VAS_Direct for more 
+ *   info.
+ *
+ * #define PJ_CONFIG_WIN32_WMME_DIRECT
+ *   Configuration to activate "APS-Direct" media mode on Windows or
+ *   Windows Mobile, useful for testing purposes only.
  */
 
@@ -15,24 +25,61 @@
  */
 #if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
-#   define PJ_HAS_FLOATING_POINT	0
-
-#   define PJMEDIA_HAS_G711_PLC		0
-//#   define PJMEDIA_HAS_SMALL_FILTER	1
-//#   define PJMEDIA_HAS_LARGE_FILTER	0
-#   define PJMEDIA_HAS_L16_CODEC	0
-/*#   define PJMEDIA_HAS_GSM_CODEC	0*/
-/*#   define PJMEDIA_HAS_ILBC_CODEC	0*/
-/*#   define PJMEDIA_HAS_SPEEX_CODEC	0*/
-#   define PJMEDIA_HAS_SPEEX_AEC	0
-#   undef PJMEDIA_RESAMPLE_IMP
-#   define PJMEDIA_RESAMPLE_IMP		PJMEDIA_RESAMPLE_LIBRESAMPLE
-#   define PJMEDIA_WSOLA_IMP		PJMEDIA_WSOLA_IMP_WSOLA_LITE
-
-    /* Speex default quality settings */
-#   define PJSUA_DEFAULT_CODEC_QUALITY	5
-#   define PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY	5
-
-#   define PJMEDIA_SDP_NEG_PREFER_REMOTE_CODEC_ORDER	0
-#endif
+
+    /*
+     * PJLIB settings.
+     */
+
+    /* Disable floating point support */
+    #define PJ_HAS_FLOATING_POINT		0
+
+    /*
+     * PJMEDIA settings
+     */
+
+    /* Select codecs to disable */
+    #define PJMEDIA_HAS_L16_CODEC		0
+    #define PJMEDIA_HAS_ILBC_CODEC		0
+
+    /* We probably need more buffers on WM, so increase the limit */
+    #define PJMEDIA_SOUND_BUFFER_COUNT		32
+
+    /* Fine tune Speex's default settings for best performance/quality */
+    #define PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY	5
+
+    /* For CPU reason, disable speex AEC and use the echo suppressor. */
+    #define PJMEDIA_HAS_SPEEX_AEC		0
+
+    /* Shouldn't use resampling for performance reason too. */
+    #define PJMEDIA_RESAMPLE_IMP		PJMEDIA_RESAMPLE_NONE
+
+    /* Use the lighter WSOLA implementation */
+    #define PJMEDIA_WSOLA_IMP			PJMEDIA_WSOLA_IMP_WSOLA_LITE
+
+    /*
+     * PJSIP settings.
+     */
+
+    /* Set maximum number of dialog/transaction/calls to minimum to reduce
+     * memory usage 
+     */
+    #define PJSIP_MAX_TSX_COUNT 		31
+    #define PJSIP_MAX_DIALOG_COUNT 		31
+    #define PJSUA_MAX_CALLS			4
+
+    /*
+     * PJSUA settings
+     */
+
+    /* Default codec (Speex) quality */
+    #define PJSUA_DEFAULT_CODEC_QUALITY		5
+
+    /* Set maximum number of objects to minimum to reduce memory usage */
+    #define PJSUA_MAX_ACC			4
+    #define PJSUA_MAX_PLAYERS			4
+    #define PJSUA_MAX_RECORDERS			4
+    #define PJSUA_MAX_CONF_PORTS		(PJSUA_MAX_CALLS+2*PJSUA_MAX_PLAYERS)
+    #define PJSUA_MAX_BUDDIES			32
+
+#endif	/* PJ_WIN32_WINCE */
 
 
@@ -42,35 +89,13 @@
 #if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
 
-    /* We don't want to use float, for now */
-#   undef PJ_HAS_FLOATING_POINT
-#   define PJ_HAS_FLOATING_POINT	0
-
-#   define PJMEDIA_SOUND_IMPLEMENTATION PJMEDIA_SOUND_NULL_SOUND
+    /*
+     * PJLIB settings.
+     */
+
+    /* Disable floating point support */
+    #define PJ_HAS_FLOATING_POINT		0
 
     /* Misc PJLIB setting */
-#   define PJ_MAXPATH			80
-
-	/* SRTP has not been ported to Symbian yet */
-#   define PJMEDIA_HAS_SRTP			1
-
-    /* Disable these */
-#   define PJMEDIA_RESAMPLE_IMP		PJMEDIA_RESAMPLE_NONE
-#   define PJMEDIA_HAS_SPEEX_AEC	0
-#   define PJMEDIA_WSOLA_IMP		PJMEDIA_WSOLA_IMP_WSOLA_LITE
-
-    /* Disable all codecs but G.711 and GSM, for now */
-#   define PJMEDIA_HAS_GSM_CODEC	1
-#   define PJMEDIA_HAS_L16_CODEC	0
-#   define PJMEDIA_HAS_ILBC_CODEC	0
-#   define PJMEDIA_HAS_SPEEX_CODEC	1
-#   define PJMEDIA_HAS_G722_CODEC	0
-
-    /* Need larger sound buffers */
-#   define PJMEDIA_SOUND_BUFFER_COUNT	16
-
-    /* Disable safe module access */
-#   define PJSIP_SAFE_MODULE		0
-
-#   define PJSIP_MAX_PKT_LEN		2000
+    #define PJ_MAXPATH				80
 
     /* This is important for Symbian. Symbian lacks vsnprintf(), so
@@ -79,42 +104,136 @@
      * to log the packet.
      */
-#   define PJ_LOG_MAX_SIZE		(PJSIP_MAX_PKT_LEN+500)
-
-    /* Since we don't have threads, log buffer can use static buffer */
-#   define PJ_LOG_USE_STACK_BUFFER	0
-
-	/* Disable check stack since it increases footprint */
-#   undef PJ_OS_HAS_CHECK_STACK
-#   define PJ_OS_HAS_CHECK_STACK	0
+    #define PJ_LOG_MAX_SIZE			(PJSIP_MAX_PKT_LEN+500)
+
+    /* Since we don't have threads, log buffer can use static buffer
+     * rather than stack
+     */
+    #define PJ_LOG_USE_STACK_BUFFER		0
+
+    /* Disable check stack since it increases footprint */
+    #define PJ_OS_HAS_CHECK_STACK		0
+
+
+    /*
+     * PJMEDIA settings
+     */
+
+    /* Select codecs to disable */
+    #define PJMEDIA_HAS_L16_CODEC		0
+    #define PJMEDIA_HAS_ILBC_CODEC		0
+
+    /* Fine tune Speex's default settings for best performance/quality */
+    #define PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY	5
+
+    /* For CPU reason, disable speex AEC and use the echo suppressor. */
+    #define PJMEDIA_HAS_SPEEX_AEC		0
+
+    /* Shouldn't use resampling for performance reason too. */
+    #define PJMEDIA_RESAMPLE_IMP		PJMEDIA_RESAMPLE_NONE
+
+    /* Use the lighter WSOLA implementation */
+    #define PJMEDIA_WSOLA_IMP			PJMEDIA_WSOLA_IMP_WSOLA_LITE
+
+    /* We probably need more buffers especially if MDA audio backend 
+     * is used, so increase the limit 
+     */
+    #define PJMEDIA_SOUND_BUFFER_COUNT		32
+
+    /*
+     * PJSIP settings.
+     */
+
+    /* Disable safe module access, since we don't use multithreading */
+    #define PJSIP_SAFE_MODULE			0
+
+    /* Increase allowable packet size, just in case */
+    #define PJSIP_MAX_PKT_LEN			2000
 
     /* Symbian has problem with too many large blocks */
-#   define PJSIP_POOL_LEN_ENDPT		1000
-#   define PJSIP_POOL_INC_ENDPT		1000
-#   define PJSIP_POOL_RDATA_LEN		2000
-#   define PJSIP_POOL_RDATA_INC		2000
-#   define PJSIP_POOL_LEN_TDATA		2000
-#   define PJSIP_POOL_INC_TDATA		512
-#   define PJSIP_POOL_LEN_UA		2000
-#   define PJSIP_POOL_INC_UA		1000
-#   define PJSIP_POOL_TSX_LAYER_LEN	256
-#   define PJSIP_POOL_TSX_LAYER_INC	256
-#   define PJSIP_POOL_TSX_LEN		512
-#   define PJSIP_POOL_TSX_INC		128
+    #define PJSIP_POOL_LEN_ENDPT		1000
+    #define PJSIP_POOL_INC_ENDPT		1000
+    #define PJSIP_POOL_RDATA_LEN		2000
+    #define PJSIP_POOL_RDATA_INC		2000
+    #define PJSIP_POOL_LEN_TDATA		2000
+    #define PJSIP_POOL_INC_TDATA		512
+    #define PJSIP_POOL_LEN_UA			2000
+    #define PJSIP_POOL_INC_UA			1000
+    #define PJSIP_POOL_TSX_LAYER_LEN		256
+    #define PJSIP_POOL_TSX_LAYER_INC		256
+    #define PJSIP_POOL_TSX_LEN			512
+    #define PJSIP_POOL_TSX_INC			128
+
+    /*
+     * PJSUA settings.
+     */
+
+    /* Default codec quality */
+    #define PJSUA_DEFAULT_CODEC_QUALITY		5
 
     /* Set maximum number of dialog/transaction/calls to minimum */
-#   define PJSIP_MAX_TSX_COUNT 		31
-#   define PJSIP_MAX_DIALOG_COUNT 	31
-#   define PJSUA_MAX_CALLS		4
+    #define PJSIP_MAX_TSX_COUNT 		31
+    #define PJSIP_MAX_DIALOG_COUNT 		31
+    #define PJSUA_MAX_CALLS			4
 
     /* Other pjsua settings */
-#   define PJSUA_MAX_ACC		4
-#   define PJSUA_MAX_PLAYERS		4
-#   define PJSUA_MAX_RECORDERS		4
-#   define PJSUA_MAX_CONF_PORTS		(PJSUA_MAX_CALLS+2*PJSUA_MAX_PLAYERS)
-#   define PJSUA_MAX_BUDDIES		32
-
-    /* Speex default quality settings */
-#   define PJSUA_DEFAULT_CODEC_QUALITY	5
-#   define PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY	5
+    #define PJSUA_MAX_ACC			4
+    #define PJSUA_MAX_PLAYERS			4
+    #define PJSUA_MAX_RECORDERS			4
+    #define PJSUA_MAX_CONF_PORTS		(PJSUA_MAX_CALLS+2*PJSUA_MAX_PLAYERS)
+    #define PJSUA_MAX_BUDDIES			32
+#endif
+
+
+/*
+ * Additional configuration to activate APS-Direct feature for
+ * Nokia S60 target
+ *
+ * Please see http://trac.pjsip.org/repos/wiki/Nokia_APS_VAS_Direct
+ */
+#ifdef PJ_CONFIG_NOKIA_APS_DIRECT
+
+    /* MUST use switchboard rather than the conference bridge */
+    #define PJMEDIA_CONF_USE_SWITCH_BOARD	1
+
+    /* Enable APS sound device backend and disable MDA */
+    #define PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA	0
+    #define PJMEDIA_AUDIO_DEV_HAS_SYMB_APS	1
+
+    /* Enable passthrough codec framework */
+    #define PJMEDIA_HAS_PASSTHROUGH_CODECS	1
+
+    /* And selectively enable which codecs are supported by the handset */
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMU	1
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMA	1
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR	1
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_G729	1
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC	1
+
+#endif
+
+
+/*
+ * Configuration to activate "APS-Direct" media mode on Windows,
+ * useful for testing purposes only.
+ */
+#ifdef PJ_CONFIG_WIN32_WMME_DIRECT
+
+    /* MUST use switchboard rather than the conference bridge */
+    #define PJMEDIA_CONF_USE_SWITCH_BOARD	1
+
+    /* Only WMME supports the "direct" feature */
+    #define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO	0
+    #define PJMEDIA_AUDIO_DEV_HAS_WMME		1
+
+    /* Enable passthrough codec framework */
+    #define PJMEDIA_HAS_PASSTHROUGH_CODECS	1
+
+    /* Only PCMA and PCMU are supported by WMME-direct */
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMU	1
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_PCMA	1
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR	0
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_G729	0
+    #define PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC	0
+
 #endif
 
Index: /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia.dsp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia.dsp	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia.dsp	(revision 2489)
@@ -230,4 +230,8 @@
 # Begin Source File
 
+SOURCE=..\src\pjmedia\sound_legacy.c
+# End Source File
+# Begin Source File
+
 SOURCE=..\src\pjmedia\sound_port.c
 # End Source File
Index: /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_audiodev.dsp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_audiodev.dsp	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_audiodev.dsp	(revision 2489)
@@ -102,4 +102,8 @@
 # Begin Source File
 
+SOURCE="..\src\pjmedia-audiodev\legacy_dev.c"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjmedia-audiodev\pa_dev.c"
 # End Source File
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev.h	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev.h	(revision 2489)
@@ -27,5 +27,5 @@
 #include <pjmedia-audiodev/config.h>
 #include <pjmedia-audiodev/errno.h>
-#include <pjmedia/port.h>
+#include <pjmedia/types.h>
 #include <pj/pool.h>
 
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/config.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/config.h	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/config.h	(revision 2489)
@@ -25,5 +25,5 @@
  * @brief Audio device API.
  */
-#include <pjmedia/port.h>
+#include <pjmedia/types.h>
 #include <pj/pool.h>
 
@@ -47,5 +47,5 @@
  */
 #ifndef PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
-#   define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO	0
+#   define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO	1
 #endif
 
@@ -72,6 +72,26 @@
  */
 #ifndef PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
-#   define PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA	0
-#endif
+#   define PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA	PJ_SYMBIAN
+#endif
+
+
+/**
+ * This setting controls whether the Audio Device API should support
+ * device implementation that is based on the old sound device API
+ * (sound.h). 
+ *
+ * Enable this API if:
+ *  - you have implemented your own sound device using the old sound
+ *    device API (sound.h), and
+ *  - you wish to be able to use your sound device implementation
+ *    using the new Audio Device API.
+ *
+ * Please see http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more
+ * info.
+ */
+#ifndef PJMEDIA_AUDIO_DEV_HAS_LEGACY_DEVICE
+#   define PJMEDIA_AUDIO_DEV_HAS_LEGACY_DEVICE	0
+#endif
+
 
 /**
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/errno.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/errno.h	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/errno.h	(revision 2489)
@@ -98,5 +98,5 @@
  * General/unknown error.
  */
-#define PJMEDIA_AUDIODEV_ERROR	(PJMEDIA_AUDIODEV_ERRNO_START+1) /* 420001 */
+#define PJMEDIA_EAUD_ERR	(PJMEDIA_AUDIODEV_ERRNO_START+1) /* 420001 */
 
 /**
@@ -161,4 +161,14 @@
 
 /**
+ * @hideinitializer
+ * Bad latency setting
+ */
+#define PJMEDIA_EAUD_BADLATENCY	(PJMEDIA_AUDIODEV_ERRNO_START+12) /* 4200012 */
+
+
+
+
+
+/**
  * Get error message for the specified error code. Note that this
  * function is only able to decode PJMEDIA Audiodev specific error code.
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/config.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/config.h	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/config.h	(revision 2489)
@@ -82,33 +82,17 @@
 
 /**
- * Setting PJMEDIA_AUDIO_API to this value will completely deprecate the use
- * of old API, and inclusion of <pjmedia/sound.h> in the code will raise 
- * compilation error.
- */
-#define PJMEDIA_AUDIO_API_NEW_ONLY	    1
-
-/**
- * Setting PJMEDIA_AUDIO_API to this value enables application to use the old
- * sound device API to access audio devices provided by the new audio device 
- * API. 
- */
-#define PJMEDIA_AUDIO_API_HAS_OLD_API	    2
-
-/**
- * Setting PJMEDIA_AUDIO_API to this value enables old sound device 
- * implementation to be accessed via both old and new API's. 
- */
-#define PJMEDIA_AUDIO_API_HAS_OLD_DEVICE    3
-
-/**
- * Specify how the audio API should handle compatibility with old sound API.
- * Valid values are: PJMEDIA_AUDIO_API_HAS_OLD_API (default, 
- * PJMEDIA_AUDIO_API_NEW_ONLY, or PJMEDIA_AUDIO_API_HAS_OLD_DEVICE. Please
- * see http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more info.
- */
-#ifndef PJMEDIA_AUDIO_API
-#   define PJMEDIA_AUDIO_API		    PJMEDIA_AUDIO_API_NEW_ONLY
-#endif
-
+ * This macro controls whether the legacy sound device API is to be
+ * implemented, for applications that still use the old sound device
+ * API (sound.h). If this macro is set to non-zero, the sound_legacy.c
+ * will be included in the compilation. The sound_legacy.c is an
+ * implementation of old sound device (sound.h) using the new Audio
+ * Device API.
+ *
+ * Please see http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more
+ * info.
+ */
+#ifndef PJMEDIA_HAS_LEGACY_SOUND_API
+#   define PJMEDIA_HAS_LEGACY_SOUND_API	    1
+#endif
 
 /**
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2489)
@@ -223,203 +223,4 @@
 
 
-/** 
- * Types of media frame. 
- */
-typedef enum pjmedia_frame_type
-{
-    PJMEDIA_FRAME_TYPE_NONE,	    /**< No frame.		*/
-    PJMEDIA_FRAME_TYPE_AUDIO,	    /**< Normal audio frame.	*/
-    PJMEDIA_FRAME_TYPE_EXTENDED	    /**< Extended audio frame.	*/
-
-} pjmedia_frame_type;
-
-
-/** 
- * This structure describes a media frame. 
- */
-typedef struct pjmedia_frame
-{
-    pjmedia_frame_type	 type;	    /**< Frame type.			    */
-    void		*buf;	    /**< Pointer to buffer.		    */
-    pj_size_t		 size;	    /**< Frame size in bytes.		    */
-    pj_timestamp	 timestamp; /**< Frame timestamp.		    */
-    pj_uint32_t		 bit_info;  /**< Bit info of the frame, sample case:
-					 a frame may not exactly start and end
-					 at the octet boundary, so this field 
-					 may be used for specifying start & 
-					 end bit offset.		    */
-} pjmedia_frame;
-
-
-/**
- * The pjmedia_frame_ext is used to carry a more complex audio frames than
- * the typical PCM audio frames, and it is signaled by setting the "type"
- * field of a pjmedia_frame to PJMEDIA_FRAME_TYPE_EXTENDED. With this set,
- * application may typecast pjmedia_frame to pjmedia_frame_ext.
- *
- * This structure may contain more than one audio frames, which subsequently
- * will be called subframes in this structure. The subframes section
- * immediately follows the end of this structure, and each subframe is
- * represented by pjmedia_frame_ext_subframe structure. Every next
- * subframe immediately follows the previous subframe, and all subframes
- * are byte-aligned although its payload may not be byte-aligned.
- */
-
-#pragma pack(1)
-typedef struct pjmedia_frame_ext {
-    pjmedia_frame   base;	    /**< Base frame info */
-    pj_uint16_t     samples_cnt;    /**< Number of samples in this frame */
-    pj_uint16_t     subframe_cnt;   /**< Number of (sub)frames in this frame */
-
-    /* Zero or more (sub)frames follows immediately after this,
-     * each will be represented by pjmedia_frame_ext_subframe
-     */
-} pjmedia_frame_ext;
-#pragma pack()
-
-/**
- * This structure represents the individual subframes in the
- * pjmedia_frame_ext structure.
- */
-#pragma pack(1)
-typedef struct pjmedia_frame_ext_subframe {
-    pj_uint16_t     bitlen;	    /**< Number of bits in the data */
-    pj_uint8_t      data[1];	    /**< Start of encoded data */
-} pjmedia_frame_ext_subframe;
-
-#pragma pack()
-
-
-/**
- * Append one subframe to #pjmedia_frame_ext.
- *
- * @param frm		    The #pjmedia_frame_ext.
- * @param src		    Subframe data.
- * @param bitlen	    Lenght of subframe, in bits.
- * @param samples_cnt	    Number of audio samples in subframe.
- */
-PJ_INLINE(void) pjmedia_frame_ext_append_subframe(pjmedia_frame_ext *frm,
-						  const void *src,
-					          unsigned bitlen,
-						  unsigned samples_cnt)
-{
-    pjmedia_frame_ext_subframe *fsub;
-    pj_uint8_t *p;
-    unsigned i;
-
-    p = (pj_uint8_t*)frm + sizeof(pjmedia_frame_ext);
-    for (i = 0; i < frm->subframe_cnt; ++i) {
-	fsub = (pjmedia_frame_ext_subframe*) p;
-	p += sizeof(fsub->bitlen) + ((fsub->bitlen+7) >> 3);
-    }
-
-    fsub = (pjmedia_frame_ext_subframe*) p;
-    fsub->bitlen = (pj_uint16_t)bitlen;
-    if (bitlen)
-	pj_memcpy(fsub->data, src, (bitlen+7) >> 3);
-
-    frm->subframe_cnt++;
-    frm->samples_cnt = (pj_uint16_t)(frm->samples_cnt + samples_cnt);
-}
-
-/**
- * Get a subframe from #pjmedia_frame_ext.
- *
- * @param frm		    The #pjmedia_frame_ext.
- * @param n		    Subframe index, zero based.
- *
- * @return		    The n-th subframe, or NULL if n is out-of-range.
- */
-PJ_INLINE(pjmedia_frame_ext_subframe*) 
-pjmedia_frame_ext_get_subframe(const pjmedia_frame_ext *frm, unsigned n)
-{
-    pjmedia_frame_ext_subframe *sf = NULL;
-
-    if (n < frm->subframe_cnt) {
-	pj_uint8_t *p;
-	unsigned i;
-
-	p = (pj_uint8_t*)frm + sizeof(pjmedia_frame_ext);
-	for (i = 0; i < n; ++i) {	
-	    sf = (pjmedia_frame_ext_subframe*) p;
-	    p += sizeof(sf->bitlen) + ((sf->bitlen+7) >> 3);
-	}
-        
-	sf = (pjmedia_frame_ext_subframe*) p;
-    }
-
-    return sf;
-}
-	
-/**
- * Extract all frame payload to the specified buffer. 
- *
- * @param frm		    The frame.
- * @param dst		    Destination buffer.
- * @param maxsize	    Maximum size to copy (i.e. the size of the
- *			    destination buffer).
- *
- * @return		    Total size of payload copied.
- */
-PJ_INLINE(unsigned) 
-pjmedia_frame_ext_copy_payload(const pjmedia_frame_ext *frm,
-			       void *dst, 
-			       unsigned maxlen)
-{
-    unsigned i, copied=0;
-    for (i=0; i<frm->subframe_cnt; ++i) {
-	pjmedia_frame_ext_subframe *sf;
-	unsigned sz;
-
-	sf = pjmedia_frame_ext_get_subframe(frm, i);
-	if (!sf)
-	    continue;
-
-	sz = ((sf->bitlen + 7) >> 3);
-	if (sz + copied > maxlen)
-	    break;
-
-	pj_memcpy(((pj_uint8_t*)dst) + copied, sf->data, sz);
-	copied += sz;
-    }
-    return copied;
-}
-
-
-/**
- * Pop out first n subframes from #pjmedia_frame_ext.
- *
- * @param frm		    The #pjmedia_frame_ext.
- * @param n		    Number of first subframes to be popped out.
- *
- * @return		    PJ_SUCCESS when successful.
- */
-PJ_INLINE(pj_status_t) 
-pjmedia_frame_ext_pop_subframes(pjmedia_frame_ext *frm, unsigned n)
-{
-    pjmedia_frame_ext_subframe *sf;
-    pj_uint8_t *move_src;
-    unsigned move_len;
-
-    if (frm->subframe_cnt <= n) {
-	frm->subframe_cnt = 0;
-	frm->samples_cnt = 0;
-	return PJ_SUCCESS;
-    }
-
-    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+7) >> 3);
-    pj_memmove((pj_uint8_t*)frm+sizeof(pjmedia_frame_ext), 
-	       move_src, move_len);
-	    
-    frm->samples_cnt = (pj_uint16_t)
-		   (frm->samples_cnt - n*frm->samples_cnt/frm->subframe_cnt);
-    frm->subframe_cnt = (pj_uint16_t) (frm->subframe_cnt - n);
-
-    return PJ_SUCCESS;
-}
-
 /**
  * Port interface.
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound.h	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound.h	(revision 2489)
@@ -22,19 +22,11 @@
 
 
-/* This is legacy sound device code, which has been superseded by the
- * new pjmedia-audiodev framework. Please see the documentation on how
- * to use this legacy API.
- */
-#if PJMEDIA_AUDIO_API==PJMEDIA_AUDIO_API_NEW_ONLY
-#   error "The sound device API is deprecated. Please see doc for details."
-#endif
-
-
 /**
  * @file sound.h
- * @brief Sound player and recorder device framework.
- */
+ * @brief Legacy sound device API
+ */
+#include <pjmedia-audiodev/audiodev.h>
 #include <pjmedia/types.h>
-#include <pj/pool.h>
+
 
 PJ_BEGIN_DECL
@@ -45,4 +37,9 @@
  * @brief PJMEDIA abstraction for sound device hardware
  * @{
+ *
+ * <strong>Warning: this sound device API has been deprecated
+ * and replaced by PJMEDIA Audio Device API. Please see
+ * http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more
+ * information.</strong>
  *
  * This section describes lower level abstraction for sound device
@@ -71,5 +68,5 @@
  */
 
-/** Opaque data type for audio stream. */
+/** Opaque declaration for pjmedia_snd_stream. */
 typedef struct pjmedia_snd_stream pjmedia_snd_stream;
 
@@ -101,32 +98,4 @@
     unsigned	play_latency;	    /**< Playback latency, in samples.	    */
 } pjmedia_snd_stream_info;
-
-/**
- * Audio routing destination.
- */
-typedef enum pjmedia_snd_route
-{
-    /** Route to default destination */
-    PJMEDIA_SND_ROUTE_DEFAULT,
-
-    /** Route to loudspeaker */
-    PJMEDIA_SND_ROUTE_LOUDSPEAKER,
-
-    /** Route to earpiece */
-    PJMEDIA_SND_ROUTE_EARPIECE,
-
-} pjmedia_snd_route;
-
-
-/** 
- * Stream setting for opening sound device with non-PCM data.
- */
-typedef struct pjmedia_snd_setting
-{
-    pjmedia_format	format;	  /**< Format.			    */ 
-    pj_bool_t		plc;	  /**< PLC enabled/disabled.	    */
-    pjmedia_snd_route	route;	  /**< Audio routing.		    */
-} pjmedia_snd_setting;
-
 
 /** 
@@ -310,44 +279,4 @@
 
 /**
- * Create sound stream for capturing audio and/or audio playback, from the 
- * same device. This also allows opening sound stream with extended settings, 
- * e.g: stream format, see #pjmedia_snd_setting.
- *
- * @param dir		    Sound stream direction.
- * @param rec_id	    Device index for recorder/capture stream, or
- *			    -1 to use the first capable device.
- * @param play_id	    Device index for playback stream, or -1 to use 
- *			    the first capable device.
- * @param clock_rate	    Sound device's clock rate to set.
- * @param channel_count	    Set number of channels, 1 for mono, or 2 for
- *			    stereo. The channel count determines the format
- *			    of the frame.
- * @param samples_per_frame Number of samples per frame.
- * @param bits_per_sample   Set the number of bits per sample. The normal 
- *			    value for this parameter is 16 bits per sample.
- * @param rec_cb	    Callback to handle captured audio samples.
- * @param play_cb	    Callback to be called when the sound player needs
- *			    more audio samples to play.
- * @param user_data	    User data to be associated with the stream.
- * @param setting	    Sound device extended setting.
- * @param p_snd_strm	    Pointer to receive the stream instance.
- *
- * @return		    PJ_SUCCESS on success.
- */
-PJ_DECL(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);
-
-
-/**
  * Get information about live stream.
  *
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/types.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/types.h	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/types.h	(revision 2489)
@@ -325,4 +325,204 @@
 }
 
+/** 
+ * Types of media frame. 
+ */
+typedef enum pjmedia_frame_type
+{
+    PJMEDIA_FRAME_TYPE_NONE,	    /**< No frame.		*/
+    PJMEDIA_FRAME_TYPE_AUDIO,	    /**< Normal audio frame.	*/
+    PJMEDIA_FRAME_TYPE_EXTENDED	    /**< Extended audio frame.	*/
+
+} pjmedia_frame_type;
+
+
+/** 
+ * This structure describes a media frame. 
+ */
+typedef struct pjmedia_frame
+{
+    pjmedia_frame_type	 type;	    /**< Frame type.			    */
+    void		*buf;	    /**< Pointer to buffer.		    */
+    pj_size_t		 size;	    /**< Frame size in bytes.		    */
+    pj_timestamp	 timestamp; /**< Frame timestamp.		    */
+    pj_uint32_t		 bit_info;  /**< Bit info of the frame, sample case:
+					 a frame may not exactly start and end
+					 at the octet boundary, so this field 
+					 may be used for specifying start & 
+					 end bit offset.		    */
+} pjmedia_frame;
+
+
+/**
+ * The pjmedia_frame_ext is used to carry a more complex audio frames than
+ * the typical PCM audio frames, and it is signaled by setting the "type"
+ * field of a pjmedia_frame to PJMEDIA_FRAME_TYPE_EXTENDED. With this set,
+ * application may typecast pjmedia_frame to pjmedia_frame_ext.
+ *
+ * This structure may contain more than one audio frames, which subsequently
+ * will be called subframes in this structure. The subframes section
+ * immediately follows the end of this structure, and each subframe is
+ * represented by pjmedia_frame_ext_subframe structure. Every next
+ * subframe immediately follows the previous subframe, and all subframes
+ * are byte-aligned although its payload may not be byte-aligned.
+ */
+
+#pragma pack(1)
+typedef struct pjmedia_frame_ext {
+    pjmedia_frame   base;	    /**< Base frame info */
+    pj_uint16_t     samples_cnt;    /**< Number of samples in this frame */
+    pj_uint16_t     subframe_cnt;   /**< Number of (sub)frames in this frame */
+
+    /* Zero or more (sub)frames follows immediately after this,
+     * each will be represented by pjmedia_frame_ext_subframe
+     */
+} pjmedia_frame_ext;
+#pragma pack()
+
+/**
+ * This structure represents the individual subframes in the
+ * pjmedia_frame_ext structure.
+ */
+#pragma pack(1)
+typedef struct pjmedia_frame_ext_subframe {
+    pj_uint16_t     bitlen;	    /**< Number of bits in the data */
+    pj_uint8_t      data[1];	    /**< Start of encoded data */
+} pjmedia_frame_ext_subframe;
+
+#pragma pack()
+
+
+/**
+ * Append one subframe to #pjmedia_frame_ext.
+ *
+ * @param frm		    The #pjmedia_frame_ext.
+ * @param src		    Subframe data.
+ * @param bitlen	    Lenght of subframe, in bits.
+ * @param samples_cnt	    Number of audio samples in subframe.
+ */
+PJ_INLINE(void) pjmedia_frame_ext_append_subframe(pjmedia_frame_ext *frm,
+						  const void *src,
+					          unsigned bitlen,
+						  unsigned samples_cnt)
+{
+    pjmedia_frame_ext_subframe *fsub;
+    pj_uint8_t *p;
+    unsigned i;
+
+    p = (pj_uint8_t*)frm + sizeof(pjmedia_frame_ext);
+    for (i = 0; i < frm->subframe_cnt; ++i) {
+	fsub = (pjmedia_frame_ext_subframe*) p;
+	p += sizeof(fsub->bitlen) + ((fsub->bitlen+7) >> 3);
+    }
+
+    fsub = (pjmedia_frame_ext_subframe*) p;
+    fsub->bitlen = (pj_uint16_t)bitlen;
+    if (bitlen)
+	pj_memcpy(fsub->data, src, (bitlen+7) >> 3);
+
+    frm->subframe_cnt++;
+    frm->samples_cnt = (pj_uint16_t)(frm->samples_cnt + samples_cnt);
+}
+
+/**
+ * Get a subframe from #pjmedia_frame_ext.
+ *
+ * @param frm		    The #pjmedia_frame_ext.
+ * @param n		    Subframe index, zero based.
+ *
+ * @return		    The n-th subframe, or NULL if n is out-of-range.
+ */
+PJ_INLINE(pjmedia_frame_ext_subframe*) 
+pjmedia_frame_ext_get_subframe(const pjmedia_frame_ext *frm, unsigned n)
+{
+    pjmedia_frame_ext_subframe *sf = NULL;
+
+    if (n < frm->subframe_cnt) {
+	pj_uint8_t *p;
+	unsigned i;
+
+	p = (pj_uint8_t*)frm + sizeof(pjmedia_frame_ext);
+	for (i = 0; i < n; ++i) {	
+	    sf = (pjmedia_frame_ext_subframe*) p;
+	    p += sizeof(sf->bitlen) + ((sf->bitlen+7) >> 3);
+	}
+        
+	sf = (pjmedia_frame_ext_subframe*) p;
+    }
+
+    return sf;
+}
+	
+/**
+ * Extract all frame payload to the specified buffer. 
+ *
+ * @param frm		    The frame.
+ * @param dst		    Destination buffer.
+ * @param maxsize	    Maximum size to copy (i.e. the size of the
+ *			    destination buffer).
+ *
+ * @return		    Total size of payload copied.
+ */
+PJ_INLINE(unsigned) 
+pjmedia_frame_ext_copy_payload(const pjmedia_frame_ext *frm,
+			       void *dst, 
+			       unsigned maxlen)
+{
+    unsigned i, copied=0;
+    for (i=0; i<frm->subframe_cnt; ++i) {
+	pjmedia_frame_ext_subframe *sf;
+	unsigned sz;
+
+	sf = pjmedia_frame_ext_get_subframe(frm, i);
+	if (!sf)
+	    continue;
+
+	sz = ((sf->bitlen + 7) >> 3);
+	if (sz + copied > maxlen)
+	    break;
+
+	pj_memcpy(((pj_uint8_t*)dst) + copied, sf->data, sz);
+	copied += sz;
+    }
+    return copied;
+}
+
+
+/**
+ * Pop out first n subframes from #pjmedia_frame_ext.
+ *
+ * @param frm		    The #pjmedia_frame_ext.
+ * @param n		    Number of first subframes to be popped out.
+ *
+ * @return		    PJ_SUCCESS when successful.
+ */
+PJ_INLINE(pj_status_t) 
+pjmedia_frame_ext_pop_subframes(pjmedia_frame_ext *frm, unsigned n)
+{
+    pjmedia_frame_ext_subframe *sf;
+    pj_uint8_t *move_src;
+    unsigned move_len;
+
+    if (frm->subframe_cnt <= n) {
+	frm->subframe_cnt = 0;
+	frm->samples_cnt = 0;
+	return PJ_SUCCESS;
+    }
+
+    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+7) >> 3);
+    pj_memmove((pj_uint8_t*)frm+sizeof(pjmedia_frame_ext), 
+	       move_src, move_len);
+	    
+    frm->samples_cnt = (pj_uint16_t)
+		   (frm->samples_cnt - n*frm->samples_cnt/frm->subframe_cnt);
+    frm->subframe_cnt = (pj_uint16_t) (frm->subframe_cnt - n);
+
+    return PJ_SUCCESS;
+}
+
+
 /**
  * @}
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiodev.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 2489)
@@ -19,4 +19,5 @@
  */
 #include <pjmedia-audiodev/audiodev_imp.h>
+#include <pj/assert.h>
 #include <pj/errno.h>
 #include <pj/log.h>
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/errno.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/errno.c	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/errno.c	(revision 2489)
@@ -47,5 +47,5 @@
 } err_str[] = 
 {
-    PJ_BUILD_ERR( PJMEDIA_AUDIODEV_ERROR,   "Unspecified audio device error" ),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_ERR,	    "Unspecified audio device error" ),
     PJ_BUILD_ERR( PJMEDIA_EAUD_SYSERR,	    "Unknown error from audio driver" ),
     PJ_BUILD_ERR( PJMEDIA_EAUD_INIT,	    "Audio subsystem not initialized" ),
@@ -57,5 +57,6 @@
     PJ_BUILD_ERR( PJMEDIA_EAUD_INVOP,	    "Invalid or unsupported audio device operation" ),
     PJ_BUILD_ERR( PJMEDIA_EAUD_BADFORMAT,   "Bad or invalid audio device format" ),
-    PJ_BUILD_ERR( PJMEDIA_EAUD_SAMPFORMAT,  "Invalid audio device sample format")
+    PJ_BUILD_ERR( PJMEDIA_EAUD_SAMPFORMAT,  "Invalid audio device sample format"),
+    PJ_BUILD_ERR( PJMEDIA_EAUD_BADLATENCY,  "Bad audio latency setting")
 
 };
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/legacy_dev.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/legacy_dev.c	(revision 2489)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/legacy_dev.c	(revision 2489)
@@ -0,0 +1,459 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjmedia-audiodev/audiodev_imp.h>
+#include <pjmedia/sound.h>
+#include <pj/assert.h>
+
+#if PJMEDIA_AUDIO_DEV_HAS_LEGACY_DEVICE
+
+#define THIS_FILE			"legacy_dev.c"
+
+/* Legacy devices factory */
+struct legacy_factory
+{
+    pjmedia_aud_dev_factory	 base;
+    pj_pool_t			*pool;
+    pj_pool_factory		*pf;
+};
+
+
+struct legacy_stream
+{
+    pjmedia_aud_stream	 base;
+
+    pj_pool_t		*pool;
+    pjmedia_aud_param    param;
+    pjmedia_snd_stream	*snd_strm;
+    pjmedia_aud_play_cb	 user_play_cb;
+    pjmedia_aud_rec_cb   user_rec_cb;
+    void		*user_user_data;
+    unsigned		 input_latency;
+    unsigned		 output_latency;
+};
+
+
+/* Prototypes */
+static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
+static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
+static unsigned    factory_get_dev_count(pjmedia_aud_dev_factory *f);
+static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, 
+					unsigned index,
+					pjmedia_aud_dev_info *info);
+static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
+					 unsigned index,
+					 pjmedia_aud_param *param);
+static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
+					 const pjmedia_aud_param *param,
+					 pjmedia_aud_rec_cb rec_cb,
+					 pjmedia_aud_play_cb play_cb,
+					 void *user_data,
+					 pjmedia_aud_stream **p_aud_strm);
+
+static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
+				    pjmedia_aud_param *param);
+static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
+				  pjmedia_aud_dev_cap cap,
+				  void *value);
+static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
+				  pjmedia_aud_dev_cap cap,
+				  const void *value);
+static pj_status_t stream_start(pjmedia_aud_stream *strm);
+static pj_status_t stream_stop(pjmedia_aud_stream *strm);
+static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
+
+
+/* Operations */
+static pjmedia_aud_dev_factory_op factory_op =
+{
+    &factory_init,
+    &factory_destroy,
+    &factory_get_dev_count,
+    &factory_get_dev_info,
+    &factory_default_param,
+    &factory_create_stream
+};
+
+static pjmedia_aud_stream_op stream_op = 
+{
+    &stream_get_param,
+    &stream_get_cap,
+    &stream_set_cap,
+    &stream_start,
+    &stream_stop,
+    &stream_destroy
+};
+
+
+/****************************************************************************
+ * Factory operations
+ */
+
+/*
+ * Init legacy audio driver.
+ */
+pjmedia_aud_dev_factory* pjmedia_legacy_factory(pj_pool_factory *pf)
+{
+    struct legacy_factory *f;
+    pj_pool_t *pool;
+
+    pool = pj_pool_create(pf, "legacy-snd", 512, 512, NULL);
+    f = PJ_POOL_ZALLOC_T(pool, struct legacy_factory);
+    f->pf = pf;
+    f->pool = pool;
+    f->base.op = &factory_op;
+
+    return &f->base;
+}
+
+
+/* API: init factory */
+static pj_status_t factory_init(pjmedia_aud_dev_factory *f)
+{
+    struct legacy_factory *wf = (struct legacy_factory*)f;
+
+    return pjmedia_snd_init(wf->pf);
+}
+
+/* API: destroy factory */
+static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f)
+{
+    struct legacy_factory *wf = (struct legacy_factory*)f;
+    pj_status_t status;
+
+    status = pjmedia_snd_deinit();
+
+    if (status == PJ_SUCCESS) {
+	pj_pool_t *pool = wf->pool;
+	wf->pool = NULL;
+	pj_pool_release(pool);
+    }
+
+    return status;
+}
+
+/* API: get number of devices */
+static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f)
+{
+    PJ_UNUSED_ARG(f);
+    return pjmedia_snd_get_dev_count();
+}
+
+/* API: get device info */
+static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, 
+					unsigned index,
+					pjmedia_aud_dev_info *info)
+{
+    const pjmedia_snd_dev_info *si = 
+	pjmedia_snd_get_dev_info(index);;
+
+    PJ_UNUSED_ARG(f);
+
+    if (si == NULL)
+	return PJMEDIA_EAUD_INVDEV;
+
+    pj_bzero(info, sizeof(*info));
+    pj_ansi_strncpy(info->name, si->name, sizeof(info->name));
+    info->name[sizeof(info->name)-1] = '\0';
+    info->input_count = si->input_count;
+    info->output_count = si->output_count;
+    info->default_samples_per_sec = si->default_samples_per_sec;
+    pj_ansi_strcpy(info->driver, "legacy");
+    info->caps = PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 
+		 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
+
+    return PJ_SUCCESS;
+}
+
+/* API: create default device parameter */
+static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
+					 unsigned index,
+					 pjmedia_aud_param *param)
+{
+    pjmedia_aud_dev_info di;
+    pj_status_t status;
+
+    status = factory_get_dev_info(f, index, &di);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pj_bzero(param, sizeof(*param));
+    if (di.input_count && di.output_count) {
+	param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+	param->rec_id = index;
+	param->play_id = index;
+    } else if (di.input_count) {
+	param->dir = PJMEDIA_DIR_CAPTURE;
+	param->rec_id = index;
+	param->play_id = PJMEDIA_AUD_INVALID_DEV;
+    } else if (di.output_count) {
+	param->dir = PJMEDIA_DIR_PLAYBACK;
+	param->play_id = index;
+	param->rec_id = PJMEDIA_AUD_INVALID_DEV;
+    } else {
+	return PJMEDIA_EAUD_INVDEV;
+    }
+
+    param->clock_rate = di.default_samples_per_sec;
+    param->channel_count = 1;
+    param->samples_per_frame = di.default_samples_per_sec * 20 / 1000;
+    param->bits_per_sample = 16;
+    param->flags = di.caps;
+    param->input_latency_ms = PJMEDIA_SND_DEFAULT_REC_LATENCY;
+    param->output_latency_ms = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
+
+    return PJ_SUCCESS;
+}
+
+/* Callback from legacy sound device */
+static pj_status_t snd_play_cb(/* in */   void *user_data,
+			       /* in */   pj_uint32_t timestamp,
+			       /* out */  void *output,
+			       /* out */  unsigned size)
+{
+    struct legacy_stream *strm = (struct legacy_stream*)user_data;
+    pjmedia_frame frame;
+    pj_status_t status;
+
+    frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+    frame.buf = output;
+    frame.size = size;
+    frame.timestamp.u64 = timestamp;
+
+    status = strm->user_play_cb(strm->user_user_data, &frame);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) {
+	pj_bzero(output, size);
+    }
+
+    return PJ_SUCCESS;
+}
+
+/* Callback from legacy sound device */
+static pj_status_t snd_rec_cb( /* in */   void *user_data,
+			       /* in */   pj_uint32_t timestamp,
+			       /* in */   void *input,
+			       /* in*/    unsigned size)
+{
+    struct legacy_stream *strm = (struct legacy_stream*)user_data;
+    pjmedia_frame frame;
+    
+    frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+    frame.buf = input;
+    frame.size = size;
+    frame.timestamp.u64 = timestamp;
+
+    return strm->user_rec_cb(strm->user_user_data, &frame);
+}
+
+/* API: create stream */
+static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
+					 const pjmedia_aud_param *param,
+					 pjmedia_aud_rec_cb rec_cb,
+					 pjmedia_aud_play_cb play_cb,
+					 void *user_data,
+					 pjmedia_aud_stream **p_aud_strm)
+{
+    struct legacy_factory *wf = (struct legacy_factory*)f;
+    pj_pool_t *pool;
+    struct legacy_stream *strm;
+    pj_status_t status;
+
+    /* Initialize our stream data */
+    pool = pj_pool_create(wf->pf, "legacy-snd", 512, 512, NULL);
+    strm = PJ_POOL_ZALLOC_T(pool, struct legacy_stream);
+    strm->pool = pool;
+    strm->user_rec_cb = rec_cb;
+    strm->user_play_cb = play_cb;
+    strm->user_user_data = user_data;
+    pj_memcpy(&strm->param, param, sizeof(*param));
+
+    /* Set the latency if wanted */
+    if (param->dir==PJMEDIA_DIR_CAPTURE_PLAYBACK &&
+	param->flags & (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
+			PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY))
+    {
+	PJ_ASSERT_RETURN(param->input_latency_ms &&
+			 param->output_latency_ms,
+			 PJMEDIA_EAUD_BADLATENCY);
+
+	strm->input_latency = param->input_latency_ms;
+	strm->output_latency = param->output_latency_ms;
+
+	status = pjmedia_snd_set_latency(param->input_latency_ms,
+					 param->output_latency_ms);
+	if (status != PJ_SUCCESS) {
+	    pj_pool_release(pool);
+	    return status;
+	}
+    }
+
+    /* Open the stream */
+    if (param->dir == PJMEDIA_DIR_CAPTURE) {
+	status = pjmedia_snd_open_rec(param->rec_id,
+				      param->clock_rate,
+				      param->channel_count,
+				      param->samples_per_frame,
+				      param->bits_per_sample,
+				      &snd_rec_cb,
+				      strm,
+				      &strm->snd_strm);
+    } else if (param->dir == PJMEDIA_DIR_PLAYBACK) {
+	status = pjmedia_snd_open_player(param->play_id,
+					 param->clock_rate,
+					 param->channel_count,
+					 param->samples_per_frame,
+					 param->bits_per_sample,
+					 &snd_play_cb,
+					 strm,
+					 &strm->snd_strm);
+
+    } else if (param->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK) {
+	status = pjmedia_snd_open(param->rec_id,
+				  param->play_id,
+				  param->clock_rate,
+				  param->channel_count,
+				  param->samples_per_frame,
+				  param->bits_per_sample,
+				  &snd_rec_cb,
+				  &snd_play_cb,
+				  strm,
+				  &strm->snd_strm);
+    } else {
+	pj_assert(!"Invalid direction!");
+	return PJ_EINVAL;
+    }
+
+    if (status != PJ_SUCCESS) {
+	pj_pool_release(pool);
+	return status;
+    }
+
+    *p_aud_strm = &strm->base;
+    return PJ_SUCCESS;
+}
+
+/* API: Get stream info. */
+static pj_status_t stream_get_param(pjmedia_aud_stream *s,
+				    pjmedia_aud_param *pi)
+{
+    struct legacy_stream *strm = (struct legacy_stream*)s;
+    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
+
+    pj_memcpy(pi, &strm->param, sizeof(*pi));
+
+    if (strm->input_latency) {
+	pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
+	pi->input_latency_ms = strm->input_latency;
+    } else {
+	pi->flags &= ~PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
+    }
+
+    if (strm->output_latency) {
+	pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
+	pi->output_latency_ms = strm->output_latency;
+    } else {
+	pi->flags &= ~PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
+    }
+
+    return PJ_SUCCESS;
+}
+
+/* API: get capability */
+static pj_status_t stream_get_cap(pjmedia_aud_stream *s,
+				  pjmedia_aud_dev_cap cap,
+				  void *pval)
+{
+    struct legacy_stream *strm = (struct legacy_stream*)s;
+
+    PJ_ASSERT_RETURN(strm && pval, PJ_EINVAL);
+
+    if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY && 
+	(strm->param.dir & PJMEDIA_DIR_CAPTURE)) 
+    {
+	/* Recording latency */
+	if (strm->input_latency) {
+	    *(unsigned*)pval = strm->input_latency;
+	    return PJ_SUCCESS;
+	} else {
+	    return PJMEDIA_EAUD_INVCAP;
+	}
+
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY  && 
+	       (strm->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+	/* Playback latency */
+	if (strm->output_latency) {
+	    *(unsigned*)pval = strm->output_latency;
+	    return PJ_SUCCESS;
+	} else {
+	    return PJMEDIA_EAUD_INVCAP;
+	}
+    } else {
+	return PJMEDIA_EAUD_INVCAP;
+    }
+}
+
+/* API: set capability */
+static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
+				  pjmedia_aud_dev_cap cap,
+				  const void *pval)
+{
+    PJ_UNUSED_ARG(s);
+    PJ_UNUSED_ARG(cap);
+    PJ_UNUSED_ARG(pval);
+    return PJMEDIA_EAUD_INVCAP;
+}
+
+/* API: Start stream. */
+static pj_status_t stream_start(pjmedia_aud_stream *s)
+{
+    struct legacy_stream *strm = (struct legacy_stream*)s;
+    return pjmedia_snd_stream_start(strm->snd_strm);
+}
+
+/* API: Stop stream. */
+static pj_status_t stream_stop(pjmedia_aud_stream *s)
+{
+    struct legacy_stream *strm = (struct legacy_stream*)s;
+    return pjmedia_snd_stream_stop(strm->snd_strm);
+}
+
+
+/* API: Destroy stream. */
+static pj_status_t stream_destroy(pjmedia_aud_stream *s)
+{
+    struct legacy_stream *strm = (struct legacy_stream*)s;
+    pj_status_t status;
+
+    status = pjmedia_snd_stream_close(strm->snd_strm);
+
+    if (status == PJ_SUCCESS) {
+	pj_pool_t *pool = strm->pool;
+
+	strm->pool = NULL;
+	pj_pool_release(pool);
+    }
+
+    return status;
+}
+
+#endif	/* PJMEDIA_AUDIO_DEV_HAS_LEGACY_DEVICE */
+
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp	(revision 2489)
@@ -20,5 +20,4 @@
 #include <pjmedia-audiodev/audiodev_imp.h>
 #include <pjmedia/alaw_ulaw.h>
-#include <pjmedia/errno.h>
 #include <pj/assert.h>
 #include <pj/log.h>
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/wmme_dev.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/wmme_dev.c	(revision 2488)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/wmme_dev.c	(revision 2489)
@@ -1150,5 +1150,5 @@
 	return PJ_SUCCESS;
     } else {
-	return PJ_ENOTSUP;
+	return PJMEDIA_EAUD_INVCAP;
     }
 }
@@ -1176,9 +1176,7 @@
 	return (mr==MMSYSERR_NOERROR)? PJ_SUCCESS : 
 				PJMEDIA_AUDIODEV_ERRNO_FROM_WMME_OUT(mr);
-    } else {
-	return PJ_ENOTSUP;
-    }
-
-    return PJ_ENOTSUP;
+    }
+
+    return PJMEDIA_EAUD_INVCAP;
 }
 
Index: project/branches/projects/aps-direct/pjmedia/src/pjmedia/dsound.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/dsound.c	(revision 2488)
+++ 	(revision )
@@ -1,1113 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
- * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#include <pjmedia/sound.h>
-#include <pjmedia/errno.h>
-#include <pj/assert.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/string.h>
-
-#if PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_WIN32_DIRECT_SOUND
-
-#define	PJ_MIN(x, y)	((x < y) ? (x) : (y))
-
-#ifdef _MSC_VER
-#   pragma warning(push, 3)
-#endif
-
-#include <windows.h>
-#include <mmsystem.h>
-#include <dsound.h>
-
-#ifdef _MSC_VER
-#   pragma warning(pop)
-#endif
-
-
-#define THIS_FILE	    "dsound.c"
-#define BITS_PER_SAMPLE	    16
-#define BYTES_PER_SAMPLE    (BITS_PER_SAMPLE/8)
-
-#define MAX_PACKET_BUFFER_COUNT	    50
-#define MIN_PACKET_BUFFER_COUNT	    2
-
-#define MAX_HARDWARE		    16
-
-struct dsound_dev_info
-{
-    pjmedia_snd_dev_info    info;
-    LPGUID		    lpGuid;
-    GUID		    guid;
-};
-
-static unsigned dev_count;
-static struct dsound_dev_info dev_info[MAX_HARDWARE];
-static int snd_init_count;
-
-/* Latency settings */
-static unsigned snd_input_latency  = PJMEDIA_SND_DEFAULT_REC_LATENCY;
-static unsigned snd_output_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
-
-
-/* Individual DirectSound capture/playback stream descriptor */
-struct dsound_stream
-{
-    union 
-    {
-	struct
-	{
-	    LPDIRECTSOUND	    lpDs;
-	    LPDIRECTSOUNDBUFFER	    lpDsBuffer;
-	} play;
-
-	struct
-	{
-	    LPDIRECTSOUNDCAPTURE	lpDs;
-	    LPDIRECTSOUNDCAPTUREBUFFER	lpDsBuffer;
-	} capture;
-    } ds;
-
-    HANDLE		    hEvent;
-    LPDIRECTSOUNDNOTIFY	    lpDsNotify;
-    DWORD		    dwBytePos;
-    DWORD		    dwDsBufferSize;
-    pj_timestamp	    timestamp;
-    unsigned		    latency;
-};
-
-
-/* Sound stream.    */
-struct pjmedia_snd_stream
-{
-    pjmedia_dir		    dir;		/**< Sound direction.	    */
-    int			    play_id;		/**< Playback dev id.	    */
-    int			    rec_id;		/**< Recording dev id.	    */
-    pj_pool_t		   *pool;		/**< Memory pool.	    */
-  
-    pjmedia_snd_rec_cb	    rec_cb;		/**< Capture callback.	    */
-    pjmedia_snd_play_cb	    play_cb;		/**< Playback callback.	    */
-    void		   *user_data;		/**< Application data.	    */
-
-    struct dsound_stream    play_strm;		/**< Playback stream.	    */
-    struct dsound_stream    rec_strm;		/**< Capture stream.	    */
-
-    void		   *buffer;		/**< Temp. frame buffer.    */
-    unsigned		    clock_rate;		/**< Clock rate.	    */
-    unsigned		    samples_per_frame;	/**< Samples per frame.	    */
-    unsigned		    bits_per_sample;	/**< Bits per sample.	    */
-    unsigned		    channel_count;	/**< Channel count.	    */
-
-    pj_thread_t		   *thread;		/**< Thread handle.	    */
-    HANDLE		    thread_quit_event;	/**< Quit signal to thread  */
-};
-
-
-static pj_pool_factory *pool_factory;
-
-
-static void init_waveformatex (PCMWAVEFORMAT *pcmwf, 
-			       unsigned clock_rate,
-			       unsigned channel_count)
-{
-    pj_bzero(pcmwf, sizeof(PCMWAVEFORMAT)); 
-    pcmwf->wf.wFormatTag = WAVE_FORMAT_PCM; 
-    pcmwf->wf.nChannels = (pj_uint16_t)channel_count;
-    pcmwf->wf.nSamplesPerSec = clock_rate;
-    pcmwf->wf.nBlockAlign = (pj_uint16_t)(channel_count * BYTES_PER_SAMPLE);
-    pcmwf->wf.nAvgBytesPerSec = clock_rate * channel_count * BYTES_PER_SAMPLE;
-    pcmwf->wBitsPerSample = BITS_PER_SAMPLE;
-}
-
-
-/*
- * Initialize DirectSound player device.
- */
-static pj_status_t init_player_stream( struct dsound_stream *ds_strm,
-				       int dev_id,
-				       unsigned clock_rate,
-				       unsigned channel_count,
-				       unsigned samples_per_frame,
-				       unsigned buffer_count)
-{
-    HRESULT hr;
-    HWND hwnd;
-    PCMWAVEFORMAT pcmwf; 
-    DSBUFFERDESC dsbdesc;
-    DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT];
-    unsigned bytes_per_frame;
-    unsigned max_latency;
-    unsigned i;
-
-
-    PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL);
-
-    /* Check device ID */
-    if (dev_id == -1)
-	dev_id = 0;
-
-    PJ_ASSERT_RETURN(dev_id>=0 && dev_id < (int)dev_count, PJ_EINVAL);
-
-    /*
-     * Create DirectSound device.
-     */
-    hr = DirectSoundCreate(dev_info[dev_id].lpGuid, &ds_strm->ds.play.lpDs, 
-			   NULL);
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-    hwnd = GetForegroundWindow();
-    if (hwnd == NULL) {
-	hwnd = GetDesktopWindow();
-    }    
-    hr = IDirectSound_SetCooperativeLevel( ds_strm->ds.play.lpDs, hwnd, 
-					   DSSCL_PRIORITY);
-    if FAILED(hr)
-	return PJ_RETURN_OS_ERROR(hr);
-    
-    /*
-     * Set up wave format structure for initialize DirectSound play
-     * buffer. 
-     */
-    init_waveformatex(&pcmwf, clock_rate, channel_count);
-    bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;
-
-    /* Set up DSBUFFERDESC structure. */
-    pj_bzero(&dsbdesc, sizeof(DSBUFFERDESC)); 
-    dsbdesc.dwSize = sizeof(DSBUFFERDESC); 
-    dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY |
-		      DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
-
-    dsbdesc.dwBufferBytes = buffer_count * bytes_per_frame;
-    dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; 
-
-    /*
-     * Create DirectSound playback buffer. 
-     */
-    hr = IDirectSound_CreateSoundBuffer(ds_strm->ds.play.lpDs, &dsbdesc, 
-					&ds_strm->ds.play.lpDsBuffer, NULL); 
-    if (FAILED(hr) )
-	return PJ_RETURN_OS_ERROR(hr);
-
-    /*
-     * Create event for play notification.
-     */
-    ds_strm->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
-    if (ds_strm->hEvent == NULL)
-	return pj_get_os_error();
-
-    /*
-     * Setup notification for play.
-     */
-    hr = IDirectSoundBuffer_QueryInterface( ds_strm->ds.play.lpDsBuffer, 
-					    &IID_IDirectSoundNotify, 
-					    (LPVOID *)&ds_strm->lpDsNotify); 
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-    
-    for (i=0; i<buffer_count; ++i) {
-	dsPosNotify[i].dwOffset = i * bytes_per_frame;
-	dsPosNotify[i].hEventNotify = ds_strm->hEvent;
-    }
-    
-    hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify, 
-						      buffer_count, 
-						      dsPosNotify);
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-
-    hr = IDirectSoundBuffer_SetCurrentPosition(ds_strm->ds.play.lpDsBuffer, 0);
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-
-    ds_strm->dwBytePos = 0;
-    ds_strm->dwDsBufferSize = buffer_count * bytes_per_frame;
-    ds_strm->timestamp.u64 = 0;
-    /*
-     * Play latency does not need to be on a frame boundry, it is just how far
-     * ahead of the read pointer we set the write pointer.  So we should just
-     * use the user configured latency.  However, if the latency measured in
-     * bytes causes more buffers than we are allowed, we must cap the latency
-     * at the time contained in 1-buffer_count.
-     */
-    max_latency = (1 - buffer_count) * samples_per_frame * 1000 / clock_rate /
-        channel_count;
-    ds_strm->latency = PJ_MIN(max_latency, snd_output_latency);
-
-    /* Done setting up play device. */
-    PJ_LOG(5,(THIS_FILE, 
-	      " DirectSound player \"%s\" initialized (clock_rate=%d, "
-	      "channel_count=%d, samples_per_frame=%d (%dms))",
-	      dev_info[dev_id].info.name,
-	      clock_rate, channel_count, samples_per_frame,
-	      samples_per_frame * 1000 / clock_rate));
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Initialize DirectSound recorder device
- */
-static pj_status_t init_capture_stream( struct dsound_stream *ds_strm,
-				        int dev_id,
-				        unsigned clock_rate,
-				        unsigned channel_count,
-				        unsigned samples_per_frame,
-				        unsigned buffer_count)
-{
-    HRESULT hr;
-    PCMWAVEFORMAT pcmwf; 
-    DSCBUFFERDESC dscbdesc;
-    DSBPOSITIONNOTIFY dsPosNotify[MAX_PACKET_BUFFER_COUNT];
-    unsigned bytes_per_frame;
-    unsigned i;
-
-
-    PJ_ASSERT_RETURN(buffer_count <= MAX_PACKET_BUFFER_COUNT, PJ_EINVAL);
-
-
-    /* Check device id */
-    if (dev_id == -1)
-	dev_id = 0;
-
-    PJ_ASSERT_RETURN(dev_id>=0 && dev_id < (int)dev_count, PJ_EINVAL);
-
-    /*
-     * Creating recorder device.
-     */
-    hr = DirectSoundCaptureCreate(dev_info[dev_id].lpGuid, 
-				  &ds_strm->ds.capture.lpDs, NULL);
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-
-    /* Init wave format to initialize buffer */
-    init_waveformatex( &pcmwf, clock_rate, channel_count);
-    bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;
-
-    /* 
-     * Setup capture buffer using sound buffer structure that was passed
-     * to play buffer creation earlier.
-     */
-    pj_bzero(&dscbdesc, sizeof(DSCBUFFERDESC));
-    dscbdesc.dwSize = sizeof(DSCBUFFERDESC); 
-    dscbdesc.dwFlags = DSCBCAPS_WAVEMAPPED ;
-    dscbdesc.dwBufferBytes = buffer_count * bytes_per_frame; 
-    dscbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; 
-
-    hr = IDirectSoundCapture_CreateCaptureBuffer( ds_strm->ds.capture.lpDs,
-						  &dscbdesc, 
-						  &ds_strm->ds.capture.lpDsBuffer,
-						  NULL);
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-    /*
-     * Create event for play notification.
-     */
-    ds_strm->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
-    if (ds_strm->hEvent == NULL)
-	return pj_get_os_error();
-
-    /*
-     * Setup notifications for recording.
-     */
-    hr = IDirectSoundCaptureBuffer_QueryInterface( ds_strm->ds.capture.lpDsBuffer, 
-						   &IID_IDirectSoundNotify, 
-						   (LPVOID *)&ds_strm->lpDsNotify); 
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-    
-    for (i=0; i<buffer_count; ++i) {
-	dsPosNotify[i].dwOffset = i * bytes_per_frame;
-	dsPosNotify[i].hEventNotify = ds_strm->hEvent;
-    }
-    
-    hr = IDirectSoundNotify_SetNotificationPositions( ds_strm->lpDsNotify, 
-						      buffer_count, 
-						      dsPosNotify);
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-    hr = IDirectSoundCaptureBuffer_GetCurrentPosition( ds_strm->ds.capture.lpDsBuffer, 
-						       NULL, &ds_strm->dwBytePos );
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-    ds_strm->timestamp.u64 = 0;
-    ds_strm->dwDsBufferSize = buffer_count * bytes_per_frame;
-    /*
-     * Capture latency must always be on a frame boundry,
-     * so compute it based off the calculated buffer_count.
-     */
-    ds_strm->latency = buffer_count * samples_per_frame * 1000 / clock_rate / 
-		       channel_count;
-
-    /* Done setting up recorder device. */
-    PJ_LOG(5,(THIS_FILE, 
-	      " DirectSound capture \"%s\" initialized (clock_rate=%d, "
-	      "channel_count=%d, samples_per_frame=%d (%dms))",
-	      dev_info[dev_id].info.name,
-	      clock_rate, channel_count, samples_per_frame,
-	      samples_per_frame * 1000 / clock_rate));
-
-    return PJ_SUCCESS;
-}
-
-
-
-static BOOL AppReadDataFromBuffer(LPDIRECTSOUNDCAPTUREBUFFER lpDsb, // The buffer.
-				  DWORD dwOffset,		    // Our own write cursor.
-				  LPBYTE lpbSoundData,		    // Start of our data.
-				  DWORD dwSoundBytes)		    // Size of block to copy.
-{ 
-    LPVOID  lpvPtr1; 
-    DWORD dwBytes1; 
-    LPVOID  lpvPtr2; 
-    DWORD dwBytes2; 
-    HRESULT hr; 
-    
-    // Obtain memory address of write block. This will be in two parts
-    // if the block wraps around.
-    
-    hr = IDirectSoundCaptureBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 
-					 &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
-    
-    if SUCCEEDED(hr) { 
-	// Read from pointers. 
-	pj_memcpy(lpbSoundData, lpvPtr1, dwBytes1); 
-	if (lpvPtr2 != NULL)
-	    pj_memcpy(lpbSoundData+dwBytes1, lpvPtr2, dwBytes2); 
-	
-	// Release the data back to DirectSound. 
-	hr = IDirectSoundCaptureBuffer_Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); 
-	if SUCCEEDED(hr)
-	    return TRUE; 
-    } 
-    
-    // Lock, Unlock, or Restore failed. 
-    return FALSE; 
-}
-
-
-static BOOL AppWriteDataToBuffer(LPDIRECTSOUNDBUFFER lpDsb,  // The buffer.
-				 DWORD dwOffset,	      // Our own write cursor.
-				 LPBYTE lpbSoundData,	      // Start of our data.
-				 DWORD dwSoundBytes)	      // Size of block to copy.
-{ 
-    LPVOID  lpvPtr1; 
-    DWORD dwBytes1; 
-    LPVOID  lpvPtr2; 
-    DWORD dwBytes2; 
-    HRESULT hr; 
-    
-    // Obtain memory address of write block. This will be in two parts
-    // if the block wraps around.
-    
-    hr = IDirectSoundBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 
-				  &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
-    
-    // If the buffer was lost, restore and retry lock. 
-    if (DSERR_BUFFERLOST == hr) { 
-	IDirectSoundBuffer_Restore(lpDsb); 
-	hr = IDirectSoundBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, 
-				      &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
-    } 
-    if SUCCEEDED(hr) { 
-	pj_memcpy(lpvPtr1, lpbSoundData, dwBytes1); 
-	if (NULL != lpvPtr2) 
-	    pj_memcpy(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2); 
-	
-	hr = IDirectSoundBuffer_Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); 
-	if SUCCEEDED(hr)
-	    return TRUE; 
-    } 
-    
-    return FALSE; 
-}
-
-/*
- * Check if there is space in playing buffer.
- */
-static unsigned dsound_play_empty_size(struct dsound_stream *dsound_strm)
-{
-    HRESULT hr;
-    long size_available;
-    DWORD writePos, readPos;
-
-    hr = IDirectSoundBuffer_GetCurrentPosition(dsound_strm->ds.play.lpDsBuffer, 
-					       &readPos, &writePos);
-    if FAILED(hr)
-	return PJ_FALSE;
-
-    if (readPos < dsound_strm->dwBytePos)
-	size_available = readPos + dsound_strm->dwDsBufferSize - 
-			 dsound_strm->dwBytePos;
-    else
-	size_available = readPos - dsound_strm->dwBytePos;
-
-    return size_available;
-}
-
-
-/*
- * Check if there are captured frames in DirectSound capture buffer.
- */
-static unsigned dsound_captured_size(struct dsound_stream *dsound_strm)
-{
-    HRESULT hr;
-    long size_available;
-    DWORD writePos, readPos;
-
-    hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
-					dsound_strm->ds.capture.lpDsBuffer, 
-					&writePos, &readPos);
-    if FAILED(hr)
-	return PJ_FALSE;
-
-    if (readPos < dsound_strm->dwBytePos)
-	size_available = readPos +
-		    (dsound_strm->dwDsBufferSize) - dsound_strm->dwBytePos;
-    else
-	size_available = readPos - dsound_strm->dwBytePos;
-
-    return size_available;
-}
-
-/*
- * DirectSound capture and playback thread.
- */
-static int dsound_dev_thread(void *arg)
-{
-    pjmedia_snd_stream *strm = arg;
-    HANDLE events[3];
-    unsigned eventCount;
-    unsigned bytes_per_frame;
-    pj_status_t status;
-
-
-    eventCount = 0;
-    events[eventCount++] = strm->thread_quit_event;
-    if (strm->dir & PJMEDIA_DIR_PLAYBACK)
-	events[eventCount++] = strm->play_strm.hEvent;
-    if (strm->dir & PJMEDIA_DIR_CAPTURE)
-	events[eventCount++] = strm->rec_strm.hEvent;
-
-
-    /* Raise self priority. We don't want the audio to be distorted by
-     * system activity.
-     */
-    SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
-
-    /* Calculate bytes per frame */
-    bytes_per_frame = strm->samples_per_frame * BYTES_PER_SAMPLE;
-
-    /*
-     * Loop while not signalled to quit, wait for event objects to be 
-     * signalled by DirectSound capture and play buffer.
-     */
-    while (PJ_TRUE) {
-	
-	DWORD rc;
-	pjmedia_dir signalled_dir;
-
-	rc = WaitForMultipleObjects(eventCount, events, FALSE, INFINITE);
-	if (rc < WAIT_OBJECT_0 || rc >= WAIT_OBJECT_0+eventCount)
-	    continue;
-
-
-	if (rc == WAIT_OBJECT_0)
-		break;
-	if (rc == (WAIT_OBJECT_0 + 1)) {
-	    if (events[1] == strm->play_strm.hEvent)
-	        signalled_dir = PJMEDIA_DIR_PLAYBACK;
-	    else
-	        signalled_dir = PJMEDIA_DIR_CAPTURE;
-	} else {
-	    if (events[2] == strm->play_strm.hEvent)
-	        signalled_dir = PJMEDIA_DIR_PLAYBACK;
-	    else
-	        signalled_dir = PJMEDIA_DIR_CAPTURE;
-	}
-
-
-	if (signalled_dir == PJMEDIA_DIR_PLAYBACK) {
-	    
-	    struct dsound_stream *dsound_strm;
-
-	    /*
-	     * DirectSound has requested us to feed some frames to
-	     * playback buffer.
-	     */
-
-	    dsound_strm = &strm->play_strm;
-	    status = PJ_SUCCESS;
-
-	    while (dsound_play_empty_size(dsound_strm) > bytes_per_frame) {
-		/* Get frame from application. */
-		status = (*strm->play_cb)(strm->user_data, 
-					  dsound_strm->timestamp.u32.lo,
-					  strm->buffer,
-					  bytes_per_frame);
-		if (status != PJ_SUCCESS)
-		    break;
-
-		/* Write to DirectSound buffer. */
-		AppWriteDataToBuffer( dsound_strm->ds.play.lpDsBuffer, 
-				      dsound_strm->dwBytePos,
-				      (LPBYTE)strm->buffer, 
-				      bytes_per_frame);
-
-		/* Increment position. */
-		dsound_strm->dwBytePos += bytes_per_frame;
-		if (dsound_strm->dwBytePos >= dsound_strm->dwDsBufferSize)
-		    dsound_strm->dwBytePos -= dsound_strm->dwDsBufferSize;
-		dsound_strm->timestamp.u64 += strm->samples_per_frame;
-	    }
-
-	} else {
-	    /*
-	     * DirectSound has indicated that it has some frames ready
-	     * in the capture buffer. Get as much frames as possible to
-	     * prevent overflows.
-	     */
-	    struct dsound_stream *dsound_strm;
-	    BOOL rc;
-
-	    dsound_strm = &strm->rec_strm;
-
-	    /* Fetch while we have more than 1 frame */
-	    while (dsound_captured_size(dsound_strm) > bytes_per_frame) {
-
-		/* Capture from DirectSound buffer. */
-		rc = AppReadDataFromBuffer(dsound_strm->ds.capture.lpDsBuffer, 
-					   dsound_strm->dwBytePos,
-					   (LPBYTE)strm->buffer, 
-					   bytes_per_frame);
-        	
-		if (!rc) {
-		    pj_bzero(strm->buffer, bytes_per_frame);
-		} 
-
-		/* Call callback */
-		status = (*strm->rec_cb)(strm->user_data, 
-					 dsound_strm->timestamp.u32.lo, 
-					 strm->buffer, 
-					 bytes_per_frame);
-
-		/* Quit thread on error. */
-		if (status != PJ_SUCCESS)
-		    goto on_error;
-
-
-		/* Increment position. */
-		dsound_strm->dwBytePos += bytes_per_frame;
-		if (dsound_strm->dwBytePos >= dsound_strm->dwDsBufferSize)
-		    dsound_strm->dwBytePos -= dsound_strm->dwDsBufferSize;
-		dsound_strm->timestamp.u64 += strm->samples_per_frame;
-	    }
-	}
-    }
-
-
-on_error:
-    PJ_LOG(5,(THIS_FILE, "DirectSound: thread stopping.."));
-    return 0;
-}
-
-
-/* DirectSound enum device callback */
-static BOOL CALLBACK DSEnumCallback( LPGUID lpGuid, LPCTSTR lpcstrDescription,  
-				     LPCTSTR lpcstrModule, LPVOID lpContext)
-{
-    unsigned index, max = sizeof(dev_info[index].info.name);
-    pj_bool_t is_capture_device = (lpContext != NULL);
-
-
-    PJ_UNUSED_ARG(lpcstrModule);
-
-
-    /* Put the capture and playback of the same devices to the same 
-     * dev_info item, by looking at the GUID.
-     */
-    for (index=0; index<dev_count; ++index) {
-	if ((dev_info[index].lpGuid==NULL && lpGuid==NULL) ||
-	    pj_memcmp(&dev_info[index].guid, lpGuid, sizeof(GUID))==0)
-	{
-	    break;
-	}
-    }
-
-    if (index == dev_count)
-	++dev_count;
-    else if (dev_count >= MAX_HARDWARE) {
-	pj_assert(!"Too many DirectSound hardware found");
-	PJ_LOG(4,(THIS_FILE, "Too many hardware found, some devices will "
-			     "not be listed"));
-	return FALSE;
-    }
-
-#ifdef UNICODE
-    WideCharToMultiByte(CP_ACP, 0, lpcstrDescription, wcslen(lpcstrDescription),
-			dev_info[index].info.name, max, NULL, NULL);
-#else
-    strncpy(dev_info[index].info.name, lpcstrDescription, max);
-#endif
-
-    dev_info[index].info.name[max-1] = '\0';
-    if (lpGuid == NULL) {
-	dev_info[index].lpGuid = NULL;
-    } else {
-	pj_memcpy(&dev_info[index].guid, lpGuid, sizeof(GUID));
-	dev_info[index].lpGuid = &dev_info[index].guid;
-    }
-    dev_info[index].info.default_samples_per_sec = 44100;
-    
-    /* Just assumed that device supports stereo capture/playback */
-    if (is_capture_device)
-	dev_info[index].info.input_count+=2;
-    else
-	dev_info[index].info.output_count+=2;
-
-    return TRUE;
-}
-
-
-/*
- * Init sound library.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
-{
-    HRESULT hr;
-    unsigned i;
-
-    if (++snd_init_count != 1)
-	return PJ_SUCCESS;
-
-    pool_factory = factory;
-
-    /* Enumerate sound playback devices */
-    hr = DirectSoundEnumerate(&DSEnumCallback, NULL);
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-    /* Enumerate sound capture devices */
-    hr = DirectSoundCaptureEnumerate(&DSEnumCallback, (void*)1);
-    if (FAILED(hr))
-	return PJ_RETURN_OS_ERROR(hr);
-
-    PJ_LOG(4,(THIS_FILE, "DirectSound initialized, found %d devices:",
-	      dev_count));
-    for (i=0; i<dev_count; ++i) {
-	PJ_LOG(4,(THIS_FILE, " dev_id %d: %s  (in=%d, out=%d)", 
-		  i, dev_info[i].info.name, 
-		  dev_info[i].info.input_count, 
-		  dev_info[i].info.output_count));
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Deinitialize sound library.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
-{
-    --snd_init_count;
-    return PJ_SUCCESS;
-}
-
-/*
- * Get device count.
- */
-PJ_DEF(int) pjmedia_snd_get_dev_count(void)
-{
-    return dev_count;
-}
-
-/*
- * Get device info.
- */
-PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
-{
-    if (index == (unsigned)-1) 
-	index = 0;
-
-    PJ_ASSERT_RETURN(index < dev_count, NULL);
-
-    return &dev_info[index].info;
-}
-
-
-/*
- * Open stream.
- */
-static pj_status_t open_stream( 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,
-				pjmedia_snd_stream **p_snd_strm)
-{
-    pj_pool_t *pool;
-    pjmedia_snd_stream *strm;
-    pj_status_t status;
-
-    /* Make sure sound subsystem has been initialized with
-     * pjmedia_snd_init()
-     */
-    PJ_ASSERT_RETURN( pool_factory != NULL, PJ_EINVALIDOP );
-
-
-    /* Can only support 16bits per sample */
-    PJ_ASSERT_RETURN(bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);
-
-    /* Create and Initialize stream descriptor */
-    pool = pj_pool_create(pool_factory, "dsound-dev", 1000, 1000, NULL);
-    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
-
-    strm = pj_pool_zalloc(pool, sizeof(pjmedia_snd_stream));
-    strm->dir = dir;
-    strm->play_id = play_id;
-    strm->rec_id = rec_id;
-    strm->pool = pool;
-    strm->rec_cb = rec_cb;
-    strm->play_cb = play_cb;
-    strm->user_data = user_data;
-    strm->clock_rate = clock_rate;
-    strm->samples_per_frame = samples_per_frame;
-    strm->bits_per_sample = bits_per_sample;
-    strm->channel_count = channel_count;
-    strm->buffer = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE);
-    if (!strm->buffer) {
-	pj_pool_release(pool);
-	return PJ_ENOMEM;
-    }
-
-    /*
-     * Create event for stopping the worker thread.
-     */
-    strm->thread_quit_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (strm->thread_quit_event == NULL) {
-	status = pj_get_os_error();
-	pj_pool_release(pool);
-	return status;
-    }
-
-    /* Create player stream */
-    if (dir & PJMEDIA_DIR_PLAYBACK) {
-	unsigned buffer_count;
-	
-	/* Calculate buffer count, in frame unit */
-	buffer_count = clock_rate * snd_output_latency / samples_per_frame /
-		       1000;
-	/* There must always be one more buffer than required for the latency */
-	buffer_count += 1;
-	if (buffer_count < MIN_PACKET_BUFFER_COUNT)
-	    buffer_count = MIN_PACKET_BUFFER_COUNT;
-	if (buffer_count > MAX_PACKET_BUFFER_COUNT)
-	    buffer_count = MAX_PACKET_BUFFER_COUNT;
-
-	status = init_player_stream( &strm->play_strm, play_id, clock_rate,
-				     channel_count, samples_per_frame,
-				     buffer_count );
-	if (status != PJ_SUCCESS) {
-	    pjmedia_snd_stream_close(strm);
-	    return status;
-	}
-    }
-
-    /* Create capture stream */
-    if (dir & PJMEDIA_DIR_CAPTURE) {
-	unsigned buffer_count;
-	
-	/* Calculate buffer count, in frame unit */
-	buffer_count = clock_rate * snd_input_latency / samples_per_frame /
-		       1000;
-	if (buffer_count < MIN_PACKET_BUFFER_COUNT)
-	    buffer_count = MIN_PACKET_BUFFER_COUNT;
-	if (buffer_count > MAX_PACKET_BUFFER_COUNT)
-	    buffer_count = MAX_PACKET_BUFFER_COUNT;
-
-	status = init_capture_stream( &strm->rec_strm, rec_id, clock_rate,
-				      channel_count, samples_per_frame,
-				      buffer_count);
-	if (status != PJ_SUCCESS) {
-	    pjmedia_snd_stream_close(strm);
-	    return status;
-	}
-    }
-
-
-    /* Create and start the thread */
-    status = pj_thread_create(pool, "dsound", &dsound_dev_thread, strm,
-			      0, 0, &strm->thread);
-    if (status != PJ_SUCCESS) {
-	pjmedia_snd_stream_close(strm);
-	return status;
-    }
-
-    *p_snd_strm = strm;
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Open stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
-					  unsigned clock_rate,
-					  unsigned channel_count,
-					  unsigned samples_per_frame,
-					  unsigned bits_per_sample,
-					  pjmedia_snd_rec_cb rec_cb,
-					  void *user_data,
-					  pjmedia_snd_stream **p_snd_strm)
-{
-    PJ_ASSERT_RETURN(rec_cb && p_snd_strm, PJ_EINVAL);
-
-    return open_stream( PJMEDIA_DIR_CAPTURE, index, -1,
-			clock_rate, channel_count, samples_per_frame,
-			bits_per_sample, rec_cb, NULL, user_data,
-			p_snd_strm);
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
-					unsigned clock_rate,
-					unsigned channel_count,
-					unsigned samples_per_frame,
-					unsigned bits_per_sample,
-					pjmedia_snd_play_cb play_cb,
-					void *user_data,
-					pjmedia_snd_stream **p_snd_strm)
-{
-    PJ_ASSERT_RETURN(play_cb && p_snd_strm, PJ_EINVAL);
-
-    return open_stream( PJMEDIA_DIR_PLAYBACK, -1, index,
-			clock_rate, channel_count, samples_per_frame,
-			bits_per_sample, NULL, play_cb, user_data,
-			p_snd_strm);
-}
-
-/*
- * Open both player and recorder.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_open( 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,
-				      pjmedia_snd_stream **p_snd_strm)
-{
-    PJ_ASSERT_RETURN(rec_cb && play_cb && p_snd_strm, PJ_EINVAL);
-
-    return open_stream( PJMEDIA_DIR_CAPTURE_PLAYBACK, rec_id, play_id,
-			clock_rate, channel_count, samples_per_frame,
-			bits_per_sample, rec_cb, play_cb, user_data,
-			p_snd_strm );
-}
-
-/*
- * Get stream info.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
-						pjmedia_snd_stream_info *pi)
-{
-
-    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
-
-    pj_bzero(pi, sizeof(*pi));
-    pi->dir = strm->dir;
-    pi->play_id = strm->play_id;
-    pi->rec_id = strm->rec_id;
-    pi->clock_rate = strm->clock_rate;
-    pi->channel_count = strm->channel_count;
-    pi->samples_per_frame = strm->samples_per_frame;
-    pi->bits_per_sample = strm->bits_per_sample;
-    pi->rec_latency = strm->rec_strm.latency * strm->clock_rate * 
-		      strm->channel_count/ 1000;
-    pi->play_latency = strm->play_strm.latency * strm->clock_rate * 
-		       strm->channel_count/ 1000;
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Start stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
-{
-    HRESULT hr;
-
-    if (stream->play_strm.ds.play.lpDsBuffer) {
-	hr = IDirectSoundBuffer_SetCurrentPosition(
-				stream->play_strm.ds.play.lpDsBuffer, 0);
-	if (FAILED(hr))
-	    return PJ_RETURN_OS_ERROR(hr);
-	
-	/* Set the write pointer ahead of the read pointer by latency bytes */
-	stream->play_strm.dwBytePos = BYTES_PER_SAMPLE * stream->clock_rate *
-		stream->channel_count * stream->play_strm.latency / 1000;
-
-	hr = IDirectSoundBuffer_Play(stream->play_strm.ds.play.lpDsBuffer, 
-				     0, 0, DSBPLAY_LOOPING);
-	if (FAILED(hr))
-	    return PJ_RETURN_OS_ERROR(hr);
-	PJ_LOG(5,(THIS_FILE, "DirectSound playback stream started"));
-    }
-    
-    if (stream->rec_strm.ds.capture.lpDsBuffer) {
-	hr = IDirectSoundCaptureBuffer_GetCurrentPosition( 
-				stream->rec_strm.ds.capture.lpDsBuffer, 
-				NULL, &stream->rec_strm.dwBytePos );
-	if (FAILED(hr))
-	    return PJ_RETURN_OS_ERROR(hr);
-
-	hr = IDirectSoundCaptureBuffer_Start(
-				stream->rec_strm.ds.capture.lpDsBuffer,
-				DSCBSTART_LOOPING );
-	if (FAILED(hr))
-	    return PJ_RETURN_OS_ERROR(hr);
-	PJ_LOG(5,(THIS_FILE, "DirectSound capture stream started"));
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Stop stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
-{
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-
-    if (stream->play_strm.ds.play.lpDsBuffer) {
-	PJ_LOG(5,(THIS_FILE, "Stopping DirectSound playback stream"));
-	IDirectSoundBuffer_Stop( stream->play_strm.ds.play.lpDsBuffer );
-    }
-
-    if (stream->rec_strm.ds.capture.lpDsBuffer) {
-	PJ_LOG(5,(THIS_FILE, "Stopping DirectSound capture stream"));
-	IDirectSoundCaptureBuffer_Stop(stream->rec_strm.ds.capture.lpDsBuffer);
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Destroy stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
-{
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-
-    pjmedia_snd_stream_stop(stream);
-
-    if (stream->thread) {
-	pj_assert(stream->thread_quit_event);
-	SetEvent(stream->thread_quit_event);
-	pj_thread_join(stream->thread);
-	pj_thread_destroy(stream->thread);
-	stream->thread = NULL;
-    }
-
-    if (stream->thread_quit_event) {
-	CloseHandle(stream->thread_quit_event);
-	stream->thread_quit_event = NULL;
-    }
-
-    if (stream->play_strm.lpDsNotify) {
-	IDirectSoundNotify_Release( stream->play_strm.lpDsNotify );
-	stream->play_strm.lpDsNotify = NULL;
-    }
-    
-    if (stream->play_strm.hEvent) {
-	CloseHandle(stream->play_strm.hEvent);
-	stream->play_strm.hEvent = NULL;
-    }
-
-    if (stream->play_strm.ds.play.lpDsBuffer) {
-	IDirectSoundBuffer_Release( stream->play_strm.ds.play.lpDsBuffer );
-	stream->play_strm.ds.play.lpDsBuffer = NULL;
-    }
-
-    if (stream->play_strm.ds.play.lpDs) {
-	IDirectSound_Release( stream->play_strm.ds.play.lpDs );
-	stream->play_strm.ds.play.lpDs = NULL;
-    }
-
-    if (stream->rec_strm.lpDsNotify) {
-	IDirectSoundNotify_Release( stream->rec_strm.lpDsNotify );
-	stream->rec_strm.lpDsNotify = NULL;
-    }
-    
-    if (stream->rec_strm.hEvent) {
-	CloseHandle(stream->rec_strm.hEvent);
-	stream->rec_strm.hEvent = NULL;
-    }
-
-    if (stream->rec_strm.ds.capture.lpDsBuffer) {
-	IDirectSoundCaptureBuffer_Release( stream->rec_strm.ds.capture.lpDsBuffer );
-	stream->rec_strm.ds.capture.lpDsBuffer = NULL;
-    }
-
-    if (stream->rec_strm.ds.capture.lpDs) {
-	IDirectSoundCapture_Release( stream->rec_strm.ds.capture.lpDs );
-	stream->rec_strm.ds.capture.lpDs = NULL;
-    }
-
-
-    pj_pool_release(stream->pool);
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Set sound latency.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, 
-					    unsigned output_latency)
-{
-    snd_input_latency  = (input_latency == 0)? 
-			 PJMEDIA_SND_DEFAULT_REC_LATENCY : input_latency;
-    snd_output_latency = (output_latency == 0)? 
-			 PJMEDIA_SND_DEFAULT_PLAY_LATENCY : output_latency;
-
-    return PJ_SUCCESS;
-}
-
-#endif	/* PJMEDIA_SOUND_IMPLEMENTATION */
-
Index: project/branches/projects/aps-direct/pjmedia/src/pjmedia/nullsound.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/nullsound.c	(revision 2488)
+++ 	(revision )
@@ -1,197 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
- * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#include <pjmedia/sound.h>
-#include <pjmedia/errno.h>
-#include <pj/assert.h>
-#include <pj/pool.h>
-
-#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_NULL_SOUND
-
-static pjmedia_snd_dev_info null_info = 
-{
-    "Null Device",
-    1,
-    1,
-    8000
-};
-
-static pj_pool_factory *pool_factory;
-
-struct pjmedia_snd_stream 
-{
-	pj_pool_t		*pool;
-	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;
-};
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
-{
-    pool_factory = factory;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
-{
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(int) pjmedia_snd_get_dev_count(void)
-{
-    return 1;
-}
-
-PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
-{
-    PJ_ASSERT_RETURN(index==0 || index==(unsigned)-1, NULL);
-    return &null_info;
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
-					  unsigned clock_rate,
-					  unsigned channel_count,
-					  unsigned samples_per_frame,
-					  unsigned bits_per_sample,
-					  pjmedia_snd_rec_cb rec_cb,
-					  void *user_data,
-					  pjmedia_snd_stream **p_snd_strm)
-{
-    return pjmedia_snd_open(index, -2, clock_rate, channel_count,
-    			    samples_per_frame, bits_per_sample,
-    			    rec_cb, NULL, user_data, p_snd_strm);
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
-					unsigned clock_rate,
-					unsigned channel_count,
-					unsigned samples_per_frame,
-					unsigned bits_per_sample,
-					pjmedia_snd_play_cb play_cb,
-					void *user_data,
-					pjmedia_snd_stream **p_snd_strm )
-{
-    return pjmedia_snd_open(-2, index, clock_rate, channel_count,
-    			    samples_per_frame, bits_per_sample,
-    			    NULL, play_cb, user_data, p_snd_strm);
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_open( 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,
-				      pjmedia_snd_stream **p_snd_strm)
-{
-    pj_pool_t *pool;
-    pjmedia_snd_stream *snd_strm;
-
-    pool = pj_pool_create(pool_factory, NULL, 128, 128, NULL);
-    snd_strm = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
-    
-    snd_strm->pool = pool;
-    
-    if (rec_id == -1) rec_id = 0;
-    if (play_id == -1) play_id = 0;
-    
-    if (rec_id != -2 && play_id != -2)
-    	snd_strm->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
-    else if (rec_id != -2)
-    	snd_strm->dir = PJMEDIA_DIR_CAPTURE;
-    else if (play_id != -2)
-    	snd_strm->dir = PJMEDIA_DIR_PLAYBACK;
-    
-    snd_strm->rec_id = rec_id;
-    snd_strm->play_id = play_id;
-    snd_strm->clock_rate = clock_rate;
-    snd_strm->channel_count = channel_count;
-    snd_strm->samples_per_frame = samples_per_frame;
-    snd_strm->bits_per_sample = bits_per_sample;
-    snd_strm->rec_cb = rec_cb;
-    snd_strm->play_cb = play_cb;
-    snd_strm->user_data = user_data;
-    
-    *p_snd_strm = snd_strm;
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
-{
-    PJ_UNUSED_ARG(stream);
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
-{
-    PJ_UNUSED_ARG(stream);
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
-						pjmedia_snd_stream_info *pi)
-{
-
-    pj_bzero(pi, sizeof(pjmedia_snd_stream_info));
-    pi->dir = strm->dir;
-    pi->play_id = strm->play_id;
-    pi->rec_id = strm->rec_id;
-    pi->clock_rate = strm->clock_rate;
-    pi->channel_count = strm->channel_count;
-    pi->samples_per_frame = strm->samples_per_frame;
-    pi->bits_per_sample = strm->bits_per_sample;
-    pi->rec_latency = 0;
-    pi->play_latency = 0;
-    
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
-{
-    pj_pool_release(stream->pool);
-    return PJ_SUCCESS;
-}
-
-/*
- * Set sound latency.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, 
-					    unsigned output_latency)
-{
-    /* Nothing to do */
-    PJ_UNUSED_ARG(input_latency);
-    PJ_UNUSED_ARG(output_latency);
-    return PJ_SUCCESS;
-}
-
-#endif	/* PJMEDIA_SOUND_IMPLEMENTATION */
Index: project/branches/projects/aps-direct/pjmedia/src/pjmedia/pasound.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/pasound.c	(revision 2488)
+++ 	(revision )
@@ -1,1037 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
- * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#include <pjmedia/sound.h>
-#include <pjmedia/errno.h>
-#include <pj/assert.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/string.h>
-#include <portaudio.h>
-
-#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_PORTAUDIO_SOUND
-
-#define THIS_FILE	"pasound.c"
-
-static int snd_init_count;
-
-/* Latency settings */
-static unsigned snd_input_latency  = PJMEDIA_SND_DEFAULT_REC_LATENCY;
-static unsigned snd_output_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
-
-static struct snd_mgr
-{
-    pj_pool_factory *factory;
-} snd_mgr;
-
-/* 
- * Sound stream descriptor.
- * This struct may be used for both unidirectional or bidirectional sound
- * streams.
- */
-struct pjmedia_snd_stream
-{
-    pj_pool_t		*pool;
-    pj_str_t		 name;
-    pjmedia_dir		 dir;
-    int			 play_id;
-    int			 rec_id;
-    int			 bytes_per_sample;
-    pj_uint32_t		 samples_per_sec;
-    unsigned		 samples_per_frame;
-    int			 channel_count;
-
-    PaStream		*rec_strm;
-    PaStream		*play_strm;
-
-    void		*user_data;
-    pjmedia_snd_rec_cb   rec_cb;
-    pjmedia_snd_play_cb  play_cb;
-
-    pj_uint32_t		 play_timestamp;
-    pj_uint32_t		 rec_timestamp;
-    pj_uint32_t		 underflow;
-    pj_uint32_t		 overflow;
-
-    pj_bool_t		 quit_flag;
-
-    pj_bool_t		 rec_thread_exited;
-    pj_bool_t		 rec_thread_initialized;
-    pj_thread_desc	 rec_thread_desc;
-    pj_thread_t		*rec_thread;
-
-    pj_bool_t		 play_thread_exited;
-    pj_bool_t		 play_thread_initialized;
-    pj_thread_desc	 play_thread_desc;
-    pj_thread_t		*play_thread;
-
-    /* Sometime the record callback does not return framesize as configured
-     * (e.g: in OSS), while this module must guarantee returning framesize
-     * as configured in the creation settings. In this case, we need a buffer 
-     * for the recorded samples.
-     */
-    pj_int16_t		*rec_buf;
-    unsigned		 rec_buf_count;
-
-    /* Sometime the player callback does not request framesize as configured
-     * (e.g: in Linux OSS) while sound device will always get samples from 
-     * the other component as many as configured samples_per_frame. 
-     */
-    pj_int16_t		*play_buf;
-    unsigned		 play_buf_count;
-};
-
-
-static int PaRecorderCallback(const void *input, 
-			      void *output,
-			      unsigned long frameCount,
-			      const PaStreamCallbackTimeInfo* timeInfo,
-			      PaStreamCallbackFlags statusFlags,
-			      void *userData )
-{
-    pjmedia_snd_stream *stream = (pjmedia_snd_stream*) userData;
-    pj_status_t status = 0;
-    unsigned nsamples;
-
-    PJ_UNUSED_ARG(output);
-    PJ_UNUSED_ARG(timeInfo);
-
-    if (stream->quit_flag)
-	goto on_break;
-
-    if (input == NULL)
-	return paContinue;
-
-    /* Known cases of callback's thread:
-     * - The thread may be changed in the middle of a session, e.g: in MacOS 
-     *   it happens when plugging/unplugging headphone.
-     * - The same thread may be reused in consecutive sessions. The first
-     *   session will leave TLS set, but release the TLS data address,
-     *   so the second session must re-register the callback's thread.
-     */
-    if (stream->rec_thread_initialized == 0 || !pj_thread_is_registered()) 
-    {
-	status = pj_thread_register("pa_rec", stream->rec_thread_desc, 
-				    &stream->rec_thread);
-	stream->rec_thread_initialized = 1;
-	PJ_LOG(5,(THIS_FILE, "Recorder thread started"));
-    }
-
-    if (statusFlags & paInputUnderflow)
-	++stream->underflow;
-    if (statusFlags & paInputOverflow)
-	++stream->overflow;
-
-    stream->rec_timestamp += frameCount;
-
-    /* Calculate number of samples we've got */
-    nsamples = frameCount * stream->channel_count + stream->rec_buf_count;
-
-    if (nsamples >= stream->samples_per_frame) 
-    {
-	/* If buffer is not empty, combine the buffer with the just incoming
-	 * samples, then call put_frame.
-	 */
-	if (stream->rec_buf_count) {
-	    unsigned chunk_count = 0;
-	
-	    chunk_count = stream->samples_per_frame - stream->rec_buf_count;
-	    pjmedia_copy_samples(stream->rec_buf + stream->rec_buf_count,
-				 (pj_int16_t*)input, chunk_count);
-	    status = (*stream->rec_cb)(stream->user_data, 
-				       stream->rec_timestamp,
-				       (void*) stream->rec_buf, 
-				       stream->samples_per_frame * 
-				       stream->bytes_per_sample);
-
-	    input = (pj_int16_t*) input + chunk_count;
-	    nsamples -= stream->samples_per_frame;
-	    stream->rec_buf_count = 0;
-	}
-
-	/* Give all frames we have */
-	while (nsamples >= stream->samples_per_frame && status == 0) {
-	    status = (*stream->rec_cb)(stream->user_data, 
-				       stream->rec_timestamp,
-				       (void*) input, 
-				       stream->samples_per_frame * 
-				       stream->bytes_per_sample);
-	    input = (pj_int16_t*) input + stream->samples_per_frame;
-	    nsamples -= stream->samples_per_frame;
-	}
-
-	/* Store the remaining samples into the buffer */
-	if (nsamples && status == 0) {
-	    stream->rec_buf_count = nsamples;
-	    pjmedia_copy_samples(stream->rec_buf, (pj_int16_t*)input, 
-			         nsamples);
-	}
-
-    } else {
-	/* Not enough samples, let's just store them in the buffer */
-	pjmedia_copy_samples(stream->rec_buf + stream->rec_buf_count,
-			     (pj_int16_t*)input, 
-			     frameCount * stream->channel_count);
-	stream->rec_buf_count += frameCount * stream->channel_count;
-    }
-
-    if (status==0) 
-	return paContinue;
-
-on_break:
-    stream->rec_thread_exited = 1;
-    return paAbort;
-}
-
-static int PaPlayerCallback( const void *input, 
-			     void *output,
-			     unsigned long frameCount,
-			     const PaStreamCallbackTimeInfo* timeInfo,
-			     PaStreamCallbackFlags statusFlags,
-			     void *userData )
-{
-    pjmedia_snd_stream *stream = (pjmedia_snd_stream*) userData;
-    pj_status_t status = 0;
-    unsigned nsamples_req = frameCount * stream->channel_count;
-
-    PJ_UNUSED_ARG(input);
-    PJ_UNUSED_ARG(timeInfo);
-
-    if (stream->quit_flag)
-	goto on_break;
-
-    if (output == NULL)
-	return paContinue;
-
-    /* Known cases of callback's thread:
-     * - The thread may be changed in the middle of a session, e.g: in MacOS 
-     *   it happens when plugging/unplugging headphone.
-     * - The same thread may be reused in consecutive sessions. The first
-     *   session will leave TLS set, but release the TLS data address,
-     *   so the second session must re-register the callback's thread.
-     */
-    if (stream->play_thread_initialized == 0 || !pj_thread_is_registered()) 
-    {
-	status = pj_thread_register("portaudio", stream->play_thread_desc,
-				    &stream->play_thread);
-	stream->play_thread_initialized = 1;
-	PJ_LOG(5,(THIS_FILE, "Player thread started"));
-    }
-
-    if (statusFlags & paOutputUnderflow)
-	++stream->underflow;
-    if (statusFlags & paOutputOverflow)
-	++stream->overflow;
-
-    stream->play_timestamp += frameCount;
-
-    /* Check if any buffered samples */
-    if (stream->play_buf_count) {
-	/* samples buffered >= requested by sound device */
-	if (stream->play_buf_count >= nsamples_req) {
-	    pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf, 
-				 nsamples_req);
-	    stream->play_buf_count -= nsamples_req;
-	    pjmedia_move_samples(stream->play_buf, 
-				 stream->play_buf + nsamples_req,
-				 stream->play_buf_count);
-	    nsamples_req = 0;
-	    
-	    return paContinue;
-	}
-
-	/* samples buffered < requested by sound device */
-	pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf, 
-			     stream->play_buf_count);
-	nsamples_req -= stream->play_buf_count;
-	output = (pj_int16_t*)output + stream->play_buf_count;
-	stream->play_buf_count = 0;
-    }
-
-    /* Fill output buffer as requested */
-    while (nsamples_req && status == 0) {
-	if (nsamples_req >= stream->samples_per_frame) {
-	    status = (*stream->play_cb)(stream->user_data, 
-					stream->play_timestamp, 
-					output, 
-					stream->samples_per_frame * 
-					stream->bytes_per_sample);
-	    nsamples_req -= stream->samples_per_frame;
-	    output = (pj_int16_t*)output + stream->samples_per_frame;
-	} else {
-	    status = (*stream->play_cb)(stream->user_data, 
-					stream->play_timestamp, 
-					stream->play_buf,
-					stream->samples_per_frame * 
-					stream->bytes_per_sample);
-	    pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf, 
-				 nsamples_req);
-	    stream->play_buf_count = stream->samples_per_frame - nsamples_req;
-	    pjmedia_move_samples(stream->play_buf, 
-				 stream->play_buf+nsamples_req,
-				 stream->play_buf_count);
-	    nsamples_req = 0;
-	}
-    }
-    
-    if (status==0) 
-	return paContinue;
-
-on_break:
-    stream->play_thread_exited = 1;
-    return paAbort;
-}
-
-
-static int PaRecorderPlayerCallback( const void *input, 
-				     void *output,
-				     unsigned long frameCount,
-				     const PaStreamCallbackTimeInfo* timeInfo,
-				     PaStreamCallbackFlags statusFlags,
-				     void *userData )
-{
-    int rc;
-
-    rc = PaRecorderCallback(input, output, frameCount, timeInfo,
-			    statusFlags, userData);
-    if (rc != paContinue)
-	return rc;
-
-    rc = PaPlayerCallback(input, output, frameCount, timeInfo,
-			  statusFlags, userData);
-    return rc;
-}
-
-/* Logging callback from PA */
-static void pa_log_cb(const char *log)
-{
-    PJ_LOG(5,(THIS_FILE, "PA message: %s", log));
-}
-
-/* We should include pa_debugprint.h for this, but the header
- * is not available publicly. :(
- */
-typedef void (*PaUtilLogCallback ) (const char *log);
-void PaUtil_SetDebugPrintFunction(PaUtilLogCallback  cb);
-
-/*
- * Init sound library.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
-{
-    if (++snd_init_count == 1) {
-	int err;
-
-	PaUtil_SetDebugPrintFunction(&pa_log_cb);
-
-	snd_mgr.factory = factory;
-	err = Pa_Initialize();
-
-	PJ_LOG(4,(THIS_FILE, 
-		  "PortAudio sound library initialized, status=%d", err));
-	PJ_LOG(4,(THIS_FILE, "PortAudio host api count=%d",
-			     Pa_GetHostApiCount()));
-	PJ_LOG(4,(THIS_FILE, "Sound device count=%d",
-			     pjmedia_snd_get_dev_count()));
-
-	return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
-    } else {
-	return PJ_SUCCESS;
-    }
-}
-
-
-/*
- * Get device count.
- */
-PJ_DEF(int) pjmedia_snd_get_dev_count(void)
-{
-    int count = Pa_GetDeviceCount();
-    return count < 0 ? 0 : count;
-}
-
-
-/*
- * Get device info.
- */
-PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
-{
-    static pjmedia_snd_dev_info info;
-    const PaDeviceInfo *pa_info;
-
-    pa_info = Pa_GetDeviceInfo(index);
-    if (!pa_info)
-	return NULL;
-
-    pj_bzero(&info, sizeof(info));
-    strncpy(info.name, pa_info->name, sizeof(info.name));
-    info.name[sizeof(info.name)-1] = '\0';
-    info.input_count = pa_info->maxInputChannels;
-    info.output_count = pa_info->maxOutputChannels;
-    info.default_samples_per_sec = (unsigned)pa_info->defaultSampleRate;
-
-    return &info;
-}
-
-
-/* Get PortAudio default input device ID */
-static int pa_get_default_input_dev(int channel_count)
-{
-    int i, count;
-
-    /* Special for Windows - try to use the DirectSound implementation
-     * first since it provides better latency.
-     */
-#if PJMEDIA_PREFER_DIRECT_SOUND
-    if (Pa_HostApiTypeIdToHostApiIndex(paDirectSound) >= 0) {
-	const PaHostApiInfo *pHI;
-	int index = Pa_HostApiTypeIdToHostApiIndex(paDirectSound);
-	pHI = Pa_GetHostApiInfo(index);
-	if (pHI) {
-	    const PaDeviceInfo *paDevInfo = NULL;
-	    paDevInfo = Pa_GetDeviceInfo(pHI->defaultInputDevice);
-	    if (paDevInfo && paDevInfo->maxInputChannels >= channel_count)
-		return pHI->defaultInputDevice;
-	}
-    }
-#endif
-
-    /* Enumerate the host api's for the default devices, and return
-     * the device with suitable channels.
-     */
-    count = Pa_GetHostApiCount();
-    for (i=0; i < count; ++i) {
-	const PaHostApiInfo *pHAInfo;
-
-	pHAInfo = Pa_GetHostApiInfo(i);
-	if (!pHAInfo)
-	    continue;
-
-	if (pHAInfo->defaultInputDevice >= 0) {
-	    const PaDeviceInfo *paDevInfo;
-
-	    paDevInfo = Pa_GetDeviceInfo(pHAInfo->defaultInputDevice);
-
-	    if (paDevInfo->maxInputChannels >= channel_count)
-		return pHAInfo->defaultInputDevice;
-	}
-    }
-
-    /* If still no device is found, enumerate all devices */
-    count = pjmedia_snd_get_dev_count();
-    for (i=0; i<count; ++i) {
-	const PaDeviceInfo *paDevInfo;
-
-	paDevInfo = Pa_GetDeviceInfo(i);
-	if (paDevInfo->maxInputChannels >= channel_count)
-	    return i;
-    }
-    
-    return -1;
-}
-
-/* Get PortAudio default output device ID */
-static int pa_get_default_output_dev(int channel_count)
-{
-    int i, count;
-
-    /* Special for Windows - try to use the DirectSound implementation
-     * first since it provides better latency.
-     */
-#if PJMEDIA_PREFER_DIRECT_SOUND
-    if (Pa_HostApiTypeIdToHostApiIndex(paDirectSound) >= 0) {
-	const PaHostApiInfo *pHI;
-	int index = Pa_HostApiTypeIdToHostApiIndex(paDirectSound);
-	pHI = Pa_GetHostApiInfo(index);
-	if (pHI) {
-	    const PaDeviceInfo *paDevInfo = NULL;
-	    paDevInfo = Pa_GetDeviceInfo(pHI->defaultOutputDevice);
-	    if (paDevInfo && paDevInfo->maxOutputChannels >= channel_count)
-		return pHI->defaultOutputDevice;
-	}
-    }
-#endif
-
-    /* Enumerate the host api's for the default devices, and return
-     * the device with suitable channels.
-     */
-    count = Pa_GetHostApiCount();
-    for (i=0; i < count; ++i) {
-	const PaHostApiInfo *pHAInfo;
-
-	pHAInfo = Pa_GetHostApiInfo(i);
-	if (!pHAInfo)
-	    continue;
-
-	if (pHAInfo->defaultOutputDevice >= 0) {
-	    const PaDeviceInfo *paDevInfo;
-
-	    paDevInfo = Pa_GetDeviceInfo(pHAInfo->defaultOutputDevice);
-
-	    if (paDevInfo->maxOutputChannels >= channel_count)
-		return pHAInfo->defaultOutputDevice;
-	}
-    }
-
-    /* If still no device is found, enumerate all devices */
-    count = pjmedia_snd_get_dev_count();
-    for (i=0; i<count; ++i) {
-	const PaDeviceInfo *paDevInfo;
-
-	paDevInfo = Pa_GetDeviceInfo(i);
-	if (paDevInfo->maxOutputChannels >= channel_count)
-	    return i;
-    }
-
-    return -1;
-}
-
-
-/*
- * Open stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
-					  unsigned clock_rate,
-					  unsigned channel_count,
-					  unsigned samples_per_frame,
-					  unsigned bits_per_sample,
-					  pjmedia_snd_rec_cb rec_cb,
-					  void *user_data,
-					  pjmedia_snd_stream **p_snd_strm)
-{
-    pj_pool_t *pool;
-    pjmedia_snd_stream *stream;
-    PaStreamParameters inputParam;
-    int sampleFormat;
-    const PaDeviceInfo *paDevInfo = NULL;
-    const PaHostApiInfo *paHostApiInfo = NULL;
-    unsigned paFrames, paRate, paLatency;
-    const PaStreamInfo *paSI;
-    PaError err;
-
-    if (index < 0) {
-	index = pa_get_default_input_dev(channel_count);
-	if (index < 0) {
-	    /* No such device. */
-	    return PJMEDIA_ENOSNDREC;
-	}
-    }
-
-    paDevInfo = Pa_GetDeviceInfo(index);
-    if (!paDevInfo) {
-	/* Assumed it is "No such device" error. */
-	return PJMEDIA_ESNDINDEVID;
-    }
-
-    if (bits_per_sample == 8)
-	sampleFormat = paUInt8;
-    else if (bits_per_sample == 16)
-	sampleFormat = paInt16;
-    else if (bits_per_sample == 32)
-	sampleFormat = paInt32;
-    else
-	return PJMEDIA_ESNDINSAMPLEFMT;
-    
-    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
-    if (!pool)
-	return PJ_ENOMEM;
-
-    stream = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
-    stream->pool = pool;
-    pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
-    stream->dir = PJMEDIA_DIR_CAPTURE;
-    stream->rec_id = index;
-    stream->play_id = -1;
-    stream->user_data = user_data;
-    stream->samples_per_sec = clock_rate;
-    stream->samples_per_frame = samples_per_frame;
-    stream->bytes_per_sample = bits_per_sample / 8;
-    stream->channel_count = channel_count;
-    stream->rec_cb = rec_cb;
-
-    stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool, 
-		      stream->samples_per_frame * stream->bytes_per_sample);
-    stream->rec_buf_count = 0;
-
-    pj_bzero(&inputParam, sizeof(inputParam));
-    inputParam.device = index;
-    inputParam.channelCount = channel_count;
-    inputParam.hostApiSpecificStreamInfo = NULL;
-    inputParam.sampleFormat = sampleFormat;
-    inputParam.suggestedLatency = snd_input_latency / 1000.0;
-
-    paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi);
-
-    /* Frames in PortAudio is number of samples in a single channel */
-    paFrames = samples_per_frame / channel_count;
-
-    err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL,
-			 clock_rate, paFrames, 
-			 paClipOff, &PaRecorderCallback, stream );
-    if (err != paNoError) {
-	pj_pool_release(pool);
-	return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
-    }
-
-    paSI = Pa_GetStreamInfo(stream->rec_strm);
-    paRate = (unsigned)paSI->sampleRate;
-    paLatency = (unsigned)(paSI->inputLatency * 1000);
-
-    PJ_LOG(5,(THIS_FILE, "Opened device %s (%s) for recording, sample "
-			 "rate=%d, ch=%d, "
-			 "bits=%d, %d samples per frame, latency=%d ms",
-			 paDevInfo->name, paHostApiInfo->name,
-			 paRate, channel_count,
-			 bits_per_sample, samples_per_frame,
-			 paLatency));
-
-    *p_snd_strm = stream;
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
-					unsigned clock_rate,
-					unsigned channel_count,
-					unsigned samples_per_frame,
-					unsigned bits_per_sample,
-					pjmedia_snd_play_cb play_cb,
-					void *user_data,
-					pjmedia_snd_stream **p_snd_strm)
-{
-    pj_pool_t *pool;
-    pjmedia_snd_stream *stream;
-    PaStreamParameters outputParam;
-    int sampleFormat;
-    const PaDeviceInfo *paDevInfo = NULL;
-    const PaHostApiInfo *paHostApiInfo = NULL;
-    const PaStreamInfo *paSI;
-    unsigned paFrames, paRate, paLatency;
-    PaError err;
-
-    if (index < 0) {
-	index = pa_get_default_output_dev(channel_count);
-	if (index < 0) {
-	    /* No such device. */
-	    return PJMEDIA_ENOSNDPLAY;
-	}
-    } 
-
-    paDevInfo = Pa_GetDeviceInfo(index);
-    if (!paDevInfo) {
-	/* Assumed it is "No such device" error. */
-	return PJMEDIA_ESNDINDEVID;
-    }
-
-    if (bits_per_sample == 8)
-	sampleFormat = paUInt8;
-    else if (bits_per_sample == 16)
-	sampleFormat = paInt16;
-    else if (bits_per_sample == 32)
-	sampleFormat = paInt32;
-    else
-	return PJMEDIA_ESNDINSAMPLEFMT;
-    
-    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
-    if (!pool)
-	return PJ_ENOMEM;
-
-    stream = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
-    stream->pool = pool;
-    pj_strdup2_with_null(pool, &stream->name, paDevInfo->name);
-    stream->dir = PJMEDIA_DIR_PLAYBACK;
-    stream->play_id = index;
-    stream->rec_id = -1;
-    stream->user_data = user_data;
-    stream->samples_per_sec = clock_rate;
-    stream->samples_per_frame = samples_per_frame;
-    stream->bytes_per_sample = bits_per_sample / 8;
-    stream->channel_count = channel_count;
-    stream->play_cb = play_cb;
-
-    stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool, 
-		       stream->samples_per_frame * stream->bytes_per_sample);
-    stream->play_buf_count = 0;
-
-    pj_bzero(&outputParam, sizeof(outputParam));
-    outputParam.device = index;
-    outputParam.channelCount = channel_count;
-    outputParam.hostApiSpecificStreamInfo = NULL;
-    outputParam.sampleFormat = sampleFormat;
-    outputParam.suggestedLatency = snd_output_latency / 1000.0;
-
-    paHostApiInfo = Pa_GetHostApiInfo(paDevInfo->hostApi);
-
-    /* Frames in PortAudio is number of samples in a single channel */
-    paFrames = samples_per_frame / channel_count;
-
-    err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam,
-			 clock_rate,  paFrames, 
-			 paClipOff, &PaPlayerCallback, stream );
-    if (err != paNoError) {
-	pj_pool_release(pool);
-	return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
-    }
-
-    paSI = Pa_GetStreamInfo(stream->play_strm);
-    paRate = (unsigned)(paSI->sampleRate);
-    paLatency = (unsigned)(paSI->outputLatency * 1000);
-
-    PJ_LOG(5,(THIS_FILE, "Opened device %d: %s(%s) for playing, sample rate=%d"
-			 ", ch=%d, "
-			 "bits=%d, %d samples per frame, latency=%d ms",
-			 index, paDevInfo->name, paHostApiInfo->name, 
-			 paRate, channel_count,
-		 	 bits_per_sample, samples_per_frame, paLatency));
-
-    *p_snd_strm = stream;
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Open both player and recorder.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_open( 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,
-				      pjmedia_snd_stream **p_snd_strm)
-{
-    pj_pool_t *pool;
-    pjmedia_snd_stream *stream;
-    PaStream *paStream = NULL;
-    PaStreamParameters inputParam;
-    PaStreamParameters outputParam;
-    int sampleFormat;
-    const PaDeviceInfo *paRecDevInfo = NULL;
-    const PaDeviceInfo *paPlayDevInfo = NULL;
-    const PaHostApiInfo *paRecHostApiInfo = NULL;
-    const PaHostApiInfo *paPlayHostApiInfo = NULL;
-    const PaStreamInfo *paSI;
-    unsigned paFrames, paRate, paInputLatency, paOutputLatency;
-    PaError err;
-
-    if (rec_id < 0) {
-	rec_id = pa_get_default_input_dev(channel_count);
-	if (rec_id < 0) {
-	    /* No such device. */
-	    return PJMEDIA_ENOSNDREC;
-	}
-    }
-
-    paRecDevInfo = Pa_GetDeviceInfo(rec_id);
-    if (!paRecDevInfo) {
-	/* Assumed it is "No such device" error. */
-	return PJMEDIA_ESNDINDEVID;
-    }
-
-    if (play_id < 0) {
-	play_id = pa_get_default_output_dev(channel_count);
-	if (play_id < 0) {
-	    /* No such device. */
-	    return PJMEDIA_ENOSNDPLAY;
-	}
-    } 
-
-    paPlayDevInfo = Pa_GetDeviceInfo(play_id);
-    if (!paPlayDevInfo) {
-	/* Assumed it is "No such device" error. */
-	return PJMEDIA_ESNDINDEVID;
-    }
-
-
-    if (bits_per_sample == 8)
-	sampleFormat = paUInt8;
-    else if (bits_per_sample == 16)
-	sampleFormat = paInt16;
-    else if (bits_per_sample == 32)
-	sampleFormat = paInt32;
-    else
-	return PJMEDIA_ESNDINSAMPLEFMT;
-    
-    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
-    if (!pool)
-	return PJ_ENOMEM;
-
-    stream = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
-    stream->pool = pool;
-    pj_strdup2_with_null(pool, &stream->name, paRecDevInfo->name);
-    stream->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
-    stream->play_id = play_id;
-    stream->rec_id = rec_id;
-    stream->user_data = user_data;
-    stream->samples_per_sec = clock_rate;
-    stream->samples_per_frame = samples_per_frame;
-    stream->bytes_per_sample = bits_per_sample / 8;
-    stream->channel_count = channel_count;
-    stream->rec_cb = rec_cb;
-    stream->play_cb = play_cb;
-
-    stream->rec_buf = (pj_int16_t*)pj_pool_alloc(pool, 
-		      stream->samples_per_frame * stream->bytes_per_sample);
-    stream->rec_buf_count = 0;
-
-    stream->play_buf = (pj_int16_t*)pj_pool_alloc(pool, 
-		       stream->samples_per_frame * stream->bytes_per_sample);
-    stream->play_buf_count = 0;
-
-    pj_bzero(&inputParam, sizeof(inputParam));
-    inputParam.device = rec_id;
-    inputParam.channelCount = channel_count;
-    inputParam.hostApiSpecificStreamInfo = NULL;
-    inputParam.sampleFormat = sampleFormat;
-    inputParam.suggestedLatency = snd_input_latency / 1000.0;
-
-    paRecHostApiInfo = Pa_GetHostApiInfo(paRecDevInfo->hostApi);
-
-    pj_bzero(&outputParam, sizeof(outputParam));
-    outputParam.device = play_id;
-    outputParam.channelCount = channel_count;
-    outputParam.hostApiSpecificStreamInfo = NULL;
-    outputParam.sampleFormat = sampleFormat;
-    outputParam.suggestedLatency = snd_output_latency / 1000.0;
-
-    paPlayHostApiInfo = Pa_GetHostApiInfo(paPlayDevInfo->hostApi);
-
-    /* Frames in PortAudio is number of samples in a single channel */
-    paFrames = samples_per_frame / channel_count;
-
-    /* If both input and output are on the same device, open a single stream
-     * for both input and output.
-     */
-    if (rec_id == play_id) {
-	err = Pa_OpenStream( &paStream, &inputParam, &outputParam,
-			     clock_rate, paFrames, 
-			     paClipOff, &PaRecorderPlayerCallback, stream );
-	if (err == paNoError) {
-	    /* Set play stream and record stream to the same stream */
-	    stream->play_strm = stream->rec_strm = paStream;
-	}
-    } else {
-	err = -1;
-    }
-
-    /* .. otherwise if input and output are on the same device, OR if we're
-     * unable to open a bidirectional stream, then open two separate
-     * input and output stream.
-     */
-    if (paStream == NULL) {
-	/* Open input stream */
-	err = Pa_OpenStream( &stream->rec_strm, &inputParam, NULL,
-			     clock_rate, paFrames, 
-			     paClipOff, &PaRecorderCallback, stream );
-	if (err == paNoError) {
-	    /* Open output stream */
-	    err = Pa_OpenStream( &stream->play_strm, NULL, &outputParam,
-				 clock_rate, paFrames, 
-				 paClipOff, &PaPlayerCallback, stream );
-	    if (err != paNoError)
-		Pa_CloseStream(stream->rec_strm);
-	}
-    }
-
-    if (err != paNoError) {
-	pj_pool_release(pool);
-	return PJMEDIA_ERRNO_FROM_PORTAUDIO(err);
-    }
-
-    paSI = Pa_GetStreamInfo(stream->rec_strm);
-    paRate = (unsigned)(paSI->sampleRate);
-    paInputLatency = (unsigned)(paSI->inputLatency * 1000);
-    paSI = Pa_GetStreamInfo(stream->play_strm);
-    paOutputLatency = (unsigned)(paSI->outputLatency * 1000);
-
-    PJ_LOG(5,(THIS_FILE, "Opened device %s(%s)/%s(%s) for recording and "
-			 "playback, sample rate=%d, ch=%d, "
-			 "bits=%d, %d samples per frame, input latency=%d ms, "
-			 "output latency=%d ms",
-			 paRecDevInfo->name, paRecHostApiInfo->name,
-			 paPlayDevInfo->name, paPlayHostApiInfo->name,
-			 paRate, channel_count,
-			 bits_per_sample, samples_per_frame,
-			 paInputLatency, paOutputLatency));
-
-    *p_snd_strm = stream;
-
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Get stream info.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
-						pjmedia_snd_stream_info *pi)
-{
-    const PaStreamInfo *paPlaySI = NULL, *paRecSI = NULL;
-
-    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
-    PJ_ASSERT_RETURN(strm->play_strm || strm->rec_strm, PJ_EINVALIDOP);
-
-    if (strm->play_strm) {
-	paPlaySI = Pa_GetStreamInfo(strm->play_strm);
-    }
-    if (strm->rec_strm) {
-	paRecSI = Pa_GetStreamInfo(strm->rec_strm);
-    }
-
-    pj_bzero(pi, sizeof(*pi));
-    pi->dir = strm->dir;
-    pi->play_id = strm->play_id;
-    pi->rec_id = strm->rec_id;
-    pi->clock_rate = (unsigned)(paPlaySI ? paPlaySI->sampleRate : 
-				paRecSI->sampleRate);
-    pi->channel_count = strm->channel_count;
-    pi->samples_per_frame = strm->samples_per_frame;
-    pi->bits_per_sample = strm->bytes_per_sample * 8;
-    pi->rec_latency = (unsigned)(paRecSI ? paRecSI->inputLatency * 
-					   paRecSI->sampleRate : 0);
-    pi->play_latency = (unsigned)(paPlaySI ? paPlaySI->outputLatency * 
-					     paPlaySI->sampleRate : 0);
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Start stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
-{
-    int err = 0;
-
-    PJ_LOG(5,(THIS_FILE, "Starting %s stream..", stream->name.ptr));
-
-    if (stream->play_strm)
-	err = Pa_StartStream(stream->play_strm);
-
-    if (err==0 && stream->rec_strm && stream->rec_strm != stream->play_strm) {
-	err = Pa_StartStream(stream->rec_strm);
-	if (err != 0)
-	    Pa_StopStream(stream->play_strm);
-    }
-
-    PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));
-
-    return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
-}
-
-/*
- * Stop stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
-{
-    int i, err = 0;
-
-    stream->quit_flag = 1;
-    for (i=0; !stream->rec_thread_exited && i<100; ++i)
-	pj_thread_sleep(10);
-    for (i=0; !stream->play_thread_exited && i<100; ++i)
-	pj_thread_sleep(10);
-
-    pj_thread_sleep(1);
-
-    PJ_LOG(5,(THIS_FILE, "Stopping stream.."));
-
-    if (stream->play_strm)
-	err = Pa_StopStream(stream->play_strm);
-
-    if (stream->rec_strm && stream->rec_strm != stream->play_strm)
-	err = Pa_StopStream(stream->rec_strm);
-
-    stream->play_thread_initialized = 0;
-    stream->rec_thread_initialized = 0;
-
-    PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));
-
-    return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
-}
-
-/*
- * Destroy stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
-{
-    int i, err = 0;
-
-    stream->quit_flag = 1;
-    for (i=0; !stream->rec_thread_exited && i<100; ++i) {
-	pj_thread_sleep(1);
-    }
-    for (i=0; !stream->play_thread_exited && i<100; ++i) {
-	pj_thread_sleep(1);
-    }
-
-    PJ_LOG(5,(THIS_FILE, "Closing %.*s: %lu underflow, %lu overflow",
-			 (int)stream->name.slen,
-			 stream->name.ptr,
-			 stream->underflow, stream->overflow));
-
-    if (stream->play_strm)
-	err = Pa_CloseStream(stream->play_strm);
-
-    if (stream->rec_strm && stream->rec_strm != stream->play_strm)
-	err = Pa_CloseStream(stream->rec_strm);
-
-    pj_pool_release(stream->pool);
-
-    return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
-}
-
-/*
- * Deinitialize sound library.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
-{
-    if (--snd_init_count == 0) {
-	int err;
-
-	PJ_LOG(4,(THIS_FILE, "PortAudio sound library shutting down.."));
-
-	err = Pa_Terminate();
-
-	return err ? PJMEDIA_ERRNO_FROM_PORTAUDIO(err) : PJ_SUCCESS;
-    } else {
-	return PJ_SUCCESS;
-    }
-}
-
-/*
- * Set sound latency.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, 
-					    unsigned output_latency)
-{
-    snd_input_latency  = (input_latency == 0)? 
-			 PJMEDIA_SND_DEFAULT_REC_LATENCY : input_latency;
-    snd_output_latency = (output_latency == 0)? 
-			 PJMEDIA_SND_DEFAULT_PLAY_LATENCY : output_latency;
-
-    return PJ_SUCCESS;
-}
-
-#endif	/* PJMEDIA_SOUND_IMPLEMENTATION */
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_legacy.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_legacy.c	(revision 2489)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_legacy.c	(revision 2489)
@@ -0,0 +1,284 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+/*
+ * This is implementation of legacy sound device API, for applications
+ * that still use the old/deprecated sound device API. This implementation
+ * uses the new Audio Device API.
+ *
+ * Please see http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more
+ * information.
+ */
+
+#include <pjmedia/sound.h>
+#include <pjmedia-audiodev/errno.h>
+#include <pj/assert.h>
+
+#if PJMEDIA_HAS_LEGACY_SOUND_API
+
+static struct legacy_subsys
+{
+    pjmedia_snd_dev_info     info[4];
+    unsigned		     info_counter;
+    unsigned		     user_rec_latency;
+    unsigned		     user_play_latency;
+} g_sys;
+
+struct pjmedia_snd_stream
+{
+    pj_pool_t		*pool;
+    pjmedia_aud_stream	*aud_strm;
+    pjmedia_snd_rec_cb	 user_rec_cb;
+    pjmedia_snd_play_cb  user_play_cb;
+    void		*user_user_data;
+};
+
+PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
+{
+    return pjmedia_aud_subsys_init(factory);
+}
+
+PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
+{
+    return pjmedia_aud_subsys_shutdown();
+}
+
+PJ_DEF(int) pjmedia_snd_get_dev_count(void)
+{
+    return pjmedia_aud_dev_count();
+}
+
+PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
+{
+    pjmedia_snd_dev_info *oi = &g_sys.info[g_sys.info_counter];
+    pjmedia_aud_dev_info di;
+
+    g_sys.info_counter = (g_sys.info_counter+1) % PJ_ARRAY_SIZE(g_sys.info);
+
+    if (pjmedia_aud_dev_get_info(index, &di) != PJ_SUCCESS)
+	return NULL;
+
+    pj_bzero(oi, sizeof(*oi));
+    pj_ansi_strncpy(oi->name, di.name, sizeof(oi->name));
+    oi->name[sizeof(oi->name)-1] = '\0';
+    oi->input_count = di.input_count;
+    oi->output_count = di.output_count;
+    oi->default_samples_per_sec = di.default_samples_per_sec;
+
+    return oi;
+}
+
+
+static pj_status_t snd_play_cb(void *user_data,
+			       pjmedia_frame *frame)
+{
+    pjmedia_snd_stream *strm = (pjmedia_snd_stream*)user_data;
+
+    frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
+    return strm->user_play_cb(strm->user_user_data, 
+			      frame->timestamp.u32.lo,
+			      frame->buf,
+			      frame->size);
+}
+
+static pj_status_t snd_rec_cb(void *user_data,
+			      pjmedia_frame *frame)
+{
+    pjmedia_snd_stream *strm = (pjmedia_snd_stream*)user_data;
+    return strm->user_rec_cb(strm->user_user_data, 
+			     frame->timestamp.u32.lo,
+			     frame->buf,
+			     frame->size);
+}
+
+static pj_status_t open_stream( 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,
+				pjmedia_snd_stream **p_snd_strm)
+{
+    pj_pool_t *pool;
+    pjmedia_snd_stream *snd_strm;
+    pjmedia_aud_param param;
+    pj_status_t status;
+
+    /* Initialize parameters */
+    if (dir & PJMEDIA_DIR_CAPTURE) {
+	status = pjmedia_aud_dev_default_param(rec_id, &param);
+    } else {
+	status = pjmedia_aud_dev_default_param(play_id, &param);
+    }
+    if (status != PJ_SUCCESS)
+	return status;
+
+    param.dir = dir;
+    param.rec_id = rec_id;
+    param.play_id = play_id;
+    param.clock_rate = clock_rate;
+    param.channel_count = channel_count;
+    param.samples_per_frame = samples_per_frame;
+    param.bits_per_sample = bits_per_sample;
+
+    /* Latencies setting */
+    if ((dir & PJMEDIA_DIR_CAPTURE) && g_sys.user_rec_latency) {
+	param.flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
+	param.input_latency_ms = g_sys.user_rec_latency;
+    }
+    if ((dir & PJMEDIA_DIR_PLAYBACK) && g_sys.user_play_latency) {
+	param.flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
+	param.output_latency_ms = g_sys.user_play_latency;
+    }
+
+    /* Create sound wrapper */
+    pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(),
+			  "legacy-snd", 512, 512, NULL);
+    snd_strm = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_stream);
+    snd_strm->pool = pool;
+    snd_strm->user_rec_cb = rec_cb;
+    snd_strm->user_play_cb = play_cb;
+    snd_strm->user_user_data = user_data;
+
+    /* Create the stream */
+    status = pjmedia_aud_stream_create(&param, &snd_rec_cb, 
+				       &snd_play_cb, snd_strm,
+				       &snd_strm->aud_strm);
+    if (status != PJ_SUCCESS) {
+	pj_pool_release(pool);
+	return status;
+    }
+
+    *p_snd_strm = snd_strm;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
+					  unsigned clock_rate,
+					  unsigned channel_count,
+					  unsigned samples_per_frame,
+					  unsigned bits_per_sample,
+					  pjmedia_snd_rec_cb rec_cb,
+					  void *user_data,
+					  pjmedia_snd_stream **p_snd_strm)
+{
+    return open_stream(PJMEDIA_DIR_CAPTURE, index, PJMEDIA_AUD_INVALID_DEV,
+		       clock_rate, channel_count, samples_per_frame,
+		       bits_per_sample, rec_cb, NULL,
+		       user_data, p_snd_strm);
+}
+
+PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
+					unsigned clock_rate,
+					unsigned channel_count,
+					unsigned samples_per_frame,
+					unsigned bits_per_sample,
+					pjmedia_snd_play_cb play_cb,
+					void *user_data,
+					pjmedia_snd_stream **p_snd_strm )
+{
+    return open_stream(PJMEDIA_DIR_PLAYBACK, PJMEDIA_AUD_INVALID_DEV, index, 
+		       clock_rate, channel_count, samples_per_frame,
+		       bits_per_sample, NULL, play_cb,
+		       user_data, p_snd_strm);
+}
+
+PJ_DEF(pj_status_t) pjmedia_snd_open( 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,
+				      pjmedia_snd_stream **p_snd_strm)
+{
+    return open_stream(PJMEDIA_DIR_CAPTURE_PLAYBACK, rec_id, play_id,
+		       clock_rate, channel_count, samples_per_frame,
+		       bits_per_sample, rec_cb, play_cb, 
+		       user_data, p_snd_strm);
+}
+
+PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
+{
+    return pjmedia_aud_stream_start(stream->aud_strm);
+}
+
+PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
+{
+    return pjmedia_aud_stream_stop(stream->aud_strm);
+}
+
+PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
+						pjmedia_snd_stream_info *pi)
+{
+    pjmedia_aud_param param;
+    pj_status_t status;
+
+    status = pjmedia_aud_stream_get_param(strm->aud_strm, &param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pj_bzero(pi, sizeof(*pi));
+    pi->dir = param.dir;
+    pi->play_id = param.play_id;
+    pi->rec_id = param.rec_id;
+    pi->clock_rate = param.clock_rate;
+    pi->channel_count = param.channel_count;
+    pi->samples_per_frame = param.samples_per_frame;
+    pi->bits_per_sample = param.bits_per_sample;
+
+    if (param.flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) {
+	pi->rec_latency = param.input_latency_ms;
+    }
+    if (param.flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) {
+	pi->play_latency = param.output_latency_ms;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
+{
+    pj_status_t status;
+
+    status = pjmedia_aud_stream_destroy(stream->aud_strm);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pj_pool_release(stream->pool);
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, 
+					    unsigned output_latency)
+{
+    g_sys.user_rec_latency = input_latency;
+    g_sys.user_play_latency = output_latency;
+    return PJ_SUCCESS;
+}
+
+#endif	/* PJMEDIA_HAS_LEGACY_SOUND_API */
+
Index: project/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound.cpp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound.cpp	(revision 2488)
+++ 	(revision )
@@ -1,947 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
- * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#include <pjmedia/sound.h>
-#include <pjmedia/errno.h>
-#include <pj/assert.h>
-#include <pj/log.h>
-#include <pj/os.h>
-
-#if PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_SYMB_MDA_SOUND
-
-/*
- * This file provides sound implementation for Symbian Audio Streaming
- * device. Application using this sound abstraction must link with:
- *  - mediaclientaudiostream.lib, and
- *  - mediaclientaudioinputstream.lib 
- */
-#include <mda/common/audio.h>
-#include <mdaaudiooutputstream.h>
-#include <mdaaudioinputstream.h>
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-
-#define THIS_FILE	    "symbian_sound.cpp"
-#define BYTES_PER_SAMPLE    2
-#define POOL_NAME	    "SymbianSound"
-#define POOL_SIZE	    512
-#define POOL_INC	    512
-
-static pjmedia_snd_dev_info symbian_snd_dev_info = 
-{
-    "Symbian Sound Device",
-    1,
-    1,
-    8000
-};
-
-class CPjAudioInputEngine;
-class CPjAudioOutputEngine;
-
-/* 
- * PJMEDIA Sound Stream instance 
- */
-struct pjmedia_snd_stream
-{
-    // Pool
-    pj_pool_t			*pool;
-
-    // Common settings.
-    pjmedia_dir		 	 dir;
-    unsigned			 clock_rate;
-    unsigned			 channel_count;
-    unsigned			 samples_per_frame;
-
-    // Input stream
-    CPjAudioInputEngine		*inEngine;
-
-    // Output stream
-    CPjAudioOutputEngine	*outEngine;
-};
-
-static pj_pool_factory *snd_pool_factory;
-
-
-/*
- * Convert clock rate to Symbian's TMdaAudioDataSettings capability.
- */
-static TInt get_clock_rate_cap(unsigned clock_rate)
-{
-    switch (clock_rate) {
-    case 8000:  return TMdaAudioDataSettings::ESampleRate8000Hz;
-    case 11025: return TMdaAudioDataSettings::ESampleRate11025Hz;
-    case 12000: return TMdaAudioDataSettings::ESampleRate12000Hz;
-    case 16000: return TMdaAudioDataSettings::ESampleRate16000Hz;
-    case 22050: return TMdaAudioDataSettings::ESampleRate22050Hz;
-    case 24000: return TMdaAudioDataSettings::ESampleRate24000Hz;
-    case 32000: return TMdaAudioDataSettings::ESampleRate32000Hz;
-    case 44100: return TMdaAudioDataSettings::ESampleRate44100Hz;
-    case 48000: return TMdaAudioDataSettings::ESampleRate48000Hz;
-    case 64000: return TMdaAudioDataSettings::ESampleRate64000Hz;
-    case 96000: return TMdaAudioDataSettings::ESampleRate96000Hz;
-    default:
-	return 0;
-    }
-}
-
-
-/*
- * Convert number of channels into Symbian's TMdaAudioDataSettings capability.
- */
-static TInt get_channel_cap(unsigned channel_count)
-{
-    switch (channel_count) {
-    case 1: return TMdaAudioDataSettings::EChannelsMono;
-    case 2: return TMdaAudioDataSettings::EChannelsStereo;
-    default:
-	return 0;
-    }
-}
-
-
-/*
- * Utility: print sound device error
- */
-static void snd_perror(const char *title, TInt rc) 
-{
-    PJ_LOG(1,(THIS_FILE, "%s: error code %d", title, rc));
-}
- 
-//////////////////////////////////////////////////////////////////////////////
-//
-
-/*
- * Implementation: Symbian Input Stream.
- */
-class CPjAudioInputEngine : public CBase, MMdaAudioInputStreamCallback
-{
-public:
-    enum State
-    {
-	STATE_INACTIVE,
-	STATE_ACTIVE,
-    };
-
-    ~CPjAudioInputEngine();
-
-    static CPjAudioInputEngine *NewL(pjmedia_snd_stream *parent_strm,
-				     pjmedia_snd_rec_cb rec_cb,
-				     void *user_data);
-
-    static CPjAudioInputEngine *NewLC(pjmedia_snd_stream *parent_strm,
-				      pjmedia_snd_rec_cb rec_cb,
-				      void *user_data);
-
-    pj_status_t StartRecord();
-    void Stop();
-
-private:
-    State		     state_;
-    pjmedia_snd_stream	    *parentStrm_;
-    pjmedia_snd_rec_cb	     recCb_;
-    void		    *userData_;
-    CMdaAudioInputStream    *iInputStream_;
-    HBufC8		    *iStreamBuffer_;
-    TPtr8		     iFramePtr_;
-    TInt		     lastError_;
-    pj_uint32_t		     timeStamp_;
-
-    // cache variable
-    // to avoid calculating frame length repeatedly
-    TInt			  frameLen_;
-    
-    // in some SymbianOS (e.g: OSv9.1), sometimes recorded size != requested framesize
-    // so let's provide a buffer to make sure the rec callback returns framesize as requested.
-    TUint8		     *frameRecBuf_;
-    TInt			  frameRecBufLen_;
-
-    CPjAudioInputEngine(pjmedia_snd_stream *parent_strm,
-			pjmedia_snd_rec_cb rec_cb,
-			void *user_data);
-    void ConstructL();
-    TPtr8 & GetFrame();
-    
-public:
-    virtual void MaiscOpenComplete(TInt aError);
-    virtual void MaiscBufferCopied(TInt aError, const TDesC8 &aBuffer);
-    virtual void MaiscRecordComplete(TInt aError);
-
-};
-
-
-CPjAudioInputEngine::CPjAudioInputEngine(pjmedia_snd_stream *parent_strm,
-					 pjmedia_snd_rec_cb rec_cb,
-					 void *user_data)
-    : state_(STATE_INACTIVE), parentStrm_(parent_strm), 
-      recCb_(rec_cb), userData_(user_data), 
-      iInputStream_(NULL), iStreamBuffer_(NULL), iFramePtr_(0, 0),
-      lastError_(KErrNone), timeStamp_(0),
-      frameLen_(parent_strm->samples_per_frame * parent_strm->channel_count * BYTES_PER_SAMPLE),
-      frameRecBuf_(NULL), frameRecBufLen_(0)
-{
-}
-
-CPjAudioInputEngine::~CPjAudioInputEngine()
-{
-    Stop();
-
-    delete iStreamBuffer_;
-    iStreamBuffer_ = NULL;
-    
-    delete [] frameRecBuf_;
-    frameRecBuf_ = NULL;
-    frameRecBufLen_ = 0;
-}
-
-void CPjAudioInputEngine::ConstructL()
-{
-    iStreamBuffer_ = HBufC8::NewL(frameLen_);
-    CleanupStack::PushL(iStreamBuffer_);
-
-    frameRecBuf_ = new TUint8[frameLen_*2];
-    CleanupStack::PushL(frameRecBuf_);
-}
-
-CPjAudioInputEngine *CPjAudioInputEngine::NewLC(pjmedia_snd_stream *parent,
-					        pjmedia_snd_rec_cb rec_cb,
-					        void *user_data)
-{
-    CPjAudioInputEngine* self = new (ELeave) CPjAudioInputEngine(parent,
-								 rec_cb, 
-								 user_data);
-    CleanupStack::PushL(self);
-    self->ConstructL();
-    return self;
-}
-
-CPjAudioInputEngine *CPjAudioInputEngine::NewL(pjmedia_snd_stream *parent,
-					       pjmedia_snd_rec_cb rec_cb,
-					       void *user_data)
-{
-    CPjAudioInputEngine *self = NewLC(parent, rec_cb, user_data);
-    CleanupStack::Pop(self->frameRecBuf_);
-    CleanupStack::Pop(self->iStreamBuffer_);
-    CleanupStack::Pop(self);
-    return self;
-}
-
-
-pj_status_t CPjAudioInputEngine::StartRecord()
-{
-
-    // Ignore command if recording is in progress.
-    if (state_ == STATE_ACTIVE)
-	return PJ_SUCCESS;
-
-    // According to Nokia's AudioStream example, some 2nd Edition, FP2 devices
-    // (such as Nokia 6630) require the stream to be reconstructed each time 
-    // before calling Open() - otherwise the callback never gets called.
-    // For uniform behavior, lets just delete/re-create the stream for all
-    // devices.
-
-    // Destroy existing stream.
-    if (iInputStream_) delete iInputStream_;
-    iInputStream_ = NULL;
-
-    // Create the stream.
-    TRAPD(err, iInputStream_ = CMdaAudioInputStream::NewL(*this));
-    if (err != KErrNone)
-	return PJ_RETURN_OS_ERROR(err);
-
-    // Initialize settings.
-    TMdaAudioDataSettings iStreamSettings;
-    iStreamSettings.iChannels = get_channel_cap(parentStrm_->channel_count);
-    iStreamSettings.iSampleRate = get_clock_rate_cap(parentStrm_->clock_rate);
-
-    pj_assert(iStreamSettings.iChannels != 0 && 
-	      iStreamSettings.iSampleRate != 0);
-
-    PJ_LOG(4,(THIS_FILE, "Opening sound device for capture, "
-    		         "clock rate=%d, channel count=%d..",
-    		         parentStrm_->clock_rate, 
-    		         parentStrm_->channel_count));
-    
-    // Open stream.
-    lastError_ = KRequestPending;
-    iInputStream_->Open(&iStreamSettings);
-    
-    // Success
-    PJ_LOG(4,(THIS_FILE, "Sound capture started."));
-    return PJ_SUCCESS;
-}
-
-
-void CPjAudioInputEngine::Stop()
-{
-    // If capture is in progress, stop it.
-    if (iInputStream_ && state_ == STATE_ACTIVE) {
-    	lastError_ = KRequestPending;
-    	iInputStream_->Stop();
-
-	// Wait until it's actually stopped
-    	while (lastError_ == KRequestPending)
-	    pj_symbianos_poll(-1, 100);
-    }
-
-    if (iInputStream_) {
-	delete iInputStream_;
-	iInputStream_ = NULL;
-    }
-    
-    state_ = STATE_INACTIVE;
-}
-
-
-TPtr8 & CPjAudioInputEngine::GetFrame() 
-{
-    //iStreamBuffer_->Des().FillZ(frameLen_);
-    iFramePtr_.Set((TUint8*)(iStreamBuffer_->Ptr()), frameLen_, frameLen_);
-    return iFramePtr_;
-}
-
-void CPjAudioInputEngine::MaiscOpenComplete(TInt aError)
-{
-    lastError_ = aError;
-    if (aError != KErrNone) {
-        snd_perror("Error in MaiscOpenComplete()", aError);
-    	return;
-    }
-
-    // set stream priority to normal and time sensitive
-    iInputStream_->SetPriority(EPriorityNormal, 
-    			       EMdaPriorityPreferenceTime);				
-
-    // Read the first frame.
-    TPtr8 & frm = GetFrame();
-    TRAPD(err2, iInputStream_->ReadL(frm));
-    if (err2) {
-    	PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
-    }
-}
-
-void CPjAudioInputEngine::MaiscBufferCopied(TInt aError, 
-					    const TDesC8 &aBuffer)
-{
-    lastError_ = aError;
-    if (aError != KErrNone) {
-    	snd_perror("Error in MaiscBufferCopied()", aError);
-	return;
-    }
-
-    if (frameRecBufLen_ || aBuffer.Size() < frameLen_) {
-		pj_memcpy(frameRecBuf_ + frameRecBufLen_, (void*) aBuffer.Ptr(), aBuffer.Size());
-		frameRecBufLen_ += aBuffer.Size();
-    }
-
-    if (frameRecBufLen_) {
-    	while (frameRecBufLen_ >= frameLen_) {
-	    	// Call the callback.
-		    recCb_(userData_, timeStamp_, frameRecBuf_, frameLen_);
-		    // Increment timestamp.
-		    timeStamp_ += parentStrm_->samples_per_frame;
-
-		    frameRecBufLen_ -= frameLen_;
-		    pj_memmove(frameRecBuf_, frameRecBuf_+frameLen_, frameRecBufLen_);
-    	}
-    } else {
-    	// Call the callback.
-	    recCb_(userData_, timeStamp_, (void*) aBuffer.Ptr(), aBuffer.Size());
-	    // Increment timestamp.
-	    timeStamp_ += parentStrm_->samples_per_frame;
-    }
-
-    // Record next frame
-    TPtr8 & frm = GetFrame();
-    TRAPD(err2, iInputStream_->ReadL(frm));
-    if (err2) {
-    	PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
-    }
-}
-
-
-void CPjAudioInputEngine::MaiscRecordComplete(TInt aError)
-{
-    lastError_ = aError;
-    state_ = STATE_INACTIVE;
-    if (aError != KErrNone) {
-    	snd_perror("Error in MaiscRecordComplete()", aError);
-    }
-}
-
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-
-/*
- * Implementation: Symbian Output Stream.
- */
-
-class CPjAudioOutputEngine : public CBase, MMdaAudioOutputStreamCallback
-{
-public:
-    enum State
-    {
-	STATE_INACTIVE,
-	STATE_ACTIVE,
-    };
-
-    ~CPjAudioOutputEngine();
-
-    static CPjAudioOutputEngine *NewL(pjmedia_snd_stream *parent_strm,
-				      pjmedia_snd_play_cb play_cb,
-				      void *user_data);
-
-    static CPjAudioOutputEngine *NewLC(pjmedia_snd_stream *parent_strm,
-				       pjmedia_snd_play_cb rec_cb,
-				       void *user_data);
-
-    pj_status_t StartPlay();
-    void Stop();
-
-private:
-    State		     state_;
-    pjmedia_snd_stream	    *parentStrm_;
-    pjmedia_snd_play_cb	     playCb_;
-    void		    *userData_;
-    CMdaAudioOutputStream   *iOutputStream_;
-    TUint8		    *frameBuf_;
-    unsigned		     frameBufSize_;
-    TPtrC8		     frame_;
-    TInt		     lastError_;
-    unsigned		     timestamp_;
-
-    CPjAudioOutputEngine(pjmedia_snd_stream *parent_strm,
-			 pjmedia_snd_play_cb play_cb,
-			 void *user_data);
-    void ConstructL();
-
-    virtual void MaoscOpenComplete(TInt aError);
-    virtual void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
-    virtual void MaoscPlayComplete(TInt aError);
-};
-
-
-CPjAudioOutputEngine::CPjAudioOutputEngine(pjmedia_snd_stream *parent_strm,
-					   pjmedia_snd_play_cb play_cb,
-					   void *user_data) 
-: state_(STATE_INACTIVE), parentStrm_(parent_strm), playCb_(play_cb), 
-  userData_(user_data), iOutputStream_(NULL), frameBuf_(NULL),
-  lastError_(KErrNone), timestamp_(0)
-{
-}
-
-
-void CPjAudioOutputEngine::ConstructL()
-{
-    frameBufSize_ = parentStrm_->samples_per_frame *
-			   parentStrm_->channel_count * 
-			   BYTES_PER_SAMPLE;
-    frameBuf_ = new TUint8[frameBufSize_];
-}
-
-CPjAudioOutputEngine::~CPjAudioOutputEngine()
-{
-    Stop();
-    delete [] frameBuf_;	
-}
-
-CPjAudioOutputEngine *
-CPjAudioOutputEngine::NewLC(pjmedia_snd_stream *parent_strm,
-			    pjmedia_snd_play_cb rec_cb,
-			    void *user_data)
-{
-    CPjAudioOutputEngine* self = new (ELeave) CPjAudioOutputEngine(parent_strm,
-								   rec_cb, 
-								   user_data);
-    CleanupStack::PushL(self);
-    self->ConstructL();
-    return self;
-}
-
-CPjAudioOutputEngine *
-CPjAudioOutputEngine::NewL(pjmedia_snd_stream *parent_strm,
-			   pjmedia_snd_play_cb play_cb,
-			   void *user_data)
-{
-    CPjAudioOutputEngine *self = NewLC(parent_strm, play_cb, user_data);
-    CleanupStack::Pop(self);
-    return self;
-}
-
-pj_status_t CPjAudioOutputEngine::StartPlay()
-{
-    // Ignore command if playing is in progress.
-    if (state_ == STATE_ACTIVE)
-	return PJ_SUCCESS;
-    
-    // Destroy existing stream.
-    if (iOutputStream_) delete iOutputStream_;
-    iOutputStream_ = NULL;
-    
-    // Create the stream
-    TRAPD(err, iOutputStream_ = CMdaAudioOutputStream::NewL(*this));
-    if (err != KErrNone)
-	return PJ_RETURN_OS_ERROR(err);
-    
-    // Initialize settings.
-    TMdaAudioDataSettings iStreamSettings;
-    iStreamSettings.iChannels = get_channel_cap(parentStrm_->channel_count);
-    iStreamSettings.iSampleRate = get_clock_rate_cap(parentStrm_->clock_rate);
-
-    pj_assert(iStreamSettings.iChannels != 0 && 
-	      iStreamSettings.iSampleRate != 0);
-    
-    PJ_LOG(4,(THIS_FILE, "Opening sound device for playback, "
-    		         "clock rate=%d, channel count=%d..",
-    		         parentStrm_->clock_rate, 
-    		         parentStrm_->channel_count));
-
-    // Open stream.
-    lastError_ = KRequestPending;
-    iOutputStream_->Open(&iStreamSettings);
-
-    // Success
-    PJ_LOG(4,(THIS_FILE, "Sound playback started"));
-    return PJ_SUCCESS;
-
-}
-
-void CPjAudioOutputEngine::Stop()
-{
-    // Stop stream if it's playing
-    if (iOutputStream_ && state_ != STATE_INACTIVE) {
-    	lastError_ = KRequestPending;
-    	iOutputStream_->Stop();
-
-	// Wait until it's actually stopped
-    	while (lastError_ == KRequestPending)
-	    pj_symbianos_poll(-1, 100);
-    }
-    
-    if (iOutputStream_) {	
-	delete iOutputStream_;
-	iOutputStream_ = NULL;
-    }
-    
-    state_ = STATE_INACTIVE;
-}
-
-void CPjAudioOutputEngine::MaoscOpenComplete(TInt aError)
-{
-    lastError_ = aError;
-    
-    if (aError==KErrNone) {
-	// output stream opened succesfully, set status to Active
-	state_ = STATE_ACTIVE;
-
-	// set stream properties, 16bit 8KHz mono
-	TMdaAudioDataSettings iSettings;
-	iSettings.iChannels = get_channel_cap(parentStrm_->channel_count);
-	iSettings.iSampleRate = get_clock_rate_cap(parentStrm_->clock_rate);
-
-	iOutputStream_->SetAudioPropertiesL(iSettings.iSampleRate, 
-					    iSettings.iChannels);
-
-	// set volume to 1/2th of stream max volume
-	iOutputStream_->SetVolume(iOutputStream_->MaxVolume()/2);
-	
-	// set stream priority to normal and time sensitive
-	iOutputStream_->SetPriority(EPriorityNormal, 
-				    EMdaPriorityPreferenceTime);				
-
-	// Call callback to retrieve frame from upstream.
-	pj_status_t status;
-	status = playCb_(this->userData_, timestamp_, frameBuf_, 
-			 frameBufSize_);
-	if (status != PJ_SUCCESS) {
-	    this->Stop();
-	    return;
-	}
-
-	// Increment timestamp.
-	timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
-
-	// issue WriteL() to write the first audio data block, 
-	// subsequent calls to WriteL() will be issued in 
-	// MMdaAudioOutputStreamCallback::MaoscBufferCopied() 
-	// until whole data buffer is written.
-	frame_.Set(frameBuf_, frameBufSize_);
-	iOutputStream_->WriteL(frame_);
-    } else {
-    	snd_perror("Error in MaoscOpenComplete()", aError);
-    }
-}
-
-void CPjAudioOutputEngine::MaoscBufferCopied(TInt aError, 
-					     const TDesC8& aBuffer)
-{
-    PJ_UNUSED_ARG(aBuffer);
-
-    if (aError==KErrNone) {
-    	// Buffer successfully written, feed another one.
-
-	// Call callback to retrieve frame from upstream.
-	pj_status_t status;
-	status = playCb_(this->userData_, timestamp_, frameBuf_, 
-			 frameBufSize_);
-	if (status != PJ_SUCCESS) {
-	    this->Stop();
-	    return;
-	}
-
-	// Increment timestamp.
-	timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
-
-	// Write to playback stream.
-	frame_.Set(frameBuf_, frameBufSize_);
-	iOutputStream_->WriteL(frame_);
-
-    } else if (aError==KErrAbort) {
-	// playing was aborted, due to call to CMdaAudioOutputStream::Stop()
-	state_ = STATE_INACTIVE;
-    } else  {
-	// error writing data to output
-	lastError_ = aError;
-	state_ = STATE_INACTIVE;
-	snd_perror("Error in MaoscBufferCopied()", aError);
-    }
-}
-
-void CPjAudioOutputEngine::MaoscPlayComplete(TInt aError)
-{
-    lastError_ = aError;
-    state_ = STATE_INACTIVE;
-    if (aError != KErrNone) {
-    	snd_perror("Error in MaoscPlayComplete()", aError);
-    }
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-
-
-/*
- * Initialize sound subsystem.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
-{
-    snd_pool_factory = factory;
-    return PJ_SUCCESS;
-}
-
-/*
- * Get device count.
- */
-PJ_DEF(int) pjmedia_snd_get_dev_count(void)
-{
-    /* Always return 1 */
-    return 1;
-}
-
-/*
- * Get device info.
- */
-PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
-{
-    /* Always return the default sound device */
-    if (index == (unsigned)-1)
-	index = 0;
-
-    PJ_ASSERT_RETURN(index==0, NULL);
-    return &symbian_snd_dev_info;
-}
-
-
-
-/*
- * Open sound recorder stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
-					  unsigned clock_rate,
-					  unsigned channel_count,
-					  unsigned samples_per_frame,
-					  unsigned bits_per_sample,
-					  pjmedia_snd_rec_cb rec_cb,
-					  void *user_data,
-					  pjmedia_snd_stream **p_snd_strm)
-{
-    pj_pool_t *pool;
-    pjmedia_snd_stream *strm;
-
-    if (index==-1) index = 0;
-    
-    PJ_ASSERT_RETURN(index == 0, PJ_EINVAL);
-    PJ_ASSERT_RETURN(clock_rate && channel_count && samples_per_frame &&
-    		     bits_per_sample && rec_cb && p_snd_strm, PJ_EINVAL);
-
-    pool = pj_pool_create(snd_pool_factory, POOL_NAME, POOL_SIZE, POOL_INC, 
-    			  NULL);
-    if (!pool)
-	return PJ_ENOMEM;
-
-    strm = (pjmedia_snd_stream*) pj_pool_zalloc(pool, 
-    						sizeof(pjmedia_snd_stream));
-    strm->dir = PJMEDIA_DIR_CAPTURE;
-    strm->pool = pool;
-    strm->clock_rate = clock_rate;
-    strm->channel_count = channel_count;
-    strm->samples_per_frame = samples_per_frame;
-
-    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);
-    PJ_ASSERT_RETURN(get_clock_rate_cap(clock_rate) != 0, PJ_EINVAL);
-    PJ_ASSERT_RETURN(get_channel_cap(channel_count) != 0, PJ_EINVAL);
-
-    // Create the input stream.
-    TRAPD(err, strm->inEngine = CPjAudioInputEngine::NewL(strm, rec_cb, 
-    							  user_data));
-    if (err != KErrNone) {
-    	pj_pool_release(pool);
-    	return PJ_RETURN_OS_ERROR(err);
-    }
-
-    // Done.
-    *p_snd_strm = strm;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
-					unsigned clock_rate,
-					unsigned channel_count,
-					unsigned samples_per_frame,
-					unsigned bits_per_sample,
-					pjmedia_snd_play_cb play_cb,
-					void *user_data,
-					pjmedia_snd_stream **p_snd_strm )
-{
-    pj_pool_t *pool;
-    pjmedia_snd_stream *strm;
-
-    if (index == -1) index = 0;
-    
-    PJ_ASSERT_RETURN(index == 0, PJ_EINVAL);
-    PJ_ASSERT_RETURN(clock_rate && channel_count && samples_per_frame &&
-    		     bits_per_sample && play_cb && p_snd_strm, PJ_EINVAL);
-
-    pool = pj_pool_create(snd_pool_factory, POOL_NAME, POOL_SIZE, POOL_INC, 
-    			  NULL);
-    if (!pool)
-	return PJ_ENOMEM;
-
-    strm = (pjmedia_snd_stream*) pj_pool_zalloc(pool, 
-    						sizeof(pjmedia_snd_stream));
-    strm->dir = PJMEDIA_DIR_PLAYBACK;    
-    strm->pool = pool;
-    strm->clock_rate = clock_rate;
-    strm->channel_count = channel_count;
-    strm->samples_per_frame = samples_per_frame;
-
-    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);
-    PJ_ASSERT_RETURN(get_clock_rate_cap(clock_rate) != 0, PJ_EINVAL);
-    PJ_ASSERT_RETURN(get_channel_cap(channel_count) != 0, PJ_EINVAL);
-
-    // Create the output stream.
-    TRAPD(err, strm->outEngine = CPjAudioOutputEngine::NewL(strm, play_cb, 
-    							    user_data));
-    if (err != KErrNone) {
-    	pj_pool_release(pool);	
-	return PJ_RETURN_OS_ERROR(err);
-    }
-
-    // Done.
-    *p_snd_strm = strm;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_open( 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,
-				      pjmedia_snd_stream **p_snd_strm)
-{
-    pj_pool_t *pool;
-    pjmedia_snd_stream *strm;
-
-    if (rec_id == -1) rec_id = 0;
-    if (play_id == -1) play_id = 0;
-    
-    PJ_ASSERT_RETURN(rec_id == 0 && play_id == 0, PJ_EINVAL);
-    PJ_ASSERT_RETURN(clock_rate && channel_count && samples_per_frame &&
-    		     bits_per_sample && rec_cb && play_cb && p_snd_strm, 
-    		     PJ_EINVAL);
-
-    pool = pj_pool_create(snd_pool_factory, POOL_NAME, POOL_SIZE, POOL_INC, 
-    			  NULL);
-    if (!pool)
-	return PJ_ENOMEM;
-
-    strm = (pjmedia_snd_stream*) pj_pool_zalloc(pool, 
-    						sizeof(pjmedia_snd_stream));
-    strm->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
-    strm->pool = pool;
-    strm->clock_rate = clock_rate;
-    strm->channel_count = channel_count;
-    strm->samples_per_frame = samples_per_frame;
-
-    PJ_ASSERT_RETURN(bits_per_sample == 16, PJ_EINVAL);
-    PJ_ASSERT_RETURN(get_clock_rate_cap(clock_rate) != 0, PJ_EINVAL);
-    PJ_ASSERT_RETURN(get_channel_cap(channel_count) != 0, PJ_EINVAL);
-
-    // Create the output stream.
-    TRAPD(err, strm->outEngine = CPjAudioOutputEngine::NewL(strm, play_cb, 
-    							    user_data));
-    if (err != KErrNone) {
-    	pj_pool_release(pool);	
-	return PJ_RETURN_OS_ERROR(err);
-    }
-
-    // Create the input stream.
-    TRAPD(err1, strm->inEngine = CPjAudioInputEngine::NewL(strm, rec_cb, 
-    							   user_data));
-    if (err1 != KErrNone) {
-        strm->inEngine = NULL;
-        delete strm->outEngine;
-    	strm->outEngine = NULL;
-    	pj_pool_release(pool);	
-	return PJ_RETURN_OS_ERROR(err1);
-    }
-
-    // Done.
-    *p_snd_strm = strm;
-    return PJ_SUCCESS;
-}
-
-/*
- * Get stream info.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
-						pjmedia_snd_stream_info *pi)
-{
-    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
-
-    pj_bzero(pi, sizeof(*pi));
-    pi->dir = strm->dir;
-    pi->play_id = 0;
-    pi->rec_id = 0;
-    pi->clock_rate = strm->clock_rate;
-    pi->channel_count = strm->channel_count;
-    pi->samples_per_frame = strm->samples_per_frame;
-    pi->bits_per_sample = BYTES_PER_SAMPLE * 8;
-    // Symbian uses 4096 bytes buffer (~2048 samples/256 ms) for PCM rec & play.
-    // The latencies below are rounded up to be a multiplication of 80.
-    pi->rec_latency  = 2080;
-    pi->play_latency = 2080;
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
-{
-    pj_status_t status;
-    
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-    
-    if (stream->outEngine) {
-    	status = stream->outEngine->StartPlay();
-    	if (status != PJ_SUCCESS)
-    	    return status;
-    }
-    
-    if (stream->inEngine) {
-    	status = stream->inEngine->StartRecord();
-    	if (status != PJ_SUCCESS)
-    	    return status;
-    }
-    	
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
-{
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-    
-    if (stream->inEngine) {
-    	stream->inEngine->Stop();
-    }
-    	
-    if (stream->outEngine) {
-    	stream->outEngine->Stop();
-    }
-    
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
-{
-    pj_pool_t *pool;
-    
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-    
-    if (stream->inEngine) {
-    	delete stream->inEngine;
-    	stream->inEngine = NULL;
-    }
-
-    if (stream->outEngine) {
-    	delete stream->outEngine;
-    	stream->outEngine = NULL;
-    }
-    
-    pool = stream->pool;
-    if (pool) {	
-    	stream->pool = NULL;
-    	pj_pool_release(pool);
-    }
-    
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
-{
-    /* Nothing to do */
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Set sound latency.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency, 
-					    unsigned output_latency)
-{
-    /* Nothing to do */
-    PJ_UNUSED_ARG(input_latency);
-    PJ_UNUSED_ARG(output_latency);
-    return PJ_SUCCESS;
-}
-
-#endif
Index: project/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound_aps.cpp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/symbian_sound_aps.cpp	(revision 2488)
+++ 	(revision )
@@ -1,1427 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
- * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#include <pjmedia/sound.h>
-#include <pjmedia/symbian_sound_aps.h>
-#include <pjmedia/alaw_ulaw.h>
-#include <pjmedia/errno.h>
-#include <pjmedia/port.h>
-#include <pj/assert.h>
-#include <pj/log.h>
-#include <pj/math.h>
-#include <pj/os.h>
-
-#if PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_SYMB_APS_SOUND
-
-#include <e32msgqueue.h>
-#include <sounddevice.h>
-#include <APSClientSession.h>
-
-//////////////////////////////////////////////////////////////////////////////
-//
-
-#define THIS_FILE	    "symbian_sound_aps.cpp"
-
-#define BYTES_PER_SAMPLE    2
-#define POOL_NAME	    "SymbianSoundAps"
-#define POOL_SIZE	    512
-#define POOL_INC	    512
-
-#if 1
-#   define TRACE_(st) PJ_LOG(3, st)
-#else
-#   define TRACE_(st)
-#endif
-
-static pjmedia_snd_dev_info symbian_snd_dev_info =
-{
-    "Symbian Sound Device (APS)",
-    1,
-    1,
-    8000
-};
-
-/* App UID to open global APS queues to communicate with the APS server. */
-extern TPtrC		    APP_UID;
-
-/* APS G.711 frame length */
-static pj_uint8_t aps_g711_frame_len;
-
-/* Pool factory */
-static pj_pool_factory *snd_pool_factory;
-
-/* Forward declaration of CPjAudioEngine */
-class CPjAudioEngine;
-
-/*
- * PJMEDIA Sound Stream instance
- */
-struct pjmedia_snd_stream
-{
-    // Pool
-    pj_pool_t		*pool;
-
-    // Common settings.
-    pjmedia_dir		 dir;
-    unsigned		 clock_rate;
-    unsigned		 channel_count;
-    unsigned		 samples_per_frame;
-    pjmedia_snd_rec_cb   rec_cb;
-    pjmedia_snd_play_cb	 play_cb;
-    void                *user_data;
-    pjmedia_snd_setting  setting;
-
-    // Audio engine
-    CPjAudioEngine	*engine;
-
-    pj_timestamp  	 ts_play;
-    pj_timestamp	 ts_rec;
-
-    pj_int16_t		*play_buf;
-    pj_uint16_t		 play_buf_len;
-    pj_uint16_t		 play_buf_start;
-    pj_int16_t		*rec_buf;
-    pj_uint16_t		 rec_buf_len;
-    void                *strm_data;
-};
-
-
-/*
- * Utility: print sound device error
- */
-static void snd_perror(const char *title, TInt rc)
-{
-    PJ_LOG(1,(THIS_FILE, "%s (error code=%d)", title, rc));
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//
-
-typedef void(*PjAudioCallback)(TAPSCommBuffer &buf, void *user_data);
-
-/**
- * Abstract class for handler of callbacks from APS client.
- */
-class MQueueHandlerObserver
-{
-public:
-    MQueueHandlerObserver(PjAudioCallback RecCb_, PjAudioCallback PlayCb_,
-			  void *UserData_)
-    : RecCb(RecCb_), PlayCb(PlayCb_), UserData(UserData_)
-    {}
-
-    virtual void InputStreamInitialized(const TInt aStatus) = 0;
-    virtual void OutputStreamInitialized(const TInt aStatus) = 0;
-    virtual void NotifyError(const TInt aError) = 0;
-
-public:
-    PjAudioCallback RecCb;
-    PjAudioCallback PlayCb;
-    void *UserData;
-};
-
-/**
- * Handler for communication and data queue.
- */
-class CQueueHandler : public CActive
-{
-public:
-    // Types of queue handler
-    enum TQueueHandlerType {
-        ERecordCommQueue,
-        EPlayCommQueue,
-        ERecordQueue,
-        EPlayQueue
-    };
-
-    // The order corresponds to the APS Server state, do not change!
-    enum TState {
-    	EAPSPlayerInitialize        = 1,
-    	EAPSRecorderInitialize      = 2,
-    	EAPSPlayData                = 3,
-    	EAPSRecordData              = 4,
-    	EAPSPlayerInitComplete      = 5,
-    	EAPSRecorderInitComplete    = 6
-    };
-
-    static CQueueHandler* NewL(MQueueHandlerObserver* aObserver,
-			       RMsgQueue<TAPSCommBuffer>* aQ,
-			       RMsgQueue<TAPSCommBuffer>* aWriteQ,
-			       TQueueHandlerType aType)
-    {
-	CQueueHandler* self = new (ELeave) CQueueHandler(aObserver, aQ, aWriteQ,
-							 aType);
-	CleanupStack::PushL(self);
-	self->ConstructL();
-	CleanupStack::Pop(self);
-	return self;
-    }
-
-    // Destructor
-    ~CQueueHandler() { Cancel(); }
-
-    // Start listening queue event
-    void Start() {
-	iQ->NotifyDataAvailable(iStatus);
-	SetActive();
-    }
-
-private:
-    // Constructor
-    CQueueHandler(MQueueHandlerObserver* aObserver,
-		  RMsgQueue<TAPSCommBuffer>* aQ,
-		  RMsgQueue<TAPSCommBuffer>* aWriteQ,
-		  TQueueHandlerType aType)
-	: CActive(CActive::EPriorityHigh),
-	  iQ(aQ), iWriteQ(aWriteQ), iObserver(aObserver), iType(aType)
-    {
-	CActiveScheduler::Add(this);
-
-	// use lower priority for comm queues
-	if ((iType == ERecordCommQueue) || (iType == EPlayCommQueue))
-	    SetPriority(CActive::EPriorityStandard);
-    }
-
-    // Second phase constructor
-    void ConstructL() {}
-
-    // Inherited from CActive
-    void DoCancel() { iQ->CancelDataAvailable(); }
-
-    void RunL() {
-	if (iStatus != KErrNone) {
-	    iObserver->NotifyError(iStatus.Int());
-	    return;
-        }
-
-	TAPSCommBuffer buffer;
-	TInt ret = iQ->Receive(buffer);
-
-	if (ret != KErrNone) {
-	    iObserver->NotifyError(ret);
-	    return;
-	}
-
-	switch (iType) {
-	case ERecordQueue:
-	    if (buffer.iCommand == EAPSRecordData) {
-		iObserver->RecCb(buffer, iObserver->UserData);
-	    } else {
-		iObserver->NotifyError(buffer.iStatus);
-	    }
-	    break;
-
-	// Callbacks from the APS main thread
-	case EPlayCommQueue:
-	    switch (buffer.iCommand) {
-		case EAPSPlayData:
-		    if (buffer.iStatus == KErrUnderflow) {
-			iObserver->PlayCb(buffer, iObserver->UserData);
-			iWriteQ->Send(buffer);
-		    }
-		    break;
-		case EAPSPlayerInitialize:
-		    iObserver->NotifyError(buffer.iStatus);
-		    break;
-		case EAPSPlayerInitComplete:
-		    iObserver->OutputStreamInitialized(buffer.iStatus);
-		    break;
-		case EAPSRecorderInitComplete:
-		    iObserver->InputStreamInitialized(buffer.iStatus);
-		    break;
-		default:
-		    iObserver->NotifyError(buffer.iStatus);
-		    break;
-	    }
-	    break;
-
-	// Callbacks from the APS recorder thread
-	case ERecordCommQueue:
-	    switch (buffer.iCommand) {
-		// The APS recorder thread will only report errors
-		// through this handler. All other callbacks will be
-		// sent from the APS main thread through EPlayCommQueue
-		case EAPSRecorderInitialize:
-		case EAPSRecordData:
-		default:
-		    iObserver->NotifyError(buffer.iStatus);
-		    break;
-	    }
-	    break;
-
-	default:
-	    break;
-        }
-
-        // issue next request
-        iQ->NotifyDataAvailable(iStatus);
-        SetActive();
-    }
-
-    TInt RunError(TInt) {
-	return 0;
-    }
-
-    // Data
-    RMsgQueue<TAPSCommBuffer>	*iQ;   // (not owned)
-    RMsgQueue<TAPSCommBuffer>	*iWriteQ;   // (not owned)
-    MQueueHandlerObserver	*iObserver; // (not owned)
-    TQueueHandlerType            iType;
-};
-
-/*
- * Audio setting for CPjAudioEngine.
- */
-class CPjAudioSetting
-{
-public:
-    TFourCC		 fourcc;
-    TAPSCodecMode	 mode;
-    TBool		 plc;
-    TBool		 vad;
-    TBool		 cng;
-    TBool		 loudspk;
-};
-
-/*
- * Implementation: Symbian Input & Output Stream.
- */
-class CPjAudioEngine : public CBase, MQueueHandlerObserver
-{
-public:
-    enum State
-    {
-	STATE_NULL,
-	STATE_READY,
-	STATE_STREAMING
-    };
-
-    ~CPjAudioEngine();
-
-    static CPjAudioEngine *NewL(pjmedia_snd_stream *parent_strm,
-			        PjAudioCallback rec_cb,
-				PjAudioCallback play_cb,
-				void *user_data,
-				const CPjAudioSetting &setting);
-
-    TInt StartL();
-    void Stop();
-
-    TInt ActivateSpeaker(TBool active);
-
-private:
-    CPjAudioEngine(pjmedia_snd_stream *parent_strm,
-		   PjAudioCallback rec_cb,
-		   PjAudioCallback play_cb,
-		   void *user_data,
-		   const CPjAudioSetting &setting);
-    void ConstructL();
-
-    TInt InitPlayL();
-    TInt InitRecL();
-    TInt StartStreamL();
-
-    // Inherited from MQueueHandlerObserver
-    virtual void InputStreamInitialized(const TInt aStatus);
-    virtual void OutputStreamInitialized(const TInt aStatus);
-    virtual void NotifyError(const TInt aError);
-
-    State			 state_;
-    pjmedia_snd_stream		*parentStrm_;
-    CPjAudioSetting		 setting_;
-
-    RAPSSession                  iSession;
-    TAPSInitSettings             iPlaySettings;
-    TAPSInitSettings             iRecSettings;
-
-    RMsgQueue<TAPSCommBuffer>    iReadQ;
-    RMsgQueue<TAPSCommBuffer>    iReadCommQ;
-    RMsgQueue<TAPSCommBuffer>    iWriteQ;
-    RMsgQueue<TAPSCommBuffer>    iWriteCommQ;
-
-    CQueueHandler		*iPlayCommHandler;
-    CQueueHandler		*iRecCommHandler;
-    CQueueHandler		*iRecHandler;
-};
-
-
-CPjAudioEngine* CPjAudioEngine::NewL(pjmedia_snd_stream *parent_strm,
-				     PjAudioCallback rec_cb,
-				     PjAudioCallback play_cb,
-				     void *user_data,
-				     const CPjAudioSetting &setting)
-{
-    CPjAudioEngine* self = new (ELeave) CPjAudioEngine(parent_strm,
-						       rec_cb, play_cb,
-						       user_data,
-						       setting);
-    CleanupStack::PushL(self);
-    self->ConstructL();
-    CleanupStack::Pop(self);
-    return self;
-}
-
-CPjAudioEngine::CPjAudioEngine(pjmedia_snd_stream *parent_strm,
-			       PjAudioCallback rec_cb,
-			       PjAudioCallback play_cb,
-			       void *user_data,
-			       const CPjAudioSetting &setting)
-      : MQueueHandlerObserver(rec_cb, play_cb, user_data),
-	state_(STATE_NULL),
-	parentStrm_(parent_strm),
-	setting_(setting),
-	iPlayCommHandler(0),
-	iRecCommHandler(0),
-	iRecHandler(0)
-{
-}
-
-CPjAudioEngine::~CPjAudioEngine()
-{
-    Stop();
-
-    delete iRecHandler;
-    delete iPlayCommHandler;
-    delete iRecCommHandler;
-
-    // On some devices, immediate closing after stopping may cause APS server
-    // panic KERN-EXEC 0, so let's wait for sometime before really closing
-    // the client session.
-    TTime start, now;
-    enum { APS_CLOSE_WAIT_TIME = 200 }; /* in msecs */
-    
-    start.UniversalTime();
-    do {
-	pj_symbianos_poll(-1, APS_CLOSE_WAIT_TIME);
-	now.UniversalTime();
-    } while (now.MicroSecondsFrom(start) < APS_CLOSE_WAIT_TIME * 1000);
-
-    iSession.Close();
-
-    if (state_ == STATE_READY) {
-	if (parentStrm_->dir != PJMEDIA_DIR_PLAYBACK) {
-	    iReadQ.Close();
-	    iReadCommQ.Close();
-	}
-	iWriteQ.Close();
-	iWriteCommQ.Close();
-    }
-}
-
-TInt CPjAudioEngine::InitPlayL()
-{
-    if (state_ == STATE_STREAMING || state_ == STATE_READY)
-	return 0;
-
-    TInt err = iSession.InitializePlayer(iPlaySettings);
-    if (err != KErrNone) {
-	snd_perror("Failed to initialize player", err);
-	return err;
-    }
-
-    // Open message queues for the output stream
-    TBuf<128> buf2 = iPlaySettings.iGlobal;
-    buf2.Append(_L("PlayQueue"));
-    TBuf<128> buf3 = iPlaySettings.iGlobal;
-    buf3.Append(_L("PlayCommQueue"));
-
-    while (iWriteQ.OpenGlobal(buf2))
-	User::After(10);
-    while (iWriteCommQ.OpenGlobal(buf3))
-	User::After(10);
-
-    // Construct message queue handler
-    iPlayCommHandler = CQueueHandler::NewL(this, &iWriteCommQ, &iWriteQ,
-					   CQueueHandler::EPlayCommQueue);
-
-    // Start observing APS callbacks on output stream message queue
-    iPlayCommHandler->Start();
-
-    return 0;
-}
-
-TInt CPjAudioEngine::InitRecL()
-{
-    if (state_ == STATE_STREAMING || state_ == STATE_READY)
-	return 0;
-
-    // Initialize input stream device
-    TInt err = iSession.InitializeRecorder(iRecSettings);
-    if (err != KErrNone && err != KErrAlreadyExists) {
-	snd_perror("Failed to initialize recorder", err);
-	return err;
-    }
-
-    TBuf<128> buf1 = iRecSettings.iGlobal;
-    buf1.Append(_L("RecordQueue"));
-    TBuf<128> buf4 = iRecSettings.iGlobal;
-    buf4.Append(_L("RecordCommQueue"));
-
-    // Must wait for APS thread to finish creating message queues
-    // before we can open and use them.
-    while (iReadQ.OpenGlobal(buf1))
-	User::After(10);
-    while (iReadCommQ.OpenGlobal(buf4))
-	User::After(10);
-
-    // Construct message queue handlers
-    iRecHandler = CQueueHandler::NewL(this, &iReadQ, NULL,
-				      CQueueHandler::ERecordQueue);
-    iRecCommHandler = CQueueHandler::NewL(this, &iReadCommQ, NULL,
-					  CQueueHandler::ERecordCommQueue);
-
-    // Start observing APS callbacks from on input stream message queue
-    iRecHandler->Start();
-    iRecCommHandler->Start();
-
-    return 0;
-}
-
-TInt CPjAudioEngine::StartL()
-{
-    if (state_ == STATE_READY)
-	return StartStreamL();
-
-    // Even if only capturer are opened, playback thread of APS Server need
-    // to be run(?). Since some messages will be delivered via play comm queue.
-    return InitPlayL();
-}
-
-void CPjAudioEngine::Stop()
-{
-    if (state_ == STATE_STREAMING) {
-	iSession.Stop();
-	state_ = STATE_READY;
-	TRACE_((THIS_FILE, "Sound device stopped"));
-    }
-}
-
-void CPjAudioEngine::ConstructL()
-{
-    // Recorder settings
-    iRecSettings.iFourCC		= setting_.fourcc;
-    iRecSettings.iGlobal		= APP_UID;
-    iRecSettings.iPriority		= TMdaPriority(100);
-    iRecSettings.iPreference		= TMdaPriorityPreference(0x05210001);
-    iRecSettings.iSettings.iChannels	= EMMFMono;
-    iRecSettings.iSettings.iSampleRate	= EMMFSampleRate8000Hz;
-
-    // Player settings
-    iPlaySettings.iFourCC		= setting_.fourcc;
-    iPlaySettings.iGlobal		= APP_UID;
-    iPlaySettings.iPriority		= TMdaPriority(100);
-    iPlaySettings.iPreference		= TMdaPriorityPreference(0x05220001);
-    iPlaySettings.iSettings.iChannels	= EMMFMono;
-    iPlaySettings.iSettings.iSampleRate = EMMFSampleRate8000Hz;
-    iPlaySettings.iSettings.iVolume	= 0;
-
-    User::LeaveIfError(iSession.Connect());
-}
-
-TInt CPjAudioEngine::StartStreamL()
-{
-    if (state_ == STATE_STREAMING)
-	return 0;
-
-    iSession.SetCng(setting_.cng);
-    iSession.SetVadMode(setting_.vad);
-    iSession.SetPlc(setting_.plc);
-    iSession.SetEncoderMode(setting_.mode);
-    iSession.SetDecoderMode(setting_.mode);
-    iSession.ActivateLoudspeaker(setting_.loudspk);
-
-    // Not only capture
-    if (parentStrm_->dir != PJMEDIA_DIR_CAPTURE) {
-	iSession.Write();
-	TRACE_((THIS_FILE, "Player started"));
-    }
-
-    // Not only playback
-    if (parentStrm_->dir != PJMEDIA_DIR_PLAYBACK) {
-	iSession.Read();
-	TRACE_((THIS_FILE, "Recorder started"));
-    }
-
-    state_ = STATE_STREAMING;
-    return 0;
-}
-
-///////////////////////////////////////////////////////////
-// Inherited from MQueueHandlerObserver
-//
-
-void CPjAudioEngine::InputStreamInitialized(const TInt aStatus)
-{
-    TRACE_((THIS_FILE, "Recorder initialized, err=%d", aStatus));
-
-    state_ = STATE_READY;
-    if (aStatus == KErrNone) {
-	StartStreamL();
-    }
-}
-
-void CPjAudioEngine::OutputStreamInitialized(const TInt aStatus)
-{
-    TRACE_((THIS_FILE, "Player initialized, err=%d", aStatus));
-
-    if (aStatus == KErrNone) {
-	if (parentStrm_->dir == PJMEDIA_DIR_PLAYBACK) {
-	    state_ = STATE_READY;
-	    // Only playback, start directly
-	    StartStreamL();
-	} else
-	    InitRecL();
-    }
-}
-
-void CPjAudioEngine::NotifyError(const TInt aError)
-{
-    snd_perror("Error from CQueueHandler", aError);
-}
-
-//
-// End of inherited from MQueueHandlerObserver
-/////////////////////////////////////////////////////////////
-
-
-TInt CPjAudioEngine::ActivateSpeaker(TBool active)
-{
-    if (state_ == STATE_READY || state_ == STATE_STREAMING) {
-        iSession.ActivateLoudspeaker(active);
-        TRACE_((THIS_FILE, "Loudspeaker turned %s", (active? "on":"off")));
-	return KErrNone;
-    }
-    return KErrNotReady;
-}
-//////////////////////////////////////////////////////////////////////////////
-//
-
-
-static void RecCbPcm(TAPSCommBuffer &buf, void *user_data)
-{
-    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);
-
-    /* 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));
-    }
-
-    /* Decode APS buffer (coded in G.711) and put the PCM result into rec_buf.
-     * Whenever rec_buf is full, call parent stream callback.
-     */
-    unsigned dec_len = 0;
-
-    while (dec_len < aps_g711_frame_len) {
-	unsigned tmp;
-
-	tmp = PJ_MIN(strm->samples_per_frame - strm->rec_buf_len,
-		     aps_g711_frame_len - dec_len);
-	pjmedia_ulaw_decode(&strm->rec_buf[strm->rec_buf_len],
-			    buf.iBuffer.Ptr() + 2 + dec_len,
-			    tmp);
-	strm->rec_buf_len += tmp;
-	dec_len += tmp;
-
-	pj_assert(strm->rec_buf_len <= strm->samples_per_frame);
-
-	if (strm->rec_buf_len == strm->samples_per_frame) {
-	    strm->rec_cb(strm->user_data, 0, strm->rec_buf,
-			 strm->rec_buf_len << 1);
-	    strm->rec_buf_len = 0;
-	}
-    }
-}
-
-static void PlayCbPcm(TAPSCommBuffer &buf, void *user_data)
-{
-    pjmedia_snd_stream *strm = (pjmedia_snd_stream*) user_data;
-    unsigned g711_frame_len = aps_g711_frame_len;
-
-    /* Init buffer attributes and header. */
-    buf.iCommand = CQueueHandler::EAPSPlayData;
-    buf.iStatus = 0;
-    buf.iBuffer.Zero();
-    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 PCM samples to play,
-     * encode the PCM samples into G.711 and put it into APS buffer.
-     */
-    unsigned enc_len = 0;
-    while (enc_len < g711_frame_len) {
-	if (strm->play_buf_len == 0) {
-	    strm->play_cb(strm->user_data, 0, strm->play_buf,
-			  strm->samples_per_frame<<1);
-	    strm->play_buf_len = strm->samples_per_frame;
-	    strm->play_buf_start = 0;
-	}
-
-	unsigned tmp;
-
-	tmp = PJ_MIN(strm->play_buf_len, g711_frame_len - enc_len);
-	pjmedia_ulaw_encode((pj_uint8_t*)&strm->play_buf[strm->play_buf_start],
-			    &strm->play_buf[strm->play_buf_start],
-			    tmp);
-	buf.iBuffer.Append((TUint8*)&strm->play_buf[strm->play_buf_start], tmp);
-	enc_len += tmp;
-	strm->play_buf_len -= tmp;
-	strm->play_buf_start += tmp;
-    }
-}
-
-/* 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;
-    
-    switch(strm->setting.format.id) {
-    case PJMEDIA_FORMAT_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, p, len << 3, 160);
-	    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_FORMAT_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_FORMAT_ILBC:
-	{
-	    unsigned samples_got;
-	    
-	    samples_got = strm->setting.format.bitrate == 15200? 160 : 240;
-	    
-	    /* 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_FORMAT_PCMU:
-    case PJMEDIA_FORMAT_PCMA:
-	{
-	    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;
-    }
-}
-
-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;
-
-    /* Init buffer attributes and header. */
-    buf.iCommand = CQueueHandler::EAPSPlayData;
-    buf.iStatus = 0;
-    buf.iBuffer.Zero();
-
-    switch(strm->setting.format.id) {
-    case PJMEDIA_FORMAT_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+7)>>3;
-		    enum {SID_FT = 8 };
-		    pj_uint8_t amr_header = 4, ft = SID_FT;
-
-		    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_FORMAT_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_FORMAT_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.format.bitrate == 15200 && 
-			   samples_cnt == 160) ||
-			  (strm->setting.format.bitrate != 15200 &&
-			   samples_cnt == 240));
-		
-		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_FORMAT_PCMU:
-    case PJMEDIA_FORMAT_PCMA:
-	{
-	    unsigned samples_ready = 0;
-	    unsigned samples_req = aps_g711_frame_len;
-	    
-	    /* Assume frame size is 10ms if frame size hasn't been known. */
-	    if (samples_req == 0)
-		samples_req = 80;
-	    
-	    buf.iBuffer.Append(1);
-	    buf.iBuffer.Append(0);
-	    
-	    /* Call parent stream callback to get samples to play. */
-	    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, 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) {
-			buf.iBuffer.Append((TUint8*)sf->data, sf->bitlen>>3);
-		    } else {
-			pj_uint8_t silc;
-			silc = (strm->setting.format.id==PJMEDIA_FORMAT_PCMU)?
-				pjmedia_linear2ulaw(0) : pjmedia_linear2alaw(0);
-			buf.iBuffer.AppendFill(silc, samples_cnt);
-		    }
-		    samples_ready += samples_cnt;
-		    
-		    pjmedia_frame_ext_pop_subframes(frame, 1);
-		
-		} else { /* PJMEDIA_FRAME_TYPE_NONE */
-		    pj_uint8_t silc;
-		    
-		    silc = (strm->setting.format.id==PJMEDIA_FORMAT_PCMU)?
-			    pjmedia_linear2ulaw(0) : pjmedia_linear2alaw(0);
-		    buf.iBuffer.AppendFill(silc, samples_req - samples_ready);
-
-		    samples_ready = samples_req;
-		    frame->samples_cnt = 0;
-		    frame->subframe_cnt = 0;
-		}
-	    }
-	}
-	break;
-	
-    default:
-	break;
-    }
-}
-
-/*
- * Initialize sound subsystem.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
-{
-    snd_pool_factory = factory;
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Get device count.
- */
-PJ_DEF(int) pjmedia_snd_get_dev_count(void)
-{
-    /* Always return 1 */
-    return 1;
-}
-
-/*
- * Get device info.
- */
-PJ_DEF(const pjmedia_snd_dev_info*) pjmedia_snd_get_dev_info(unsigned index)
-{
-    /* Always return the default sound device */
-    if (index == (unsigned)-1)
-	index = 0;
-
-    PJ_ASSERT_RETURN(index==0, NULL);
-    return &symbian_snd_dev_info;
-}
-
-static pj_status_t sound_open(pjmedia_dir dir,
-			      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)
-{
-    pj_pool_t *pool;
-    pjmedia_snd_stream *strm;
-    CPjAudioSetting aps_setting;
-    PjAudioCallback aps_rec_cb;
-    PjAudioCallback aps_play_cb;
-
-    PJ_ASSERT_RETURN(p_snd_strm, PJ_EINVAL);
-    PJ_ASSERT_RETURN(clock_rate == 8000 && channel_count == 1 &&
-		     bits_per_sample == 16, PJ_ENOTSUP);
-    PJ_ASSERT_RETURN((dir == PJMEDIA_DIR_CAPTURE_PLAYBACK && rec_cb && play_cb)
-		     || (dir == PJMEDIA_DIR_CAPTURE && rec_cb && !play_cb)
-		     || (dir == PJMEDIA_DIR_PLAYBACK && !rec_cb && play_cb),
-		     PJ_EINVAL);
-
-    pool = pj_pool_create(snd_pool_factory, POOL_NAME, POOL_SIZE, POOL_INC,
-    			  NULL);
-    if (!pool)
-	return PJ_ENOMEM;
-
-    strm = (pjmedia_snd_stream*) pj_pool_zalloc(pool,
-    						sizeof(pjmedia_snd_stream));
-    strm->dir = dir;
-    strm->pool = pool;
-    strm->clock_rate = clock_rate;
-    strm->channel_count = channel_count;
-    strm->samples_per_frame = samples_per_frame;
-    strm->setting = *setting;
-
-    /* Set audio engine fourcc. */
-    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.mode = (TAPSCodecMode)strm->setting.format.bitrate;
-    } 
-    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.id == PJMEDIA_FORMAT_PCMA ||
-	    (strm->setting.format.id == PJMEDIA_FORMAT_ILBC &&
-	     strm->setting.format.bitrate == 15200))
-    {
-	aps_setting.mode = EALawOr20ms;
-    }
-
-    /* Disable VAD on L16 and G711. */
-    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.format.vad;
-    }
-    
-    /* Set other audio engine attributes. */
-    aps_setting.plc = strm->setting.plc;
-    aps_setting.cng = aps_setting.vad;
-    aps_setting.loudspk = strm->setting.route == PJMEDIA_SND_ROUTE_LOUDSPEAKER;
-
-    /* Set audio engine callbacks. */
-    if (strm->setting.format.id == PJMEDIA_FORMAT_L16) {
-	aps_play_cb = &PlayCbPcm;
-	aps_rec_cb  = &RecCbPcm;
-    } else {
-	aps_play_cb = &PlayCb;
-	aps_rec_cb  = &RecCb;
-    }
-
-    /* Create the audio engine. */
-    TRAPD(err, strm->engine = CPjAudioEngine::NewL(strm,
-						   aps_rec_cb, aps_play_cb,
-						   strm, aps_setting));
-    if (err != KErrNone) {
-    	pj_pool_release(pool);
-	return PJ_RETURN_OS_ERROR(err);
-    }
-
-    strm->rec_cb = rec_cb;
-    strm->play_cb = play_cb;
-    strm->user_data = user_data;
-
-    /* play_buf size is samples per frame. */
-    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_zalloc(pool, samples_per_frame << 1);
-    strm->rec_buf_len = 0;
-
-    if (strm->setting.format.id == PJMEDIA_FORMAT_G729) {
-	TBitStream *g729_bitstream = new TBitStream;
-	
-	PJ_ASSERT_RETURN(g729_bitstream, PJ_ENOMEM);
-	strm->strm_data = (void*)g729_bitstream;
-    }
-	
-    // Done.
-    *p_snd_strm = strm;
-    return PJ_SUCCESS;
-}
-
-
-
-/*
- * Open sound recorder stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_open_rec( int index,
-					  unsigned clock_rate,
-					  unsigned channel_count,
-					  unsigned samples_per_frame,
-					  unsigned bits_per_sample,
-					  pjmedia_snd_rec_cb rec_cb,
-					  void *user_data,
-					  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.id = PJMEDIA_FORMAT_L16;
-    
-    return sound_open(PJMEDIA_DIR_CAPTURE, clock_rate, channel_count,
-		      samples_per_frame, bits_per_sample, rec_cb, NULL,
-		      user_data, &setting, p_snd_strm);
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_open_player( int index,
-					unsigned clock_rate,
-					unsigned channel_count,
-					unsigned samples_per_frame,
-					unsigned bits_per_sample,
-					pjmedia_snd_play_cb play_cb,
-					void *user_data,
-					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.id = PJMEDIA_FORMAT_L16;
-
-    return sound_open(PJMEDIA_DIR_PLAYBACK, clock_rate, channel_count,
-		      samples_per_frame, bits_per_sample, NULL, play_cb,
-		      user_data, &setting, p_snd_strm);
-}
-
-PJ_DEF(pj_status_t) pjmedia_snd_open( 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,
-				      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.id = PJMEDIA_FORMAT_L16;
-
-    return sound_open(PJMEDIA_DIR_CAPTURE_PLAYBACK, clock_rate, channel_count,
-		      samples_per_frame, bits_per_sample, rec_cb, play_cb,
-		      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);
-}
-
-/*
- * Get stream info.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_get_info(pjmedia_snd_stream *strm,
-						pjmedia_snd_stream_info *pi)
-{
-    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
-
-    pj_bzero(pi, sizeof(*pi));
-    pi->dir = strm->dir;
-    pi->play_id = 0;
-    pi->rec_id = 0;
-    pi->clock_rate = strm->clock_rate;
-    pi->channel_count = strm->channel_count;
-    pi->samples_per_frame = strm->samples_per_frame;
-    pi->bits_per_sample = BYTES_PER_SAMPLE * 8;
-    // latencies approximation (in samples)
-    pi->rec_latency  = strm->samples_per_frame * 2;
-    pi->play_latency = strm->samples_per_frame * 2;
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_start(pjmedia_snd_stream *stream)
-{
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-
-    if (stream->engine) {
-	TInt err = stream->engine->StartL();
-    	if (err != KErrNone)
-    	    return PJ_RETURN_OS_ERROR(err);
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
-{
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-
-    if (stream->engine) {
-    	stream->engine->Stop();
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
-{
-    pj_pool_t *pool;
-
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-
-    delete stream->engine;
-    stream->engine = NULL;
-
-    if (stream->setting.format.id == PJMEDIA_FORMAT_G729) {
-	TBitStream *g729_bitstream = (TBitStream*)stream->strm_data;
-	stream->strm_data = NULL;
-	delete g729_bitstream;
-    }
-
-    pool = stream->pool;
-    if (pool) {
-    	stream->pool = NULL;
-    	pj_pool_release(pool);
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
-{
-    /* Nothing to do */
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Set sound latency.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_set_latency(unsigned input_latency,
-					    unsigned output_latency)
-{
-    /* Nothing to do */
-    PJ_UNUSED_ARG(input_latency);
-    PJ_UNUSED_ARG(output_latency);
-    return PJ_SUCCESS;
-}
-
-/*
- * Activate/deactivate loudspeaker.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_aps_set_route( pjmedia_snd_stream *stream,
-					       pjmedia_snd_route route)
-{
-    PJ_ASSERT_RETURN(stream && stream->engine, PJ_EINVAL);
-
-    TBool loudspk_active;
-    
-    switch (route) {
-    case PJMEDIA_SND_ROUTE_DEFAULT:
-    case PJMEDIA_SND_ROUTE_EARPIECE:
-	loudspk_active = EFalse;
-	break;
-    case PJMEDIA_SND_ROUTE_LOUDSPEAKER:
-	loudspk_active = ETrue;
-	break;
-    default:
-	return PJ_EINVAL;
-    }
-    
-    TInt err = stream->engine->ActivateSpeaker(loudspk_active);
-    if (err != KErrNone)
-	return PJ_RETURN_OS_ERROR(err);
-
-    return PJ_SUCCESS;
-}
-
-#endif // PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_SYMB_APS_SOUND
