Index: /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia.dsp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia.dsp	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia.dsp	(revision 2468)
@@ -122,8 +122,4 @@
 # Begin Source File
 
-SOURCE=..\src\pjmedia\dsound.c
-# End Source File
-# Begin Source File
-
 SOURCE=..\src\pjmedia\echo_common.c
 # End Source File
@@ -178,12 +174,4 @@
 # Begin Source File
 
-SOURCE=..\src\pjmedia\nullsound.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjmedia\pasound.c
-# End Source File
-# Begin Source File
-
 SOURCE=..\src\pjmedia\plc_common.c
 # End Source File
@@ -295,8 +283,4 @@
 
 SOURCE=..\src\pjmedia\wave.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\src\pjmedia\wmme_sound.c
 # End Source File
 # Begin Source File
Index: /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_audiodev.dsp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_audiodev.dsp	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_audiodev.dsp	(revision 2468)
@@ -102,4 +102,14 @@
 # Begin Source File
 
+SOURCE="..\src\pjmedia-audiodev\symb_aps_dev.cpp"
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-audiodev\symb_mda_dev.cpp"
+# PROP Exclude_From_Build 1
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjmedia-audiodev\wmme_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 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev.h	(revision 2468)
@@ -18,6 +18,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#ifndef __AUDIODEV_H__
-#define __AUDIODEV_H__
+#ifndef __PJMEDIA_AUDIODEV_AUDIODEV_H__
+#define __PJMEDIA_AUDIODEV_AUDIODEV_H__
 
 /**
@@ -52,9 +52,19 @@
  */
 
-/** Device identifier */
-typedef pj_int32_t pjmedia_aud_dev_id;
-
-/** Constant to denote default ID */
-#define PJMEDIA_AUD_DEV_DEFAULT_ID  (-1)
+/** 
+ * Type for device index.
+ */
+typedef pj_int32_t pjmedia_aud_dev_index;
+
+/** 
+ * Constant to denote default device 
+ */
+#define PJMEDIA_AUD_DEV_DEFAULT  (-1)
+
+/** 
+ * Type for device unique identifier. The unique device ID can be used to save
+ * a reference to a particular device across software reboots.
+ */
+typedef pj_uint32_t pjmedia_aud_dev_uid;
 
 
@@ -67,5 +77,5 @@
  *
  * Application can also set the specific features/capabilities when opening
- * the audio stream by setting the \a flags member of #pjmedia_aud_dev_param
+ * the audio stream by setting the \a flags member of #pjmedia_aud_param
  * structure.
  *
@@ -118,5 +128,5 @@
      * the audio volume in percent.
      */
-    PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_VOLUME = 32,
+    PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_METER = 32,
 
     /** 
@@ -125,5 +135,5 @@
      * the audio volume in percent.
      */
-    PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_VOLUME = 64,
+    PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_METER = 64,
 
     /** 
@@ -142,5 +152,5 @@
     /** 
      * The audio device has echo cancellation feature. The value of this
-     * capability is an integer containing boolean PJ_TRUE or PJ_FALSE.
+     * capability is a pj_bool_t containing boolean PJ_TRUE or PJ_FALSE.
      */
     PJMEDIA_AUD_DEV_CAP_EC = 512,
@@ -155,5 +165,5 @@
     /** 
      * The audio device has voice activity detection feature. The value
-     * of this capability is an integer containing boolean PJ_TRUE or 
+     * of this capability is a pj_bool_t containing boolean PJ_TRUE or 
      * PJ_FALSE.
      */
@@ -162,5 +172,5 @@
     /** 
      * The audio device has comfort noise generation feature. The value
-     * of this capability is an integer containing boolean PJ_TRUE or 
+     * of this capability is a pj_bool_t containing boolean PJ_TRUE or 
      * PJ_FALSE.
      */
@@ -169,5 +179,5 @@
     /** 
      * The audio device has packet loss concealment feature. The value
-     * of this capability is an integer containing boolean PJ_TRUE or 
+     * of this capability is a pj_bool_t containing boolean PJ_TRUE or 
      * PJ_FALSE.
      */
@@ -226,5 +236,5 @@
      * The underlying driver name 
      */
-    char driver[128];
+    char driver[32];
 
     /** 
@@ -290,7 +300,7 @@
 
 /**
- * This structure specifies the parameters to open the audio device stream.
- */
-typedef struct pjmedia_aud_dev_param
+ * This structure specifies the parameters to open the audio stream.
+ */
+typedef struct pjmedia_aud_param
 {
     /**
@@ -303,5 +313,5 @@
      * direction includes input/capture direction.
      */
-    pjmedia_aud_dev_id rec_id;
+    pjmedia_aud_dev_index rec_id;
 
     /**
@@ -309,5 +319,5 @@
      * direction includes output/playback direction.
      */
-    pjmedia_aud_dev_id play_id;
+    pjmedia_aud_dev_index play_id;
 
     /** 
@@ -387,5 +397,5 @@
     pj_bool_t cng_enabled;
 
-} pjmedia_aud_dev_param;
+} pjmedia_aud_param;
 
 
@@ -432,4 +442,17 @@
 
 /**
+ * Get string info for the specified capability.
+ *
+ * @param cap		The capability ID.
+ * @param p_desc	Optional pointer which will be filled with longer 
+ *			description about the capability.
+ *
+ * @return		Capability name.
+ */
+PJ_DECL(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
+					      const char **p_desc);
+
+
+/**
  * Get the number of sound devices installed in the system.
  *
@@ -438,15 +461,4 @@
 PJ_DECL(unsigned) pjmedia_aud_dev_count(void);
 
-
-/**
- * Enumerate device ID's.
- *
- * @param max_count	Maximum number of device id's to retrieve.
- * @param ids		Array to receive the device id's.
- *
- * @return		The actual number of device id's filled in.
- */
-PJ_DECL(unsigned) pjmedia_aud_dev_enum(unsigned max_count,
-				       pjmedia_aud_dev_id ids[]);
 
 /**
@@ -460,6 +472,19 @@
  *			error code.
  */
-PJ_DECL(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_id id,
+PJ_DECL(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
 					      pjmedia_aud_dev_info *info);
+
+
+/**
+ * Lookup device index based on the driver and device name.
+ *
+ * @param drv_name	The driver name.
+ * @param dev_name	The device name.
+ *
+ * @return		PJ_SUCCESS if the device can be found.
+ */
+PJ_DECL(pj_status_t) pjmedia_aud_dev_lookup(const char *drv_name,
+					    const char *dev_name,
+					    pjmedia_aud_dev_index *id);
 
 
@@ -475,6 +500,6 @@
  *			error code.
  */
-PJ_DECL(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_id id,
-						   pjmedia_aud_dev_param *param);
+PJ_DECL(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
+						   pjmedia_aud_param *param);
 
 
@@ -493,9 +518,9 @@
  *			error code.
  */
-PJ_DECL(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_dev_param *param,
+PJ_DECL(pj_status_t) pjmedia_aud_stream_create(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);
+					       pjmedia_aud_stream **p_strm);
 
 /**
@@ -510,5 +535,5 @@
  */
 PJ_DECL(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
-						  pjmedia_aud_dev_param *param);
+						  pjmedia_aud_param *param);
 
 /**
@@ -581,4 +606,7 @@
 #define PJMEDIA_EAUD_NOTREADY	-1
 
+/* Invalid audio capability or audio capability not supported */
+#define PJMEDIA_EAUD_INVCAP	-1
+
 /* Unknown system error */
 #define PJMEDIA_EAUD_SYSERR	-1
@@ -592,4 +620,4 @@
 
 
-#endif	/* __AUDIODEV_H__ */
-
+#endif	/* __PJMEDIA_AUDIODEV_AUDIODEV_H__ */
+
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev_imp.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev_imp.h	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev_imp.h	(revision 2468)
@@ -80,5 +80,5 @@
     pj_status_t (*default_param)(pjmedia_aud_dev_factory *f,
 				 unsigned index,
-				 pjmedia_aud_dev_param *param);
+				 pjmedia_aud_param *param);
 
     /**
@@ -87,5 +87,5 @@
      */
     pj_status_t (*create_stream)(pjmedia_aud_dev_factory *f,
-				 const pjmedia_aud_dev_param *param,
+				 const pjmedia_aud_param *param,
 				 pjmedia_aud_rec_cb rec_cb,
 				 pjmedia_aud_play_cb play_cb,
@@ -120,5 +120,5 @@
      */
     pj_status_t (*get_param)(pjmedia_aud_stream *strm,
-			     pjmedia_aud_dev_param *param);
+			     pjmedia_aud_param *param);
 
     /**
@@ -159,6 +159,6 @@
 struct pjmedia_aud_stream
 {
-    /** Factory */
-    pjmedia_aud_dev_factory *factory;
+    /** Factory id (internal) */
+    unsigned factory_id;
 
     /** Operations */
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiotest.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiotest.h	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiotest.h	(revision 2468)
@@ -18,6 +18,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#ifndef __AUDIOTEST_H__
-#define __AUDIOTEST_H__
+#ifndef __PJMEDIA_AUDIODEV_AUDIOTEST_H__
+#define __PJMEDIA_AUDIODEV_AUDIOTEST_H__
 
 /**
@@ -92,5 +92,5 @@
  * Perform audio device testing.
  */
-PJ_DECL(pj_status_t) pjmedia_aud_test(const pjmedia_aud_dev_param *param,
+PJ_DECL(pj_status_t) pjmedia_aud_test(const pjmedia_aud_param *param,
 				      pjmedia_aud_test_results *result);
 
@@ -102,5 +102,5 @@
 
 
-#endif	/* __AUDIOTEST_H__ */
+#endif	/* __PJMEDIA_AUDIODEV_AUDIOTEST_H__ */
 
 
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia.h	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia.h	(revision 2468)
@@ -53,5 +53,8 @@
 #include <pjmedia/session.h>
 #include <pjmedia/silencedet.h>
+/* This sound API is deprecated. Please see:
+http://trac.pjsip.org/repos/wiki/Audio_Dev_API
 #include <pjmedia/sound.h>
+*/
 #include <pjmedia/sound_port.h>
 #include <pjmedia/splitcomb.h>
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/config.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/config.h	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/config.h	(revision 2468)
@@ -65,71 +65,53 @@
  */
 
-/** Constant for NULL sound backend. */
-#define PJMEDIA_SOUND_NULL_SOUND	    0
-
-/** Constant for PortAudio sound backend. */
-#define PJMEDIA_SOUND_PORTAUDIO_SOUND	    1
-
-/** Constant for Win32 DirectSound sound backend. */
-#define PJMEDIA_SOUND_WIN32_DIRECT_SOUND    2
-
-/** Constant for Win32 MME sound backend. */
-#define PJMEDIA_SOUND_WIN32_MME_SOUND	    3
-
-/** Constant for Symbian Multimedia Audio Stream backend. */
-#define PJMEDIA_SOUND_SYMB_MDA_SOUND	    4
-
-/** Constant for Symbian APS backend. */
-#define PJMEDIA_SOUND_SYMB_APS_SOUND	    5
-
-/** Constant for Symbian VAS backend. */
-#define PJMEDIA_SOUND_SYMB_VAS_SOUND	    6
-
-
-/** When this is set, pjmedia will not provide any sound device backend. 
- *  Application will have to provide its own sound device backend
- *  and link the application with it.
- */
-#define PJMEDIA_SOUND_EXTERNAL		    255
-
-
-/**
- * Unless specified otherwise, sound device uses PortAudio implementation
- * by default.
- */
-#ifndef PJMEDIA_SOUND_IMPLEMENTATION
-#  if defined(PJ_WIN32) && PJ_WIN32!=0
-/*#   define PJMEDIA_SOUND_IMPLEMENTATION   PJMEDIA_SOUND_WIN32_DIRECT_SOUND*/
-/*#   define PJMEDIA_SOUND_IMPLEMENTATION   PJMEDIA_SOUND_WIN32_MME_SOUND*/
-#   define PJMEDIA_SOUND_IMPLEMENTATION	    PJMEDIA_SOUND_PORTAUDIO_SOUND
-#  else
-#   define PJMEDIA_SOUND_IMPLEMENTATION	    PJMEDIA_SOUND_PORTAUDIO_SOUND
-#  endif
-#endif
-
-/**
- * Specify if the sound device implementation supports handling encoded
- * frames. Setting this to zero will activate some emulation in the
- * sound port.
- */
-#if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_SYMB_APS_SOUND || \
-    PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_SYMB_VAS_SOUND
-#   define PJMEDIA_SND_SUPPORT_OPEN2	1
-#else
-#   define PJMEDIA_SND_SUPPORT_OPEN2	0
-#endif
-
-/**
- * Specify whether we prefer to use DirectSound on Windows.
- *
- * Default: 0
- */
-#ifndef PJMEDIA_PREFER_DIRECT_SOUND
-#   define PJMEDIA_PREFER_DIRECT_SOUND	    0
-#endif
-
-
-/**
- * Specify sound device latency default, in milisecond.
+/**
+ * This macro has been deprecated in releasee 1.1. Please see
+ * http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more information.
+ */
+#if defined(PJMEDIA_SOUND_IMPLEMENTATION)
+#   error PJMEDIA_SOUND_IMPLEMENTATION has been deprecated
+#endif
+
+/**
+ * This macro has been deprecated in releasee 1.1. Please see
+ * http://trac.pjsip.org/repos/wiki/Audio_Dev_API for more information.
+ */
+#if defined(PJMEDIA_PREFER_DIRECT_SOUND)
+#   error PJMEDIA_PREFER_DIRECT_SOUND has been deprecated
+#endif
+
+/**
+ * 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
+
+
+/**
+ * Specify default sound device latency, in milisecond.
  */
 #ifndef PJMEDIA_SND_DEFAULT_REC_LATENCY
@@ -137,22 +119,9 @@
 #endif
 
+/**
+ * Specify default sound device latency, in milisecond.
+ */
 #ifndef PJMEDIA_SND_DEFAULT_PLAY_LATENCY
 #   define PJMEDIA_SND_DEFAULT_PLAY_LATENCY 100
-#endif
-
-
-/**
- * Specify whether delay buffer is used for sound device.
- * When delay buffer is enabled, the sound device callback 
- * will be called one after another evenly.
- * The delay buffer also performs the best delay calculation
- * for the sound device, and will try to limit the delay caused
- * by uneven callback calls to this delay.
- *
- * When this setting is enabled, the PJMEDIA_SOUND_BUFFER_COUNT
- * macro will specify the maximum size of the delay buffer.
- */
-#ifndef PJMEDIA_SOUND_USE_DELAYBUF
-#   define PJMEDIA_SOUND_USE_DELAYBUF	    0
 #endif
 
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/endpoint.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/endpoint.h	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/endpoint.h	(revision 2468)
@@ -38,5 +38,4 @@
  */
 
-#include <pjmedia/sound.h>
 #include <pjmedia/codec.h>
 #include <pjmedia/sdp.h>
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound.h	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound.h	(revision 2468)
@@ -20,4 +20,13 @@
 #ifndef __PJMEDIA_SOUND_H__
 #define __PJMEDIA_SOUND_H__
+
+
+/* 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
 
 
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound_port.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound_port.h	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/sound_port.h	(revision 2468)
@@ -25,5 +25,5 @@
  * @brief Media port connection abstraction to sound device.
  */
-#include <pjmedia/sound.h>
+#include <pjmedia-audiodev/audiodev.h>
 #include <pjmedia/port.h>
 
@@ -163,23 +163,8 @@
 
 /**
- * Create unidirectional or bidirectional sound port. This also allows
- * creating sound port with extended settings, e.g: audio format, see 
- * #pjmedia_snd_setting.
- *
- * @param pool		    Pool to allocate sound port structure.
- * @param dir		    Sound device 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 setting	    Sound device extended settings, see 
- *			    #pjmedia_snd_setting.
+ * Create sound device port according to the specified parameters.
+ *
+ * @param pool		    Pool to allocate sound port structure.
+ * @param prm		    Sound device settings.
  * @param p_port	    Pointer to receive the sound device port instance.
  *
@@ -188,12 +173,5 @@
  */
 PJ_DECL(pj_status_t) pjmedia_snd_port_create2(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,
-					      const pjmedia_snd_setting *setting,
+					      const pjmedia_aud_param *prm,
 					      pjmedia_snd_port **p_port);
 
@@ -217,17 +195,21 @@
  * @return		    The sound stream instance.
  */
-PJ_DECL(pjmedia_snd_stream*) pjmedia_snd_port_get_snd_stream(
+PJ_DECL(pjmedia_aud_stream*) pjmedia_snd_port_get_snd_stream(
 						pjmedia_snd_port *snd_port);
 
 
 /**
- * Configure the echo cancellation tail length. By default, echo canceller
- * is enabled in the sound device with the default tail length. After the
- * sound port is created, application can query the current echo canceller
- * tail length by calling #pjmedia_snd_port_get_ec_tail.
- *
- * Note that you should only change the EC settings when the sound port
- * is not connected to any downstream ports, otherwise race condition may
- * occur.
+ * Change the echo cancellation settings. The echo cancellation settings 
+ * should have been specified when this sound port was created, by setting
+ * the appropriate fields in the pjmedia_aud_param, because not all sound
+ * device implementation supports changing the EC setting once the device
+ * has been opened.
+ *
+ * The behavior of this function depends on whether device or software AEC
+ * is being used. If the device supports AEC, this function will forward
+ * the change request to the device and it will be up to the device whether
+ * to support the request. If software AEC is being used (the software EC
+ * will be used if the device does not support AEC), this function will
+ * change the software EC settings.
  *
  * @param snd_port	    The sound device port.
@@ -237,4 +219,5 @@
  *			    be disabled.
  * @param options	    The options to be passed to #pjmedia_echo_create().
+ *			    This is only used if software EC is being used.
  *
  * @return		    PJ_SUCCESS on success.
Index: /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/stream.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/stream.h	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/stream.h	(revision 2468)
@@ -27,5 +27,4 @@
  */
 
-#include <pjmedia/sound.h>
 #include <pjmedia/codec.h>
 #include <pjmedia/endpoint.h>
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiodev.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 2468)
@@ -20,13 +20,39 @@
 #include <pjmedia-audiodev/audiodev_imp.h>
 #include <pj/errno.h>
+#include <pj/log.h>
+#include <pj/string.h>
+
+#define THIS_FILE   "audiodev.c"
+
+/* Capability names */
+static struct cap_info
+{
+    const char *name;
+    const char *info;
+} cap_infos[] = 
+{
+    {"ext-fmt",	    "Extended/non-PCM format"},
+    {"latency-in",  "Input latency/buffer size setting"},
+    {"latency-out", "Output latency/buffer size setting"},
+    {"vol-in",	    "Input volume setting"},
+    {"vol-out",	    "Output volume setting"},
+    {"meter-in",    "Input meter"},
+    {"meter-out",   "Output meter"},
+    {"route-in",    "Input routing"},
+    {"route-out",   "Output routing"},
+    {"aec",	    "Accoustic echo cancellation"},
+    {"aec-tail",    "Tail length setting for AEC"},
+    {"vad",	    "Voice activity detection"},
+    {"cng",	    "Comfort noise generation"},
+    {"plg",	    "Packet loss concealment"}
+};
+
 
 /*
- * The Device ID seen by application and driver is different. 
+ * The device index seen by application and driver is different. 
  *
- * At application level, device ID is a 32bit value. The high 16bit contains
- * the factory ID, and the low 16bit contains the device index in the 
- * specified factory. The device ID may also be -1 to denote default device.
- *
- * At driver level, device ID is a 16bit unsigned integer index.
+ * At application level, device index is index to global list of device.
+ * At driver level, device index is index to device list on that particular
+ * factory only.
  */
 #define MAKE_DEV_ID(f_id, index)   (((f_id & 0xFFFF) << 16) | (index & 0xFFFF))
@@ -41,18 +67,30 @@
 
 #define MAX_DRIVERS	16
+#define MAX_DEVS	64
+
+/* typedef for factory creation function */
+typedef pjmedia_aud_dev_factory*  (*create_func_ptr)(pj_pool_factory*);
+
+/* driver structure */
+struct driver
+{
+    create_func_ptr	     create;	/* Creation function.		    */
+    pjmedia_aud_dev_factory *f;		/* Factory instance.		    */
+    char		     name[32];	/* Driver name			    */
+    unsigned		     dev_cnt;	/* Number of devices		    */
+    unsigned		     start_idx;	/* Start index in global list	    */
+};
 
 /* The audio subsystem */
 static struct aud_subsys
 {
-    unsigned	     init_count;
-    pj_pool_factory *pf;
-    unsigned	     factory_cnt;
-
-    struct factory
-    {
-	pjmedia_aud_dev_factory*   (*create)(pj_pool_factory*);
-	pjmedia_aud_dev_factory	    *f;
-
-    } factories[MAX_DRIVERS];
+    unsigned	     init_count;	/* How many times init() is called  */
+    pj_pool_factory *pf;		/* The pool factory.		    */
+
+    unsigned	     drv_cnt;		/* Number of drivers.		    */
+    struct driver    drv[MAX_DRIVERS];	/* Array of drivers.		    */
+
+    unsigned	     dev_cnt;		/* Total number of devices.	    */
+    pj_uint32_t	     dev_list[MAX_DEVS];/* Array of device IDs.		    */
 
 } aud_subsys;
@@ -74,16 +112,23 @@
 
     aud_subsys.pf = pf;
-    aud_subsys.factory_cnt = 0;
-
-    aud_subsys.factories[aud_subsys.factory_cnt++].create = &pjmedia_pa_factory;
-    aud_subsys.factories[aud_subsys.factory_cnt++].create = &pjmedia_wmme_factory;
-
-    for (i=0; i<aud_subsys.factory_cnt; ++i) {
+    aud_subsys.drv_cnt = 0;
+    aud_subsys.dev_cnt = 0;
+
+    /* Register creation functions */
+    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory;
+    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;
+
+    /* Initialize each factory and build the device ID list */
+    for (i=0; i<aud_subsys.drv_cnt; ++i) {
 	pjmedia_aud_dev_factory *f;
-
-	f = (*aud_subsys.factories[i].create)(pf);
+	pjmedia_aud_dev_info info;
+	unsigned j, dev_cnt;
+
+	/* Create the factory */
+	f = (*aud_subsys.drv[i].create)(pf);
 	if (!f)
 	    continue;
 
+	/* Call factory->init() */
 	status = f->op->init(f);
 	if (status != PJ_SUCCESS) {
@@ -92,9 +137,40 @@
 	}
 
-	aud_subsys.factories[i].f = f;
-	aud_subsys.factories[i].f->internal.id = i;
-    }
-
-    return aud_subsys.factory_cnt ? PJ_SUCCESS : status;
+	/* Build device list */
+	dev_cnt = f->op->get_dev_count(f);
+	if (dev_cnt == 0) {
+	    f->op->destroy(f);
+	    continue;
+	}
+
+	/* Get one device info */
+	status = f->op->get_dev_info(f, 0, &info);
+	if (status != PJ_SUCCESS) {
+	    f->op->destroy(f);
+	    continue;
+	}
+
+	/* Register the factory */
+	aud_subsys.drv[i].f = f;
+	aud_subsys.drv[i].f->internal.id = i;
+	aud_subsys.drv[i].start_idx = aud_subsys.dev_cnt;
+	pj_ansi_strncpy(aud_subsys.drv[i].name, info.driver,
+			sizeof(aud_subsys.drv[i].name));
+	aud_subsys.drv[i].name[sizeof(aud_subsys.drv[i].name)-1] = '\0';
+
+	/* Register devices */
+	if (aud_subsys.dev_cnt + dev_cnt > MAX_DEVS) {
+	    PJ_LOG(4,(THIS_FILE, "%d device(s) cannot be registered because"
+				  " there are too many sound devices",
+				  aud_subsys.dev_cnt + dev_cnt - MAX_DEVS));
+	    dev_cnt = MAX_DEVS - aud_subsys.dev_cnt;
+	}
+	for (j=0; j<dev_cnt; ++j) {
+	    aud_subsys.dev_list[aud_subsys.dev_cnt++] = MAKE_DEV_ID(i, j);
+	}
+
+    }
+
+    return aud_subsys.drv_cnt ? PJ_SUCCESS : status;
 }
 
@@ -118,6 +194,6 @@
     --aud_subsys.init_count;
 
-    for (i=0; i<aud_subsys.factory_cnt; ++i) {
-	pjmedia_aud_dev_factory *f = aud_subsys.factories[i].f;
+    for (i=0; i<aud_subsys.drv_cnt; ++i) {
+	pjmedia_aud_dev_factory *f = aud_subsys.drv[i].f;
 
 	if (!f)
@@ -125,8 +201,31 @@
 
 	f->op->destroy(f);
-	aud_subsys.factories[i].f = NULL;
-    }
-
-    return PJ_SUCCESS;
+	aud_subsys.drv[i].f = NULL;
+    }
+
+    return PJ_SUCCESS;
+}
+
+/* API: get capability name/info */
+PJ_DEF(const char*) pjmedia_aud_dev_cap_name(pjmedia_aud_dev_cap cap,
+					     const char **p_desc)
+{
+    char *desc;
+    unsigned i;
+
+    if (p_desc==NULL) p_desc = &desc;
+
+    for (i=0; i<PJ_ARRAY_SIZE(cap_infos); ++i) {
+	if ((1 << i)==cap)
+	    break;
+    }
+
+    if (i==32) {
+	*p_desc = "??";
+	return "??";
+    }
+
+    *p_desc = cap_infos[i].info;
+    return cap_infos[i].name;
 }
 
@@ -134,62 +233,111 @@
 PJ_DEF(unsigned) pjmedia_aud_dev_count(void)
 {
-    unsigned i, count = 0;
-
-    for (i=0; i<aud_subsys.factory_cnt; ++i) {
-	pjmedia_aud_dev_factory *f = aud_subsys.factories[i].f;
-
-	if (!f)
-	    continue;
-
-	count += f->op->get_dev_count(f);
-    }
-
-    return count;
-}
-
-/* API: Enumerate device ID's. */
-PJ_DEF(unsigned) pjmedia_aud_dev_enum(unsigned max_count,
-				      pjmedia_aud_dev_id ids[])
-{
-    unsigned i, count = 0;
-
-    for (i=0; i<aud_subsys.factory_cnt && count < max_count; ++i) {
-	pjmedia_aud_dev_factory *f = aud_subsys.factories[i].f;
-	unsigned j, fcount;
-
-	if (!f)
-	    continue;
-
-	fcount = f->op->get_dev_count(f);
-	for (j=0; j<fcount && count<max_count; ++j) {
-	    ids[count++] = MAKE_DEV_ID(i, j);
-	}
-    }
-
-    return count;
-}
-
+    return aud_subsys.dev_cnt;
+}
+
+/* Internal: lookup device id */
+static pj_status_t lookup_dev(pjmedia_aud_dev_index id,
+			      pjmedia_aud_dev_factory **p_f,
+			      unsigned *p_local_index)
+{
+    int f_id, index;
+
+    if (id == PJMEDIA_AUD_DEV_DEFAULT)
+	id = DEFAULT_DEV_ID;
+
+    PJ_ASSERT_RETURN(id>=0 && id<(int)aud_subsys.dev_cnt, 
+		     PJMEDIA_EAUD_INVDEV);
+
+    f_id = GET_FID(aud_subsys.dev_list[id]);
+    index = GET_INDEX(aud_subsys.dev_list[id]);
+
+    if (f_id < 0 || f_id >= (int)aud_subsys.drv_cnt)
+	return PJMEDIA_EAUD_INVDEV;
+
+    if (index < 0 || index >= (int)aud_subsys.drv[f_id].dev_cnt)
+	return PJMEDIA_EAUD_INVDEV;
+
+    *p_f = aud_subsys.drv[f_id].f;
+    *p_local_index = (unsigned)index;
+
+    return PJ_SUCCESS;
+
+}
+
+/* Internal: convert local index to global device index */
+static pj_status_t make_global_index(pjmedia_aud_dev_factory *f,
+				     pjmedia_aud_dev_index *id)
+{
+    unsigned f_id = f->internal.id;
+
+    if (*id == PJMEDIA_AUD_DEV_DEFAULT)
+	return PJ_SUCCESS;
+
+    /* Check that factory still exists */
+    PJ_ASSERT_RETURN(f, PJ_EBUG);
+
+    /* Check that device index is valid */
+    PJ_ASSERT_RETURN(*id>=0 && *id<(int)aud_subsys.drv[f_id].dev_cnt, PJ_EBUG);
+
+    *id += aud_subsys.drv[f_id].start_idx;
+    return PJ_SUCCESS;
+}
 
 /* API: Get device information. */
-PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_id id,
+PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_index id,
 					     pjmedia_aud_dev_info *info)
 {
     pjmedia_aud_dev_factory *f;
-    int f_id, index;
-
-    if (id == PJMEDIA_AUD_DEV_DEFAULT_ID)
-	id = DEFAULT_DEV_ID;
-
-    f_id = GET_FID(id);
-    index = GET_INDEX(id);
-
-    if (f_id < 0 || f_id >= (int)aud_subsys.factory_cnt)
-	return PJMEDIA_EAUD_INVDEV;
-
-    f = aud_subsys.factories[f_id].f;
-    if (f == NULL)
-	return PJMEDIA_EAUD_INVDEV;
+    unsigned index;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(info, PJ_EINVAL);
+
+    status = lookup_dev(id, &f, &index);
+    if (status != PJ_SUCCESS)
+	return status;
 
     return f->op->get_dev_info(f, index, info);
+}
+
+/* API: find device */
+PJ_DEF(pj_status_t) pjmedia_aud_dev_lookup( const char *drv_name,
+					    const char *dev_name,
+					    pjmedia_aud_dev_index *id)
+{
+    pjmedia_aud_dev_factory *f = NULL;
+    unsigned i, j;
+
+    PJ_ASSERT_RETURN(drv_name && dev_name && id, PJ_EINVAL);
+
+    for (i=0; i<aud_subsys.drv_cnt; ++i) {
+	if (!pj_ansi_stricmp(drv_name, aud_subsys.drv[i].name)) {
+	    f = aud_subsys.drv[i].f;
+	    break;
+	}
+    }
+
+    if (!f)
+	return PJ_ENOTFOUND;
+
+    for (j=0; j<aud_subsys.drv[i].dev_cnt; ++j) {
+	pjmedia_aud_dev_info info;
+	pj_status_t status;
+
+	status = f->op->get_dev_info(f, j, &info);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	if (!pj_ansi_stricmp(dev_name, info.name))
+	    break;
+    }
+
+    if (j==aud_subsys.drv[i].dev_cnt)
+	return PJ_ENOTFOUND;
+
+    *id = j;
+    make_global_index(f, id);
+
+    return PJ_SUCCESS;
 }
 
@@ -197,23 +345,16 @@
  * specified device.
  */
-PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_id id,
-						  pjmedia_aud_dev_param *param)
+PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_index id,
+						  pjmedia_aud_param *param)
 {
     pjmedia_aud_dev_factory *f;
-    int f_id, index;
+    unsigned index;
     pj_status_t status;
 
-    if (id == PJMEDIA_AUD_DEV_DEFAULT_ID)
-	id = DEFAULT_DEV_ID;
-
-    f_id = GET_FID(id);
-    index = GET_INDEX(id);
-
-    if (f_id < 0 || f_id >= (int)aud_subsys.factory_cnt)
-	return PJMEDIA_EAUD_INVDEV;
-
-    f = aud_subsys.factories[f_id].f;
-    if (f == NULL)
-	return PJMEDIA_EAUD_INVDEV;
+    PJ_ASSERT_RETURN(param, PJ_EINVAL);
+
+    status = lookup_dev(id, &f, &index);
+    if (status != PJ_SUCCESS)
+	return status;
 
     status = f->op->default_param(f, index, param);
@@ -222,8 +363,6 @@
 
     /* Normalize device IDs */
-    if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
-	param->rec_id = MAKE_DEV_ID(f_id, param->rec_id);
-    if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
-	param->play_id = MAKE_DEV_ID(f_id, param->play_id);
+    make_global_index(f, &param->rec_id);
+    make_global_index(f, &param->play_id);
 
     return PJ_SUCCESS;
@@ -231,5 +370,5 @@
 
 /* API: Open audio stream object using the specified parameters. */
-PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_dev_param *p,
+PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_param *prm,
 					      pjmedia_aud_rec_cb rec_cb,
 					      pjmedia_aud_play_cb play_cb,
@@ -237,34 +376,42 @@
 					      pjmedia_aud_stream **p_aud_strm)
 {
-    pjmedia_aud_dev_factory *f;
-    pjmedia_aud_dev_param param;
-    int f_id;
+    pjmedia_aud_dev_factory *rec_f=NULL, *play_f=NULL, *f=NULL;
+    pjmedia_aud_param param;
     pj_status_t status;
 
+    PJ_ASSERT_RETURN(prm && prm->dir && p_aud_strm, PJ_EINVAL);
+
     /* Must make copy of param because we're changing device ID */
-    pj_memcpy(&param, p, sizeof(param));
-
-    /* Set default device */
-    if (param.rec_id == PJMEDIA_AUD_DEV_DEFAULT_ID) 
-	param.rec_id = DEFAULT_DEV_ID;
-    if (param.play_id == PJMEDIA_AUD_DEV_DEFAULT_ID) 
-	param.play_id = DEFAULT_DEV_ID;
+    pj_memcpy(&param, prm, sizeof(param));
+
+    /* Normalize rec_id */
+    if (param.dir & PJMEDIA_DIR_CAPTURE) {
+	unsigned index;
+
+	status = lookup_dev(param.rec_id, &rec_f, &index);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	param.rec_id = index;
+	f = rec_f;
+    }
+
+    /* Normalize play_id */
+    if (param.dir & PJMEDIA_DIR_PLAYBACK) {
+	unsigned index;
+
+	status = lookup_dev(param.play_id, &play_f, &index);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	param.play_id = index;
+	f = play_f;
+
+	/* For now, rec_id and play_id must belong to the same factory */
+	PJ_ASSERT_RETURN(rec_f == play_f, PJ_EINVAL);
+    }
+
     
-    if (param.dir & PJMEDIA_DIR_CAPTURE)
-	f_id = GET_FID(param.rec_id);
-    else
-	f_id = GET_FID(param.play_id);
-
-    if (f_id < 0 || f_id >= (int)aud_subsys.factory_cnt)
-	return PJMEDIA_EAUD_INVDEV;
-    
-    /* Normalize device id's */
-    param.rec_id = GET_INDEX(param.rec_id);
-    param.play_id = GET_INDEX(param.play_id);
-
-    f = aud_subsys.factories[f_id].f;
-    if (f == NULL)
-	return PJMEDIA_EAUD_INVDEV;
-
+    /* Create the stream */
     status = f->op->create_stream(f, &param, rec_cb, play_cb,
 				  user_data, p_aud_strm);
@@ -272,5 +419,6 @@
 	return status;
 
-    (*p_aud_strm)->factory = f;
+    /* Assign factory id to the stream */
+    (*p_aud_strm)->factory_id = f->internal.id;
     return PJ_SUCCESS;
 }
@@ -278,5 +426,5 @@
 /* API: Get the running parameters for the specified audio stream. */
 PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm,
-						 pjmedia_aud_dev_param *param)
+						 pjmedia_aud_param *param)
 {
     pj_status_t status;
@@ -287,8 +435,6 @@
 
     /* Normalize device id's */
-    if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
-	param->rec_id = MAKE_DEV_ID(strm->factory->internal.id, param->rec_id);
-    if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID)
-	param->play_id = MAKE_DEV_ID(strm->factory->internal.id, param->play_id);
+    make_global_index(aud_subsys.drv[strm->factory_id].f, &param->rec_id);
+    make_global_index(aud_subsys.drv[strm->factory_id].f, &param->play_id);
 
     return PJ_SUCCESS;
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiotest.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiotest.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiotest.c	(revision 2468)
@@ -52,5 +52,5 @@
 {
     pj_pool_t			   *pool;
-    const pjmedia_aud_dev_param    *param;
+    const pjmedia_aud_param    *param;
     pjmedia_aud_test_results	   *result;
     pj_bool_t			    running;
@@ -182,5 +182,5 @@
 
 
-PJ_DEF(pj_status_t) pjmedia_aud_test( const pjmedia_aud_dev_param *param,
+PJ_DEF(pj_status_t) pjmedia_aud_test( const pjmedia_aud_param *param,
 				      pjmedia_aud_test_results *result)
 {
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/pa_dev.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/pa_dev.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/pa_dev.c	(revision 2468)
@@ -106,7 +106,7 @@
 static pj_status_t  pa_default_param(pjmedia_aud_dev_factory *f,
 				     unsigned index,
-				     pjmedia_aud_dev_param *param);
+				     pjmedia_aud_param *param);
 static pj_status_t  pa_create_stream(pjmedia_aud_dev_factory *f,
-				     const pjmedia_aud_dev_param *param,
+				     const pjmedia_aud_param *param,
 				     pjmedia_aud_rec_cb rec_cb,
 				     pjmedia_aud_play_cb play_cb,
@@ -116,5 +116,5 @@
 /* Stream prototypes */
 static pj_status_t strm_get_param(pjmedia_aud_stream *strm,
-				  pjmedia_aud_dev_param *param);
+				  pjmedia_aud_param *param);
 static pj_status_t strm_get_cap(pjmedia_aud_stream *strm,
 	 		        pjmedia_aud_dev_cap cap,
@@ -515,5 +515,5 @@
 static pj_status_t  pa_default_param(pjmedia_aud_dev_factory *f,
 				     unsigned index,
-				     pjmedia_aud_dev_param *param)
+				     pjmedia_aud_param *param)
 {
     pjmedia_aud_dev_info adi;
@@ -534,9 +534,9 @@
 	param->dir = PJMEDIA_DIR_CAPTURE;
 	param->rec_id = index;
-	param->play_id = PJMEDIA_AUD_DEV_DEFAULT_ID;
+	param->play_id = PJMEDIA_AUD_DEV_DEFAULT;
     } else if (adi.output_count) {
 	param->dir = PJMEDIA_DIR_PLAYBACK;
 	param->play_id = index;
-	param->rec_id = PJMEDIA_AUD_DEV_DEFAULT_ID;
+	param->rec_id = PJMEDIA_AUD_DEV_DEFAULT;
     } else {
 	return PJMEDIA_EAUD_INVDEV;
@@ -670,5 +670,5 @@
 /* Internal: create capture/recorder stream */
 static pj_status_t create_rec_stream( struct pa_aud_factory *pa,
-				      const pjmedia_aud_dev_param *param,
+				      const pjmedia_aud_param *param,
 				      pjmedia_aud_rec_cb rec_cb,
 				      void *user_data,
@@ -676,5 +676,5 @@
 {
     pj_pool_t *pool;
-    pjmedia_aud_dev_id rec_id;
+    pjmedia_aud_dev_index rec_id;
     struct pa_aud_stream *stream;
     PaStreamParameters inputParam;
@@ -775,5 +775,5 @@
 /* Internal: create playback stream */
 static pj_status_t create_play_stream(struct pa_aud_factory *pa,
-				      const pjmedia_aud_dev_param *param,
+				      const pjmedia_aud_param *param,
 				      pjmedia_aud_play_cb play_cb,
 				      void *user_data,
@@ -781,5 +781,5 @@
 {
     pj_pool_t *pool;
-    pjmedia_aud_dev_id play_id;
+    pjmedia_aud_dev_index play_id;
     struct pa_aud_stream *stream;
     PaStreamParameters outputParam;
@@ -882,5 +882,5 @@
 /* Internal: Create both player and recorder stream */
 static pj_status_t create_bidir_stream(struct pa_aud_factory *pa,
-				       const pjmedia_aud_dev_param *param,
+				       const pjmedia_aud_param *param,
 				       pjmedia_aud_rec_cb rec_cb,
 				       pjmedia_aud_play_cb play_cb,
@@ -889,5 +889,5 @@
 {
     pj_pool_t *pool;
-    pjmedia_aud_dev_id rec_id, play_id;
+    pjmedia_aud_dev_index rec_id, play_id;
     struct pa_aud_stream *stream;
     PaStream *paStream = NULL;
@@ -1061,5 +1061,5 @@
 /* API: create stream */
 static pj_status_t  pa_create_stream(pjmedia_aud_dev_factory *f,
-				     const pjmedia_aud_dev_param *param,
+				     const pjmedia_aud_param *param,
 				     pjmedia_aud_rec_cb rec_cb,
 				     pjmedia_aud_play_cb play_cb,
@@ -1092,5 +1092,5 @@
 /* API: Get stream parameters */
 static pj_status_t strm_get_param(pjmedia_aud_stream *s,
-				  pjmedia_aud_dev_param *pi)
+				  pjmedia_aud_param *pi)
 {
     struct pa_aud_stream *strm = (struct pa_aud_stream*)s;
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/symb_aps_dev.cpp	(revision 2468)
@@ -72,5 +72,5 @@
 
     // Common settings.
-    pjmedia_aud_dev_param param;		/**< Stream param.	*/
+    pjmedia_aud_param param;		/**< Stream param.	*/
     pjmedia_aud_rec_cb   rec_cb;		/**< Record callback.  	*/
     pjmedia_aud_play_cb	 play_cb;		/**< Playback callback. */
@@ -101,7 +101,7 @@
 static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
 					 unsigned index,
-					 pjmedia_aud_dev_param *param);
+					 pjmedia_aud_param *param);
 static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
-					 const pjmedia_aud_dev_param *param,
+					 const pjmedia_aud_param *param,
 					 pjmedia_aud_rec_cb rec_cb,
 					 pjmedia_aud_play_cb play_cb,
@@ -110,5 +110,5 @@
 
 static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
-				    pjmedia_aud_dev_param *param);
+				    pjmedia_aud_param *param);
 static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
 				  pjmedia_aud_dev_cap cap,
@@ -1176,5 +1176,5 @@
 static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
 					 unsigned index,
-					 pjmedia_aud_dev_param *param)
+					 pjmedia_aud_param *param)
 {
     struct aps_factory *af = (struct aps_factory*)f;
@@ -1200,5 +1200,5 @@
 /* API: create stream */
 static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
-					 const pjmedia_aud_dev_param *param,
+					 const pjmedia_aud_param *param,
 					 pjmedia_aud_rec_cb rec_cb,
 					 pjmedia_aud_play_cb play_cb,
@@ -1333,5 +1333,5 @@
 /* API: Get stream info. */
 static pj_status_t stream_get_param(pjmedia_aud_stream *s,
-				    pjmedia_aud_dev_param *pi)
+				    pjmedia_aud_param *pi)
 {
     struct aps_stream *strm = (struct aps_stream*)s;
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 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp	(revision 2468)
@@ -73,5 +73,5 @@
 
     // Common settings.
-    pjmedia_aud_dev_param param;		/**< Stream param.	*/
+    pjmedia_aud_param param;		/**< Stream param.	*/
 
     // Audio engine
@@ -90,7 +90,7 @@
 static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
 					 unsigned index,
-					 pjmedia_aud_dev_param *param);
+					 pjmedia_aud_param *param);
 static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
-					 const pjmedia_aud_dev_param *param,
+					 const pjmedia_aud_param *param,
 					 pjmedia_aud_rec_cb rec_cb,
 					 pjmedia_aud_play_cb play_cb,
@@ -99,5 +99,5 @@
 
 static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
-				    pjmedia_aud_dev_param *param);
+				    pjmedia_aud_param *param);
 static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
 				  pjmedia_aud_dev_cap cap,
@@ -845,5 +845,5 @@
 static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
 					 unsigned index,
-					 pjmedia_aud_dev_param *param)
+					 pjmedia_aud_param *param)
 {
     struct mda_factory *af = (struct mda_factory*)f;
@@ -867,5 +867,5 @@
 /* API: create stream */
 static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
-					 const pjmedia_aud_dev_param *param,
+					 const pjmedia_aud_param *param,
 					 pjmedia_aud_rec_cb rec_cb,
 					 pjmedia_aud_play_cb play_cb,
@@ -922,5 +922,5 @@
 /* API: Get stream info. */
 static pj_status_t stream_get_param(pjmedia_aud_stream *s,
-				    pjmedia_aud_dev_param *pi)
+				    pjmedia_aud_param *pi)
 {
     struct mda_stream *strm = (struct mda_stream*)s;
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 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/wmme_dev.c	(revision 2468)
@@ -121,7 +121,7 @@
 static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
 					 unsigned index,
-					 pjmedia_aud_dev_param *param);
+					 pjmedia_aud_param *param);
 static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
-					 const pjmedia_aud_dev_param *param,
+					 const pjmedia_aud_param *param,
 					 pjmedia_aud_rec_cb rec_cb,
 					 pjmedia_aud_play_cb play_cb,
@@ -130,5 +130,5 @@
 
 static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
-				    pjmedia_aud_dev_param *param);
+				    pjmedia_aud_param *param);
 static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
 				  pjmedia_aud_dev_cap cap,
@@ -399,5 +399,5 @@
 static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
 					 unsigned index,
-					 pjmedia_aud_dev_param *param)
+					 pjmedia_aud_param *param)
 {
     struct wmme_factory *wf = (struct wmme_factory*)f;
@@ -414,9 +414,9 @@
 	param->dir = PJMEDIA_DIR_CAPTURE;
 	param->rec_id = index;
-	param->play_id = PJMEDIA_AUD_DEV_DEFAULT_ID;
+	param->play_id = PJMEDIA_AUD_DEV_DEFAULT;
     } else if (di->info.output_count) {
 	param->dir = PJMEDIA_DIR_PLAYBACK;
 	param->play_id = index;
-	param->rec_id = PJMEDIA_AUD_DEV_DEFAULT_ID;
+	param->rec_id = PJMEDIA_AUD_DEV_DEFAULT;
     } else {
 	return PJMEDIA_EAUD_INVDEV;
@@ -816,5 +816,5 @@
 /* API: create stream */
 static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
-					 const pjmedia_aud_dev_param *param,
+					 const pjmedia_aud_param *param,
 					 pjmedia_aud_rec_cb rec_cb,
 					 pjmedia_aud_play_cb play_cb,
@@ -930,5 +930,5 @@
 /* API: Get stream info. */
 static pj_status_t stream_get_param(pjmedia_aud_stream *s,
-				    pjmedia_aud_dev_param *pi)
+				    pjmedia_aud_param *pi)
 {
     struct wmme_stream *strm = (struct wmme_stream*)s;
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conf_switch.c	(revision 2468)
@@ -114,5 +114,4 @@
     unsigned		  port_cnt;	/**< Current number of ports.	    */
     unsigned		  connect_cnt;	/**< Total number of connections    */
-    pjmedia_snd_port	 *snd_dev_port;	/**< Sound device port.		    */
     pjmedia_port	 *master_port;	/**< Port zero's port.		    */
     char		  master_name_buf[80]; /**< Port0 name buffer.	    */
@@ -188,58 +187,7 @@
     pj_status_t status;
 
-
     status = create_conf_port(pool, conf, conf->master_port, &name, &conf_port);
     if (status != PJ_SUCCESS)
 	return status;
-
-
-    /* Create sound device port: */
-
-    if ((conf->options & PJMEDIA_CONF_NO_DEVICE) == 0) {
-	pjmedia_snd_stream *strm;
-	pjmedia_snd_stream_info si;
-	pjmedia_port_info *master_port_info = (pjmedia_port_info*)
-					      &conf->master_port->info;
-
-	/*
-	 * If capture is disabled then create player only port.
-	 * Otherwise create bidirectional sound device port.
-	 */
-	if (conf->options & PJMEDIA_CONF_NO_MIC)  {
-	    status = pjmedia_snd_port_create_player(
-					pool, -1, 
-					master_port_info->clock_rate,
-					master_port_info->channel_count,
-					master_port_info->samples_per_frame,
-					master_port_info->bits_per_sample, 
-					0,	/* options */
-					&conf->snd_dev_port);
-
-	} else {
-	    status = pjmedia_snd_port_create( 
-					pool, -1, -1, 
-					master_port_info->clock_rate, 
-					master_port_info->channel_count, 
-					master_port_info->samples_per_frame,
-					master_port_info->bits_per_sample,
-					0,    /* Options */
-					&conf->snd_dev_port);
-	}
-
-	if (status != PJ_SUCCESS)
-	    return status;
-
-	strm = pjmedia_snd_port_get_snd_stream(conf->snd_dev_port);
-	status = pjmedia_snd_stream_get_info(strm, &si);
-	if (status == PJ_SUCCESS) {
-	    const pjmedia_snd_dev_info *snd_dev_info;
-	    if (conf->options & PJMEDIA_CONF_NO_MIC)
-		snd_dev_info = pjmedia_snd_get_dev_info(si.play_id);
-	    else
-		snd_dev_info = pjmedia_snd_get_dev_info(si.rec_id);
-	    pj_strdup2_with_null(pool, &conf_port->name, snd_dev_info->name);
-	}
-    }
-
 
      /* Add the port to the bridge */
@@ -247,5 +195,4 @@
     conf->ports[0] = conf_port;
     conf->port_cnt++;
-
 
     PJ_LOG(5,(THIS_FILE, "Sound device successfully created for port 0"));
@@ -312,16 +259,4 @@
 	return status;
 
-    /* If sound device was created, connect sound device to the
-     * master port.
-     */
-    if (conf->snd_dev_port) {
-	status = pjmedia_snd_port_connect( conf->snd_dev_port, 
-					   conf->master_port );
-	if (status != PJ_SUCCESS) {
-	    pjmedia_conf_destroy(conf);
-	    return status;
-	}
-    }
-
     /* Done */
 
@@ -359,10 +294,4 @@
 {
     PJ_ASSERT_RETURN(conf != NULL, PJ_EINVAL);
-
-    /* Destroy sound device port. */
-    if (conf->snd_dev_port) {
-	pjmedia_snd_port_destroy(conf->snd_dev_port);
-	conf->snd_dev_port = NULL;
-    }
 
     /* Destroy mutex */
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conference.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conference.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/conference.c	(revision 2468)
@@ -466,6 +466,6 @@
 
     if ((conf->options & PJMEDIA_CONF_NO_DEVICE) == 0) {
-	pjmedia_snd_stream *strm;
-	pjmedia_snd_stream_info si;
+	pjmedia_aud_stream *strm;
+	pjmedia_aud_param param;
 
 	/*
@@ -495,12 +495,12 @@
 
 	strm = pjmedia_snd_port_get_snd_stream(conf->snd_dev_port);
-	status = pjmedia_snd_stream_get_info(strm, &si);
+	status = pjmedia_aud_stream_get_param(strm, &param);
 	if (status == PJ_SUCCESS) {
-	    const pjmedia_snd_dev_info *snd_dev_info;
+	    pjmedia_aud_dev_info snd_dev_info;
 	    if (conf->options & PJMEDIA_CONF_NO_MIC)
-		snd_dev_info = pjmedia_snd_get_dev_info(si.play_id);
+		pjmedia_aud_dev_get_info(param.play_id, &snd_dev_info);
 	    else
-		snd_dev_info = pjmedia_snd_get_dev_info(si.rec_id);
-	    pj_strdup2_with_null(pool, &conf_port->name, snd_dev_info->name);
+		pjmedia_aud_dev_get_info(param.rec_id, &snd_dev_info);
+	    pj_strdup2_with_null(pool, &conf_port->name, snd_dev_info.name);
 	}
     }
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/endpoint.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/endpoint.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/endpoint.c	(revision 2468)
@@ -21,4 +21,5 @@
 #include <pjmedia/errno.h>
 #include <pjmedia/sdp.h>
+#include <pjmedia-audiodev/audiodev.h>
 #include <pj/assert.h>
 #include <pj/ioqueue.h>
@@ -122,5 +123,5 @@
 
     /* Sound */
-    status = pjmedia_snd_init(pf);
+    status = pjmedia_aud_subsys_init(pf);
     if (status != PJ_SUCCESS)
 	goto on_error;
@@ -172,5 +173,5 @@
 	pj_ioqueue_destroy(endpt->ioqueue);
 
-    pjmedia_snd_deinit();
+    pjmedia_aud_subsys_shutdown();
     pj_pool_release(pool);
     return status;
@@ -213,5 +214,5 @@
     endpt->pf = NULL;
 
-    pjmedia_snd_deinit();
+    pjmedia_aud_subsys_shutdown();
     pj_pool_release (endpt->pool);
 
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c	(revision 2468)
@@ -23,5 +23,4 @@
 #include <pjmedia/echo.h>
 #include <pjmedia/errno.h>
-#include <pjmedia/plc.h>
 #include <pj/assert.h>
 #include <pj/log.h>
@@ -29,5 +28,4 @@
 #include <pj/string.h>	    /* pj_memset() */
 
-//#define SIMULATE_LOST_PCT   20
 #define AEC_TAIL	    128	    /* default AEC length in ms */
 #define AEC_SUSPEND_LIMIT   5	    /* seconds of no activity	*/
@@ -41,16 +39,9 @@
     int			 rec_id;
     int			 play_id;
-    pjmedia_snd_stream	*snd_stream;
+    pj_uint32_t		 aud_caps;
+    pjmedia_aud_param	 aud_param;
+    pjmedia_aud_stream	*aud_stream;
     pjmedia_dir		 dir;
     pjmedia_port	*port;
-
-    pjmedia_echo_state	*ec_state;
-    unsigned		 aec_tail_len;
-
-    pj_bool_t		 ec_suspended;
-    unsigned		 ec_suspend_count;
-    unsigned		 ec_suspend_limit;
-
-    pjmedia_plc		*plc;
 
     unsigned		 clock_rate;
@@ -58,16 +49,12 @@
     unsigned		 samples_per_frame;
     unsigned		 bits_per_sample;
-    pjmedia_snd_setting  setting;
-
-#if PJMEDIA_SOUND_USE_DELAYBUF
-    pjmedia_delay_buf	*delay_buf;
-#endif
-
-    /* Encoded sound emulation */
-#if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || !PJMEDIA_SND_SUPPORT_OPEN2
-    unsigned		 frm_buf_size;
-    pj_uint8_t		*put_frm_buf;
-    pj_uint8_t		*get_frm_buf;
-#endif
+
+    /* software ec */
+    pjmedia_echo_state	*ec_state;
+    unsigned		 ec_options;
+    unsigned		 ec_tail_len;
+    pj_bool_t		 ec_suspended;
+    unsigned		 ec_suspend_count;
+    unsigned		 ec_suspend_limit;
 };
 
@@ -76,12 +63,9 @@
  * played.
  */
-static pj_status_t play_cb(/* in */   void *user_data,
-			   /* in */   pj_uint32_t timestamp,
-			   /* out */  void *output,
-			   /* out */  unsigned size)
+static pj_status_t play_cb(void *user_data, pjmedia_frame *frame)
 {
     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
     pjmedia_port *port;
-    pjmedia_frame frame;
+    unsigned required_size = frame->size;
     pj_status_t status;
 
@@ -90,56 +74,14 @@
 	goto no_frame;
 
-    frame.buf = output;
-    frame.size = size;
-    frame.timestamp.u32.hi = 0;
-    frame.timestamp.u32.lo = timestamp;
-
-#if PJMEDIA_SOUND_USE_DELAYBUF
-    if (snd_port->delay_buf) {
-	status = pjmedia_delay_buf_get(snd_port->delay_buf, (pj_int16_t*)output);
-	if (status != PJ_SUCCESS)
-	    pj_bzero(output, size);
-
-	frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
-	pjmedia_port_put_frame(port, &frame);
-
-#ifdef TEST_OVERFLOW_UNDERFLOW
-	{
-	    static int count = 1;
-	    if (++count % 10 == 0) {
-		status = pjmedia_delay_buf_get(snd_port->delay_buf, 
-					       (pj_int16_t*)output);
-		if (status != PJ_SUCCESS)
-		    pj_bzero(output, size);
-
-		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
-		pjmedia_port_put_frame(port, &frame);
-	    }
-	}
-#endif
-
-    }
-#endif
-
-    status = pjmedia_port_get_frame(port, &frame);
+    status = pjmedia_port_get_frame(port, frame);
     if (status != PJ_SUCCESS)
 	goto no_frame;
 
-    if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
+    if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO)
 	goto no_frame;
 
     /* Must supply the required samples */
-    pj_assert(frame.size == size);
-
-#ifdef SIMULATE_LOST_PCT
-    /* Simulate packet lost */
-    if (pj_rand() % 100 < SIMULATE_LOST_PCT) {
-	PJ_LOG(4,(THIS_FILE, "Frame dropped"));
-	goto no_frame;
-    }
-#endif
-
-    if (snd_port->plc)
-	pjmedia_plc_save(snd_port->plc, (pj_int16_t*) output);
+    PJ_UNUSED_ARG(required_size);
+    pj_assert(frame->size == required_size);
 
     if (snd_port->ec_state) {
@@ -150,5 +92,5 @@
 	}
 	snd_port->ec_suspend_count = 0;
-	pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)output);
+	pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf);
     }
 
@@ -166,19 +108,7 @@
 	if (snd_port->ec_state) {
 	    /* To maintain correct delay in EC */
-	    pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)output);
-	}
-    }
-
-    /* Apply PLC */
-    if (snd_port->plc) {
-
-	pjmedia_plc_generate(snd_port->plc, (pj_int16_t*) output);
-#ifdef SIMULATE_LOST_PCT
-	PJ_LOG(4,(THIS_FILE, "Lost frame generated"));
-#endif
-    } else {
-	pj_bzero(output, size);
-    }
-
+	    pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf);
+	}
+    }
 
     return PJ_SUCCESS;
@@ -190,12 +120,8 @@
  * frame.
  */
-static pj_status_t rec_cb(/* in */   void *user_data,
-			  /* in */   pj_uint32_t timestamp,
-			  /* in */   void *input,
-			  /* in*/    unsigned size)
+static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame)
 {
     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
     pjmedia_port *port;
-    pjmedia_frame frame;
 
     port = snd_port->port;
@@ -205,26 +131,8 @@
     /* Cancel echo */
     if (snd_port->ec_state && !snd_port->ec_suspended) {
-	pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) input, 0);
-    }
-
-#if PJMEDIA_SOUND_USE_DELAYBUF
-    if (snd_port->delay_buf) {
-	pjmedia_delay_buf_put(snd_port->delay_buf, (pj_int16_t*)input);
-    } else {
-	frame.buf = (void*)input;
-	frame.size = size;
-	frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
-	frame.timestamp.u32.lo = timestamp;
-
-	pjmedia_port_put_frame(port, &frame);
-    }
-#else
-    frame.buf = (void*)input;
-    frame.size = size;
-    frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
-    frame.timestamp.u32.lo = timestamp;
-
-    pjmedia_port_put_frame(port, &frame);
-#endif
+	pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) frame->buf, 0);
+    }
+
+    pjmedia_port_put_frame(port, frame);
 
     return PJ_SUCCESS;
@@ -235,22 +143,9 @@
  * played. This version is for non-PCM data.
  */
-static pj_status_t play_cb_ext(/* in */   void *user_data,
-			       /* in */   pj_uint32_t timestamp,
-			       /* out */  void *output,
-			       /* out */  unsigned size)
-{
-#if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0
-    /* This is the version to use when the sound device supports
-     * open2().
-     */
+static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame)
+{
     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
-    pjmedia_port *port;
-    pjmedia_frame *frame = (pjmedia_frame*) output;
-    pj_status_t status;
-
-    PJ_UNUSED_ARG(size);
-    PJ_UNUSED_ARG(timestamp);
-
-    port = snd_port->port;
+    pjmedia_port *port = snd_port->port;
+
     if (port == NULL) {
 	frame->type = PJMEDIA_FRAME_TYPE_NONE;
@@ -258,93 +153,7 @@
     }
 
-    status = pjmedia_port_get_frame(port, frame);
-
-    return status;
-#else
-    /* This is the emulation version */
-    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
-    pjmedia_port *port = snd_port->port;
-    pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->get_frm_buf;
-    pj_status_t status;
-
-    if (port==NULL) {
-	goto no_frame;
-    }
-
-    pj_bzero(fx, sizeof(*fx));
-    fx->base.type = PJMEDIA_FRAME_TYPE_NONE;
-    fx->base.buf = ((pj_uint8_t*)fx) + sizeof(*fx);
-    fx->base.size = snd_port->frm_buf_size - sizeof(*fx);
-    fx->base.timestamp.u32.hi = 0;
-    fx->base.timestamp.u32.lo = timestamp;
-
-    status = pjmedia_port_get_frame(port, &fx->base);
-    if (status != PJ_SUCCESS)
-	goto no_frame;
-
-    if (fx->base.type == PJMEDIA_FRAME_TYPE_AUDIO) {
-	pj_assert(fx->base.size == size);
-	pj_memcpy(output, fx->base.buf, size);
-    } else if (fx->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
-	void (*decoder)(pj_int16_t*, const pj_uint8_t*, pj_size_t) = NULL;
-	unsigned i, size_decoded;
-
-	switch (snd_port->setting.format.id) {
-	case PJMEDIA_FORMAT_PCMA:
-	    decoder = &pjmedia_alaw_decode;
-	    break;
-	case PJMEDIA_FORMAT_PCMU:
-	    decoder = &pjmedia_ulaw_decode;
-	    break;
-	default:
-	    PJ_LOG(1,(THIS_FILE, "Unsupported format %d", 
-		      snd_port->setting.format.id));
-	    goto no_frame;
-	}
-
-	if (fx->samples_cnt > size>>1) {
-	    PJ_LOG(4,(THIS_FILE, "Frame too large by %d samples", 
-		      fx->samples_cnt - (size>>1)));
-	} else if (fx->samples_cnt < size>>1) {
-	    PJ_LOG(4,(THIS_FILE, "Not enough frame by %d samples", 
-		      (size>>1) - fx->samples_cnt));
-	}
-
-	for (i=0, size_decoded=0; 
-	     i<fx->subframe_cnt && size_decoded<size; 
-	     ++i) 
-	{
-	    pjmedia_frame_ext_subframe *subfrm;
-
-	    subfrm = pjmedia_frame_ext_get_subframe(fx, i);	    
-
-	    if (!subfrm || subfrm->bitlen==0)
-		continue;
-
-	    if ((subfrm->bitlen>>3) > (int)(size-size_decoded)) {
-		subfrm->bitlen = (pj_uint16_t)((size-size_decoded) << 3);
-	    }
-
-	    (*decoder)((short*)((pj_uint8_t*)output + size_decoded),
-		       subfrm->data, subfrm->bitlen>>3);
-
-	    size_decoded += (subfrm->bitlen>>3) << 1;
-	}
-
-	if (size_decoded < size) {
-	    pj_bzero((pj_uint8_t*)output + size_decoded, size-size_decoded);
-	}
-
-    } else {
-	goto no_frame;
-    }
-
-    return PJ_SUCCESS;
-
-no_frame:
-    pj_bzero(output, size);
-    return PJ_SUCCESS;
-
-#endif	/* PJMEDIA_SND_SUPPORT_OPEN2 */
+    pjmedia_port_get_frame(port, frame);
+
+    return PJ_SUCCESS;
 }
 
@@ -354,19 +163,8 @@
  * frame. This version is for non-PCM data.
  */
-static pj_status_t rec_cb_ext(/* in */   void *user_data,
-			      /* in */   pj_uint32_t timestamp,
-			      /* in */   void *input,
-			      /* in*/    unsigned size)
-{
-#if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0
-    /* This is the version to use when the sound device supports
-     * open2().
-     */
+static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame)
+{
     pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
     pjmedia_port *port;
-    pjmedia_frame *frame = (pjmedia_frame*)input;
-
-    PJ_UNUSED_ARG(size);
-    PJ_UNUSED_ARG(timestamp);
 
     port = snd_port->port;
@@ -377,40 +175,4 @@
 
     return PJ_SUCCESS;
-#else
-    pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;
-    pjmedia_port *port = snd_port->port;
-    pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->put_frm_buf;
-    void (*encoder)(pj_uint8_t*, const pj_int16_t*, pj_size_t) = NULL;
-
-    if (port==NULL)
-	return PJ_SUCCESS;
-
-    pj_bzero(fx, sizeof(*fx));
-    fx->base.buf = NULL;
-    fx->base.size = snd_port->frm_buf_size - sizeof(*fx);
-    fx->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
-    fx->base.timestamp.u32.lo = timestamp;
-
-    switch (snd_port->setting.format.id) {
-    case PJMEDIA_FORMAT_PCMA:
-	encoder = &pjmedia_alaw_encode;
-	break;
-    case PJMEDIA_FORMAT_PCMU:
-	encoder = &pjmedia_ulaw_encode;
-	break;
-    default:
-	PJ_LOG(1,(THIS_FILE, "Unsupported format %d", 
-		  snd_port->setting.format.id));
-	return PJ_SUCCESS;
-    }
-
-    (*encoder)((pj_uint8_t*)input, (pj_int16_t*)input, size >> 1);
-
-    pjmedia_frame_ext_append_subframe(fx, input, (size >> 1) << 3, 
-				      size >> 1);
-    pjmedia_port_put_frame(port, &fx->base);
-
-    return PJ_SUCCESS;
-#endif
 }
 
@@ -422,10 +184,11 @@
 				       pjmedia_snd_port *snd_port )
 {
-    pjmedia_snd_rec_cb snd_rec_cb;
-    pjmedia_snd_play_cb snd_play_cb;
+    pjmedia_aud_rec_cb snd_rec_cb;
+    pjmedia_aud_play_cb snd_play_cb;
+    pjmedia_aud_param param_copy;
     pj_status_t status;
 
     /* Check if sound has been started. */
-    if (snd_port->snd_stream != NULL)
+    if (snd_port->aud_stream != NULL)
 	return PJ_SUCCESS;
 
@@ -435,5 +198,36 @@
 		     PJ_EBUG);
 
-    if (snd_port->setting.format.id == PJMEDIA_FORMAT_L16) {
+    /* Get device caps */
+    if (snd_port->aud_param.dir & PJMEDIA_DIR_CAPTURE) {
+	pjmedia_aud_dev_info dev_info;
+
+	status = pjmedia_aud_dev_get_info(snd_port->aud_param.rec_id, 
+					  &dev_info);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	snd_port->aud_caps = dev_info.caps;
+    } else {
+	snd_port->aud_caps = 0;
+    }
+
+    /* Process EC settings */
+    pj_memcpy(&param_copy, &snd_port->aud_param, sizeof(param_copy));
+    if (param_copy.flags & PJMEDIA_AUD_DEV_CAP_EC) {
+	/* EC is wanted */
+	if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) {
+	    /* Device supports EC */
+	    /* Nothing to do */
+	} else {
+	    /* Device doesn't support EC, remove EC settings from
+	     * device parameters
+	     */
+	    param_copy.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC |
+				  PJMEDIA_AUD_DEV_CAP_EC_TAIL);
+	}
+    }
+
+    /* Use different callback if format is not PCM */
+    if (snd_port->aud_param.ext_fmt.id == PJMEDIA_FORMAT_L16) {
 	snd_rec_cb = &rec_cb;
 	snd_play_cb = &play_cb;
@@ -443,54 +237,13 @@
     }
 
-#if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0
-    status = pjmedia_snd_open2( snd_port->dir,
-				snd_port->rec_id, 
-				snd_port->play_id,
-				snd_port->clock_rate,
-				snd_port->channel_count,
-				snd_port->samples_per_frame,
-				snd_port->bits_per_sample,
-				snd_rec_cb,
-				snd_play_cb,
-				snd_port,
-				&snd_port->setting,
-				&snd_port->snd_stream);
-#else
-    status = pjmedia_snd_open(  snd_port->rec_id, 
-				snd_port->play_id,
-				snd_port->clock_rate,
-				snd_port->channel_count,
-				snd_port->samples_per_frame,
-				snd_port->bits_per_sample,
-				snd_rec_cb,
-				snd_play_cb,
-				snd_port,
-				&snd_port->snd_stream);
-#endif
+    /* Open the device */
+    status = pjmedia_aud_stream_create(&param_copy,
+				       snd_rec_cb,
+				       snd_play_cb,
+				       snd_port,
+				       &snd_port->aud_stream);
 
     if (status != PJ_SUCCESS)
 	return status;
-
-
-#ifdef SIMULATE_LOST_PCT
-    snd_port->setting.plc = PJ_TRUE;
-#endif
-
-    /* If we have player components, allocate buffer to save the last
-     * frame played to the speaker. The last frame is used for packet
-     * lost concealment (PLC) algorithm.
-     */
-    if ((snd_port->dir & PJMEDIA_DIR_PLAYBACK) &&
-	(snd_port->setting.plc)) 
-    {
-	status = pjmedia_plc_create(pool, snd_port->clock_rate, 
-				    snd_port->samples_per_frame * 
-					snd_port->channel_count,
-				    0, &snd_port->plc);
-	if (status != PJ_SUCCESS) {
-	    PJ_LOG(4,(THIS_FILE, "Unable to create PLC"));
-	    snd_port->plc = NULL;
-	}
-    }
 
     /* Inactivity limit before EC is suspended. */
@@ -499,9 +252,31 @@
 				  snd_port->samples_per_frame);
 
+    /* Create software EC if parameter specifies EC but device 
+     * doesn't support EC
+     */
+    if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC) &&
+	(snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0)
+    {
+	if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) {
+	    snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL;
+	    snd_port->aud_param.ec_tail_ms = AEC_TAIL;
+	    PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms",
+				 snd_port->aud_param.ec_tail_ms));
+	}
+	    
+	status = pjmedia_snd_port_set_ec(snd_port, pool, 
+					 snd_port->aud_param.ec_tail_ms, 0);
+	if (status != PJ_SUCCESS) {
+	    pjmedia_aud_stream_destroy(snd_port->aud_stream);
+	    snd_port->aud_stream = NULL;
+	    return status;
+	}
+    }
+
     /* Start sound stream. */
-    status = pjmedia_snd_stream_start(snd_port->snd_stream);
+    status = pjmedia_aud_stream_start(snd_port->aud_stream);
     if (status != PJ_SUCCESS) {
-	pjmedia_snd_stream_close(snd_port->snd_stream);
-	snd_port->snd_stream = NULL;
+	pjmedia_aud_stream_destroy(snd_port->aud_stream);
+	snd_port->aud_stream = NULL;
 	return status;
     }
@@ -518,8 +293,8 @@
 {
     /* Check if we have sound stream device. */
-    if (snd_port->snd_stream) {
-	pjmedia_snd_stream_stop(snd_port->snd_stream);
-	pjmedia_snd_stream_close(snd_port->snd_stream);
-	snd_port->snd_stream = NULL;
+    if (snd_port->aud_stream) {
+	pjmedia_aud_stream_stop(snd_port->aud_stream);
+	pjmedia_aud_stream_destroy(snd_port->aud_stream);
+	snd_port->aud_stream = NULL;
     }
 
@@ -547,46 +322,22 @@
 					     pjmedia_snd_port **p_port)
 {
-    pjmedia_snd_port *snd_port;
+    pjmedia_aud_param param;
+    pj_status_t status;
 
     PJ_UNUSED_ARG(options);
 
-    PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
-
-    snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);
-    PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);
-
-    snd_port->rec_id = rec_id;
-    snd_port->play_id = play_id;
-    snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
-    snd_port->clock_rate = clock_rate;
-    snd_port->channel_count = channel_count;
-    snd_port->samples_per_frame = samples_per_frame;
-    snd_port->bits_per_sample = bits_per_sample;
-    
-#if PJMEDIA_SOUND_USE_DELAYBUF
-    do {
-	pj_status_t status;
-	unsigned ptime;
-    
-	ptime = samples_per_frame * 1000 / (clock_rate * channel_count);
-    
-	status = pjmedia_delay_buf_create(pool, "snd_buff", 
-					  clock_rate, samples_per_frame,
-					  channel_count,
-					  PJMEDIA_SOUND_BUFFER_COUNT * ptime,
-					  0, &snd_port->delay_buf);
-	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    } while (0);
-#endif
-
-    *p_port = snd_port;
-
-
-    /* Start sound device immediately.
-     * If there's no port connected, the sound callback will return
-     * empty signal.
-     */
-    return start_sound_device( pool, snd_port );
-
+    status = pjmedia_aud_dev_default_param(rec_id, &param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+    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;
+
+    return pjmedia_snd_port_create2(pool, &param, p_port);
 }
 
@@ -603,27 +354,21 @@
 						 pjmedia_snd_port **p_port)
 {
-    pjmedia_snd_port *snd_port;
+    pjmedia_aud_param param;
+    pj_status_t status;
 
     PJ_UNUSED_ARG(options);
 
-    PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
-
-    snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);
-    PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);
-
-    snd_port->rec_id = dev_id;
-    snd_port->dir = PJMEDIA_DIR_CAPTURE;
-    snd_port->clock_rate = clock_rate;
-    snd_port->channel_count = channel_count;
-    snd_port->samples_per_frame = samples_per_frame;
-    snd_port->bits_per_sample = bits_per_sample;
-
-    *p_port = snd_port;
-
-    /* Start sound device immediately.
-     * If there's no port connected, the sound callback will return
-     * empty signal.
-     */
-    return start_sound_device( pool, snd_port );
+    status = pjmedia_aud_dev_default_param(dev_id, &param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    param.dir = PJMEDIA_DIR_CAPTURE;
+    param.rec_id = dev_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;
+
+    return pjmedia_snd_port_create2(pool, &param, p_port);
 }
 
@@ -641,21 +386,50 @@
 						    pjmedia_snd_port **p_port)
 {
+    pjmedia_aud_param param;
+    pj_status_t status;
+
+    PJ_UNUSED_ARG(options);
+
+    status = pjmedia_aud_dev_default_param(dev_id, &param);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    param.dir = PJMEDIA_DIR_PLAYBACK;
+    param.play_id = dev_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;
+
+    return pjmedia_snd_port_create2(pool, &param, p_port);
+}
+
+
+/*
+ * Create sound port.
+ */
+PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool,
+					     const pjmedia_aud_param *prm,
+					     pjmedia_snd_port **p_port)
+{
     pjmedia_snd_port *snd_port;
 
-    PJ_UNUSED_ARG(options);
-
-    PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
+    PJ_ASSERT_RETURN(pool && prm && p_port, PJ_EINVAL);
 
     snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);
     PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);
 
-    snd_port->play_id = dev_id;
-    snd_port->dir = PJMEDIA_DIR_PLAYBACK;
-    snd_port->clock_rate = clock_rate;
-    snd_port->channel_count = channel_count;
-    snd_port->samples_per_frame = samples_per_frame;
-    snd_port->bits_per_sample = bits_per_sample;
-
+    snd_port->dir = prm->dir;
+    snd_port->rec_id = prm->rec_id;
+    snd_port->play_id = prm->play_id;
+    snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+    snd_port->clock_rate = prm->clock_rate;
+    snd_port->channel_count = prm->channel_count;
+    snd_port->samples_per_frame = prm->samples_per_frame;
+    snd_port->bits_per_sample = prm->bits_per_sample;
+    pj_memcpy(&snd_port->aud_param, prm, sizeof(*prm));
+    
     *p_port = snd_port;
+
 
     /* Start sound device immediately.
@@ -664,75 +438,4 @@
      */
     return start_sound_device( pool, snd_port );
-}
-
-
-/*
- * Create bidirectional port.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_port_create2(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,
-					     const pjmedia_snd_setting *setting,
-					     pjmedia_snd_port **p_port)
-{
-    pjmedia_snd_port *snd_port;
-
-    PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
-
-    snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);
-    PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);
-
-    snd_port->dir = dir;
-    snd_port->rec_id = rec_id;
-    snd_port->play_id = play_id;
-    snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
-    snd_port->clock_rate = clock_rate;
-    snd_port->channel_count = channel_count;
-    snd_port->samples_per_frame = samples_per_frame;
-    snd_port->bits_per_sample = bits_per_sample;
-    pj_memcpy(&snd_port->setting, setting, sizeof(*setting));
-    
-#if PJMEDIA_SOUND_USE_DELAYBUF
-    if (snd_port->setting.format.u32 == PJMEDIA_FORMAT_L16) {
-	pj_status_t status;
-	unsigned ptime;
-    
-	ptime = samples_per_frame * 1000 / (clock_rate * channel_count);
-    
-	status = pjmedia_delay_buf_create(pool, "snd_buff", 
-					  clock_rate, samples_per_frame,
-					  channel_count,
-					  PJMEDIA_SOUND_BUFFER_COUNT * ptime,
-					  0, &snd_port->delay_buf);
-	PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    }
-#endif
-
-#if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || PJMEDIA_SND_SUPPORT_OPEN2==0
-    /* For devices that doesn't support open2(), enable simulation */
-    if (snd_port->setting.format.id != PJMEDIA_FORMAT_L16) {
-	snd_port->frm_buf_size = sizeof(pjmedia_frame_ext) + 
-				 (samples_per_frame << 1) +
-				 16 * sizeof(pjmedia_frame_ext_subframe);
-	snd_port->put_frm_buf = (pj_uint8_t*)
-				pj_pool_alloc(pool, snd_port->frm_buf_size);
-	snd_port->get_frm_buf = (pj_uint8_t*)
-				pj_pool_alloc(pool, snd_port->frm_buf_size);
-    }
-#endif
-
-    *p_port = snd_port;
-
-
-    /* Start sound device immediately.
-     * If there's no port connected, the sound callback will return
-     * empty signal.
-     */
-    return start_sound_device( pool, snd_port );
 
 }
@@ -753,14 +456,14 @@
  * Retrieve the sound stream associated by this sound device port.
  */
-PJ_DEF(pjmedia_snd_stream*) pjmedia_snd_port_get_snd_stream(
+PJ_DEF(pjmedia_aud_stream*) pjmedia_snd_port_get_snd_stream(
 						pjmedia_snd_port *snd_port)
 {
     PJ_ASSERT_RETURN(snd_port, NULL);
-    return snd_port->snd_stream;
-}
-
-
-/*
- * Enable AEC
+    return snd_port->aud_stream;
+}
+
+
+/*
+ * Change EC settings.
  */
 PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec( pjmedia_snd_port *snd_port,
@@ -769,5 +472,5 @@
 					     unsigned options)
 {
-    pjmedia_snd_stream_info si;
+    pjmedia_aud_param prm;
     pj_status_t status;
 
@@ -777,41 +480,98 @@
 		     PJ_EINVALIDOP);
 
-    /* Sound port must have 16bits per sample */
-    PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16,
-		     PJ_EINVALIDOP);
-
-    /* Destroy AEC */
-    if (snd_port->ec_state) {
-	pjmedia_echo_destroy(snd_port->ec_state);
-	snd_port->ec_state = NULL;
-    }
-
-    snd_port->aec_tail_len = tail_ms;
-
-    if (tail_ms != 0) {
-	unsigned delay_ms;
-
-	status = pjmedia_snd_stream_get_info(snd_port->snd_stream, &si);
+    /* Determine whether we use device or software EC */
+    if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) {
+	/* We use device EC */
+	pj_bool_t ec_enabled;
+
+	/* Query EC status */
+	status = pjmedia_aud_stream_get_cap(snd_port->aud_stream,
+					    PJMEDIA_AUD_DEV_CAP_EC,
+					    &ec_enabled);
 	if (status != PJ_SUCCESS)
-	    si.rec_latency = si.play_latency = 0;
-
-	//No need to add input latency in the latency calculation,
-	//since actual input latency should be zero.
-	//delay_ms = (si.rec_latency + si.play_latency) * 1000 /
-	//	   snd_port->clock_rate;
-	delay_ms = si.play_latency * 1000 / snd_port->clock_rate;
-	status = pjmedia_echo_create2(pool, snd_port->clock_rate, 
-				      snd_port->channel_count,
-				      snd_port->samples_per_frame, 
-				      tail_ms, delay_ms,
-				      options, &snd_port->ec_state);
-	if (status != PJ_SUCCESS)
+	    return status;
+
+	if (tail_ms != 0) {
+	    /* Change EC setting */
+
+	    if (!ec_enabled) {
+		/* Enable EC first */
+		pj_bool_t value = PJ_TRUE;
+		status = pjmedia_aud_stream_set_cap(snd_port->aud_stream, 
+						    PJMEDIA_AUD_DEV_CAP_EC,
+						    &value);
+		if (status != PJ_SUCCESS)
+		    return status;
+	    }
+
+	    if ((snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) {
+		/* Device does not support setting EC tail */
+		return PJMEDIA_EAUD_INVCAP;
+	    }
+
+	    return pjmedia_aud_stream_set_cap(snd_port->aud_stream,
+					      PJMEDIA_AUD_DEV_CAP_EC_TAIL,
+					      &tail_ms);
+
+	} else if (ec_enabled) {
+	    /* Disable EC */
+	    pj_bool_t value = PJ_FALSE;
+	    return pjmedia_aud_stream_set_cap(snd_port->aud_stream, 
+					      PJMEDIA_AUD_DEV_CAP_EC,
+					      &value);
+	} else {
+	    /* Request to disable EC but EC has been disabled */
+	    /* Do nothing */
+	    return PJ_SUCCESS;
+	}
+
+    } else {
+	/* We use software EC */
+	/* Sound port must have 16bits per sample */
+	PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16,
+			 PJ_EINVALIDOP);
+
+	/* Check if there is change in parameters */
+	if (tail_ms==snd_port->ec_tail_len && options==snd_port->ec_options) {
+	    PJ_LOG(5,(THIS_FILE, "pjmedia_snd_port_set_ec() ignored, no "
+				 "change in settings"));
+	    return PJ_SUCCESS;
+	}
+
+	/* Destroy AEC */
+	if (snd_port->ec_state) {
+	    pjmedia_echo_destroy(snd_port->ec_state);
 	    snd_port->ec_state = NULL;
-	else
-	    snd_port->ec_suspended = PJ_FALSE;
-    } else {
-	PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the "
-			     "sound port"));
-	status = PJ_SUCCESS;
+	}
+
+	snd_port->ec_options = options;
+	snd_port->ec_tail_len = tail_ms;
+
+	if (tail_ms != 0) {
+	    unsigned delay_ms;
+
+	    status = pjmedia_aud_stream_get_param(snd_port->aud_stream, &prm);
+	    if (status != PJ_SUCCESS)
+		prm.input_latency_ms = prm.output_latency_ms = 0;
+
+	    //No need to add input latency in the latency calculation,
+	    //since actual input latency should be zero.
+	    //delay_ms = (si.rec_latency + si.play_latency) * 1000 /
+	    //	   snd_port->clock_rate;
+	    delay_ms = prm.output_latency_ms;
+	    status = pjmedia_echo_create2(pool, snd_port->clock_rate, 
+					  snd_port->channel_count,
+					  snd_port->samples_per_frame, 
+					  tail_ms, delay_ms,
+					  options, &snd_port->ec_state);
+	    if (status != PJ_SUCCESS)
+		snd_port->ec_state = NULL;
+	    else
+		snd_port->ec_suspended = PJ_FALSE;
+	} else {
+	    PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the "
+				 "sound port"));
+	    status = PJ_SUCCESS;
+	}
     }
 
@@ -825,8 +585,38 @@
 {
     PJ_ASSERT_RETURN(snd_port && p_length, PJ_EINVAL);
-    *p_length =  snd_port->ec_state ? snd_port->aec_tail_len : 0;
-    return PJ_SUCCESS;
-}
-
+
+    /* Determine whether we use device or software EC */
+    if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) {
+	/* We use device EC */
+	pj_bool_t ec_enabled;
+	pj_status_t status;
+
+	/* Query EC status */
+	status = pjmedia_aud_stream_get_cap(snd_port->aud_stream,
+					    PJMEDIA_AUD_DEV_CAP_EC,
+					    &ec_enabled);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	if (!ec_enabled) {
+	    *p_length = 0;
+	} else if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL) {
+	    /* Get device EC tail */
+	    status = pjmedia_aud_stream_get_cap(snd_port->aud_stream,
+						PJMEDIA_AUD_DEV_CAP_EC_TAIL,
+						p_length);
+	    if (status != PJ_SUCCESS)
+		return status;
+	} else {
+	    /* Just use default */
+	    *p_length = AEC_TAIL;
+	}
+
+    } else {
+	/* We use software EC */
+	*p_length =  snd_port->ec_state ? snd_port->ec_tail_len : 0;
+    }
+    return PJ_SUCCESS;
+}
 
 
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/transport_ice.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/transport_ice.c	(revision 2468)
@@ -22,4 +22,5 @@
 #include <pj/assert.h>
 #include <pj/log.h>
+#include <pj/pool.h>
 #include <pj/rand.h>
 
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/transport_loop.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/transport_loop.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/transport_loop.c	(revision 2468)
@@ -23,4 +23,5 @@
 #include <pj/ioqueue.h>
 #include <pj/log.h>
+#include <pj/pool.h>
 #include <pj/rand.h>
 #include <pj/string.h>
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/transport_udp.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/transport_udp.c	(revision 2468)
@@ -24,4 +24,5 @@
 #include <pj/ioqueue.h>
 #include <pj/log.h>
+#include <pj/pool.h>
 #include <pj/rand.h>
 #include <pj/string.h>
Index: /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/wmme_sound.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/wmme_sound.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/wmme_sound.c	(revision 2468)
@@ -1,1008 +1,0 @@
-#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_MME_SOUND
-
-#ifdef _MSC_VER
-#   pragma warning(push, 3)
-#endif
-
-#include <windows.h>
-#include <mmsystem.h>
-
-#ifdef _MSC_VER
-#   pragma warning(pop)
-#endif
-
-#if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
-#   pragma comment(lib, "Coredll.lib")
-#elif defined(_MSC_VER)
-#   pragma comment(lib, "winmm.lib")
-#endif
-
-
-#define THIS_FILE			"wmme_sound.c"
-#define BITS_PER_SAMPLE			16
-#define BYTES_PER_SAMPLE		(BITS_PER_SAMPLE/8)
-
-#define MAX_PACKET_BUFFER_COUNT		32
-#define MAX_HARDWARE			16
-
-struct wmme_dev_info
-{
-    pjmedia_snd_dev_info info;
-    unsigned             deviceId;
-};
-
-static unsigned dev_count;
-static struct wmme_dev_info dev_info[MAX_HARDWARE];
-static pj_bool_t snd_initialized = PJ_FALSE;
-
-/* Latency settings */
-static unsigned snd_input_latency  = PJMEDIA_SND_DEFAULT_REC_LATENCY;
-static unsigned snd_output_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
-
-
-/* Individual WMME capture/playback stream descriptor */
-struct wmme_stream
-{
-    union
-    {
-	HWAVEIN   In;
-	HWAVEOUT  Out;
-    } hWave;
-
-    WAVEHDR      *WaveHdr;
-    HANDLE        hEvent;
-    DWORD         dwBufIdx;
-    DWORD         dwMaxBufIdx;
-    pj_timestamp  timestamp;
-};
-
-
-/* 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 wmme_stream   play_strm;         /**< Playback stream.      */
-    struct wmme_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 (LPWAVEFORMATEX pcmwf, 
-			       unsigned clock_rate,
-			       unsigned channel_count)
-{
-    pj_bzero(pcmwf, sizeof(PCMWAVEFORMAT)); 
-    pcmwf->wFormatTag = WAVE_FORMAT_PCM; 
-    pcmwf->nChannels = (pj_uint16_t)channel_count;
-    pcmwf->nSamplesPerSec = clock_rate;
-    pcmwf->nBlockAlign = (pj_uint16_t)(channel_count * BYTES_PER_SAMPLE);
-    pcmwf->nAvgBytesPerSec = clock_rate * channel_count * BYTES_PER_SAMPLE;
-    pcmwf->wBitsPerSample = BITS_PER_SAMPLE;
-}
-
-
-/*
- * Initialize WMME player device.
- */
-static pj_status_t init_player_stream(  pj_pool_t *pool,
-				        struct wmme_stream *wmme_strm,
-					int dev_id,
-					unsigned clock_rate,
-					unsigned channel_count,
-					unsigned samples_per_frame,
-					unsigned buffer_count)
-{
-    MMRESULT mr;
-    WAVEFORMATEX pcmwf; 
-    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);
-
-    /*
-     * Create a wait event.
-     */
-    wmme_strm->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (NULL == wmme_strm->hEvent)
-	return pj_get_os_error();
-
-    /*
-     * Set up wave format structure for opening the device.
-     */
-    init_waveformatex(&pcmwf, clock_rate, channel_count);
-    bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;
-
-    /*
-     * Open wave device.
-     */
-    mr = waveOutOpen(&wmme_strm->hWave.Out, dev_info[dev_id].deviceId, &pcmwf, 
-		     (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
-    if (mr != MMSYSERR_NOERROR)
-	/* TODO: This is for HRESULT/GetLastError() */
-	PJ_RETURN_OS_ERROR(mr);
-
-    /* Pause the wave out device */
-    mr = waveOutPause(wmme_strm->hWave.Out);
-    if (mr != MMSYSERR_NOERROR)
-	/* TODO: This is for HRESULT/GetLastError() */
-	PJ_RETURN_OS_ERROR(mr);
-
-    /*
-     * Create the buffers. 
-     */
-    wmme_strm->WaveHdr = pj_pool_zalloc(pool, sizeof(WAVEHDR) * buffer_count);
-    for (i = 0; i < buffer_count; ++i)
-    {
-	wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, bytes_per_frame);
-	wmme_strm->WaveHdr[i].dwBufferLength = bytes_per_frame;
-	mr = waveOutPrepareHeader(wmme_strm->hWave.Out, 
-				  &(wmme_strm->WaveHdr[i]),
-				  sizeof(WAVEHDR));
-	if (mr != MMSYSERR_NOERROR)
-	    /* TODO: This is for HRESULT/GetLastError() */
-	    PJ_RETURN_OS_ERROR(mr); 
-	mr = waveOutWrite(wmme_strm->hWave.Out, &(wmme_strm->WaveHdr[i]), 
-			  sizeof(WAVEHDR));
-	if (mr != MMSYSERR_NOERROR)
-	    /* TODO: This is for HRESULT/GetLastError() */
-	    PJ_RETURN_OS_ERROR(mr);
-    }
-
-    wmme_strm->dwBufIdx = 0;
-    wmme_strm->dwMaxBufIdx = buffer_count;
-    wmme_strm->timestamp.u64 = 0;
-
-    /* Done setting up play device. */
-    PJ_LOG(5, (THIS_FILE, 
-	       " WaveAPI Sound 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 Windows Multimedia recorder device
- */
-static pj_status_t init_capture_stream( pj_pool_t *pool,
-					struct wmme_stream *wmme_strm,
-					int dev_id,
-					unsigned clock_rate,
-					unsigned channel_count,
-					unsigned samples_per_frame,
-					unsigned buffer_count)
-{
-    MMRESULT mr;
-    WAVEFORMATEX pcmwf; 
-    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);
-
-    /*
-    * Create a wait event.
-    */
-    wmme_strm->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (NULL == wmme_strm->hEvent)
-	return pj_get_os_error();
-
-    /*
-     * Set up wave format structure for opening the device.
-     */
-    init_waveformatex(&pcmwf, clock_rate, channel_count);
-    bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;
-
-    /*
-     * Open wave device.
-     */
-    mr = waveInOpen(&wmme_strm->hWave.In, dev_info[dev_id].deviceId, &pcmwf, 
-		    (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
-    if (mr != MMSYSERR_NOERROR)
-	/* TODO: This is for HRESULT/GetLastError() */
-	PJ_RETURN_OS_ERROR(mr);
-
-    /*
-     * Create the buffers. 
-     */
-    wmme_strm->WaveHdr = pj_pool_zalloc(pool, sizeof(WAVEHDR) * buffer_count);
-    for (i = 0; i < buffer_count; ++i)
-    {
-	wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, bytes_per_frame);
-	wmme_strm->WaveHdr[i].dwBufferLength = bytes_per_frame;
-	mr = waveInPrepareHeader(wmme_strm->hWave.In, &(wmme_strm->WaveHdr[i]),
-							sizeof(WAVEHDR));
-	if (mr != MMSYSERR_NOERROR)
-	    /* TODO: This is for HRESULT/GetLastError() */
-	    PJ_RETURN_OS_ERROR(mr);
-	mr = waveInAddBuffer(wmme_strm->hWave.In, &(wmme_strm->WaveHdr[i]), 
-			     sizeof(WAVEHDR));
-	if (mr != MMSYSERR_NOERROR)
-	    /* TODO: This is for HRESULT/GetLastError() */
-	    PJ_RETURN_OS_ERROR(mr);
-    }
-
-    wmme_strm->dwBufIdx = 0;
-    wmme_strm->dwMaxBufIdx = buffer_count;
-    wmme_strm->timestamp.u64 = 0;
-
-    /* Done setting up play device. */
-    PJ_LOG(5,(THIS_FILE, 
-	" WaveAPI Sound recorder \"%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;
-}
-
-
-
-/*
-* WMME capture and playback thread.
-*/
-static int PJ_THREAD_FUNC wmme_dev_thread(void *arg)
-{
-    pjmedia_snd_stream *strm = arg;
-    HANDLE events[3];
-    unsigned eventCount;
-    unsigned bytes_per_frame;
-    pj_status_t status = PJ_SUCCESS;
-
-
-    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.
-     */
-#if defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE != 0
-    if (strm->dir & PJMEDIA_DIR_PLAYBACK)
-	CeSetThreadPriority(GetCurrentThread(), 153);
-    else
-	CeSetThreadPriority(GetCurrentThread(), 247);
-#else
-    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
-#endif
-
-    /* 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 WMME capture and play buffer.
-     */
-    while (status == PJ_SUCCESS)
-    {
-
-	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 wmme_stream *wmme_strm = &strm->play_strm;
-	    MMRESULT mr = MMSYSERR_NOERROR;
-	    status = PJ_SUCCESS;
-
-	    /*
-	    * Windows Multimedia has requested us to feed some frames to
-	    * playback buffer.
-	    */
-
-	    while (wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwFlags & WHDR_DONE)
-	    {
-		void* buffer = wmme_strm->WaveHdr[wmme_strm->dwBufIdx].lpData;
-
-		PJ_LOG(5,(THIS_FILE, "Finished writing buffer %d", 
-			  wmme_strm->dwBufIdx));
-
-		/* Get frame from application. */
-		status = (*strm->play_cb)(strm->user_data, 
-					  wmme_strm->timestamp.u32.lo,
-					  buffer,
-					  bytes_per_frame);
-
-		if (status != PJ_SUCCESS)
-		    break;
-
-		/* Write to the device. */
-		mr = waveOutWrite(wmme_strm->hWave.Out, 
-				  &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]), 
-				  sizeof(WAVEHDR));
-		if (mr != MMSYSERR_NOERROR)
-		{
-		    status = PJ_STATUS_FROM_OS(mr);
-		    break;
-		}
-
-		/* Increment position. */
-		if (++wmme_strm->dwBufIdx >= wmme_strm->dwMaxBufIdx)
-		    wmme_strm->dwBufIdx = 0;
-		wmme_strm->timestamp.u64 += strm->samples_per_frame / 
-					    strm->channel_count;
-	    }
-	}
-	else
-	{
-	    struct wmme_stream *wmme_strm = &strm->rec_strm;
-	    MMRESULT mr = MMSYSERR_NOERROR;
-	    status = PJ_SUCCESS;
-
-	    /*
-	    * Windows Multimedia has indicated that it has some frames ready
-	    * in the capture buffer. Get as much frames as possible to
-	    * prevent overflows.
-	    */
-#if 0
-	    {
-		static DWORD tc = 0;
-		DWORD now = GetTickCount();
-		DWORD i = 0;
-		DWORD bits = 0;
-
-		if (tc == 0) tc = now;
-
-		for (i = 0; i < wmme_strm->dwMaxBufIdx; ++i)
-		{
-		    bits = bits << 4;
-		    bits |= wmme_strm->WaveHdr[i].dwFlags & WHDR_DONE;
-		}
-		PJ_LOG(5,(THIS_FILE, "Record Signal> Index: %d, Delta: %4.4d, "
-			  "Flags: %6.6x\n",
-			  wmme_strm->dwBufIdx,
-			  now - tc,
-			  bits));
-		tc = now;
-	    }
-#endif
-
-	    while (wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwFlags & WHDR_DONE)
-	    {
-		char* buffer = (char*)
-			       wmme_strm->WaveHdr[wmme_strm->dwBufIdx].lpData;
-		unsigned cap_len = 
-			wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwBytesRecorded;
-
-		/*
-		PJ_LOG(5,(THIS_FILE, "Read %d bytes from buffer %d", cap_len, 
-			  wmme_strm->dwBufIdx));
-		*/
-
-		if (cap_len < bytes_per_frame)
-		    pj_bzero(buffer + cap_len, bytes_per_frame - cap_len);
-
-		/* Copy the audio data out of the wave buffer. */
-		pj_memcpy(strm->buffer, buffer, bytes_per_frame);
-
-		/* Re-add the buffer to the device. */
-		mr = waveInAddBuffer(wmme_strm->hWave.In, 
-				     &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]), 
-				     sizeof(WAVEHDR));
-		if (mr != MMSYSERR_NOERROR) {
-		    status = PJ_STATUS_FROM_OS(mr);
-		    break;
-		}
-
-		/* Call callback */
-		status = (*strm->rec_cb)(strm->user_data, 
-					 wmme_strm->timestamp.u32.lo, 
-					 strm->buffer, 
-					 bytes_per_frame);
-
-		if (status != PJ_SUCCESS)
-		    break;
-
-		/* Increment position. */
-		if (++wmme_strm->dwBufIdx >= wmme_strm->dwMaxBufIdx)
-		    wmme_strm->dwBufIdx = 0;
-		wmme_strm->timestamp.u64 += strm->samples_per_frame / 
-					    strm->channel_count;
-	    }
-	}
-    }
-
-    PJ_LOG(5,(THIS_FILE, "WMME: thread stopping.."));
-    return 0;
-}
-
-
-/*
-* Init sound library.
-*/
-PJ_DEF(pj_status_t) pjmedia_snd_init(pj_pool_factory *factory)
-{
-    unsigned c;
-    int i;
-    int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount;
-
-    if (snd_initialized)
-	return PJ_SUCCESS;
-
-    pj_bzero(&dev_info, sizeof(dev_info));
-
-    dev_count = 0;
-    pool_factory = factory;
-
-    /* Enumerate sound playback devices */
-    maximumPossibleDeviceCount = 0;
-
-    inputDeviceCount = waveInGetNumDevs();
-    if (inputDeviceCount > 0)
-	/* assume there is a WAVE_MAPPER */
-	maximumPossibleDeviceCount += inputDeviceCount + 1;
-
-    outputDeviceCount = waveOutGetNumDevs();
-    if (outputDeviceCount > 0)
-	/* assume there is a WAVE_MAPPER */
-	maximumPossibleDeviceCount += outputDeviceCount + 1;
-
-    if (maximumPossibleDeviceCount >= MAX_HARDWARE)
-    {
-	pj_assert(!"Too many hardware found");
-	PJ_LOG(3,(THIS_FILE, "Too many hardware found, "
-		  "some devices will not be listed"));
-    }
-
-    if (inputDeviceCount > 0)
-    {
-	/* -1 is the WAVE_MAPPER */
-	for (i = -1; i < inputDeviceCount && dev_count < MAX_HARDWARE; ++i)
-	{
-	    UINT uDeviceID = (UINT)((i==-1) ? WAVE_MAPPER : i);
-	    WAVEINCAPS wic;
-	    MMRESULT mr;
-
-	    pj_bzero(&wic, sizeof(WAVEINCAPS));
-
-	    mr = waveInGetDevCaps(uDeviceID, &wic, sizeof(WAVEINCAPS));
-
-	    if (mr == MMSYSERR_NOMEM)
-		return PJ_ENOMEM;
-
-	    if (mr != MMSYSERR_NOERROR)
-		continue;
-
-#ifdef UNICODE
-	    WideCharToMultiByte(CP_ACP, 0, wic.szPname, wcslen(wic.szPname), 
-				dev_info[dev_count].info.name, 64, NULL, NULL);
-#else
-	    strncpy(dev_info[dev_count].info.name, wic.szPname, MAXPNAMELEN);
-#endif
-	    if (uDeviceID == WAVE_MAPPER)
-		strcat(dev_info[dev_count].info.name, " - Input");
-
-	    dev_info[dev_count].info.input_count = wic.wChannels;
-	    dev_info[dev_count].info.output_count = 0;
-	    dev_info[dev_count].info.default_samples_per_sec = 44100;
-	    dev_info[dev_count].deviceId = uDeviceID;
-
-	    /* Sometimes a device can return a rediculously large number of 
-	     * channels. This happened with an SBLive card on a Windows ME box.
-	     * It also happens on Win XP!
-	     */
-	    if ((dev_info[dev_count].info.input_count < 1) || 
-		(dev_info[dev_count].info.input_count > 256))
-		dev_info[dev_count].info.input_count = 2;
-
-	    ++dev_count;
-	}
-    }
-
-    if( outputDeviceCount > 0 )
-    {
-	/* -1 is the WAVE_MAPPER */
-	for (i = -1; i < outputDeviceCount && dev_count < MAX_HARDWARE; ++i)
-	{
-	    UINT uDeviceID = (UINT)((i==-1) ? WAVE_MAPPER : i);
-	    WAVEOUTCAPS woc;
-	    MMRESULT mr;
-
-	    pj_bzero(&woc, sizeof(WAVEOUTCAPS));
-
-	    mr = waveOutGetDevCaps(uDeviceID, &woc, sizeof(WAVEOUTCAPS));
-
-	    if (mr == MMSYSERR_NOMEM)
-		return PJ_ENOMEM;
-
-	    if (mr != MMSYSERR_NOERROR)
-		continue;
-
-#ifdef UNICODE
-	    WideCharToMultiByte(CP_ACP, 0, woc.szPname, wcslen(woc.szPname),
-				dev_info[dev_count].info.name, 64, NULL, NULL);
-#else
-	    strncpy(dev_info[dev_count].info.name, woc.szPname, MAXPNAMELEN);
-#endif
-	    if (uDeviceID == WAVE_MAPPER)
-		strcat(dev_info[dev_count].info.name, " - Output");
-
-	    dev_info[dev_count].info.output_count = woc.wChannels;
-	    dev_info[dev_count].info.input_count = 0;
-	    dev_info[dev_count].deviceId = uDeviceID;
-	    /* TODO: Perform a search! */
-	    dev_info[dev_count].info.default_samples_per_sec = 44100;
-
-	    /* Sometimes a device can return a rediculously large number of channels.
-	     * This happened with an SBLive card on a Windows ME box.
-	     * It also happens on Win XP!
-	     */
-	    if ((dev_info[dev_count].info.output_count < 1) || 
-		(dev_info[dev_count].info.output_count > 256))
-		dev_info[dev_count].info.output_count = 2;
-
-	    ++dev_count;
-	}
-    }
-
-    PJ_LOG(4, (THIS_FILE, "WMME initialized, found %d devices:", dev_count));
-    for (c = 0; c < dev_count; ++c)
-    {
-	PJ_LOG(4, (THIS_FILE, " dev_id %d: %s  (in=%d, out=%d)", 
-	    c,
-	    dev_info[c].info.name,
-	    dev_info[c].info.input_count,
-	    dev_info[c].info.output_count));
-    }
-    return PJ_SUCCESS;
-}
-
-/*
- * Deinitialize sound library.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_deinit(void)
-{
-    snd_initialized = PJ_FALSE;
-    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, "wmme-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 player stream */
-    if (dir & PJMEDIA_DIR_PLAYBACK)
-    {
-	unsigned buf_count;
-
-	buf_count = snd_output_latency * clock_rate * channel_count / 
-		    samples_per_frame / 1000;
-
-	status = init_player_stream(strm->pool,
-				    &strm->play_strm,
-				    play_id,
-				    clock_rate,
-				    channel_count,
-				    samples_per_frame,
-				    buf_count);
-
-	if (status != PJ_SUCCESS)
-	{
-	    pjmedia_snd_stream_close(strm);
-	    return status;
-	}
-    }
-
-    /* Create capture stream */
-    if (dir & PJMEDIA_DIR_CAPTURE)
-    {
-	unsigned buf_count;
-
-	buf_count = snd_input_latency * clock_rate * channel_count / 
-		    samples_per_frame / 1000;
-
-	status = init_capture_stream(strm->pool,
-				     &strm->rec_strm,
-				     rec_id,
-				     clock_rate,
-				     channel_count,
-				     samples_per_frame,
-				     buf_count);
-
-	if (status != PJ_SUCCESS)
-	{
-	    pjmedia_snd_stream_close(strm);
-	    return status;
-	}
-    }
-
-    /* Create the stop event */
-    strm->thread_quit_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (strm->thread_quit_event == NULL)
-	return pj_get_os_error();
-
-    /* Create and start the thread */
-    status = pj_thread_create(pool, "wmme", &wmme_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 = snd_input_latency * strm->clock_rate * 
-		      strm->channel_count / 1000;
-    pi->play_latency = snd_output_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)
-{
-    MMRESULT mr;
-
-    PJ_UNUSED_ARG(stream);
-
-    if (stream->play_strm.hWave.Out != NULL)
-    {
-	mr = waveOutRestart(stream->play_strm.hWave.Out);
-	if (mr != MMSYSERR_NOERROR)
-	    /* TODO: This macro is supposed to be used for HRESULT, fix. */
-	    PJ_RETURN_OS_ERROR(mr);
-	PJ_LOG(5,(THIS_FILE, "WMME playback stream started"));
-    }
-
-    if (stream->rec_strm.hWave.In != NULL)
-    {
-	mr = waveInStart(stream->rec_strm.hWave.In);
-	if (mr != MMSYSERR_NOERROR)
-	    /* TODO: This macro is supposed to be used for HRESULT, fix. */
-	    PJ_RETURN_OS_ERROR(mr);
-	PJ_LOG(5,(THIS_FILE, "WMME capture stream started"));
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Stop stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_stop(pjmedia_snd_stream *stream)
-{
-    MMRESULT mr;
-
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-
-    if (stream->play_strm.hWave.Out != NULL)
-    {
-	mr = waveOutPause(stream->play_strm.hWave.Out);
-	if (mr != MMSYSERR_NOERROR)
-	    /* TODO: This macro is supposed to be used for HRESULT, fix. */
-	    PJ_RETURN_OS_ERROR(mr);
-	PJ_LOG(5,(THIS_FILE, "Stopped WMME playback stream"));
-    }
-
-    if (stream->rec_strm.hWave.In != NULL)
-    {
-	mr = waveInStop(stream->rec_strm.hWave.In);
-	if (mr != MMSYSERR_NOERROR)
-	    /* TODO: This macro is supposed to be used for HRESULT, fix. */
-	    PJ_RETURN_OS_ERROR(mr);
-	PJ_LOG(5,(THIS_FILE, "Stopped WMME capture stream"));
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Destroy stream.
- */
-PJ_DEF(pj_status_t) pjmedia_snd_stream_close(pjmedia_snd_stream *stream)
-{
-    unsigned i;
-
-    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
-
-    pjmedia_snd_stream_stop(stream);
-
-    if (stream->thread)
-    {
-	SetEvent(stream->thread_quit_event);
-	pj_thread_join(stream->thread);
-	pj_thread_destroy(stream->thread);
-	stream->thread = NULL;
-    }
-
-    /* Unprepare the headers and close the play device */
-    if (stream->play_strm.hWave.Out)
-    {
-	waveOutReset(stream->play_strm.hWave.Out);
-	for (i = 0; i < stream->play_strm.dwMaxBufIdx; ++i)
-	    waveOutUnprepareHeader(stream->play_strm.hWave.Out, 
-				   &(stream->play_strm.WaveHdr[i]),
-				   sizeof(WAVEHDR));
-	waveOutClose(stream->play_strm.hWave.Out);
-	stream->play_strm.hWave.Out = NULL;
-    }
-
-    /* Close the play event */
-    if (stream->play_strm.hEvent)
-    {
-	CloseHandle(stream->play_strm.hEvent);
-	stream->play_strm.hEvent = NULL;
-    }
-
-    /* Unprepare the headers and close the record device */
-    if (stream->rec_strm.hWave.In)
-    {
-	waveInReset(stream->rec_strm.hWave.In);
-	for (i = 0; i < stream->play_strm.dwMaxBufIdx; ++i)
-	    waveInUnprepareHeader(stream->rec_strm.hWave.In, 
-				  &(stream->rec_strm.WaveHdr[i]),
-				  sizeof(WAVEHDR));
-	waveInClose(stream->rec_strm.hWave.In);
-	stream->rec_strm.hWave.In = NULL;
-    }
-
-    /* Close the record event */
-    if (stream->rec_strm.hEvent)
-    {
-	CloseHandle(stream->rec_strm.hEvent);
-	stream->rec_strm.hEvent = 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: /pjproject/branches/projects/aps-direct/pjproject.dsw
===================================================================
--- /pjproject/branches/projects/aps-direct/pjproject.dsw	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjproject.dsw	(revision 2468)
@@ -234,4 +234,7 @@
     Project_Dep_Name pjnath
     End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjmedia_audiodev
+    End Project Dependency
 }}}
 
@@ -363,4 +366,7 @@
     Project_Dep_Name libsrtp
     End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjmedia_audiodev
+    End Project Dependency
 }}}
 
@@ -451,4 +457,61 @@
     End Project Dependency
     Begin Project Dependency
+    Project_Dep_Name libgsmcodec
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libilbccodec
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libportaudio
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libresample
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libspeex
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjnath
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name libsrtp
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjmedia_audiodev
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "samples"=".\pjsip-apps\build\samples.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+    Begin Project Dependency
+    Project_Dep_Name pjlib
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjlib_util
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjmedia
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjmedia_codec
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjsip_core
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjsip_simple
+    End Project Dependency
+    Begin Project Dependency
+    Project_Dep_Name pjsip_ua
+    End Project Dependency
+    Begin Project Dependency
     Project_Dep_Name pjsua_lib
     End Project Dependency
@@ -481,5 +544,5 @@
 ###############################################################################
 
-Project: "samples"=".\pjsip-apps\build\samples.dsp" - Package Owner=<4>
+Project: "test_pjsip"=".\pjsip\build\test_pjsip.dsp" - Package Owner=<4>
 
 Package=<5>
@@ -513,61 +576,4 @@
     Project_Dep_Name pjsua_lib
     End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name libgsmcodec
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name libilbccodec
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name libportaudio
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name libresample
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name libspeex
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name pjnath
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name libsrtp
-    End Project Dependency
-}}}
-
-###############################################################################
-
-Project: "test_pjsip"=".\pjsip\build\test_pjsip.dsp" - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-    Begin Project Dependency
-    Project_Dep_Name pjlib
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name pjlib_util
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name pjmedia
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name pjmedia_codec
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name pjsip_core
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name pjsip_simple
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name pjsip_ua
-    End Project Dependency
-    Begin Project Dependency
-    Project_Dep_Name pjsua_lib
-    End Project Dependency
 }}}
 
Index: /pjproject/branches/projects/aps-direct/pjsip-apps/build/Samples-vc.mak
===================================================================
--- /pjproject/branches/projects/aps-direct/pjsip-apps/build/Samples-vc.mak	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjsip-apps/build/Samples-vc.mak	(revision 2468)
@@ -14,4 +14,5 @@
 PJMEDIA_LIB = ..\..\pjmedia\lib\pjmedia-$(TARGET)$(LIBEXT)
 PJMEDIA_CODEC_LIB = ..\..\pjmedia\lib\pjmedia-codec-$(TARGET)$(LIBEXT)
+PJMEDIA_AUDIODEV_LIB = ..\..\pjmedia\lib\pjmedia-audiodev-$(TARGET)$(LIBEXT)
 PJSIP_LIB = ..\..\pjsip\lib\pjsip-core-$(TARGET)$(LIBEXT)
 PJSIP_UA_LIB = ..\..\pjsip\lib\pjsip-ua-$(TARGET)$(LIBEXT)
@@ -30,6 +31,6 @@
 
 LIBS = $(PJSUA_LIB_LIB) $(PJSIP_UA_LIB) $(PJSIP_SIMPLE_LIB) \
-	  $(PJSIP_LIB) $(PJMEDIA_CODEC_LIB) $(PJMEDIA_LIB) $(PJNATH_LIB) \
-	  $(PJLIB_UTIL_LIB) $(PJLIB_LIB) \
+	  $(PJSIP_LIB) $(PJMEDIA_CODEC_LIB) $(PJMEDIA_AUDIODEV_LIB) \
+	  $(PJMEDIA_LIB) $(PJNATH_LIB) $(PJLIB_UTIL_LIB) $(PJLIB_LIB) \
 	  $(THIRD_PARTY_LIBS)
 
@@ -50,5 +51,6 @@
 
 
-SAMPLES = $(BINDIR)\confsample.exe \
+SAMPLES = $(BINDIR)\auddemo.exe \
+	  $(BINDIR)\confsample.exe \
 	  $(BINDIR)\confbench.exe \
 	  $(BINDIR)\encdec.exe \
@@ -66,6 +68,4 @@
 	  $(BINDIR)\siprtp.exe \
 	  $(BINDIR)\sipstateless.exe \
-	  $(BINDIR)\sndinfo.exe \
-	  $(BINDIR)\sndtest.exe \
 	  $(BINDIR)\stateful_proxy.exe \
 	  $(BINDIR)\stateless_proxy.exe \
Index: /pjproject/branches/projects/aps-direct/pjsip-apps/build/Samples.mak
===================================================================
--- /pjproject/branches/projects/aps-direct/pjsip-apps/build/Samples.mak	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjsip-apps/build/Samples.mak	(revision 2468)
@@ -14,5 +14,6 @@
 BINDIR := ../bin/samples
 
-SAMPLES := confsample \
+SAMPLES := auddemo \
+	   confsample \
 	   encdec \
 	   latency \
@@ -29,6 +30,4 @@
 	   siprtp \
 	   sipstateless \
-	   sndinfo \
-	   sndtest \
 	   stateful_proxy \
 	   stateless_proxy \
Index: /pjproject/branches/projects/aps-direct/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjsip-apps/src/pjsua/pjsua_app.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjsip-apps/src/pjsua/pjsua_app.c	(revision 2468)
@@ -4060,4 +4060,10 @@
     app_config.cfg.cb.on_nat_detect = &on_nat_detect;
 
+    /* Set sound device latency */
+    if (app_config.capture_lat > 0)
+	app_config.media_cfg.snd_rec_latency = app_config.capture_lat;
+    if (app_config.playback_lat)
+	app_config.media_cfg.snd_play_latency = app_config.playback_lat;
+
     /* Initialize pjsua */
     status = pjsua_init(&app_config.cfg, &app_config.log_cfg,
@@ -4318,7 +4324,4 @@
     if (status != PJ_SUCCESS)
 	goto on_error;
-
-    /* Set sound device latency */
-    pjmedia_snd_set_latency(app_config.capture_lat, app_config.playback_lat);
 
     /* Use null sound device? */
Index: /pjproject/branches/projects/aps-direct/pjsip-apps/src/samples/auddemo.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjsip-apps/src/samples/auddemo.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjsip-apps/src/samples/auddemo.c	(revision 2468)
@@ -30,5 +30,4 @@
 
 static unsigned dev_count;
-static pjmedia_aud_dev_id dev_id[MAX_DEVICES];
 
 static void app_perror(const char *title, pj_status_t status)
@@ -54,10 +53,8 @@
     PJ_LOG(3,(THIS_FILE, "Found %d devices:", dev_count));
 
-    dev_count = pjmedia_aud_dev_enum(PJ_ARRAY_SIZE(dev_id), dev_id);
-
     for (i=0; i<dev_count; ++i) {
 	pjmedia_aud_dev_info info;
 
-	status = pjmedia_aud_dev_get_info(dev_id[i], &info);
+	status = pjmedia_aud_dev_get_info(i, &info);
 	if (status != PJ_SUCCESS)
 	    continue;
@@ -71,61 +68,16 @@
 {
     static char text[200];
+    unsigned i;
 
     text[0] = '\0';
 
-    if (caps & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) {
-	strcat(text, "extfmt ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) {
-	strcat(text, "inlatency ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) {
-	strcat(text, "outlatency ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING) {
-	strcat(text, "invol ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
-	strcat(text, "outvol ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_INPUT_SIGNAL_VOLUME) {
-	strcat(text, "insignal ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_OUTPUT_SIGNAL_VOLUME) {
-	strcat(text, "outsignal ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE) {
-	strcat(text, "inroute ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE) {
-	strcat(text, "outroute ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_EC) {
-	strcat(text, "ec ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL) {
-	strcat(text, "ectail ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_VAD) {
-	strcat(text, "vad ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_CNG) {
-	strcat(text, "cng ");
-    }
-
-    if (caps & PJMEDIA_AUD_DEV_CAP_PLC) {
-	strcat(text, "plc ");
+    for (i=0; i<31; ++i) {
+	if ((1 << i) & caps) {
+	    const char *capname;
+	    capname = pjmedia_aud_dev_cap_name((pjmedia_aud_dev_cap)(1 << i), 
+					       NULL);
+	    strcat(text, capname);
+	    strcat(text, " ");
+	}
     }
 
@@ -145,5 +97,5 @@
     }
 
-    status = pjmedia_aud_dev_get_info(dev_id[index], &info);
+    status = pjmedia_aud_dev_get_info(index, &info);
     if (status != PJ_SUCCESS) {
 	app_perror("pjmedia_aud_dev_get_info() error", status);
@@ -154,5 +106,5 @@
     PJ_LOG(3, (THIS_FILE, "-------------------------"));
 
-    PJ_LOG(3, (THIS_FILE, H": %u (0x%x)", "ID", dev_id[index], dev_id[index]));
+    PJ_LOG(3, (THIS_FILE, H": %u (0x%x)", "ID", index, index));
     PJ_LOG(3, (THIS_FILE, H": %s", "Name", info.name));
     PJ_LOG(3, (THIS_FILE, H": %s", "Driver", info.driver));
@@ -205,12 +157,12 @@
 			unsigned chnum)
 {
-    pjmedia_aud_dev_param param;
+    pjmedia_aud_param param;
     pjmedia_aud_test_results result;
     pj_status_t status;
 
     if (dir & PJMEDIA_DIR_CAPTURE) {
-	status = pjmedia_aud_dev_default_param(dev_id[rec_id], &param);
+	status = pjmedia_aud_dev_default_param(rec_id, &param);
     } else {
-	status = pjmedia_aud_dev_default_param(dev_id[play_id], &param);
+	status = pjmedia_aud_dev_default_param(play_id, &param);
     }
 
@@ -221,6 +173,6 @@
 
     param.dir = dir;
-    param.rec_id = dev_id[rec_id];
-    param.play_id = dev_id[play_id];
+    param.rec_id = rec_id;
+    param.play_id = play_id;
     param.clock_rate = clock_rate;
     param.channel_count = chnum;
@@ -286,5 +238,5 @@
     pj_pool_t *pool = NULL;
     pjmedia_port *wav = NULL;
-    pjmedia_aud_dev_param param;
+    pjmedia_aud_param param;
     pjmedia_aud_stream *strm = NULL;
     char line[10];
@@ -304,5 +256,5 @@
     }
 
-    status = pjmedia_aud_dev_default_param(dev_id[rec_index], &param);
+    status = pjmedia_aud_dev_default_param(rec_index, &param);
     if (status != PJ_SUCCESS) {
 	app_perror("pjmedia_aud_dev_default_param()", status);
@@ -354,5 +306,5 @@
     pj_pool_t *pool = NULL;
     pjmedia_port *wav = NULL;
-    pjmedia_aud_dev_param param;
+    pjmedia_aud_param param;
     pjmedia_aud_stream *strm = NULL;
     char line[10];
@@ -371,5 +323,5 @@
     }
 
-    status = pjmedia_aud_dev_default_param(dev_id[play_index], &param);
+    status = pjmedia_aud_dev_default_param(play_index, &param);
     if (status != PJ_SUCCESS) {
 	app_perror("pjmedia_aud_dev_default_param()", status);
Index: project/branches/projects/aps-direct/pjsip-apps/src/samples/sndinfo.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjsip-apps/src/samples/sndinfo.c	(revision 2467)
+++ 	(revision )
@@ -1,295 +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 
- */
-
-static const char *desc = 
- " sndinfo.c								    \n"
- "									    \n"
- " PURPOSE:								    \n"
- "  Print sound device info and test open device.			    \n"
- "									    \n"
- " USAGE:								    \n"
- "  sndinfo [id rec/play/both clockrate nchan bits]			    \n"
- "									    \n"
- " DESCRIPTION:								    \n"
- "  When invoked without any arguments, it displays information about all   \n"
- "  sound devices in the system.					    \n"
- "									    \n"
- "  When invoked with arguments, the program tests if device can be opened  \n"
- "  with the specified arguments. All these arguments must be specified:    \n"
- "  - id             The device ID (-1 for the first capable device)	    \n"
- "  - rec/play/both  Specify which streams to open.			    \n"
- "  - clockrate      Specify clock rate (e.g. 8000, 11025, etc.)	    \n"
- "  - nchan	     Number of channels (1=mono, 2=stereo).		    \n"
- "  - bits	     Number of bits per sample (normally 16).		    \n";
-
-#include <pjmedia.h>
-#include <pjlib.h>
-
-#include <stdlib.h>	/* atoi() */
-#include <stdio.h>
-
-
-static void enum_devices(void)
-{
-    int i, count;
-    
-    count = pjmedia_snd_get_dev_count();
-    if (count == 0) {
-	puts("No devices found");
-	return;
-    }
-
-    for (i=0; i<count; ++i) {
-	const pjmedia_snd_dev_info *info;
-
-	info = pjmedia_snd_get_dev_info(i);
-	pj_assert(info != NULL);
-
-	printf( "Device #%02d: \n"
-		"  Name                : %s\n"
-		"  # of input channels : %d\n"
-		"  # of output channels: %d\n"
-		"  Default clock rate  : %d Hz\n\n",
-		i, info->name, info->input_count, info->output_count,
-		info->default_samples_per_sec);
-    }
-    puts("");
-    puts("Run with -h to get more options");
-}
-
-static unsigned clock_rate;
-static unsigned play_counter;
-static unsigned rec_counter;
-static unsigned min_delay = 0xFFFF, max_delay;
-static char play_delays[1000];
-static pj_uint32_t last_play_timestamp, last_rec_timestamp;
-
-static pj_status_t play_cb(void *user_data, pj_uint32_t timestamp,
-			   void *output, unsigned size)
-{
-    static pj_timestamp last_cb;
-
-
-    PJ_UNUSED_ARG(user_data);
-    PJ_UNUSED_ARG(output);
-    PJ_UNUSED_ARG(size);
-
-
-    ++play_counter;
-    last_play_timestamp = timestamp;
-
-    if (last_cb.u64 == 0) {
-	pj_get_timestamp(&last_cb);
-    } else if (play_counter <= PJ_ARRAY_SIZE(play_delays)) {
-	pj_timestamp now;
-	unsigned delay;
-
-	pj_get_timestamp(&now);
-	
-	delay = pj_elapsed_msec(&last_cb, &now);
-	if (delay < min_delay)
-	    min_delay = delay;
-	if (delay > max_delay)
-	    max_delay = delay;
-
-	last_cb = now;
-
-	play_delays[play_counter-1] = (char)delay;
-    }
-
-    return PJ_SUCCESS;
-}
-
-static pj_status_t rec_cb(void *user_data, pj_uint32_t timestamp,
-			  void *input, unsigned size)
-{
-
-    PJ_UNUSED_ARG(size);
-    PJ_UNUSED_ARG(input);
-    PJ_UNUSED_ARG(user_data);
-
-
-    ++rec_counter;
-
-    if (timestamp - last_rec_timestamp >= clock_rate && last_play_timestamp) {
-	int diff;
-	diff = last_play_timestamp - timestamp;
-	printf("Play timestamp=%u, capture timestamp=%u, diff=%d\n",
-	       last_play_timestamp, timestamp, diff);
-	last_rec_timestamp = timestamp;
-    }
-    return PJ_SUCCESS;
-}
-
-static void app_perror(const char *title, pj_status_t status)
-{
-    char errmsg[PJ_ERR_MSG_SIZE];
-
-    pj_strerror(status, errmsg, sizeof(errmsg));	
-    printf( "%s: %s (err=%d)\n",
-	    title, errmsg, status);
-}
-
-static int open_device(int dev_id, pjmedia_dir dir,
-		       int nchannel, int bits)
-{
-    pj_status_t status = PJ_SUCCESS;
-    unsigned nsamples;
-    pjmedia_snd_stream *strm;
-    const char *dirtype;
-    char tmp[10];
-    unsigned i;
-
-    switch (dir) {
-    case PJMEDIA_DIR_CAPTURE:
-	dirtype = "capture"; break;    
-    case PJMEDIA_DIR_PLAYBACK:
-	dirtype = "playback"; break;    
-    case PJMEDIA_DIR_CAPTURE_PLAYBACK:
-	dirtype = "capture/playback"; break;    
-    default:
-	return 1;
-    }
-    
-    nsamples = clock_rate * 20 / 1000;
-
-    printf( "Opening device %d for %s: clockrate=%d, nchannel=%d, "
-	    "bits=%d, nsamples=%d..\n",
-	    dev_id, dirtype, clock_rate, nchannel, bits, nsamples);
-
-    if (dir == PJMEDIA_DIR_CAPTURE) {
-	status = pjmedia_snd_open_rec( dev_id, clock_rate, nchannel,
-				       nsamples, bits, &rec_cb, NULL,
-				       &strm);
-    } else if (dir == PJMEDIA_DIR_PLAYBACK) {
-	status = pjmedia_snd_open_player( dev_id, clock_rate, nchannel,
-					  nsamples, bits, &play_cb, NULL,
-					  &strm);
-    } else {
-	status = pjmedia_snd_open( dev_id, dev_id, clock_rate, nchannel,
-				   nsamples, bits, &rec_cb, &play_cb, NULL,
-				   &strm);
-    }
-    
-    if (status != PJ_SUCCESS) {
-        app_perror("Unable to open device for capture", status);
-        return 1;
-    }
-
-    status = pjmedia_snd_stream_start(strm);
-    if (status != PJ_SUCCESS) {
-        app_perror("Unable to start capture stream", status);
-        return 1;
-    }
-    
-    /* Let playback/capture runs for a while */
-    //pj_thread_sleep(1000);
-    puts("Press <ENTER> to stop");
-    if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
-	puts("EOF while reading stdin, will quit now..");
-    }
-
-    pjmedia_snd_stream_close(strm);
-
-    if ((dir & PJMEDIA_DIR_CAPTURE) && rec_counter==0) {
-	printf("Error: capture stream was not running\n");
-	return 1;
-    }
-
-    if ((dir & PJMEDIA_DIR_PLAYBACK) && play_counter==0) {
-	printf("Error: playback stream was not running\n");
-	return 1;
-    }
-
-    puts("Success.");
-
-    printf("Delay: ");
-    for (i=0; i<play_counter; ++i)
-	printf("%d ", play_delays[i]);
-
-    puts("");
-    if (dir & PJMEDIA_DIR_PLAYBACK) {
-	printf("Callback interval: min interval=%d ms, max interval=%d ms\n",
-	       min_delay, max_delay);
-    }
-    
-
-    return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
-    pj_caching_pool cp;
-    pjmedia_endpt *med_endpt;
-    pj_status_t status;
-
-    /* Init pjlib */
-    status = pj_init();
-    PJ_ASSERT_RETURN(status==PJ_SUCCESS, 1);
-    
-    /* Must create a pool factory before we can allocate any memory. */
-    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
-
-    /* 
-     * Initialize media endpoint.
-     * This will implicitly initialize PJMEDIA too.
-     */
-    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-    
-    if (argc == 1) {
-	enum_devices();
-    } else if (argc == 6) {
-	
-	int dev_id;
-	pjmedia_dir dir = PJMEDIA_DIR_NONE;
-	int nchannel;
-	int bits;
-
-	dev_id = atoi(argv[1]);
-
-	if (strcmp(argv[2], "rec")==0)
-	    dir = PJMEDIA_DIR_CAPTURE;
-	else if (strcmp(argv[2], "play")==0)
-	    dir = PJMEDIA_DIR_PLAYBACK;
-	else if (strcmp(argv[2], "both")==0)
-	    dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
-
-	clock_rate = atoi(argv[3]);
-	nchannel = atoi(argv[4]);
-	bits = atoi(argv[5]);
-
-	return open_device(dev_id, dir, nchannel, bits);
-
-    } else {
-	puts("Error: invalid arguments");
-	puts(desc);
-	return 1;
-    }
-
-    /* Shutdown PJLIB */
-    pj_shutdown();
-
-    return 0;
-}
-
-
Index: project/branches/projects/aps-direct/pjsip-apps/src/samples/sndtest.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjsip-apps/src/samples/sndtest.c	(revision 2467)
+++ 	(revision )
@@ -1,621 +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 
- */
-
-/**
- * \page page_pjmedia_samples_sndtest_c Samples: Sound Card Benchmark
- *
- * This example can be used to benchmark the quality of the sound card
- * installed in the system. At the end of the test, it will report
- * the jitter and clock drifts of the device.
- *
- * This file is pjsip-apps/src/samples/sndtest.c
- *
- * Screenshots on WinXP: \image html sndtest.jpg
- *
- * \includelineno sndtest.c
- */
-
-
-#include <pjmedia.h>
-#include <pjlib.h>
-#include <pjlib-util.h>
-
-#include <stdlib.h>	/* atoi() */
-#include <stdio.h>
-
-
-
-#define THIS_FILE	    "sndtest.c"
-
-/* Warn (print log with yellow color) if frame jitter is larger than
- * this value (in usec).
- */
-#define WARN_JITTER_USEC    1000
-
-/* Test duration in msec */
-#define DURATION	    10000
-
-/* Skip the first msec from the calculation */
-#define SKIP_DURATION	    1000
-
-/* Max frames per sec (to calculate number of delays to keep). */
-#define MAX_FRAMES_PER_SEC  100
-
-/* Number of frame durations to keep */
-#define MAX_DELAY_COUNTER   (((DURATION/1000)+1)*MAX_FRAMES_PER_SEC)
-
-
-struct stream_data
-{
-    pj_uint32_t	    first_timestamp;
-    pj_uint32_t	    last_timestamp;
-    pj_timestamp    last_called;
-    unsigned	    counter;
-    unsigned	    min_delay;
-    unsigned	    max_delay;
-    unsigned	    delay[MAX_DELAY_COUNTER];
-};
-
-struct test_data {
-    pjmedia_dir dir;
-    unsigned clock_rate;
-    unsigned samples_per_frame;
-    unsigned channel_count;
-    pj_bool_t running;
-    pj_bool_t has_error;
-    pj_mutex_t *mutex;
-
-    struct stream_data capture_data;
-    struct stream_data playback_data;
-};
-
-
-
-static const char *desc = 
- " sndtest.c						\n"
- "							\n"
- " PURPOSE:						\n"
- "  Test the performance of sound device.		\n"
- "							\n"
- " USAGE:						\n"
- "  sndtest --help					\n"
- "  sndtest [options]					\n"
- "							\n"
- " where options:					\n"
- "  --id=ID          -i  Use device ID (default is -1)	\n"
- "  --rate=HZ        -r  Set test clock rate (default=8000)\n"
- "  --frame=SAMPLES  -f  Set number of samples per frame\n"
- "  --channel=CH     -n  Set number of channels (default=1)\n"
- "  --verbose        -v  Show verbose result		\n"
- "  --help           -h  Show this screen		\n"
-;
-
-
-
-static void enum_devices(void)
-{
-    int i, count;
-    
-    count = pjmedia_snd_get_dev_count();
-    if (count == 0) {
-	PJ_LOG(3,(THIS_FILE, "No devices found"));
-	return;
-    }
-
-    PJ_LOG(3,(THIS_FILE, "Found %d devices:", count));
-    for (i=0; i<count; ++i) {
-	const pjmedia_snd_dev_info *info;
-
-	info = pjmedia_snd_get_dev_info(i);
-	pj_assert(info != NULL);
-
-	PJ_LOG(3,(THIS_FILE," %d: %s (capture=%d, playback=%d)",
-	          i, info->name, info->input_count, info->output_count));
-    }
-}
-
-
-static pj_status_t play_cb(void *user_data, pj_uint32_t timestamp,
-			   void *output, unsigned size)
-{
-    struct test_data *test_data = user_data;
-    struct stream_data *strm_data = &test_data->playback_data;
-
-    pj_mutex_lock(test_data->mutex);
-
-    /* Skip frames when test is not started or test has finished */
-    if (!test_data->running) {
-	pj_bzero(output, size);
-
-	pj_mutex_unlock(test_data->mutex);
-	return PJ_SUCCESS;
-    }
-
-    /* Save last timestamp seen (to calculate drift) */
-    strm_data->last_timestamp = timestamp;
-
-    if (strm_data->last_called.u64 == 0) {
-	pj_get_timestamp(&strm_data->last_called);
-	/* Init min_delay to one frame */
-	strm_data->min_delay = test_data->samples_per_frame * 1000000 /
-			       test_data->clock_rate;
-	strm_data->first_timestamp = timestamp;
-
-    } else if (strm_data->counter <= MAX_DELAY_COUNTER) {
-	pj_timestamp now;
-	unsigned delay;
-
-	pj_get_timestamp(&now);
-	
-	/* Calculate frame interval */
-	delay = pj_elapsed_usec(&strm_data->last_called, &now);
-	if (delay < strm_data->min_delay)
-	    strm_data->min_delay = delay;
-	if (delay > strm_data->max_delay)
-	    strm_data->max_delay = delay;
-
-	strm_data->last_called = now;
-
-	/* Save the frame interval for later calculation */
-	strm_data->delay[strm_data->counter] = delay;
-	++strm_data->counter;
-
-    } else {
-
-	/* No space, can't take anymore frames */
-	test_data->running = 0;
-
-    }
-
-    pj_bzero(output, size);
-
-    pj_mutex_unlock(test_data->mutex);
-
-    return PJ_SUCCESS;
-}
-
-static pj_status_t rec_cb(void *user_data, pj_uint32_t timestamp,
-			  void *input, unsigned size)
-{
-
-    struct test_data *test_data = user_data;
-    struct stream_data *strm_data = &test_data->capture_data;
-
-    pj_mutex_lock(test_data->mutex);
-
-    PJ_UNUSED_ARG(input);
-    PJ_UNUSED_ARG(size);
-
-    /* Skip frames when test is not started or test has finished */
-    if (!test_data->running) {
-	pj_mutex_unlock(test_data->mutex);
-	return PJ_SUCCESS;
-    }
-
-    /* Save last timestamp seen (to calculate drift) */
-    strm_data->last_timestamp = timestamp;
-
-    if (strm_data->last_called.u64 == 0) {
-	pj_get_timestamp(&strm_data->last_called);
-	/* Init min_delay to one frame */
-	strm_data->min_delay = test_data->samples_per_frame * 1000000 /
-			       test_data->clock_rate;
-	strm_data->first_timestamp = timestamp;
-
-    } else if (strm_data->counter <= MAX_DELAY_COUNTER) {
-	pj_timestamp now;
-	unsigned delay;
-
-	pj_get_timestamp(&now);
-
-	/* Calculate frame interval */
-	delay = pj_elapsed_usec(&strm_data->last_called, &now);
-	if (delay < strm_data->min_delay)
-	    strm_data->min_delay = delay;
-	if (delay > strm_data->max_delay)
-	    strm_data->max_delay = delay;
-
-	strm_data->last_called = now;
-
-	/* Save the frame interval for later calculation */
-	strm_data->delay[strm_data->counter] = delay;
-	++strm_data->counter;
-
-    } else {
-
-	/* No space, can't take anymore frames */
-	test_data->running = 0;
-
-    }
-
-    pj_mutex_unlock(test_data->mutex);
-    return PJ_SUCCESS;
-}
-
-static void app_perror(const char *title, pj_status_t status)
-{
-    char errmsg[PJ_ERR_MSG_SIZE];
-
-    pj_strerror(status, errmsg, sizeof(errmsg));	
-    printf( "%s: %s (err=%d)\n",
-	    title, errmsg, status);
-}
-
-
-static void print_stream_data(const char *title, 
-			      struct test_data *test_data,
-			      struct stream_data *strm_data,
-			      int verbose)
-{
-    unsigned i, dur;
-    int ptime;
-    unsigned min_jitter, max_jitter, sum_jitter, avg_jitter=0;
-
-    PJ_LOG(3,(THIS_FILE, "  %s stream report:", title));
-
-    /* Check that frames are captured/played */
-    if (strm_data->counter == 0) {
-	PJ_LOG(1,(THIS_FILE, "   Error: no frames are captured/played!"));
-	test_data->has_error = 1;
-	return;
-    }
-
-    /* Duration */
-    dur = (strm_data->counter+1) * test_data->samples_per_frame * 1000 /
-		test_data->clock_rate;
-    PJ_LOG(3,(THIS_FILE, "   Duration: %ds.%03d",
-	      dur/1000, dur%1000));
-
-    /* Frame interval */
-    if (strm_data->max_delay - strm_data->min_delay < WARN_JITTER_USEC) {
-	PJ_LOG(3,(THIS_FILE, 
-		  "   Frame interval: min=%d.%03dms, max=%d.%03dms",
-		  strm_data->min_delay/1000, strm_data->min_delay%1000,
-		  strm_data->max_delay/1000, strm_data->max_delay%1000));
-    } else {
-	test_data->has_error = 1;
-	PJ_LOG(2,(THIS_FILE, 
-		  "   Frame interval: min=%d.%03dms, max=%d.%03dms",
-		  strm_data->min_delay/1000, strm_data->min_delay%1000,
-		  strm_data->max_delay/1000, strm_data->max_delay%1000));
-    }
-
-    if (verbose) {
-	unsigned i;
-	unsigned decor = pj_log_get_decor();
-
-	PJ_LOG(3,(THIS_FILE, "    Dumping frame delays:"));
-
-	pj_log_set_decor(0);
-	for (i=0; i<strm_data->counter; ++i)
-	    PJ_LOG(3,(THIS_FILE, " %d.%03d", strm_data->delay[i]/1000, 
-		      strm_data->delay[i]%1000));
-	PJ_LOG(3,(THIS_FILE, "\r\n"));
-	pj_log_set_decor(decor);
-    }
-
-    /* Calculate frame ptime in usec */
-    ptime = test_data->samples_per_frame * 1000000 /
-	    test_data->clock_rate;
-
-    /* Calculate jitter */
-    min_jitter = 0xFFFFF;
-    max_jitter = 0;
-    sum_jitter = 0;
-
-    for (i=1; i<strm_data->counter; ++i) {
-	int jitter1, jitter2, jitter;
-
-	/* jitter1 is interarrival difference */
-	jitter1 = strm_data->delay[i] - strm_data->delay[i-1];
-	if (jitter1 < 0) jitter1 = -jitter1;
-	
-	/* jitter2 is difference between actual and scheduled arrival.
-	 * This is intended to capture situation when frames are coming
-	 * instantaneously, which will calculate as zero jitter with
-	 * jitter1 calculation.
-	 */
-	jitter2 = ptime - strm_data->delay[i];
-	if (jitter2 < 0) jitter2 = -jitter2;
-
-	/* Set jitter as the maximum of the two jitter calculations. 
-	 * This is intended to show the worst result.
-	 */
-	jitter = (jitter1>jitter2) ? jitter1 : jitter2;
-
-	/* Calculate min, max, avg jitter */
-	if (jitter < (int)min_jitter) min_jitter = jitter;
-	if (jitter > (int)max_jitter) max_jitter = jitter;
-
-	sum_jitter += jitter;
-    }
-
-    avg_jitter = (sum_jitter) / (strm_data->counter - 1);
-
-    if (max_jitter < WARN_JITTER_USEC) {
-	PJ_LOG(3,(THIS_FILE, 
-		  "   Jitter: min=%d.%03dms, avg=%d.%03dms, max=%d.%03dms",
-		  min_jitter/1000, min_jitter%1000, 
-		  avg_jitter/1000, avg_jitter%1000,
-		  max_jitter/1000, max_jitter%1000));
-    } else {
-	test_data->has_error = 1;
-	PJ_LOG(2,(THIS_FILE, 
-		  "   Jitter: min=%d.%03dms, avg=%d.%03dms, max=%d.%03dms",
-		  min_jitter/1000, min_jitter%1000, 
-		  avg_jitter/1000, avg_jitter%1000,
-		  max_jitter/1000, max_jitter%1000));
-    }
-}
-
-
-static int perform_test(pj_pool_t *pool, int dev_id, pjmedia_dir dir,
-		        unsigned clock_rate, unsigned samples_per_frame, 
-			unsigned nchannel, int verbose)
-{
-    pj_status_t status = PJ_SUCCESS;
-    pjmedia_snd_stream *strm;
-    struct test_data test_data;
-    pjmedia_snd_stream_info si;
-    
-    /*
-     * Init test parameters
-     */
-    pj_bzero(&test_data, sizeof(test_data));
-    test_data.dir = dir;
-    test_data.clock_rate = clock_rate;
-    test_data.samples_per_frame = samples_per_frame;
-    test_data.channel_count = nchannel;
-
-    pj_mutex_create_simple(pool, "sndtest", &test_data.mutex); 
-
-    /*
-     * Open device.
-     */
-    if (dir == PJMEDIA_DIR_CAPTURE) {
-	status = pjmedia_snd_open_rec( dev_id, clock_rate, nchannel,
-				       samples_per_frame, 16, &rec_cb, 
-				       &test_data, &strm);
-    } else if (dir == PJMEDIA_DIR_PLAYBACK) {
-	status = pjmedia_snd_open_player( dev_id, clock_rate, nchannel,
-					  samples_per_frame, 16, &play_cb, 
-					  &test_data, &strm);
-    } else {
-	status = pjmedia_snd_open( dev_id, dev_id, clock_rate, nchannel,
-				   samples_per_frame, 16, &rec_cb, &play_cb, 
-				   &test_data, &strm);
-    }
-    
-    if (status != PJ_SUCCESS) {
-        app_perror("Unable to open device for capture", status);
-        return status;
-    }
-
-    pjmedia_snd_stream_get_info(strm, &si);
-    if (si.play_id >= 0) {
-	PJ_LOG(3,(THIS_FILE, "Testing playback device %s", 
-		  pjmedia_snd_get_dev_info(si.play_id)->name));
-    }
-    if (si.rec_id >= 0) {
-	PJ_LOG(3,(THIS_FILE, "Testing capture device %s", 
-		  pjmedia_snd_get_dev_info(si.rec_id)->name));
-    }
-
-    /* Sleep for a while to let sound device "settles" */
-    pj_thread_sleep(200);
-
-
-    /*
-     * Start the stream.
-     */
-    status = pjmedia_snd_stream_start(strm);
-    if (status != PJ_SUCCESS) {
-        app_perror("Unable to start capture stream", status);
-        return status;
-    }
-
-    PJ_LOG(3,(THIS_FILE,
-	      " Please wait while test is in progress (~%d secs)..",
-	      (DURATION+SKIP_DURATION)/1000));
-
-    /* Let the stream runs for few msec/sec to get stable result.
-     * (capture normally begins with frames available simultaneously).
-     */
-    pj_thread_sleep(SKIP_DURATION);
-
-
-    /* Begin gather data */
-    test_data.running = 1;
-
-    /* 
-     * Let the test runs for a while.
-     */
-    pj_thread_sleep(DURATION);
-
-
-    /*
-     * Close stream.
-     */
-    test_data.running = 0;
-    pjmedia_snd_stream_close(strm);
-
-
-    /* 
-     * Print results.
-     */
-    PJ_LOG(3,(THIS_FILE, " Dumping results:"));
-
-    PJ_LOG(3,(THIS_FILE, "  Parameters: clock rate=%dHz, %d samples/frame",
-	      clock_rate, samples_per_frame));
-
-    if (dir & PJMEDIA_DIR_PLAYBACK)
-	print_stream_data("Playback", &test_data, &test_data.playback_data, 
-			  verbose);
-    if (dir & PJMEDIA_DIR_CAPTURE)
-	print_stream_data("Capture", &test_data, &test_data.capture_data, 
-			   verbose);
-
-    /* Check drifting */
-    if (dir == PJMEDIA_DIR_CAPTURE_PLAYBACK) {
-	int end_diff, start_diff, drift;
-
-	end_diff = test_data.capture_data.last_timestamp -
-		   test_data.playback_data.last_timestamp;
-	start_diff = test_data.capture_data.first_timestamp-
-		      test_data.playback_data.first_timestamp;
-	drift = end_diff > start_diff? end_diff - start_diff :
-		start_diff - end_diff;
-
-	PJ_LOG(3,(THIS_FILE, "  Checking for clock drifts:"));
-
-	/* Allow one frame tolerance for clock drift detection */
-	if (drift < (int)samples_per_frame) {
-	    PJ_LOG(3,(THIS_FILE, "   No clock drifts is detected"));
-	} else {
-	    const char *which = (drift<0 ? "slower" : "faster");
-	    unsigned msec_dur;
-
-	    if (drift < 0) drift = -drift;
-
-
-	    msec_dur = (test_data.capture_data.last_timestamp - 
-		       test_data.capture_data.first_timestamp) * 1000 /
-		       test_data.clock_rate;
-
-	    PJ_LOG(2,(THIS_FILE, 
-		      "   Sound capture is %d samples %s than playback "
-		      "at the end of the test (average is %d samples"
-		      " per second)",
-		      drift, which, 
-		      drift * 1000 / msec_dur));
-
-	}
-    }
-
-    if (test_data.has_error == 0) {
-	PJ_LOG(3,(THIS_FILE, " Test completed, sound device looks okay."));
-	return 0;
-    } else {
-	PJ_LOG(2,(THIS_FILE, " Test completed with some warnings"));
-	return 1;
-    }
-}
-
-
-int main(int argc, char *argv[])
-{
-    pj_caching_pool cp;
-    pj_pool_t *pool;
-    pjmedia_endpt *med_endpt;
-    int id = -1, verbose = 0;
-    int clock_rate = 8000;
-    int frame = -1;
-    int channel = 1;
-    struct pj_getopt_option long_options[] = {
-	{ "id",	     1, 0, 'i' },
-	{ "rate",    1, 0, 'r' },
-	{ "frame",   1, 0, 'f' },
-	{ "channel", 1, 0, 'n' },
-	{ "verbose", 0, 0, 'v' },
-	{ "help",    0, 0, 'h' },
-	{ NULL, 0, 0, 0 }
-    };
-    int c, option_index;
-    
-
-    pj_status_t status;
-
-    /* Init pjlib */
-    status = pj_init();
-    PJ_ASSERT_RETURN(status==PJ_SUCCESS, 1);
-    
-    /* Must create a pool factory before we can allocate any memory. */
-    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
-
-    /* Also create pool for misc purposes */
-    pool = pj_pool_create(&cp.factory, "sndtest", 1000, 1000, NULL);
-
-    /* 
-     * Initialize media endpoint.
-     * This will implicitly initialize PJMEDIA too.
-     */
-    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-    /* Print devices */
-    enum_devices();
-
-    /* Parse options */
-    pj_optind = 0;
-    while((c=pj_getopt_long(argc,argv, "i:r:f:n:vh", 
-			    long_options, &option_index))!=-1) 
-    {
-	switch (c) {
-	case 'i':
-	    id = atoi(pj_optarg);
-	    break;
-	case 'r':
-	    clock_rate = atoi(pj_optarg);
-	    break;
-	case 'f':
-	    frame = atoi(pj_optarg);
-	    break;
-	case 'n':
-	    channel = atoi(pj_optarg);
-	    break;
-	case 'v':
-	    verbose = 1;
-	    break;
-	case 'h':
-	    puts(desc);
-	    return 0;
-	    break;
-	default:
-	    printf("Error: invalid options %s\n", argv[pj_optind-1]);
-	    puts(desc);
-	    return 1;
-	}
-    }
-
-    if (pj_optind != argc) {
-	printf("Error: invalid options\n");
-	puts(desc);
-	return 1;
-    }
-
-    if (!verbose)
-	pj_log_set_level(3);
-
-    if (frame == -1)
-	frame = 10 * clock_rate / 1000;
-
-
-    status = perform_test(pool, id, PJMEDIA_DIR_CAPTURE_PLAYBACK, 
-			  clock_rate, frame, channel, verbose);
-
-    pjmedia_endpt_destroy(med_endpt);
-    pj_pool_release(pool);
-    pj_caching_pool_destroy(&cp);
-    pj_shutdown();
-    
-    return status == PJ_SUCCESS ? 0 : 1;
-}
-
-
Index: /pjproject/branches/projects/aps-direct/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/branches/projects/aps-direct/pjsip/include/pjsua-lib/pjsua.h	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjsip/include/pjsua-lib/pjsua.h	(revision 2468)
@@ -4201,4 +4201,18 @@
     unsigned		ec_tail_len;
 
+    /**
+     * Audio capture buffer length, in milliseconds.
+     *
+     * Default: PJMEDIA_SND_DEFAULT_REC_LATENCY
+     */
+    unsigned		snd_rec_latency;
+
+    /**
+     * Audio playback buffer length, in milliseconds.
+     *
+     * Default: PJMEDIA_SND_DEFAULT_PLAY_LATENCY
+     */
+    unsigned		snd_play_latency;
+
     /** 
      * Jitter buffer initial prefetch delay in msec. The value must be
@@ -4805,7 +4819,11 @@
  *
  */
+#if PJMEDIA_AUDIO_API==PJMEDIA_AUDIO_API_NEW_ONLY
+PJ_DECL(pj_status_t) pjsua_enum_snd_devs(pjmedia_aud_dev_info info[],
+					 unsigned *count);
+#else
 PJ_DECL(pj_status_t) pjsua_enum_snd_devs(pjmedia_snd_dev_info info[],
 					 unsigned *count);
-
+#endif
 
 
@@ -4880,5 +4898,18 @@
 
 /**
- * Configure the echo canceller tail length of the sound port.
+ * Change the echo cancellation settings. The behavior of this function 
+ * depends on whether the sound device is currently active, and if it is,
+ * whether device or software AEC is being used. 
+ *
+ * If the sound device is currently active, and if the device supports AEC,
+ * this function will forward the change request to the device and it will
+ * be up to the device on whether support the request. If software AEC is
+ * being used (the software EC will be used if the device does not support
+ * AEC), this function will change the software EC settings. In all cases,
+ * the setting will be saved for future opening of the sound device.
+ *
+ * If the sound device is not currently active, this will only change the
+ * default AEC settings and the setting will be applied next time the 
+ * sound device is opened.
  *
  * @param tail_ms	The tail length, in miliseconds. Set to zero to
@@ -4911,14 +4942,4 @@
  */
 PJ_DECL(pj_status_t) pjsua_get_ec_tail(unsigned *p_tail_ms);
-
-
-/**
- * Set sound device route.
- *
- * @param route		Sound device route to be set.
- *
- * @return		PJ_SUCCESS on success, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsua_set_snd_route(pjmedia_snd_route route);
 
 
Index: /pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_core.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_core.c	(revision 2468)
@@ -178,4 +178,6 @@
     cfg->ilbc_mode = PJSUA_DEFAULT_ILBC_MODE;
     cfg->ec_tail_len = PJSUA_DEFAULT_EC_TAIL_LEN;
+    cfg->snd_rec_latency = PJMEDIA_SND_DEFAULT_REC_LATENCY;
+    cfg->snd_play_latency = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
     cfg->jb_init = cfg->jb_min_pre = cfg->jb_max_pre = cfg->jb_max = -1;
     cfg->snd_auto_close_time = -1;
Index: /pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2467)
+++ /pjproject/branches/projects/aps-direct/pjsip/src/pjsua-lib/pjsua_media.c	(revision 2468)
@@ -1515,18 +1515,13 @@
  * Open sound device with extended setting.
  */
-static pj_status_t open_snd_dev_ext( int capture_dev,
-				     int playback_dev,
-				     unsigned clock_rate,
-				     unsigned channel_count,
-				     unsigned samples_per_frame,
-				     const pjmedia_snd_setting *setting)
+static pj_status_t open_snd_dev_ext(pjmedia_aud_param *param)
 {
     pjmedia_port *conf_port;
     pj_status_t status;
 
-    PJ_ASSERT_RETURN(setting, PJ_EINVAL);
+    PJ_ASSERT_RETURN(param, PJ_EINVAL);
 
     /* Check if NULL sound device is used */
-    if (NULL_SND_DEV_ID == capture_dev || NULL_SND_DEV_ID == playback_dev) {
+    if (NULL_SND_DEV_ID==param->rec_id || NULL_SND_DEV_ID==param->play_id) {
 	return pjsua_set_null_snd_dev();
     }
@@ -1545,24 +1540,17 @@
 
     PJ_LOG(4,(THIS_FILE, "Opening sound device @%d/%d/%s",
-	      clock_rate, channel_count,
-	      (setting->format.id==PJMEDIA_FORMAT_L16?"raw":"encoded")));
+	      param->clock_rate, param->channel_count,
+	      (param->ext_fmt.id==PJMEDIA_FORMAT_L16?"pcm":"encoded")));
 
     status = pjmedia_snd_port_create2( pjsua_var.snd_pool, 
-				       PJMEDIA_DIR_CAPTURE_PLAYBACK,
-				       capture_dev,
-				       playback_dev, 
-				       clock_rate, 
-				       channel_count,
-				       samples_per_frame,
-				       16, 
-				       setting, 
-				       &pjsua_var.snd_port);
+				       param,  &pjsua_var.snd_port);
 
     /* Update port 0 info when sound dev opened successfully. */
     if (status == PJ_SUCCESS) {
-	conf_port->info.format = setting->format;
-	conf_port->info.clock_rate = clock_rate;
-	conf_port->info.samples_per_frame = samples_per_frame;
-	conf_port->info.channel_count = channel_count;
+	pj_memcpy(&conf_port->info.format, &param->ext_fmt, 
+		  sizeof(conf_port->info.format));
+	conf_port->info.clock_rate = param->clock_rate;
+	conf_port->info.samples_per_frame = param->samples_per_frame;
+	conf_port->info.channel_count = param->channel_count;
 	conf_port->info.bits_per_sample = 16;
     } else {
@@ -1583,21 +1571,21 @@
 
     /* Save the device IDs */
-    pjsua_var.cap_dev = capture_dev;
-    pjsua_var.play_dev = playback_dev;
+    pjsua_var.cap_dev = param->rec_id;
+    pjsua_var.play_dev = param->play_id;
 
     /* Update sound device name. */
-    do {
-	const pjmedia_snd_dev_info *play_info;
-	pjmedia_snd_stream *strm;
-	pjmedia_snd_stream_info si;
+    {
+	pjmedia_aud_dev_info play_info;
+	pjmedia_aud_stream *strm;
+	pjmedia_aud_param si;
         pj_str_t tmp;
 
 	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
-	pjmedia_snd_stream_get_info(strm, &si);
-	play_info = pjmedia_snd_get_dev_info(si.rec_id);
-
-	pjmedia_conf_set_port0_name(pjsua_var.mconf, 
-				    pj_cstr(&tmp, play_info->name));
-    } while(0);
+	pjmedia_aud_stream_get_param(strm, &si);
+	if (pjmedia_aud_dev_get_info(si.play_id, &play_info)==PJ_SUCCESS) {
+	    pjmedia_conf_set_port0_name(pjsua_var.mconf, 
+					pj_cstr(&tmp, play_info.name));
+	}
+    };
 
     return PJ_SUCCESS;
@@ -1612,12 +1600,15 @@
     /* Close sound device */
     if (pjsua_var.snd_port) {
-	pjmedia_snd_dev_info cap_info, play_info;
-	pjmedia_snd_stream *strm;
-	pjmedia_snd_stream_info si;
+	pjmedia_aud_dev_info cap_info, play_info;
+	pjmedia_aud_stream *strm;
+	pjmedia_aud_param param;
 
 	strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
-	pjmedia_snd_stream_get_info(strm, &si);
-	cap_info = *(pjmedia_snd_get_dev_info(si.rec_id));
-	play_info = *(pjmedia_snd_get_dev_info(si.play_id));
+	pjmedia_aud_stream_get_param(strm, &param);
+
+	if (pjmedia_aud_dev_get_info(param.rec_id, &cap_info) != PJ_SUCCESS)
+	    cap_info.name[0] = '\0';
+	if (pjmedia_aud_dev_get_info(param.play_id, &play_info) != PJ_SUCCESS)
+	    play_info.name[0] = '\0';
 
 	PJ_LOG(4,(THIS_FILE, "Closing %s sound playback device and "
@@ -1797,16 +1788,41 @@
 
 	if (need_reopen) {
-	    pjmedia_snd_setting setting;
-
-	    pj_bzero(&setting, sizeof(setting));
-	    setting.format = peer_info.format;
-	    setting.plc = PJ_FALSE;
-	    setting.route = PJMEDIA_SND_ROUTE_DEFAULT;
+	    pjmedia_aud_param param;
+
+	    status = pjmedia_aud_dev_default_param(pjsua_var.cap_dev, &param);
+	    if (status != PJ_SUCCESS) {
+		pjsua_perror(THIS_FILE, "Error retrieving default audio "
+					"device parameters", status);
+		return status;
+	    }
+
+	    param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+	    param.rec_id = pjsua_var.cap_dev;
+	    param.play_id = pjsua_var.play_dev;
+	    param.clock_rate = peer_info.clock_rate;
+	    param.samples_per_frame = peer_info.samples_per_frame;
+	    param.channel_count = peer_info.channel_count;
+	    param.bits_per_sample = peer_info.bits_per_sample;
+	    /* Latency setting */
+	    param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 
+			    PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY);
+	    param.input_latency_ms = pjsua_var.media_cfg.snd_rec_latency;
+	    param.output_latency_ms = pjsua_var.media_cfg.snd_play_latency;
+	    /* EC settings */
+	    if (pjsua_var.media_cfg.ec_tail_len) {
+		param.flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
+		param.ec_enabled = PJ_TRUE;
+		param.ec_tail_ms = pjsua_var.media_cfg.ec_tail_len;
+	    } else {
+		param.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
+	    }
+	    /* Format */
+	    param.flags |= (PJMEDIA_AUD_DEV_CAP_EXT_FORMAT | 
+			    PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE);
+	    param.ext_fmt = peer_info.format;
+	    //param.plc = PJ_FALSE;
+	    param.out_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
 	    
-	    status = open_snd_dev_ext(pjsua_var.cap_dev, pjsua_var.play_dev,
-				      peer_info.clock_rate,
-				      peer_info.channel_count,
-				      peer_info.samples_per_frame,
-				      &setting);
+	    status = open_snd_dev_ext(&param);
 	    if (status != PJ_SUCCESS) {
 		pjsua_perror(THIS_FILE, "Error opening sound device", status);
@@ -2307,4 +2323,27 @@
  * Enum sound devices.
  */
+#if PJMEDIA_AUDIO_API==PJMEDIA_AUDIO_API_NEW_ONLY
+PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_aud_dev_info info[],
+					 unsigned *count)
+{
+    unsigned i, dev_count;
+
+    dev_count = pjmedia_aud_dev_count();
+    
+    if (dev_count > *count) dev_count = *count;
+
+    for (i=0; i<dev_count; ++i) {
+	pj_status_t status;
+
+	status = pjmedia_aud_dev_get_info(i, &info[i]);
+	if (status != PJ_SUCCESS)
+	    return status;
+    }
+
+    *count = dev_count;
+
+    return PJ_SUCCESS;
+}
+#else	/* PJMEDIA_AUDIO_API */
 PJ_DEF(pj_status_t) pjsua_enum_snd_devs( pjmedia_snd_dev_info info[],
 					 unsigned *count)
@@ -2312,13 +2351,22 @@
     unsigned i, dev_count;
 
-    dev_count = pjmedia_snd_get_dev_count();
+    dev_count = pjmedia_aud_dev_count();
     
     if (dev_count > *count) dev_count = *count;
+    pj_bzero(info, dev_count * sizeof(pjmedia_snd_dev_info));
 
     for (i=0; i<dev_count; ++i) {
-	const pjmedia_snd_dev_info *ci;
-
-	ci = pjmedia_snd_get_dev_info(i);
-	pj_memcpy(&info[i], ci, sizeof(*ci));
+	pjmedia_aud_dev_info ai;
+	pj_status_t status;
+
+	status = pjmedia_aud_dev_get_info(i, &ai);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	strncpy(info[i].name, ai.name, sizeof(info[i].name));
+	info[i].name[sizeof(info[i].name)-1] = '\0';
+	info[i].input_count = ai.input_count;
+	info[i].output_count = ai.output_count;
+	info[i].default_samples_per_sec = ai.default_samples_per_sec;
     }
 
@@ -2327,4 +2375,7 @@
     return PJ_SUCCESS;
 }
+#endif
+
+
 /*
  * Select or change sound device. Application may call this function at
@@ -2335,10 +2386,10 @@
 {
     pjmedia_port *conf_port;
-    const pjmedia_snd_dev_info *play_info;
+    pjmedia_aud_dev_info play_info;
+    pjmedia_aud_param param;
     unsigned clock_rates[] = {0, 44100, 48000, 32000, 16000, 8000};
     unsigned selected_clock_rate = 0;
     unsigned i;
-    pjmedia_snd_stream *strm;
-    pjmedia_snd_stream_info si;
+    pjmedia_aud_stream *strm;
     pj_str_t tmp;
     pj_status_t status = -1;
@@ -2353,5 +2404,5 @@
 
     /* Create memory pool for sound device. */
-    pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 4000, 4000);
+    pjsua_var.snd_pool = pjsua_pool_create("pjsua_snd", 1000, 1000);
     PJ_ASSERT_RETURN(pjsua_var.snd_pool, PJ_ENOMEM);
 
@@ -2365,8 +2416,30 @@
     pj_assert(conf_port != NULL);
 
+    /* Create default parameters for the device */
+    status = pjmedia_aud_dev_default_param(capture_dev, &param);
+    if (status != PJ_SUCCESS) {
+	return status;
+    }
+    param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+    param.rec_id = capture_dev;
+    param.play_id = playback_dev;
+    param.channel_count = pjsua_var.media_cfg.channel_count;
+    /* Latency settings */
+    param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY | 
+		    PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY);
+    param.input_latency_ms = pjsua_var.media_cfg.snd_rec_latency;
+    param.output_latency_ms = pjsua_var.media_cfg.snd_play_latency;
+    /* EC settings */
+    if (pjsua_var.media_cfg.ec_tail_len) {
+	param.flags |= (PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
+	param.ec_enabled = PJ_TRUE;
+	param.ec_tail_ms = pjsua_var.media_cfg.ec_tail_len;
+    } else {
+	param.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | PJMEDIA_AUD_DEV_CAP_EC_TAIL);
+    }
+
     /* Attempts to open the sound device with different clock rates */
     for (i=0; i<PJ_ARRAY_SIZE(clock_rates); ++i) {
 	char errmsg[PJ_ERR_MSG_SIZE];
-	unsigned samples_per_frame;
 
 	PJ_LOG(4,(THIS_FILE, 
@@ -2374,15 +2447,12 @@
 		  "@%d Hz", clock_rates[i]));
 
-	samples_per_frame = clock_rates[i] *
-			    pjsua_var.media_cfg.audio_frame_ptime *
-			    pjsua_var.media_cfg.channel_count / 1000;
+	param.clock_rate = clock_rates[i];
+	param.samples_per_frame = clock_rates[i] *
+				  pjsua_var.media_cfg.audio_frame_ptime *
+				  pjsua_var.media_cfg.channel_count / 1000;
 
 	/* Create the sound device. Sound port will start immediately. */
-	status = pjmedia_snd_port_create(pjsua_var.snd_pool, capture_dev,
-					 playback_dev, 
-					 clock_rates[i], 
-					 pjsua_var.media_cfg.channel_count,
-					 samples_per_frame,
-					 16, 0, &pjsua_var.snd_port);
+	status = pjmedia_snd_port_create2(pjsua_var.snd_pool, &param,
+					  &pjsua_var.snd_port);
 
 	if (status == PJ_SUCCESS) {
@@ -2438,9 +2508,4 @@
     }
 
-    /* Set AEC */
-    pjmedia_snd_port_set_ec( pjsua_var.snd_port, pjsua_var.snd_pool, 
-			     pjsua_var.media_cfg.ec_tail_len, 
-			     pjsua_var.media_cfg.ec_options);
-
     /* Connect sound port to the bridge */ 	 
     status = pjmedia_snd_port_connect(pjsua_var.snd_port, 	 
@@ -2460,18 +2525,18 @@
     /* Update sound device name. */
     strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
-    pjmedia_snd_stream_get_info(strm, &si);
-    play_info = pjmedia_snd_get_dev_info(si.rec_id);
-
-    if (si.clock_rate != pjsua_var.media_cfg.clock_rate) {
+    pjmedia_aud_stream_get_param(strm, &param);
+    pjmedia_aud_dev_get_info(param.play_id, &play_info);
+
+    if (param.clock_rate != pjsua_var.media_cfg.clock_rate) {
 	char tmp_buf[128];
 	int tmp_buf_len = sizeof(tmp_buf);
 
 	tmp_buf_len = pj_ansi_snprintf(tmp_buf, sizeof(tmp_buf)-1, "%s (%dKHz)",
-				       play_info->name, si.clock_rate/1000);
+				       play_info.name, param.clock_rate/1000);
 	pj_strset(&tmp, tmp_buf, tmp_buf_len);
         pjmedia_conf_set_port0_name(pjsua_var.mconf, &tmp); 
     } else {
         pjmedia_conf_set_port0_name(pjsua_var.mconf, 
-				    pj_cstr(&tmp, play_info->name));
+				    pj_cstr(&tmp, play_info.name));
     }
 
@@ -2580,27 +2645,4 @@
 }
 
-/* 
- * Header for specific Symbian APS audio routing.
- */
-#include <pjmedia/symbian_sound_aps.h>
-
-/*
- * Set sound device route.
- */
-PJ_DEF(pj_status_t) pjsua_set_snd_route(pjmedia_snd_route route)
-{
-#if PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_SYMB_APS_SOUND
-    pjmedia_snd_stream *strm;
-
-    if (!pjsua_var.snd_port)
-	return PJ_ENOTFOUND;
-
-    strm = pjmedia_snd_port_get_snd_stream(pjsua_var.snd_port);
-    return pjmedia_snd_aps_set_route(strm, route);
-#else
-    PJ_UNUSED_ARG(route);
-    return PJ_ENOTSUP;
-#endif
-}
 
 /*****************************************************************************
