Index: pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_audiodev.dsp
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_audiodev.dsp	(revision 2469)
+++ pjproject/branches/projects/aps-direct/pjmedia/build/pjmedia_audiodev.dsp	(revision 2470)
@@ -130,4 +130,8 @@
 SOURCE="..\include\pjmedia-audiodev\audiotest.h"
 # End Source File
+# Begin Source File
+
+SOURCE="..\include\pjmedia-audiodev\config.h"
+# End Source File
 # End Group
 # End Target
Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev.h	(revision 2469)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev.h	(revision 2470)
@@ -25,4 +25,5 @@
  * @brief Audio device API.
  */
+#include <pjmedia-audiodev/config.h>
 #include <pjmedia/port.h>
 #include <pj/pool.h>
@@ -32,21 +33,7 @@
 
 /**
- * @defgroup PJMED_AUD_DEV Audio device API
- * @ingroup PJMED_AUD_PORT
- * @brief API to work with audio devices and to implement new audio device backends.
- * @{
- *
- * The audio device API contains two parts:
- *  - the base API, for both applications and audio device implementors, and
- *  - the API for audio device implementors, for extending the audio device
- *    framework with new audio device drivers.
- *
- * @}
- */
-
-/**
- * @defgroup PJMED_AUD_DEV_API Base Audio Device API
- * @ingroup PJMED_AUD_DEV
- * @brief The base API, for both applications and audio device implementors
+ * @defgroup s2_audio_device_reference Audio Device API Reference
+ * @ingroup audio_device_api
+ * @brief API Reference
  * @{
  */
@@ -222,5 +209,5 @@
 
 /**
- * Device information structure returned by #pjmedia_aud_get_dev_info.
+ * Device information structure returned by #pjmedia_aud_dev_get_info().
  */
 typedef struct pjmedia_aud_dev_info
@@ -498,4 +485,5 @@
  * @param drv_name	The driver name.
  * @param dev_name	The device name.
+ * @param id		Pointer to store the returned device ID.
  *
  * @return		PJ_SUCCESS if the device can be found.
@@ -530,5 +518,5 @@
  * @param user_data	Arbitrary user data, which will be given back in the
  *			callbacks.
- * @param p_aud_strm	Pointer to receive the audio stream.
+ * @param p_strm	Pointer to receive the audio stream.
  *
  * @return		PJ_SUCCESS on successful operation or the appropriate
@@ -635,7 +623,9 @@
 #define PJMEDIA_EAUD_SYSERR	-1
 
-
-/**
- * @)
+/* Bad or invalid format */
+#define PJMEDIA_EAUD_BADFORMAT	-1
+
+/**
+ * @}
  */
 
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 2469)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiodev_imp.h	(revision 2470)
@@ -24,6 +24,6 @@
 
 /**
- * @defgroup PJMED_AUD_DEV_IMP_API Audio Device Implementors API
- * @ingroup PJMED_AUD_DEV
+ * @defgroup s8_audio_device_implementors_api Audio Device Implementors API
+ * @ingroup audio_device_api
  * @brief API for audio device implementors
  * @{
Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiotest.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiotest.h	(revision 2469)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/audiotest.h	(revision 2470)
@@ -31,6 +31,6 @@
 
 /**
- * @defgroup PJMED_AUD_TEST Audio tests utility.
- * @ingroup PJMED_AUD_PORT
+ * @defgroup s30_audio_test_utility Audio tests utility.
+ * @ingroup audio_device_api
  * @brief Audio test utility.
  * @{
@@ -96,5 +96,5 @@
 
 /**
- * @)
+ * @}
  */
 
Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/config.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/config.h	(revision 2470)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia-audiodev/config.h	(revision 2470)
@@ -0,0 +1,132 @@
+/* $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 
+ */
+#ifndef __PJMEDIA_AUDIODEV_CONFIG_H__
+#define __PJMEDIA_AUDIODEV_CONFIG_H__
+
+/**
+ * @file audiodev.h
+ * @brief Audio device API.
+ */
+#include <pjmedia/port.h>
+#include <pj/pool.h>
+
+
+PJ_BEGIN_DECL
+
+/**
+ * @defgroup audio_device_api Audio Device API
+ * @brief PJMEDIA audio device abstraction API.
+ */
+
+/**
+ * @defgroup s1_audio_device_config Compile time configurations
+ * @ingroup audio_device_api
+ * @brief Compile time configurations
+ * @{
+ */
+
+/**
+ * This setting controls whether PortAudio support should be included.
+ */
+#ifndef PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
+#   define PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO	0
+#endif
+
+
+/**
+ * This setting controls whether WMME support should be included.
+ */
+#ifndef PJMEDIA_AUDIO_DEV_HAS_WMME
+#   define PJMEDIA_AUDIO_DEV_HAS_WMME		1
+#endif
+
+
+/**
+ * @}
+ */
+
+PJ_END_DECL
+
+
+#endif	/* __PJMEDIA_AUDIODEV_CONFIG_H__ */
+
+/*
+ --------------------- DOCUMENTATION FOLLOWS ---------------------------
+ */
+
+/**
+ * @addtogroup audio_device_api Audio Device API
+ * @{
+
+PJMEDIA Audio Device API is a cross-platform audio API appropriate for use with
+VoIP applications and many other types of audio streaming applications. 
+
+The API abstracts many different audio API's on various platforms, such as:
+ - PortAudio back-end for Win32, Windows Mobile, Linux, Unix, dan MacOS X.
+ - native WMME audio for Win32 and Windows Mobile devices
+ - native Symbian audio streaming/multimedia framework (MMF) implementation
+ - native Nokia Audio Proxy Server (APS) implementation
+ - null-audio implementation
+ - and more to be implemented in the future
+
+The Audio Device API/library is an evolution from PJMEDIA @ref PJMED_SND and 
+contains many enhancements:
+
+ - Forward compatibility:
+\n
+   The new API has been designed to be extensible, it will support new API's as 
+   well as new features that may be introduced in the future without breaking 
+   compatibility with applications that use this API as well as compatibility 
+   with existing device implementations. 
+
+ - Device capabilities:
+\n
+   At the heart of the API is device capabilities management, where all possible
+   audio capabilities of audio devices should be able to be handled in a generic
+   manner. With this framework, new capabilities that may be discovered in the 
+   future can be handled in manner without breaking existing applications. 
+
+ - Built-in features:
+\n
+   The device capabilities framework enables applications to use audio features
+   built-in in the device, such as:
+    - echo cancellation, 
+    - built-in codecs, 
+    - audio routing, and 
+    - volume control. 
+
+ - Codec support:
+\n
+   Some audio devices such as Nokia/Symbian Audio Proxy Server (APS) and Nokia 
+   VoIP Audio Services (VAS) support built-in hardware audio codecs (e.g. G.729,
+   iLBC, and AMR), and application can use the sound device in encoded mode to
+   make use of these hardware codecs. 
+
+ - Multiple backends:
+\n
+   The new API supports multiple audio backends (called factories or drivers in 
+   the code) to be active simultaneously, and audio backends may be added or 
+   removed during run-time. 
+ */
+
+/**
+ * @}
+ */
+
Index: pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2469)
+++ pjproject/branches/projects/aps-direct/pjmedia/include/pjmedia/port.h	(revision 2470)
@@ -332,6 +332,5 @@
  */
 PJ_INLINE(pjmedia_frame_ext_subframe*) 
-	  pjmedia_frame_ext_get_subframe(const pjmedia_frame_ext *frm,
-					 unsigned n)
+pjmedia_frame_ext_get_subframe(const pjmedia_frame_ext *frm, unsigned n)
 {
     pjmedia_frame_ext_subframe *sf = NULL;
@@ -354,4 +353,39 @@
 	
 /**
+ * Extract all frame payload to the specified buffer. 
+ *
+ * @param frm		    The frame.
+ * @param dst		    Destination buffer.
+ * @param maxsize	    Maximum size to copy (i.e. the size of the
+ *			    destination buffer).
+ *
+ * @return		    Total size of payload copied.
+ */
+PJ_INLINE(unsigned) 
+pjmedia_frame_ext_copy_payload(const pjmedia_frame_ext *frm,
+			       void *dst, 
+			       unsigned maxlen)
+{
+    unsigned i, copied=0;
+    for (i=0; i<frm->subframe_cnt; ++i) {
+	pjmedia_frame_ext_subframe *sf;
+	unsigned sz;
+
+	sf = pjmedia_frame_ext_get_subframe(frm, i);
+	if (!sf)
+	    continue;
+
+	sz = ((sf->bitlen + 7) >> 3);
+	if (sz + copied > maxlen)
+	    break;
+
+	pj_memcpy(((pj_uint8_t*)dst) + copied, sf->data, sz);
+	copied += sz;
+    }
+    return copied;
+}
+
+
+/**
  * Pop out first n subframes from #pjmedia_frame_ext.
  *
@@ -362,5 +396,5 @@
  */
 PJ_INLINE(pj_status_t) 
-	  pjmedia_frame_ext_pop_subframes(pjmedia_frame_ext *frm, unsigned n)
+pjmedia_frame_ext_pop_subframes(pjmedia_frame_ext *frm, unsigned n)
 {
     pjmedia_frame_ext_subframe *sf;
@@ -387,5 +421,5 @@
     return PJ_SUCCESS;
 }
-	
+
 /**
  * Port interface.
Index: pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiodev.c
===================================================================
--- pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 2469)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 2470)
@@ -21,4 +21,5 @@
 #include <pj/errno.h>
 #include <pj/log.h>
+#include <pj/pool.h>
 #include <pj/string.h>
 
@@ -63,6 +64,12 @@
 
 /* extern functions to create factories */
+#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
 pjmedia_aud_dev_factory* pjmedia_pa_factory(pj_pool_factory *pf);
+#endif
+
+#if PJMEDIA_AUDIO_DEV_HAS_WMME
 pjmedia_aud_dev_factory* pjmedia_wmme_factory(pj_pool_factory *pf);
+#endif
+
 
 #define MAX_DRIVERS	16
@@ -219,6 +226,10 @@
 
     /* Register creation functions */
+#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
     aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_pa_factory;
+#endif
+#if PJMEDIA_AUDIO_DEV_HAS_WMME
     aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;
+#endif
 
     /* Initialize each factory and build the device ID list */
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 2469)
+++ pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/wmme_dev.c	(revision 2470)
@@ -31,4 +31,5 @@
 #include <windows.h>
 #include <mmsystem.h>
+#include <mmreg.h>
 
 #ifdef _MSC_VER
@@ -103,7 +104,11 @@
     void    		*buffer;	    /**< Temp. frame buffer.   */
     unsigned             clock_rate;        /**< Clock rate.           */
+    unsigned		 bytes_per_frame;   /**< Bytes per frame       */
     unsigned             samples_per_frame; /**< Samples per frame.    */
     unsigned             bits_per_sample;   /**< Bits per sample.      */
     unsigned             channel_count;     /**< Channel count.        */
+
+    pjmedia_frame_ext	*xfrm;		    /**< Extended frame buffer */
+    unsigned		 xfrm_size;	    /**< Total ext frm size    */
 
     pj_thread_t         *thread;            /**< Thread handle.        */
@@ -193,5 +198,5 @@
 /* Internal: build device info from WAVEINCAPS/WAVEOUTCAPS */
 static void build_dev_info(UINT deviceId, struct wmme_dev_info *wdi, 
-			   WAVEINCAPS *wic, WAVEOUTCAPS *woc)
+			   const WAVEINCAPS *wic, const WAVEOUTCAPS *woc)
 {
 #define WIC_WOC(wic,woc,field)	(wic? wic->field : woc->field)
@@ -205,5 +210,5 @@
 	wdi->info.name[sizeof(wdi->info.name)-1] = '\0';
     } else {
-	pj_char_t *szPname = WIC_WOC(wic, woc, szPname);
+	const pj_char_t *szPname = WIC_WOC(wic, woc, szPname);
 	PJ_DECL_ANSI_TEMP_BUF(wTmp, sizeof(wdi->info.name));
 	
@@ -246,4 +251,14 @@
 	}
     }
+
+    /* Extended formats */
+    wdi->info.caps |= PJMEDIA_AUD_DEV_CAP_EXT_FORMAT;
+    wdi->info.ext_fmt_cnt = 2;
+    wdi->info.ext_fmt[0].id = PJMEDIA_FORMAT_PCMU;
+    wdi->info.ext_fmt[0].bitrate = 64000;
+    wdi->info.ext_fmt[0].vad = 0;
+    wdi->info.ext_fmt[1].id = PJMEDIA_FORMAT_PCMA;
+    wdi->info.ext_fmt[1].bitrate = 64000;
+    wdi->info.ext_fmt[1].vad = 0;
 }
 
@@ -280,5 +295,5 @@
 				  sizeof(struct wmme_dev_info));
 
-    if (devCount) {
+    if (inputDeviceCount && outputDeviceCount) {
 	/* Attempt to add WAVE_MAPPER as input and output device */
 	WAVEINCAPS wic;
@@ -435,15 +450,47 @@
 
 /* Internal: init WAVEFORMATEX */
-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;
+static pj_status_t init_waveformatex(LPWAVEFORMATEX wfx, 
+				     const pjmedia_aud_param *prm)
+{
+
+    pj_bzero(wfx, sizeof(PCMWAVEFORMAT)); 
+    if (prm->ext_fmt.id == PJMEDIA_FORMAT_L16) {
+	wfx->wFormatTag = WAVE_FORMAT_PCM; 
+	wfx->nChannels = (pj_uint16_t)prm->channel_count;
+	wfx->nSamplesPerSec = prm->clock_rate;
+	wfx->nBlockAlign = (pj_uint16_t)(prm->channel_count * 
+					 BYTES_PER_SAMPLE);
+	wfx->nAvgBytesPerSec = prm->clock_rate * prm->channel_count * 
+			       BYTES_PER_SAMPLE;
+	wfx->wBitsPerSample = BITS_PER_SAMPLE;
+
+	return PJ_SUCCESS;
+
+    } else if ((prm->flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) &&
+	       (prm->ext_fmt.id == PJMEDIA_FORMAT_PCMA ||
+	        prm->ext_fmt.id == PJMEDIA_FORMAT_PCMU))
+    {
+	unsigned ptime;
+
+	ptime = prm->samples_per_frame * 1000 / 
+		(prm->clock_rate * prm->channel_count);
+	wfx->wFormatTag = (pj_uint16_t)
+			  ((prm->ext_fmt.id==PJMEDIA_FORMAT_PCMA) ?
+			    WAVE_FORMAT_ALAW : WAVE_FORMAT_MULAW);  
+	wfx->nChannels = (pj_uint16_t)prm->channel_count;
+	wfx->nSamplesPerSec = prm->clock_rate;
+	wfx->nAvgBytesPerSec = prm->clock_rate * prm->channel_count;
+	wfx->nBlockAlign = (pj_uint16_t)(wfx->nAvgBytesPerSec * ptime /
+					 1000);
+	wfx->wBitsPerSample = 8;
+	wfx->cbSize = 0;
+
+	return PJ_SUCCESS;
+
+    } else {
+
+	return PJMEDIA_EAUD_BADFORMAT;
+
+    }
 }
 
@@ -452,17 +499,15 @@
 static pj_status_t init_player_stream(  struct wmme_factory *wf,
 				        pj_pool_t *pool,
+					struct wmme_stream *parent,
 				        struct wmme_channel *wmme_strm,
-					unsigned dev_id,
-					unsigned clock_rate,
-					unsigned channel_count,
-					unsigned samples_per_frame,
+					const pjmedia_aud_param *prm,
 					unsigned buffer_count)
 {
     MMRESULT mr;
-    WAVEFORMATEX pcmwf; 
-    unsigned bytes_per_frame;
-    unsigned i;
-
-    PJ_ASSERT_RETURN(dev_id < wf->dev_count, PJ_EINVAL);
+    WAVEFORMATEX wfx; 
+    unsigned i, ptime;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(prm->play_id < (int)wf->dev_count, PJ_EINVAL);
 
     /*
@@ -476,12 +521,20 @@
      * 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;
+    status = init_waveformatex(&wfx, prm);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    ptime = prm->samples_per_frame * 1000 / 
+	    (prm->clock_rate * prm->channel_count);
+    ptime = prm->samples_per_frame * 1000 / 
+	    (prm->clock_rate * prm->channel_count);
+    parent->bytes_per_frame = wfx.nAvgBytesPerSec / ptime;
 
     /*
      * Open wave device.
      */
-    mr = waveOutOpen(&wmme_strm->hWave.Out, wf->dev_info[dev_id].deviceId, 
-		     &pcmwf, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
+    mr = waveOutOpen(&wmme_strm->hWave.Out, 
+		     wf->dev_info[prm->play_id].deviceId,
+		     &wfx, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
     if (mr != MMSYSERR_NOERROR) {
 	return CONVERT_MM_ERROR(mr);
@@ -500,6 +553,7 @@
 			 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;
+	wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, 
+						      parent->bytes_per_frame);
+	wmme_strm->WaveHdr[i].dwBufferLength = parent->bytes_per_frame;
 	mr = waveOutPrepareHeader(wmme_strm->hWave.Out, 
 				  &(wmme_strm->WaveHdr[i]),
@@ -523,7 +577,7 @@
 	       " WaveAPI Sound player \"%s\" initialized (clock_rate=%d, "
 	       "channel_count=%d, samples_per_frame=%d (%dms))",
-	       wf->dev_info[dev_id].info.name,
-	       clock_rate, channel_count, samples_per_frame,
-	       samples_per_frame * 1000 / clock_rate));
+	       wf->dev_info[prm->play_id].info.name,
+	       prm->clock_rate, prm->channel_count, prm->samples_per_frame,
+	       prm->samples_per_frame * 1000 / prm->clock_rate));
 
     return PJ_SUCCESS;
@@ -534,17 +588,14 @@
 static pj_status_t init_capture_stream( struct wmme_factory *wf,
 				        pj_pool_t *pool,
+					struct wmme_stream *parent,
 					struct wmme_channel *wmme_strm,
-					unsigned dev_id,
-					unsigned clock_rate,
-					unsigned channel_count,
-					unsigned samples_per_frame,
+					const pjmedia_aud_param *prm,
 					unsigned buffer_count)
 {
     MMRESULT mr;
-    WAVEFORMATEX pcmwf; 
-    unsigned bytes_per_frame;
-    unsigned i;
-
-    PJ_ASSERT_RETURN(dev_id < wf->dev_count, PJ_EINVAL);
+    WAVEFORMATEX wfx; 
+    unsigned i, ptime;
+
+    PJ_ASSERT_RETURN(prm->rec_id < (int)wf->dev_count, PJ_EINVAL);
 
     /*
@@ -559,12 +610,15 @@
      * 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;
+    init_waveformatex(&wfx, prm);
+    ptime = prm->samples_per_frame * 1000 / 
+	    (prm->clock_rate * prm->channel_count);
+    parent->bytes_per_frame = wfx.nAvgBytesPerSec / ptime;
 
     /*
      * Open wave device.
      */
-    mr = waveInOpen(&wmme_strm->hWave.In, wf->dev_info[dev_id].deviceId, 
-		    &pcmwf, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
+    mr = waveInOpen(&wmme_strm->hWave.In, 
+		    wf->dev_info[prm->rec_id].deviceId, 
+		    &wfx, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT);
     if (mr != MMSYSERR_NOERROR) {
 	return CONVERT_MM_ERROR(mr);
@@ -577,6 +631,7 @@
 			 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;
+	wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, 
+						      parent->bytes_per_frame);
+	wmme_strm->WaveHdr[i].dwBufferLength = parent->bytes_per_frame;
 	mr = waveInPrepareHeader(wmme_strm->hWave.In, 
 				 &(wmme_strm->WaveHdr[i]),
@@ -600,7 +655,7 @@
 	" WaveAPI Sound recorder \"%s\" initialized (clock_rate=%d, "
 	"channel_count=%d, samples_per_frame=%d (%dms))",
-	wf->dev_info[dev_id].info.name,
-	clock_rate, channel_count, samples_per_frame,
-	samples_per_frame * 1000 / clock_rate));
+	wf->dev_info[prm->rec_id].info.name,
+	prm->clock_rate, prm->channel_count, prm->samples_per_frame,
+	prm->samples_per_frame * 1000 / prm->clock_rate));
 
     return PJ_SUCCESS;
@@ -614,7 +669,5 @@
     HANDLE events[3];
     unsigned eventCount;
-    unsigned bytes_per_frame;
     pj_status_t status = PJ_SUCCESS;
-
 
     eventCount = 0;
@@ -638,7 +691,4 @@
 #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 
@@ -677,5 +727,5 @@
 	{
 	    struct wmme_channel *wmme_strm = &strm->play_strm;
-	    MMRESULT mr = MMSYSERR_NOERROR;
+
 	    status = PJ_SUCCESS;
 
@@ -688,33 +738,74 @@
 	    {
 		void *buffer = wmme_strm->WaveHdr[wmme_strm->dwBufIdx].lpData;
-		pjmedia_frame frame;
+		pjmedia_frame pcm_frame, *frame;
+		pj_bool_t has_frame = PJ_FALSE;
 
 		//PJ_LOG(5,(THIS_FILE, "Finished writing buffer %d", 
 		//	  wmme_strm->dwBufIdx));
 
-		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
-		frame.size = bytes_per_frame;
-		frame.buf = buffer;
-		frame.timestamp.u64 = wmme_strm->timestamp.u64;
-		frame.bit_info = 0;
+		if (strm->xfrm == NULL) {
+		    /* PCM mode */
+		    frame = &pcm_frame;
+
+		    frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
+		    frame->size = strm->bytes_per_frame;
+		    frame->buf = buffer;
+		    frame->timestamp.u64 = wmme_strm->timestamp.u64;
+		    frame->bit_info = 0;
+		} else {
+		    /* Codec mode */
+		    frame = &strm->xfrm->base;
+
+		    strm->xfrm->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
+		    strm->xfrm->base.size = strm->bytes_per_frame;
+		    strm->xfrm->base.buf = NULL;
+		    strm->xfrm->base.timestamp.u64 = wmme_strm->timestamp.u64;
+		    strm->xfrm->base.bit_info = 0;
+		}
 
 		/* Get frame from application. */
-		status = (*strm->play_cb)(strm->user_data, &frame);
+		status = (*strm->play_cb)(strm->user_data, frame);
 
 		if (status != PJ_SUCCESS)
 		    break;
 
-		if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) {
-		    pj_bzero(buffer, bytes_per_frame);
+		if (strm->xfrm == NULL) {
+		    /* PCM mode */
+		    if (frame->type == PJMEDIA_FRAME_TYPE_NONE) {
+			pj_bzero(buffer, strm->bytes_per_frame);
+			has_frame = PJ_TRUE;
+		    } else if (frame->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
+			pj_assert(!"Frame type not supported");
+		    } else if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO) {
+			has_frame = PJ_TRUE;
+		    } else {
+			pj_assert(!"Frame type not supported");
+		    }
+		} else {
+		    /* Codec mode */
+		    if (frame->type == PJMEDIA_FRAME_TYPE_NONE) {
+			/* Not supported */
+		    } else if (frame->type == PJMEDIA_FRAME_TYPE_EXTENDED) {
+			unsigned sz;
+			sz = pjmedia_frame_ext_copy_payload(strm->xfrm,
+							    buffer,
+							    strm->bytes_per_frame);
+			pj_assert(sz == strm->bytes_per_frame);
+		    } else {
+			pj_assert(!"Frame type not supported");
+		    }
 		}
 
 		/* Write to the device. */
-		mr = waveOutWrite(wmme_strm->hWave.Out, 
-				  &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]), 
-				  sizeof(WAVEHDR));
-		if (mr != MMSYSERR_NOERROR)
-		{
-		    status = CONVERT_MM_ERROR(mr);
-		    break;
+		if (has_frame) {
+		    MMRESULT mr = MMSYSERR_NOERROR;
+
+		    mr = waveOutWrite(wmme_strm->hWave.Out, 
+				      &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]),
+				      sizeof(WAVEHDR));
+		    if (mr != MMSYSERR_NOERROR) {
+			status = CONVERT_MM_ERROR(mr);
+			break;
+		    }
 		}
 
@@ -766,5 +857,5 @@
 		unsigned cap_len = 
 			wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwBytesRecorded;
-		pjmedia_frame frame;
+		pjmedia_frame pcm_frame, *frame;
 
 		/*
@@ -772,10 +863,38 @@
 			  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);
+	    
+		if (strm->xfrm == NULL) {
+		    /* PCM mode */
+		    if (cap_len < strm->bytes_per_frame)
+			pj_bzero(buffer + cap_len, 
+				 strm->bytes_per_frame - cap_len);
+
+		    /* Copy the audio data out of the wave buffer. */
+		    pj_memcpy(strm->buffer, buffer, strm->bytes_per_frame);
+
+		    /* Prepare frame */
+		    frame = &pcm_frame;
+		    frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
+		    frame->buf = strm->buffer;
+		    frame->size = strm->bytes_per_frame;
+		    frame->timestamp.u64 = wmme_strm->timestamp.u64;
+		    frame->bit_info = 0;
+
+		} else {
+		    /* Codec mode */
+		    frame = &strm->xfrm->base;
+
+		    frame->type = PJMEDIA_FRAME_TYPE_EXTENDED;
+		    frame->buf = NULL;
+		    frame->size = strm->bytes_per_frame;
+		    frame->timestamp.u64 = wmme_strm->timestamp.u64;
+		    frame->bit_info = 0;
+
+		    strm->xfrm->samples_cnt = 0;
+		    strm->xfrm->subframe_cnt = 0;
+		    pjmedia_frame_ext_append_subframe(strm->xfrm, buffer,
+						      strm->bytes_per_frame *8,
+						      strm->samples_per_frame);
+		}
 
 		/* Re-add the buffer to the device. */
@@ -788,13 +907,7 @@
 		}
 
-		/* Prepare frame */
-		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
-		frame.buf = strm->buffer;
-		frame.size = bytes_per_frame;
-		frame.timestamp.u64 = wmme_strm->timestamp.u64;
-		frame.bit_info = 0;
 
 		/* Call callback */
-		status = (*strm->rec_cb)(strm->user_data, &frame);
+		status = (*strm->rec_cb)(strm->user_data, frame);
 		if (status != PJ_SUCCESS)
 		    break;
@@ -866,9 +979,7 @@
 
 	status = init_player_stream(wf, strm->pool,
+				    strm,
 				    &strm->play_strm,
-				    param->play_id,
-				    param->clock_rate,
-				    param->channel_count,
-				    param->samples_per_frame,
+				    param,
 				    buf_count);
 
@@ -892,9 +1003,7 @@
 
 	status = init_capture_stream(wf, strm->pool,
+				     strm,
 				     &strm->rec_strm,
-				     param->rec_id,
-				     param->clock_rate,
-				     param->channel_count,
-				     param->samples_per_frame,
+				     param,
 				     buf_count);
 
@@ -903,4 +1012,15 @@
 	    return status;
 	}
+    }
+
+    /* If format is extended, must create buffer for the extended frame. */
+    if (param->ext_fmt.id != PJMEDIA_FORMAT_L16) {
+	unsigned ptime = param->samples_per_frame * 1000 /
+			 (param->clock_rate * param->channel_count);
+	strm->xfrm_size = sizeof(pjmedia_frame_ext) + 
+			  32 * sizeof(pjmedia_frame_ext_subframe) +
+			  (8000 * ptime / 1000) + 4;
+	strm->xfrm = (pjmedia_frame_ext*)
+		     pj_pool_alloc(pool, strm->xfrm_size);
     }
 
