Index: pjproject/trunk/pjmedia/build/Makefile
===================================================================
--- pjproject/trunk/pjmedia/build/Makefile	(revision 4431)
+++ pjproject/trunk/pjmedia/build/Makefile	(revision 4432)
@@ -82,5 +82,5 @@
 export PJMEDIA_AUDIODEV_OBJS +=  audiodev.o audiotest.o errno.o \
 				 coreaudio_dev.o legacy_dev.o null_dev.o pa_dev.o wmme_dev.o \
-				 alsa_dev.o bb10_dev.o
+				 alsa_dev.o bb10_dev.o bdimad_dev.o
 export PJMEDIA_AUDIODEV_CFLAGS += $(_CFLAGS)
 
Index: pjproject/trunk/pjmedia/build/pjmedia_audiodev.vcproj
===================================================================
--- pjproject/trunk/pjmedia/build/pjmedia_audiodev.vcproj	(revision 4431)
+++ pjproject/trunk/pjmedia/build/pjmedia_audiodev.vcproj	(revision 4432)
@@ -3566,4 +3566,8 @@
 			</File>
 			<File
+				RelativePath="..\src\pjmedia-audiodev\bdimad_dev.c"
+				>
+			</File>
+			<File
 				RelativePath="..\src\pjmedia-audiodev\errno.c"
 				>
Index: pjproject/trunk/pjmedia/include/pjmedia-audiodev/config.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia-audiodev/config.h	(revision 4431)
+++ pjproject/trunk/pjmedia/include/pjmedia-audiodev/config.h	(revision 4432)
@@ -95,4 +95,12 @@
 #ifndef PJMEDIA_AUDIO_DEV_HAS_WMME
 #   define PJMEDIA_AUDIO_DEV_HAS_WMME		1
+#endif
+
+ 
+/**
+ * This setting controls whether BDIMAD support should be included.
+ */
+#ifndef PJMEDIA_AUDIO_DEV_HAS_BDIMAD
+#	define PJMEDIA_AUDIO_DEV_HAS_BDIMAD	0
 #endif
 
Index: pjproject/trunk/pjmedia/include/pjmedia-audiodev/errno.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia-audiodev/errno.h	(revision 4431)
+++ pjproject/trunk/pjmedia/include/pjmedia-audiodev/errno.h	(revision 4432)
@@ -104,4 +104,17 @@
 #define PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(err) \
 	    ((int)PJMEDIA_AUDIODEV_COREAUDIO_ERRNO_START-err)
+
+/**
+ * Mapping from BDIMAD error codes to pjmedia error space.
+ */
+#define PJMEDIA_AUDIODEV_BDIMAD_ERROR_START	\
+	    (PJMEDIA_AUDIODEV_ERRNO_START + 40000)
+#define PJMEDIA_AUDIODEV_BDIMAD_ERROR_END	\
+	    (PJMEDIA_AUDIODEV_BDIMAD_ERROR_START + 2000 - 1)
+/**
+ * Convert BDIMAD error codes to PJLIB error space.
+ */
+#define PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(err) \
+	    ((int)PJMEDIA_AUDIODEV_BDIMAD_ERROR_START+err)
 
 /************************************************************
Index: pjproject/trunk/pjmedia/src/pjmedia-audiodev/audiodev.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 4431)
+++ pjproject/trunk/pjmedia/src/pjmedia-audiodev/audiodev.c	(revision 4432)
@@ -87,4 +87,8 @@
 #endif
 
+#if PJMEDIA_AUDIO_DEV_HAS_BDIMAD
+pjmedia_aud_dev_factory* pjmedia_bdimad_factory(pj_pool_factory *pf);
+#endif
+
 #if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS
 pjmedia_aud_dev_factory* pjmedia_symb_vas_factory(pj_pool_factory *pf);
@@ -406,4 +410,7 @@
 #if PJMEDIA_AUDIO_DEV_HAS_WMME
     aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_wmme_factory;
+#endif
+#if PJMEDIA_AUDIO_DEV_HAS_BDIMAD
+    aud_subsys.drv[aud_subsys.drv_cnt++].create = &pjmedia_bdimad_factory;
 #endif
 #if PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS
Index: pjproject/trunk/pjmedia/src/pjmedia-audiodev/bdimad_dev.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-audiodev/bdimad_dev.c	(revision 4432)
+++ pjproject/trunk/pjmedia/src/pjmedia-audiodev/bdimad_dev.c	(revision 4432)
@@ -0,0 +1,1185 @@
+/*******************************************************
+ 
+ bdimad_dev.c
+
+ Author: bdSound Development Team (techsupport@bdsound.com)
+ 
+ Date: 30/10/2012
+ Version 1.0.206
+
+ Copyright (c) 2012 bdSound s.r.l. (www.bdsound.com)
+ All Rights Reserved.
+ 
+ *******************************************************/
+
+#include <pjmedia-audiodev/audiodev_imp.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/string.h>
+#include <pj/unicode.h>
+#include <pjmedia/errno.h>
+
+#if defined(PJMEDIA_AUDIO_DEV_HAS_BDIMAD) && PJMEDIA_AUDIO_DEV_HAS_BDIMAD != 0
+
+#include <math.h>
+#include <wchar.h>
+
+/**************************
+*           bdIMAD
+***************************/
+#include <bdimad.h>
+
+/* Maximum supported audio devices */
+#define BD_IMAD_MAX_DEV_COUNT               100                                
+/* Maximum supported device name */
+#define BD_IMAD_MAX_DEV_LENGTH_NAME         256                                
+/* Only mono mode */
+#define BD_IMAD_MAX_CHANNELS                1                                  
+/* Frequency default value (admitted 8000 Hz, 16000 Hz, 32000 Hz and 48000Hz) */
+#define BD_IMAD_DEFAULT_FREQ                48000                              
+/* Default milliseconds per buffer */
+#define BD_IMAD_MSECOND_PER_BUFFER          16                                 
+/* Only for supported systems */
+#define BD_IMAD_STARTING_INPUT_VOLUME       50                                 
+/* Only for supported systems */
+#define BD_IMAD_STARTING_OUTPUT_VOLUME      100                                
+/* Diagnostic Enable/Disable */
+#define BD_IMAD_DIAGNOSTIC                  BD_IMAD_DIAGNOSTIC_DISABLE         
+
+/* Diagnostic folder path */ 
+wchar_t * bdImadPjDiagnosticFolderPath   = L"";                                
+
+#define THIS_FILE            "bdimad_dev.c"
+
+/* BD device info */
+struct bddev_info
+{
+    pjmedia_aud_dev_info    info;
+    unsigned            deviceId;
+};
+
+/* BD factory */
+struct bd_factory
+{
+    pjmedia_aud_dev_factory  base;
+    pj_pool_t                *base_pool;
+    pj_pool_t                *pool;
+    pj_pool_factory          *pf;
+    unsigned                 dev_count;
+    struct bddev_info        *dev_info;
+};
+
+/* Sound stream. */
+struct bd_stream
+{
+    /** Base stream.                    */
+    pjmedia_aud_stream   base;                
+    /** Settings.                       */
+    pjmedia_aud_param    param;               
+    /** Memory pool.                    */
+    pj_pool_t           *pool;                
+					
+    /** Capture callback.               */
+    pjmedia_aud_rec_cb   rec_cb;              
+    /** Playback callback.              */
+    pjmedia_aud_play_cb  play_cb;             
+    /** Application data.               */
+    void                *user_data;           
+					
+    /** Frame format                    */
+    pjmedia_format_id    fmt_id;              
+    /** Silence pattern                 */
+    pj_uint8_t           silence_char;    
+    /** Bytes per frame                 */
+    unsigned             bytes_per_frame;
+    /** Samples per frame               */
+    unsigned		 samples_per_frame;
+    /** Channel count	                 */
+    int			 channel_count;
+					
+    /** Extended frame buffer           */
+    pjmedia_frame_ext   *xfrm;                
+    /** Total ext frm size              */
+    unsigned             xfrm_size;           
+       
+    /** Check running variable          */
+    int                  go;                
+
+    /** Timestamp iterator for capture  */
+    pj_timestamp         timestampCapture;    
+    /** Timestamp iterator for playback */
+    pj_timestamp         timestampPlayback;   
+
+    /** bdIMAD current session instance */
+    bdIMADpj             bdIMADpjInstance;    
+    /** bdIMAD current session settings */
+    bdIMADpj_Setting_t  *bdIMADpjSettingsPtr; 
+    /** bdIMAD current session warnings */
+    bdIMADpj_Warnings_t *bdIMADpjWarningPtr;
+
+    pj_bool_t		 quit_flag;
+
+    pj_bool_t		 rec_thread_exited;
+    pj_bool_t		 rec_thread_initialized;
+    pj_thread_desc	 rec_thread_desc;
+    pj_thread_t		*rec_thread;
+
+    pj_bool_t		 play_thread_exited;
+    pj_bool_t		 play_thread_initialized;
+    pj_thread_desc	 play_thread_desc;
+    pj_thread_t		*play_thread;
+
+    /* Sometime the record callback does not return framesize as configured
+     * (e.g: in OSS), while this module must guarantee returning framesize
+     * as configured in the creation settings. In this case, we need a buffer 
+     * for the recorded samples.
+     */
+    pj_int16_t		*rec_buf;
+    unsigned		 rec_buf_count;
+
+    /* Sometime the player callback does not request framesize as configured
+     * (e.g: in Linux OSS) while sound device will always get samples from 
+     * the other component as many as configured samples_per_frame. 
+     */
+    pj_int16_t		*play_buf;
+    unsigned		 play_buf_count;
+};
+
+/* Prototypes */
+
+// pjmedia_aud_dev_factory_op
+static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
+static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
+static unsigned    factory_get_dev_count(pjmedia_aud_dev_factory *f);
+static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, 
+					unsigned index,    
+					pjmedia_aud_dev_info *info);
+static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f, 
+					 unsigned index, 
+					 pjmedia_aud_param *param);
+static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f, 
+					 const pjmedia_aud_param *param, 
+					 pjmedia_aud_rec_cb rec_cb, 
+					 pjmedia_aud_play_cb play_cb, 
+					 void *user_data, 
+					 pjmedia_aud_stream **p_aud_strm);
+static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f);
+
+// pjmedia_aud_stream_op
+static pj_status_t stream_get_param(pjmedia_aud_stream *strm, 
+				    pjmedia_aud_param *param);
+static pj_status_t stream_get_cap(pjmedia_aud_stream *strm, 
+				  pjmedia_aud_dev_cap cap, 
+				  void *value);
+static pj_status_t stream_set_cap(pjmedia_aud_stream *strm, 
+				  pjmedia_aud_dev_cap cap, 
+				  const void *value);
+static pj_status_t stream_start(pjmedia_aud_stream *strm);
+static pj_status_t stream_stop(pjmedia_aud_stream *strm);
+static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
+
+/* End Prototypes */
+
+/* Operations */
+static pjmedia_aud_dev_factory_op factory_op =
+{
+    &factory_init,
+    &factory_destroy,
+    &factory_get_dev_count,
+    &factory_get_dev_info,
+    &factory_default_param,
+    &factory_create_stream,
+    &factory_refresh
+};
+
+static pjmedia_aud_stream_op stream_op = 
+{
+    &stream_get_param,
+    &stream_get_cap,
+    &stream_set_cap,
+    &stream_start,
+    &stream_stop,
+    &stream_destroy
+};
+
+/* End Operations */
+
+/* Utility functions */
+
+char* BD_IMAD_PJ_WCHARtoCHAR(wchar_t *orig)
+{
+    size_t origsize = wcslen(orig)+1;
+    const size_t newsize = origsize*sizeof(wchar_t);
+    char *nstring = (char*)calloc(newsize, sizeof(char));
+    wcstombs(nstring, orig, newsize);
+    return nstring;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void manage_code(const unsigned char * pCode, unsigned char *pMsg1, 
+		 unsigned char * pMsg2);
+#ifdef __cplusplus
+}
+#endif
+
+/* End Utility functions */
+
+/****************************************************************************
+* Factory operations
+*/
+
+/* Init BDIMAD audio driver */
+pjmedia_aud_dev_factory* pjmedia_bdimad_factory(pj_pool_factory *pf)
+{
+    struct bd_factory *f;
+    pj_pool_t *pool;
+
+    pool = pj_pool_create(pf, "BDIMAD_DRIVER", 1000, 1000, NULL);
+    f = PJ_POOL_ZALLOC_T(pool, struct bd_factory);
+    f->pf = pf;
+    f->base_pool = pool;
+    f->base.op = &factory_op;
+    f->pool = NULL;
+    f->dev_count = 0;
+    f->dev_info = NULL;
+
+    return &f->base;
+}
+
+/* API: init factory */
+static pj_status_t factory_init(pjmedia_aud_dev_factory *f)
+{
+    pj_status_t ret = factory_refresh(f);
+    if (ret != PJ_SUCCESS) return ret;
+
+    PJ_LOG(4, (THIS_FILE, "BDIMAD initialized"));
+
+    return PJ_SUCCESS;
+}
+
+/* API: refresh the device list */
+static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f)
+{    
+    struct bd_factory *wf = (struct bd_factory*)f;
+    unsigned int i = 0;
+    wchar_t *deviceNamep=NULL;
+    wchar_t captureDevName[BD_IMAD_MAX_DEV_COUNT][BD_IMAD_MAX_DEV_LENGTH_NAME];
+    unsigned int captureDeviceCount = 0;
+    wchar_t playbackDevName[BD_IMAD_MAX_DEV_COUNT][BD_IMAD_MAX_DEV_LENGTH_NAME];
+    unsigned int playbackDeviceCount = 0;
+
+
+    if(wf->pool != NULL) {
+        pj_pool_release(wf->pool);
+        wf->pool = NULL;
+    }
+
+    // Enumerate capture sound devices
+    while(bdIMADpj_getDeviceName(BD_IMAD_CAPTURE_DEVICES, &deviceNamep) != 
+	  BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY)
+    {
+        wcscpy(captureDevName[captureDeviceCount], deviceNamep);
+        captureDeviceCount++;
+    }
+
+    // Enumerate playback sound devices
+    while(bdIMADpj_getDeviceName(BD_IMAD_PLAYBACK_DEVICES, &deviceNamep) != 
+	  BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY)
+    {
+        wcscpy(playbackDevName[playbackDeviceCount], deviceNamep);
+        playbackDeviceCount++;
+    }
+    
+    // Set devices info
+    wf->dev_count = captureDeviceCount + playbackDeviceCount;
+    wf->pool = pj_pool_create(wf->pf, "BD_IMAD_DEVICES", 1000, 1000, NULL);
+    wf->dev_info = (struct bddev_info*)pj_pool_calloc(wf->pool, wf->dev_count, 
+						     sizeof(struct bddev_info));
+    
+    // Capture device properties
+    for(i=0;i<captureDeviceCount;i++) {
+        wf->dev_info[i].deviceId = i;
+        wf->dev_info[i].info.caps = PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING | 
+				    PJMEDIA_AUD_DEV_CAP_EC;
+        wf->dev_info[i].info.default_samples_per_sec = BD_IMAD_DEFAULT_FREQ;
+        strcpy(wf->dev_info[i].info.driver, "BD_IMAD");
+        wf->dev_info[i].info.ext_fmt_cnt = 0;
+        wf->dev_info[i].info.input_count = BD_IMAD_MAX_CHANNELS;
+        wf->dev_info[i].info.output_count = 0;
+        strcpy(wf->dev_info[i].info.name, 
+	       BD_IMAD_PJ_WCHARtoCHAR(captureDevName[i]));
+        wf->dev_info[i].info.routes = 0;
+    }
+
+    // Playback device properties
+    for(i=0;i<playbackDeviceCount;i++) {
+        wf->dev_info[captureDeviceCount+i].deviceId = captureDeviceCount+i;
+        wf->dev_info[captureDeviceCount+i].info.caps = 
+				PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
+        wf->dev_info[captureDeviceCount+i].info.default_samples_per_sec = 
+				BD_IMAD_DEFAULT_FREQ;
+        strcpy(wf->dev_info[captureDeviceCount+i].info.driver, "BD_IMAD");
+        wf->dev_info[captureDeviceCount+i].info.ext_fmt_cnt = 0;
+        wf->dev_info[captureDeviceCount+i].info.input_count = 0;
+        wf->dev_info[captureDeviceCount+i].info.output_count = 
+				BD_IMAD_MAX_CHANNELS;
+        strcpy(wf->dev_info[captureDeviceCount+i].info.name, 
+	       BD_IMAD_PJ_WCHARtoCHAR(playbackDevName[i]));
+        wf->dev_info[captureDeviceCount+i].info.routes = 0;
+    }
+
+    PJ_LOG(4, (THIS_FILE, "BDIMAD found %d devices:", wf->dev_count));
+    for(i=0; i<wf->dev_count; i++) {
+        PJ_LOG(4,   
+	       (THIS_FILE, " dev_id %d: %s  (in=%d, out=%d)", 
+               i,
+               wf->dev_info[i].info.name,
+               wf->dev_info[i].info.input_count,
+               wf->dev_info[i].info.output_count));
+    }    
+    return PJ_SUCCESS;
+}
+
+/* API: destroy factory */
+static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f)
+{
+    struct bd_factory *wf = (struct bd_factory*)f;
+    pj_pool_t *pool = wf->base_pool;
+
+    pj_pool_release(wf->pool);
+    wf->base_pool = NULL;
+    pj_pool_release(pool);
+
+    return PJ_SUCCESS;
+}
+
+/* API: get number of devices */
+static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f)
+{
+    struct bd_factory *wf = (struct bd_factory*)f;
+    return wf->dev_count;
+}
+
+/* API: get device info */
+static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, 
+                                        unsigned index,
+                                        pjmedia_aud_dev_info *info)
+{
+    struct bd_factory *wf = (struct bd_factory*)f;
+
+    PJ_ASSERT_RETURN(index < wf->dev_count, PJMEDIA_EAUD_INVDEV);
+
+    pj_memcpy(info, &wf->dev_info[index].info, sizeof(*info));
+
+    return PJ_SUCCESS;
+}
+
+/* API: create default device parameter */
+static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
+                                         unsigned index,
+                                         pjmedia_aud_param *param)
+{
+    struct bd_factory *wf = (struct bd_factory*)f;
+    struct bddev_info *di = &wf->dev_info[index];
+
+    pj_bzero(param, sizeof(*param));
+    if (di->info.input_count && di->info.output_count) {
+        param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+        param->rec_id = index;
+        param->play_id = index;
+        param->channel_count = di->info.output_count;
+    } else if(di->info.input_count) {
+        param->dir = PJMEDIA_DIR_CAPTURE;
+        param->rec_id = index;
+        param->play_id = PJMEDIA_AUD_INVALID_DEV;
+        param->channel_count = di->info.input_count;
+    } else if(di->info.output_count) {
+        param->dir = PJMEDIA_DIR_PLAYBACK;
+        param->play_id = index;
+        param->rec_id = PJMEDIA_AUD_INVALID_DEV;
+        param->channel_count = di->info.output_count;
+    } else {
+        return PJMEDIA_EAUD_INVDEV;
+    }
+
+    param->bits_per_sample = BD_IMAD_BITS_X_SAMPLE;
+    param->clock_rate = di->info.default_samples_per_sec;
+    param->flags = di->info.caps;
+    param->samples_per_frame = di->info.default_samples_per_sec * 
+			       param->channel_count * 
+			       BD_IMAD_MSECOND_PER_BUFFER / 
+			       1000;    
+
+    if(di->info.caps & PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING) {
+        param->input_vol = BD_IMAD_STARTING_INPUT_VOLUME;
+    }
+
+    if(di->info.caps & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
+        param->output_vol = BD_IMAD_STARTING_OUTPUT_VOLUME;
+    }
+
+    if(di->info.caps & PJMEDIA_AUD_DEV_CAP_EC) {
+        param->ec_enabled = PJ_TRUE;
+    }
+
+    return PJ_SUCCESS;
+}
+
+/* callbacks to set data */
+void bdimad_CaptureCallback(void *buffer, int samples, void *user_data)
+{
+    pj_status_t status = PJ_SUCCESS;
+    pjmedia_frame frame;
+    unsigned nsamples;    
+
+    struct bd_stream *strm = (struct bd_stream*)user_data;    
+
+    if(!strm->go) 
+	goto on_break;
+
+    /* Known cases of callback's thread:
+     * - The thread may be changed in the middle of a session, e.g: in MacOS 
+     *   it happens when plugging/unplugging headphone.
+     * - The same thread may be reused in consecutive sessions. The first
+     *   session will leave TLS set, but release the TLS data address,
+     *   so the second session must re-register the callback's thread.
+     */
+    if (strm->rec_thread_initialized == 0 || !pj_thread_is_registered()) 
+    {
+	pj_bzero(strm->rec_thread_desc, sizeof(pj_thread_desc));
+	status = pj_thread_register("bd_CaptureCallback", 
+				    strm->rec_thread_desc, 
+				    &strm->rec_thread);
+	if (status != PJ_SUCCESS)
+	    goto on_break;
+
+	strm->rec_thread_initialized = 1;
+	PJ_LOG(5,(THIS_FILE, "Recorder thread started"));
+    }
+    
+    /* Calculate number of samples we've got */
+    nsamples = samples * strm->channel_count + strm->rec_buf_count;
+
+    /*
+    RECORD
+    */
+    if (strm->fmt_id == PJMEDIA_FORMAT_L16) {
+	if (nsamples >= strm->samples_per_frame) {
+	    /* If buffer is not empty, combine the buffer with the just incoming
+	     * samples, then call put_frame.
+	     */
+	    if (strm->rec_buf_count) {
+		unsigned chunk_count = 0;		
+
+		chunk_count = strm->samples_per_frame - strm->rec_buf_count;
+		pjmedia_copy_samples(strm->rec_buf + strm->rec_buf_count,
+				     (pj_int16_t*)buffer, chunk_count);
+
+		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+		frame.buf = (void*) strm->rec_buf;
+		frame.size = strm->bytes_per_frame;
+		frame.timestamp.u64 = strm->timestampCapture.u64;
+		frame.bit_info = 0;
+
+		status = (*strm->rec_cb)(strm->user_data, &frame);
+
+		buffer = (pj_int16_t*) buffer + chunk_count;
+		nsamples -= strm->samples_per_frame;
+		strm->rec_buf_count = 0;
+		strm->timestampCapture.u64 += strm->samples_per_frame /
+					      strm->channel_count;
+	    }
+
+	    /* Give all frames we have */
+	    while (nsamples >= strm->samples_per_frame && status == 0) {		
+		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+		frame.buf = (void*) buffer;
+		frame.size = strm->bytes_per_frame;
+		frame.timestamp.u64 = strm->timestampCapture.u64;
+		frame.bit_info = 0;
+
+		status = (*strm->rec_cb)(strm->user_data, &frame);
+
+		buffer = (pj_int16_t*) buffer + strm->samples_per_frame;
+		nsamples -= strm->samples_per_frame;
+		strm->timestampCapture.u64 += strm->samples_per_frame /
+					      strm->channel_count;
+	    }
+
+	    /* Store the remaining samples into the buffer */
+	    if (nsamples && status == 0) {
+		strm->rec_buf_count = nsamples;
+		pjmedia_copy_samples(strm->rec_buf, (pj_int16_t*)buffer, 
+				     nsamples);
+	    }
+
+	} else {
+	    /* Not enough samples, let's just store them in the buffer */
+	    pjmedia_copy_samples(strm->rec_buf + strm->rec_buf_count,
+				 (pj_int16_t*)buffer, 
+				 samples * strm->channel_count);
+	    strm->rec_buf_count += samples * strm->channel_count;	
+	}
+    }  else {
+        pj_assert(!"Frame type not supported");
+    }
+    
+    strm->timestampCapture.u64 += strm->param.samples_per_frame / 
+				  strm->param.channel_count;
+
+    if (status==0)
+	return;
+
+on_break:
+    strm->rec_thread_exited = 1;    
+}
+
+/* callbacks to get data */
+int bdimad_PlaybackCallback(void *buffer, int samples, void *user_data)
+{
+    pj_status_t status = PJ_SUCCESS;
+    pjmedia_frame frame;
+    struct bd_stream *strm = (struct bd_stream*)user_data;
+    unsigned nsamples_req = samples * strm->channel_count;
+
+    if(!strm->go) 
+	goto on_break;
+
+    /* Known cases of callback's thread:
+     * - The thread may be changed in the middle of a session, e.g: in MacOS 
+     *   it happens when plugging/unplugging headphone.
+     * - The same thread may be reused in consecutive sessions. The first
+     *   session will leave TLS set, but release the TLS data address,
+     *   so the second session must re-register the callback's thread.
+     */
+    if (strm->play_thread_initialized == 0 || !pj_thread_is_registered()) 
+    {
+	pj_bzero(strm->play_thread_desc, sizeof(pj_thread_desc));
+	status = pj_thread_register("bd_PlaybackCallback", 
+				    strm->play_thread_desc,
+				    &strm->play_thread);
+	if (status != PJ_SUCCESS)
+	    goto on_break;
+
+	strm->play_thread_initialized = 1;
+	PJ_LOG(5,(THIS_FILE, "Player thread started"));
+    }
+
+    /*
+    PLAY
+    */
+    if(strm->fmt_id == PJMEDIA_FORMAT_L16) {
+	/* Check if any buffered samples */
+	if (strm->play_buf_count) {
+	    /* samples buffered >= requested by sound device */
+	    if (strm->play_buf_count >= nsamples_req) {
+		pjmedia_copy_samples((pj_int16_t*)buffer, strm->play_buf, 
+				     nsamples_req);
+		strm->play_buf_count -= nsamples_req;
+		pjmedia_move_samples(strm->play_buf, 
+				     strm->play_buf + nsamples_req,
+				     strm->play_buf_count);		
+
+		return nsamples_req;
+	    }
+
+	    /* samples buffered < requested by sound device */
+	    pjmedia_copy_samples((pj_int16_t*)buffer, strm->play_buf, 
+				 strm->play_buf_count);
+	    nsamples_req -= strm->play_buf_count;
+	    buffer = (pj_int16_t*)buffer + strm->play_buf_count;
+	    strm->play_buf_count = 0;
+	}
+
+	/* Fill output buffer as requested */
+	while (nsamples_req && status == 0) {
+	    if (nsamples_req >= strm->samples_per_frame) {		
+		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+		frame.buf = buffer;
+		frame.size = strm->bytes_per_frame;
+		frame.timestamp.u64 = strm->timestampPlayback.u64;
+		frame.bit_info = 0;
+
+		status = (*strm->play_cb)(strm->user_data, &frame);
+		if (status != PJ_SUCCESS)
+		    return 0;
+
+		if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
+		    pj_bzero(frame.buf, frame.size);
+
+		nsamples_req -= strm->samples_per_frame;
+		buffer = (pj_int16_t*)buffer + strm->samples_per_frame;
+	    } else {		
+		frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+		frame.buf = strm->play_buf;
+		frame.size = strm->bytes_per_frame;
+		frame.timestamp.u64 = strm->timestampPlayback.u64;
+		frame.bit_info = 0;
+
+		status = (*strm->play_cb)(strm->user_data, &frame);
+		if (status != PJ_SUCCESS)
+		    return 0;
+
+		if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
+		    pj_bzero(frame.buf, frame.size);
+
+		pjmedia_copy_samples((pj_int16_t*)buffer, strm->play_buf, 
+				     nsamples_req);
+		strm->play_buf_count = strm->samples_per_frame - 
+				       nsamples_req;
+		pjmedia_move_samples(strm->play_buf, 
+				     strm->play_buf+nsamples_req,
+				     strm->play_buf_count);
+		nsamples_req = 0;
+	    }
+
+	    strm->timestampPlayback.u64 += strm->samples_per_frame /
+					   strm->channel_count;
+	}
+    } else {
+        pj_assert(!"Frame type not supported");
+    }
+
+    if(status != PJ_SUCCESS) {
+        return 0;
+    }
+
+    strm->timestampPlayback.u64 += strm->param.samples_per_frame / 
+				   strm->param.channel_count;
+
+    if (status == 0)
+	return samples;
+
+on_break:
+    strm->play_thread_exited = 1;
+    return 0;
+}
+
+/* Internal: Get format name */
+static const char *get_fmt_name(pj_uint32_t id)
+{
+    static char name[8];
+
+    if (id == PJMEDIA_FORMAT_L16)
+        return "PCM";
+    pj_memcpy(name, &id, 4);
+    name[4] = '\0';
+    return name;
+}
+
+/* Internal: create BD device. */
+static pj_status_t init_streams(struct bd_factory *wf,
+                                struct bd_stream *strm,
+                                const pjmedia_aud_param *prm)
+{
+    unsigned ptime;
+    enum bdIMADpj_Status errorInitAEC;
+    wchar_t *deviceNamep=NULL;
+    wchar_t captureDevName[BD_IMAD_MAX_DEV_COUNT][BD_IMAD_MAX_DEV_LENGTH_NAME];
+    int captureDeviceCount = 0;
+    wchar_t playbackDevName[BD_IMAD_MAX_DEV_COUNT][BD_IMAD_MAX_DEV_LENGTH_NAME];
+    int playbackDeviceCount = 0;
+
+    PJ_ASSERT_RETURN(prm->play_id < (int)wf->dev_count, PJ_EINVAL);
+    PJ_ASSERT_RETURN(prm->rec_id < (int)wf->dev_count, PJ_EINVAL);
+
+    ptime = prm->samples_per_frame * 
+	    1000 / 
+	    (prm->clock_rate * prm->channel_count);
+    strm->bytes_per_frame = (prm->clock_rate * 
+			    ((prm->channel_count * prm->bits_per_sample) / 8)) * 
+			     ptime / 
+			     1000;
+    strm->timestampCapture.u64 = 0;
+    strm->timestampPlayback.u64 = 0;
+
+    //BD_IMAD_PJ
+    bdIMADpj_CreateStructures(&strm->bdIMADpjSettingsPtr, 
+			      &strm->bdIMADpjWarningPtr);
+    
+    strm->bdIMADpjSettingsPtr->FrameSize_ms = ptime;
+    strm->bdIMADpjSettingsPtr->DiagnosticEnable = BD_IMAD_DIAGNOSTIC;
+    strm->bdIMADpjSettingsPtr->DiagnosticFolderPath = 
+					    bdImadPjDiagnosticFolderPath;
+    strm->bdIMADpjSettingsPtr->validate = (void *)manage_code;
+
+    if(prm->clock_rate != 8000 && prm->clock_rate != 16000 
+	   && prm->clock_rate != 32000 && prm->clock_rate != 48000) {
+        PJ_LOG(4, (THIS_FILE, 
+		   "BDIMAD support 8000 Hz, 16000 Hz, 32000 Hz and 48000 Hz "
+		   "frequency."));
+    }
+    strm->bdIMADpjSettingsPtr->SamplingFrequency = prm->clock_rate;
+
+    if(prm->channel_count > BD_IMAD_MAX_CHANNELS) {
+        PJ_LOG(4, (THIS_FILE, 
+		   "BDIMAD doesn't support a number of channels upper than %d.", 
+		   BD_IMAD_MAX_CHANNELS));
+    }
+    
+    // Enumerate capture sound devices
+    while(bdIMADpj_getDeviceName(BD_IMAD_CAPTURE_DEVICES, &deviceNamep) != 
+	  BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY)
+    {
+        wcscpy(captureDevName[captureDeviceCount], deviceNamep);
+        captureDeviceCount++;
+    }
+    strm->bdIMADpjSettingsPtr->CaptureDevice = captureDevName[(int)prm->rec_id];
+
+    // Enumerate playback sound devices
+    while(bdIMADpj_getDeviceName(BD_IMAD_PLAYBACK_DEVICES, &deviceNamep) != 
+	  BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY)
+    {
+        wcscpy(playbackDevName[playbackDeviceCount], deviceNamep);
+        playbackDeviceCount++;
+    }
+    strm->bdIMADpjSettingsPtr->PlayDevice = 
+		    playbackDevName[(int)(prm->play_id-captureDeviceCount)];
+
+    strm->bdIMADpjSettingsPtr->cb_emptyCaptureBuffer = &bdimad_CaptureCallback;
+    strm->bdIMADpjSettingsPtr->cb_emptyCaptureBuffer_user_data = (void*)strm;
+    strm->bdIMADpjSettingsPtr->cb_fillPlayBackBuffer = &bdimad_PlaybackCallback;
+    strm->bdIMADpjSettingsPtr->cb_fillPlayBackBuffer_user_data = (void*)strm;
+
+    if(strm->bdIMADpjInstance != NULL) 
+        bdIMADpj_FreeAEC(&strm->bdIMADpjInstance);
+    strm->bdIMADpjInstance = NULL;
+
+    errorInitAEC = bdIMADpj_InitAEC(&strm->bdIMADpjInstance, 
+				    &strm->bdIMADpjSettingsPtr, 
+				    &strm->bdIMADpjWarningPtr);
+
+    {
+	int auxInt = (prm->ec_enabled == PJ_TRUE ? 1 : 0);
+        bdIMADpj_setParameter(strm->bdIMADpjInstance, 
+			      BD_PARAM_IMAD_PJ_AEC_ENABLE, 
+			      &auxInt);
+        auxInt = 1;
+        //Mic control On by default
+        bdIMADpj_setParameter(strm->bdIMADpjInstance, 
+			      BD_PARAM_IMAD_PJ_MIC_CONTROL_ENABLE, 
+			      &auxInt);
+    }
+
+    if(errorInitAEC != BD_PJ_OK && 
+       errorInitAEC != BD_PJ_WARN_BDIMAD_WARNING_ASSERTED) 
+    {
+        return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(errorInitAEC);
+    }
+    
+    return PJ_SUCCESS;
+}
+
+/**************************************** 
+            API: create stream 
+*****************************************/
+static pj_status_t stream_stopBDIMAD(pjmedia_aud_stream *s)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+    pj_status_t status = PJ_SUCCESS;
+    int i, err = 0;
+
+    PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
+
+    strm->go = 0;    
+    
+    for (i=0; !strm->rec_thread_exited && i<100; ++i)
+	pj_thread_sleep(10);
+    for (i=0; !strm->play_thread_exited && i<100; ++i)
+	pj_thread_sleep(10);
+
+    pj_thread_sleep(1);
+
+    PJ_LOG(5,(THIS_FILE, "Stopping stream.."));
+
+    strm->play_thread_initialized = 0;
+    strm->rec_thread_initialized = 0;
+
+    PJ_LOG(5,(THIS_FILE, "Done, status=%d", err));
+
+    return status;
+}
+
+static pj_status_t stream_stop(pjmedia_aud_stream *s)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+
+    PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
+
+    if(strm->bdIMADpjInstance != NULL) {
+        return stream_stopBDIMAD(s);
+    } else {
+        return PJMEDIA_EAUD_ERR;
+    }
+}
+
+static pj_status_t stream_destroyBDIMAD(pjmedia_aud_stream *s)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+    int i = 0;
+
+    PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
+
+    stream_stopBDIMAD(s);
+
+    // DeInit BDIMAD
+    bdIMADpj_FreeAEC(&strm->bdIMADpjInstance); 
+	PJ_LOG(4, (THIS_FILE, "Free AEC"));
+
+    bdIMADpj_FreeStructures(&strm->bdIMADpjSettingsPtr, 
+			    &strm->bdIMADpjWarningPtr);
+    PJ_LOG(4, (THIS_FILE, "Free AEC Structure"));
+
+    strm->bdIMADpjInstance = NULL;
+    strm->bdIMADpjSettingsPtr = NULL;
+    strm->bdIMADpjWarningPtr = NULL;    
+
+    strm->quit_flag = 1;
+    for (i=0; !strm->rec_thread_exited && i<100; ++i) {
+	pj_thread_sleep(1);
+    }
+    for (i=0; !strm->play_thread_exited && i<100; ++i) {
+	pj_thread_sleep(1);
+    }
+
+    PJ_LOG(5,(THIS_FILE, "Destroying stream.."));
+
+    pj_pool_release(strm->pool);
+    return PJ_SUCCESS;
+}
+
+/* API: Destroy stream. */
+static pj_status_t stream_destroy(pjmedia_aud_stream *s)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+
+    PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
+
+    if(strm->bdIMADpjInstance != NULL) {
+        return stream_destroyBDIMAD(s);
+    } else {
+        return PJMEDIA_EAUD_ERR;
+    }
+}
+
+/* API: set capability */
+static pj_status_t stream_set_capBDIMAD(pjmedia_aud_stream *s,
+					pjmedia_aud_dev_cap cap,
+					const void *pval)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+    bdIMADpj_Status res = BD_PJ_OK;
+    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
+
+    if(cap == PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
+        /* Output volume setting */
+        float vol = (float)*(unsigned*)pval;
+
+        if(vol > 100.0f) vol = 100.0f;
+        if(vol < 0.0f) vol = 0.0f;
+
+        vol = vol / 100.0f;
+        res = bdIMADpj_setParameter(strm->bdIMADpjInstance, 
+				    BD_PARAM_IMAD_PJ_SPK_VOLUME, &vol);
+
+
+        if(res == BD_PJ_OK) {
+            strm->param.output_vol = *(unsigned*)pval;
+            return PJ_SUCCESS;
+        } else {
+            return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
+        }
+    }
+
+    if(cap == PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING) {
+        /* Input volume setting */
+        float vol = (float)*(unsigned*)pval;
+
+        if(vol > 100.0f) vol = 100.0f;
+        if(vol < 0.0f) vol = 0.0f;
+
+        vol = vol / 100.0f;
+        res = bdIMADpj_setParameter(strm->bdIMADpjInstance, 
+				    BD_PARAM_IMAD_PJ_MIC_VOLUME, &vol);
+        if(res == BD_PJ_OK) {
+            strm->param.input_vol = *(unsigned*)pval;
+            return PJ_SUCCESS;
+        } else {
+            return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
+        }
+    }
+
+    if(cap == PJMEDIA_AUD_DEV_CAP_EC) {
+        int aecOnOff = (*(pj_bool_t*)pval == PJ_TRUE ? 1 : 0);
+
+        /* AEC setting */
+        res = bdIMADpj_setParameter(strm->bdIMADpjInstance, 
+				    BD_PARAM_IMAD_PJ_AEC_ENABLE, 
+				    &aecOnOff);
+        if(res == BD_PJ_OK) {
+            strm->param.ec_enabled = (aecOnOff == 1 ? PJ_TRUE : PJ_FALSE);
+            return PJ_SUCCESS;
+        } else {
+            return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
+        }
+    }
+
+    return PJMEDIA_EAUD_INVCAP;
+}
+
+static pj_status_t factory_create_streamBDIMAD(pjmedia_aud_dev_factory *f,
+                                    const pjmedia_aud_param *param,
+                                    pjmedia_aud_rec_cb rec_cb,
+                                    pjmedia_aud_play_cb play_cb,
+                                    void *user_data,
+                                    pjmedia_aud_stream **p_aud_strm)
+{
+    struct bd_factory *wf = (struct bd_factory*)f;
+    pj_pool_t *pool;
+    struct bd_stream *strm;
+    pj_uint8_t silence_char;
+    pj_status_t status;
+
+    switch (param->ext_fmt.id) {
+    case PJMEDIA_FORMAT_L16:
+	silence_char = '\0';
+	break;
+    default:
+	return PJMEDIA_EAUD_BADFORMAT;
+    }
+
+    /* Create and Initialize stream descriptor */
+    pool = pj_pool_create(wf->pf, "BDIMAD_STREAM", 1000, 1000, NULL);
+    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
+
+    strm = PJ_POOL_ZALLOC_T(pool, struct bd_stream);
+    pj_memcpy(&strm->param, param, sizeof(*param));
+    strm->pool = pool;
+    strm->rec_cb = rec_cb;
+    strm->play_cb = play_cb;
+    strm->user_data = user_data;
+    strm->fmt_id = (pjmedia_format_id)param->ext_fmt.id;
+    strm->silence_char = silence_char;
+    strm->channel_count = param->channel_count;
+    strm->samples_per_frame = param->samples_per_frame;
+
+    if (param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK) {
+        status = init_streams(wf, strm, param);
+
+        if (status != PJ_SUCCESS) {
+            stream_destroyBDIMAD(&strm->base);
+            return status;
+        }
+    } else {
+        stream_destroyBDIMAD(&strm->base);
+        return PJMEDIA_EAUD_ERR;
+    }
+
+    strm->rec_buf = (pj_int16_t*)pj_pool_alloc(pool, 
+		    strm->bytes_per_frame);
+    if (!strm->rec_buf) {
+        pj_pool_release(pool);
+        return PJ_ENOMEM;
+    }
+    strm->rec_buf_count = 0;
+
+    strm->play_buf = (pj_int16_t*)pj_pool_alloc(pool, 
+		     strm->bytes_per_frame);
+    if (!strm->play_buf) {
+        pj_pool_release(pool);
+        return PJ_ENOMEM;
+    }
+    strm->play_buf_count = 0;
+
+    /* Apply the remaining settings */
+    if(param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
+        stream_set_capBDIMAD(&strm->base, 
+			     PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, 
+			     &param->output_vol);
+    }
+    if(param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING) {
+        stream_set_capBDIMAD(&strm->base, 
+			     PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, 
+			     &param->input_vol);
+    }
+    if(param->flags & PJMEDIA_AUD_DEV_CAP_EC) {
+        stream_set_capBDIMAD(&strm->base, 
+			     PJMEDIA_AUD_DEV_CAP_EC, 
+			     &param->ec_enabled);
+    }
+
+    strm->base.op = &stream_op;
+    *p_aud_strm = &strm->base;
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
+					 const pjmedia_aud_param *param,
+					 pjmedia_aud_rec_cb rec_cb,
+					 pjmedia_aud_play_cb play_cb,
+					 void *user_data,
+					 pjmedia_aud_stream **p_aud_strm)
+{
+    return factory_create_streamBDIMAD(f, param, rec_cb, 
+				       play_cb, user_data, p_aud_strm);
+}
+// ----------------------------------------------------------------------
+// ----------------------------------------------------------------------
+// ----------------------------------------------------------------------
+
+/* API: Get stream info. */
+static pj_status_t stream_get_param(pjmedia_aud_stream *s,
+                                    pjmedia_aud_param *pi)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+
+    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
+
+    pj_memcpy(pi, &strm->param, sizeof(*pi));
+
+    // Get the output volume setting
+    if(stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, 
+		      &pi->output_vol) == PJ_SUCCESS)
+    {
+        pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
+    }
+
+    // Get the input volume setting
+    if(stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, 
+		      &pi->input_vol) == PJ_SUCCESS)
+    {
+        pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING;
+    }
+
+    // Get the AEC setting
+    if(stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_EC, &pi->ec_enabled) == PJ_SUCCESS)
+    {
+        pi->flags |= PJMEDIA_AUD_DEV_CAP_EC;
+    }
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t stream_get_capBDIMAD(pjmedia_aud_stream *s,
+                                        pjmedia_aud_dev_cap cap,
+                                        void *pval)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+    bdIMADpj_Status res = BD_PJ_OK;
+
+    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
+
+    if(cap == PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING)
+    {
+        /* Input volume setting */
+        float vol;
+        res = bdIMADpj_getParameter(strm->bdIMADpjInstance, 
+				    BD_PARAM_IMAD_PJ_MIC_VOLUME, &vol);
+        if(res == BD_PJ_OK) {
+	    vol = vol * 100;
+	    if(vol > 100.0f) vol = 100.0f;
+	    if(vol < 0.0f) vol = 0.0f;
+	    *(unsigned int *)pval = (unsigned int)vol;
+	    return PJ_SUCCESS;
+        } else{
+            return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
+        }
+    } else if(cap == PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
+        /* Output volume setting */
+        float vol;
+        res = bdIMADpj_getParameter(strm->bdIMADpjInstance, 
+				    BD_PARAM_IMAD_PJ_SPK_VOLUME, &vol);
+        if(res == BD_PJ_OK) {
+			vol = vol * 100;
+            if(vol > 100.0f) vol = 100.0f;
+            if(vol < 0.0f) vol = 0.0f;
+            *(unsigned int *)pval = (unsigned int)vol;
+            return PJ_SUCCESS;
+        } else {
+            return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
+        }
+    }
+    else if(cap == PJMEDIA_AUD_DEV_CAP_EC) {
+        int aecIsOn;
+        res = bdIMADpj_getParameter(strm->bdIMADpjInstance, 
+				    BD_PARAM_IMAD_PJ_AEC_ENABLE, &aecIsOn);
+        if(res == BD_PJ_OK) {
+            *(pj_bool_t*)pval = (aecIsOn == 1 ? PJ_TRUE : PJ_FALSE);
+            return PJ_SUCCESS;
+        } else {
+            return PJMEDIA_AUDIODEV_ERRNO_FROM_BDIMAD(res);
+        }
+    } else {
+        return PJMEDIA_EAUD_INVCAP;
+    }
+}
+
+static pj_status_t stream_startBDIMAD(pjmedia_aud_stream *s)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+
+    PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
+
+    strm->go = 1;
+
+    return PJ_SUCCESS;
+}
+
+/* API: get capability */
+static pj_status_t stream_get_cap(pjmedia_aud_stream *s,
+                                  pjmedia_aud_dev_cap cap,
+                                  void *pval)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+
+    PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
+
+    if(strm->bdIMADpjInstance != NULL) {
+        return stream_get_capBDIMAD(s, cap, pval);
+    } else {
+        return PJMEDIA_EAUD_ERR;
+    }
+}
+
+/* API: set capability */
+static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
+                                  pjmedia_aud_dev_cap cap,
+                                  const void *pval)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+
+    PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
+
+    if(strm->bdIMADpjInstance != NULL) {
+        return stream_set_capBDIMAD(s, cap, pval);
+    } else {
+        return PJMEDIA_EAUD_ERR;
+    }
+}
+
+/* API: Start stream. */
+static pj_status_t stream_start(pjmedia_aud_stream *s)
+{
+    struct bd_stream *strm = (struct bd_stream*)s;
+
+    PJ_ASSERT_RETURN(strm != NULL, PJ_EINVAL);
+
+    if(strm->bdIMADpjInstance != NULL) {
+        return stream_startBDIMAD(s);
+    } else {
+        return PJMEDIA_EAUD_ERR;
+    }
+}
+
+#if defined (_MSC_VER)
+#pragma comment ( lib, "bdClientValidation.lib" )
+#pragma comment ( lib, "bdIMADpj.lib" )
+#endif
+
+
+#endif    /* PJMEDIA_AUDIO_DEV_HAS_BDIMAD */
+
Index: pjproject/trunk/pjmedia/src/pjmedia-audiodev/errno.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia-audiodev/errno.c	(revision 4431)
+++ pjproject/trunk/pjmedia/src/pjmedia-audiodev/errno.c	(revision 4432)
@@ -156,4 +156,18 @@
 #endif
 
+/* See if the error comes from BDIMAD */
+#if PJMEDIA_AUDIO_DEV_HAS_BDIMAD
+	
+	if (statcode >= PJMEDIA_AUDIODEV_BDIMAD_ERROR_START &&
+	    statcode <  PJMEDIA_AUDIODEV_BDIMAD_ERROR_END)
+	{
+	    pj_status_t native_err;
+	    native_err = statcode - PJMEDIA_AUDIODEV_BDIMAD_ERROR_START;
+
+	    pj_ansi_snprintf(buf, bufsize, "BDIMAD native error %d", native_err);
+	    return pj_str(buf);
+	} else
+#endif
+
     /* Audiodev error */
     if (statcode >= PJMEDIA_AUDIODEV_ERRNO_START && 
Index: pjproject/trunk/third_party/bdsound/include/bdimad.h
===================================================================
--- pjproject/trunk/third_party/bdsound/include/bdimad.h	(revision 4432)
+++ pjproject/trunk/third_party/bdsound/include/bdimad.h	(revision 4432)
@@ -0,0 +1,547 @@
+ /**
+ * @file bdIMADpj.h
+ * @brief bdSound IMproved Audio Device for PJSIP.
+ */
+ 
+/**
+ * @defgroup bd_IMAD bdIMADpj bdSound IMproved Audio Device for PJSIP.
+ * @ingroup audio_device_api
+ * 
+ * <b>bdSound IMproved Audio Device</b> is a multiplatform audio interface
+ * created to integrate in <b>PJSIP</b> library with no effort.
+ * \n Porting <b>bdIMADpj</b> across the main operating systems is
+ * straightforward, without the need of change a single line of code.
+ *
+ *    - <b>Features</b>
+ *       - Echo cancellation (Full Duplex)
+ *       - Noise reduction
+ *       - Automatic Gain Control
+ *       - Audio Enhancement
+ *
+ *    - <b>Supported operating systems</b>
+ *       - Windows
+ *       - Android
+ *       - MacOS X
+ *       - iOS
+ *       - Linux / Alsa
+ *
+ *    - <b>Supported platforms</b>
+ *       - x86
+ *       - x64
+ *       - ARM Cortex-A8/A9/A15 with NEON
+ * 
+ * Visit <a href="http:/www.bdsound.com" target="new">bdSound</a> for updated
+ * features, supported operating systems and platforms.
+ * 
+ * <b>Using PJSIP with bdIMAD audio device</b>
+ * 
+ *    - <b>Integration</b>
+ *    \n Using <b>bdIMAD</b> within <b>PJSIP</b> is simple:
+ *       -# Request for bdIMADpj library to
+ *       <a href="http:/www.bdsound.com" target="new">bdSound</a>:
+ *        bdSound will provide instruction to integrate the library depending on
+ *        the platform / O.S. / toolchain;
+ *       -# Add the <code>bdimad_dev.c</code> file to
+ *       <code>pjmedia/src/pjmedia-audiodev</code> folder;
+ *       -# Enable the bdIMAD audio device defining the periferal in the
+ *       <code>pj/config_site.h</code> and disabling all other devices:
+ *       <pre>
+ *       #define PJMEDIA_AUDIO_DEV_HAS_BDIMAD 1
+ *       </pre>
+ *
+ *    - <b>Usage</b>
+ *    \n There are only a couple of things the customer have to pay attention on
+ *    §when using bdIMAD library.
+ *
+ *       - <b>Initialization</b>
+ *       \n Since the bdIMAD library provide itself the echo cancellation
+ *       and the latency management, is necessary to disable these features
+ *       in the PJSIP librariy applications.
+ *       \n For example in PJSUA sample application there is the need
+ *       to provide the following commands:
+ *       <pre>
+ *       --ec-tail=0
+ *       --no-vad
+ *       --capture-lat=0
+ *       --playback-lat=0
+ *       </pre>
+ * 
+ *       - <b>Supported set capability</b>
+ *          - <code>PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING</code>
+ *          \n Setting speaker volume.
+ *          - <code>PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING</code>
+ *          \n Setting michrophone volume.
+ *          - <code>PJMEDIA_AUD_DEV_CAP_EC</code>
+ *          \n Enable/disable echo cancellation.
+ *
+ * For additional information visit
+ * <a href="http:/www.bdsound.com" target="new">www.bdsound.com</a>
+ * or write to info@bdsound.com
+ *
+ * @author bdSound
+ * @version   1.0.1
+ * @copyright 2012 bdSound srl. All rights reserved.
+ *
+ */
+
+/**        
+ * @defgroup groupFunction Functions      
+ * @ingroup bd_IMAD  
+ * 
+ * Functions defined in bdIMAD.
+ */
+
+/**        
+ * @defgroup groupCallback Callbacks      
+ * @ingroup bd_IMAD    
+ * 
+ * Callbacks defined in bdIMAD.
+ */
+ 
+/**        
+ * @defgroup groupStructEnum Structs and Enums       
+ * @ingroup bd_IMAD   
+ * 
+ * Struct and Enum defined in bdIMAD.
+ */
+
+#ifndef BD_IMAD_PJ_H__
+#define BD_IMAD_PJ_H__
+  
+/**
+ * @brief Macro for Windows DLL Support.
+ */
+ 
+#ifdef _BDIMADPJ_EXPORTDLL
+	#ifdef WIN32
+		#define BDIMADPJ_API __declspec(dllexport)
+	#else
+		#define BDIMADPJ_API __attribute__((visibility("default")))	
+	#endif
+#else
+	#define BDIMADPJ_API
+#endif
+
+#define BD_IMAD_CAPTURE_DEVICES      1
+#define BD_IMAD_PLAYBACK_DEVICES     0
+#define BD_IMAD_DIAGNOSTIC_ENABLE    1
+#define BD_IMAD_DIAGNOSTIC_DISABLE   0
+
+#define BD_IMAD_BITS_X_SAMPLE	     16                  /**< Bits per sample */
+
+typedef void* bdIMADpj;
+
+/**
+ * @addtogroup groupCallback
+ * @{
+ */
+
+/**
+ * @brief Callback used to fill the playback buffer of bdIMAD.
+ * The function is called by bdIMAD each time are required sample to be played.
+ * @param[in] *buffer                  pointer to the buffer with the audio
+ * 				       samples to be played(short type).
+ * @param[in] nSamples                 number of samples required.
+ * @param[in] user_data                pointer to the user data structure
+ * 				       defined in the bdIMADpj_Setting_t
+ * 				       structure.
+ * @return none.
+ */
+
+typedef int (* cb_fillPlayBackB_t) (void *buffer, int nSamples,
+				    void *user_data);
+
+/**
+ * @brief Callback used to retrive the caputre buffer of bdIMAD. The function
+ * is called by bdIMAD each time processed mic samples are available.
+ * @param[out] *buffer                 pointer to the buffer with the audio
+ * 				       samples to download(short type).
+ * @param[in] nSamples                 number of samples processed to download.
+ * @param[in] user_data                pointer to the user data structure
+ *                                     defined in the MainSet structure.
+ * @return none.
+ */
+
+typedef void (* cb_emptyCaptureB_t) (void *buffer, int nSamples,
+				     void *user_data);
+/**
+ * @}
+ */
+
+/**
+ * @addtogroup groupStructEnum
+ * @{
+ */
+ 
+/**
+ * @brief Error status returned by some functions in the library.
+ */
+
+typedef enum bdIMADpj_Status{
+    /**< No error. */
+    BD_PJ_OK                                     = 0,
+    /**< Watch bdIMADpj_Warnings_t structure to find the warnings. */
+    BD_PJ_WARN_BDIMAD_WARNING_ASSERTED           = 1,
+    /**< Error not identified. */
+    BD_PJ_ERROR_GENERIC                          = 2,
+    /**< The pointer passed is NULL. */
+    BD_PJ_ERROR_NULL_POINTER                     = 3,
+    /**< Allocation procedure failed. */
+    BD_PJ_ERROR_ALLOCATION                       = 4,
+    /**< The parameter is not existent or the set/get function is not active. */
+    BD_PJ_ERROR_PARAMETER_NOT_FOUND              = 5,
+    /**< No capture device found. */
+    BD_PJ_ERROR_IMAD_NONE_CAPTURE_DEV            = 10,
+    /**< No play device found. */
+    BD_PJ_ERROR_IMAD_NONE_PLAY_DEV               = 11,
+    /**< Frame size not allowed. */
+    BD_PJ_ERROR_IMAD_FRAME_SIZE                  = 12,
+    /**< Sample frequency not allowed. */
+    BD_PJ_ERROR_IMAD_SAMPLE_FREQ                 = 13,
+    /**< Samples missing. */
+    BD_PJ_ERROR_IMAD_MISSING_SAMPLES             = 14,
+    /**< Device list is empty. */
+    BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY           = 15,
+    /**< Library not authorized, entering demo mode. */
+    BD_PJ_ERROR_IMAD_LIB_NOT_AUTHORIZED          = 16,
+    /**< The input channel memory has not been allocated. */
+    BD_PJ_ERROR_IMAD_INPUT_CH_NOT_ALLOCATED      = 17,
+    /**< The library has expired, entering demo mode. */
+    BD_PJ_ERROR_IMAD_LICENSE_EXPIRED             = 18,
+    /**< Open of capture device failed. */
+    BD_PJ_ERROR_IMAD_OPEN_CAPTURE_DEV_FAILED     = 19,
+    /**< Open of play device failed.  */
+    BD_PJ_ERROR_IMAD_OPEN_PLAY_DEV_FAILED        = 20,
+    /**< Start of play device failed. */
+    BD_PJ_ERROR_IMAD_START_PLAY_DEV_FAILED       = 21,
+    /**< Start of capture device failed. */
+    BD_PJ_ERROR_IMAD_START_CAPTURE_DEV_FAILED    = 22,
+    /**< Start of time process failed. */
+    BD_PJ_ERROR_IMAD_START_TIME_PROCESS_FAILED   = 23,
+    /**< Start of thread process failed. */
+    BD_PJ_ERROR_IMAD_THREAD_PROCESS_FAILED       = 24,
+    /**< No volume control available. */
+    BD_PJ_ERROR_IMAD_NO_VOL_CONTROL_AVAILABLE    = 25,
+} bdIMADpj_Status;
+
+/**
+ * @brief Parameter to pass to set and get parameter functions. 
+ *
+ * For each enumeration are defined the data type and the supported operations
+ * on that parameter (set and get).
+ */
+   
+typedef enum bdIMADpj_Parameter{
+    /**< int*   \n set/get \n 1 enable / 0 disable echo cancellation. */
+    BD_PARAM_IMAD_PJ_AEC_ENABLE                 = 1,
+    /**< int*   \n set/get \n 1 enable / 0 disable microphone control
+     * (when possible). */
+    BD_PARAM_IMAD_PJ_MIC_CONTROL_ENABLE         = 2,
+    /**< int*   \n set/get \n 1 ebable / 0 disable noise reduction. */
+    BD_PARAM_IMAD_PJ_NOISE_REDUCTION_ENABLE     = 3,
+    /**< int*   \n set     \n number of channel to reset. Used to reset
+     * the input channel statistics. To be used when the same channel
+     * is assigned to another partecipant. */
+    BD_PARAM_IMAD_PJ_RESET_STATISTIC_IN_CH      = 4,
+    /**< float* \n set/get \n 0.0f -> 1.0f volume of
+     * the microphone(when possible). */
+    BD_PARAM_IMAD_PJ_MIC_VOLUME                 = 5,
+    /**< int*   \n set/get \n 0 mute / 1 not mute on microphone
+     * (when possible). */
+    BD_PARAM_IMAD_PJ_MIC_MUTE                   = 6,
+    /**< float* \n set/get \n 0.0f -> 1.0f volume of the speaker. */
+    BD_PARAM_IMAD_PJ_SPK_VOLUME                 = 7,
+    /**< int*   \n set/get \n 0 mute / 1 not mute on speaker. */
+    BD_PARAM_IMAD_PJ_SPK_MUTE                   = 8,
+} bdIMADpj_Parameter;
+
+
+/**
+ * @brief Instance structure for the information regarding the aec engine.
+ */
+
+typedef struct bdIMADpj_Setting_t{
+    /**< Sample frequency (8kHz or 16kHz). */
+    int                 SamplingFrequency;
+    /**< Audio buffer managed by the aec bdIMAD functions.
+     * (from 16ms to 80ms, 16ms recommended). */
+    int                 FrameSize_ms;
+    /**< Points to the validation functions in the validation library. */
+    void                *validate;
+    /**< Points to the the callback function used for filling
+     * the playback buffer of bdIMAD. */
+    cb_fillPlayBackB_t  cb_fillPlayBackBuffer;
+    /**< Points to user data to pass to the callback. */
+    void                *cb_fillPlayBackBuffer_user_data;
+    /**< Points to the callback function used for retreive the processed
+     * audio present in the capture buffer of bdIMAD. */
+    cb_emptyCaptureB_t  cb_emptyCaptureBuffer;
+    /**< Points to user data to pass to the callback. */
+    void                *cb_emptyCaptureBuffer_user_data;
+    /**< Is a wide char pointer to the capture device name. */
+    wchar_t             *CaptureDevice;
+    /**< Is a wide char pointer to the play device name. */
+    wchar_t             *PlayDevice;
+    /**< True to enable diagnostic, false to disable. */
+    int 	            DiagnosticEnable;
+    /**< Directory which will contains the files generated for diagnostic. */
+    wchar_t             *DiagnosticFolderPath;
+    /**< Is an auxiliary settings pointer used internally by bdIMAD. */
+    void                *bdIMADwr_SettingsData;
+} bdIMADpj_Setting_t;
+
+/**
+ * @brief Instance structure for the warnings generated by the initialization
+ * functions.
+ */
+
+typedef struct bdIMADpj_Warnings_t{
+    /**< The capture device indicated can't be opened, has been selected
+     * the default capture device. */
+    int DefaultCaptureDeviceAutomaticallySelected;
+    /**< The capture device opened has not volume control. */
+    int CaptureDeviceWithoutVolumeControl;
+    /**< The play device indicated can't be opened, has been selected
+     * the default play device. */
+    int DefaultPlayDeviceAutomaticallySelected;
+    /**< The number of channel requested is out of range. The number of
+     * channel opened is equal to the maximum. */
+    int NumberOfChannelsOutOfRange;
+    /**< The diagnostic files could not be saved. */
+    int DiagnosticSaveNotAllowed;
+    /**< The nlp level requested is not allowed, it has been automatically
+     * changed to the default value. */
+    int nlpLevelChangeSettting;
+    /**< No capture device is present. Anyway the bdSES has been
+     * istantiated only for playback. */
+    int NoCaptureDevicePresent;
+    /**< The cpu is not adapt to run the aec engine, the aec has been disabled.
+     * This appens for very old cpu like pentium III. */
+    int oldCPUdetected_AECdisable;
+    /**< Windows Direct Sound error. */
+    long directSoundError;
+    /**< Windows Direct Sound volume error. */
+    long directSoundLevel;
+    /**< No play device is present. Anyway the bdSES has been istantiated
+     * only for capture. */
+    int NoPlayDevicePresent;
+} bdIMADpj_Warnings_t;
+
+/**
+ * @brief Instance structure for the library version
+ */
+
+typedef struct bdIMADpj_libVersion_t{
+    int     major;                                /**< major version. */
+    int	    minor;                                /**< minor version. */
+    int	    build;                                /**< build number. */
+    char    *name;                                /**< name "bdIMADpj ver.X". */
+    char    *version;                             /**< beta, RC, release. */
+    char    *buildDate;                           /**< build date. */
+} bdIMADpj_libVersion_t;
+
+/**
+ * @}
+ */
+
+
+
+/**
+ * @addtogroup groupFunction
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Must be used to allocate and set to default parameter the memory
+ * for the bdIMAD.
+ *
+ * The function generate a structure bdIMADpj_Setting_t filled with the
+ * default settings.
+ * \n The user can change this settings according to the need and then
+ * launch the ::bdIMADpj_InitAEC.
+ * \n The function generate also a warning structure (::bdIMADpj_Warnings_t)
+ * that could be used in ::bdIMADpj_InitAEC to handle eventual warnings.
+ * @param[out] **ppSettings            Points to the pointer of the
+ *                                     allocated ::bdIMADpj_Setting_t.
+ * @param[out] **ppWarningMessages     Points to the pointer of the
+ *                                     allocated ::bdIMADpj_Warnings_t.
+ * @return                             ::BD_PJ_OK if the function has been
+ *                                     performed successfully, otherwise return
+ *                                     an error (refer to ::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_CreateStructures(
+				    bdIMADpj_Setting_t **ppSettings,
+				    bdIMADpj_Warnings_t **ppWarningMessages);
+
+/**
+ * @brief Is used to free the memory for the ::bdIMADpj_Setting_t structure and
+ * ::bdIMADpj_Warnings_t structure allocated with
+ * the ::bdIMADpj_CreateStructures.
+ * @param[in] **ppSettings             Pointer to a memory location filled
+ * 				       with the address of the
+ * 				       ::bdIMADpj_Setting_t structure to free.
+ * This address will be set to NULL.
+ * @param[in] **ppWarningMessages      Pointer to a memory location filled
+ * 				       with the address of the allocated
+ * 				       ::bdIMADpj_Warnings_t structure to free.
+ * 				       This address will be set to NULL.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise return
+ * 				       an error (refer to ::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_FreeStructures(
+				    bdIMADpj_Setting_t **ppSettings,
+				    bdIMADpj_Warnings_t **ppWarningMessages);
+
+/**
+ * @brief Is used to initialize the memory for bdIMAD with the settings
+ * contained in the <code>ppSettings</code>.
+ * @param[out] *pBdIMADInstance        Is the pointer to the bdIMAD object.
+ * @param[in] **ppSettings             Pointer to pointer to a
+ * 				       ::bdIMADpj_Setting_t structure, filled
+ * 				       with initialization settings to be
+ * 				       applied to the bdIMAD.
+ *                                     \n Note, the <code>pBdIMADInstance</code>
+ *                                     is modified with the applied settings.
+ * @param[out] **ppWarningMessages     Pointer to pointer to a
+ * 				       ::bdIMADpj_Warnings_t sructure,
+ * 				       which reports the warnings after the
+ * 				       initialization.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise return
+ * 				       an error (refer to ::bdIMADpj_Status).
+ *                                     \n If the error is
+ *                                     ::BD_PJ_WARN_BDIMAD_WARNING_ASSERTED
+ *                                     the init has been performed with success,
+ *                                     but with a different settings
+ *                                     respect to the ones required.
+ *                                     This mainly happens if the audio
+ *                                     device opened is different to the
+ *                                     one requested.
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_InitAEC(bdIMADpj *pBdIMADInstance,
+				      bdIMADpj_Setting_t **ppSettings,
+				      bdIMADpj_Warnings_t **ppWarningMessages);
+
+/**
+ * @brief Is used to free the bdIMAD object pointed by the
+ * <code>pBdIMADInstance</code>.
+ * @param[in] *pBdIMADInstance         Pointer to the bdIMAD object to free.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise return
+ * 				       an error (refer to ::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_FreeAEC(bdIMADpj *pBdIMADInstance);
+
+/**
+ * @brief Is used to make a list of capure and play devices available
+ * on the system.
+ * @param[in] captureDevice            Set to 1 to get the list of capture
+ * 				       devices. Set to 0 to get the list of
+ * 				       play devices.
+ * @param[in] **deviceName             Pointer to pointer to a wide char
+ * 				       containing the names of capture/play
+ * 				       devices.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise return
+ * 				       an error (refer to ::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_getDeviceName(int captureDevice,
+						    wchar_t **deviceName);
+
+/**
+ * @brief Is used to freeze the bdIMAD, stopping the audio playback
+ * and recording.
+ * @param[in] bdIMADInstance           bdIMAD object.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise
+ * 				       return an error (refer to
+ * 				       ::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_stop(bdIMADpj bdIMADInstance);
+
+/**
+ * @brief Is used to put back in play the audio after it has been stopped by the
+ * ::bdIMADpj_stop functions.
+ * @param[in] bdIMADInstance           bdIMAD object.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise
+ * 				       return an error (refer to
+ * 				       ::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_run(bdIMADpj bdIMADInstance);
+
+/**
+ * @brief Print on a standard output the warning messages.
+ * @param[in] *pWarningMessages        Pointer to the warning structure
+ * 				       to be printed.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise
+ * 				       return an error
+ * 				       (refer to ::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_DisplayWarnings(
+					bdIMADpj_Warnings_t *pWarningMessages);
+
+/**
+ * @brief Clear the warning structure after being read.
+ * @param[out] **ppWarningMessages     Pointer to pointer to the warning
+ * 				       structure to be cleared.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise
+ * 				       return an error (refer to
+ * 				       ::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_ClearAllWarnings(
+				       bdIMADpj_Warnings_t **ppWarningMessages);
+
+/**
+ * @brief Is used to set a parameter of the bdIMAD object pointed by the
+ * <code>pBdIMADInstance</code>.
+ * @param[in] bdIMADInstance           bdIMAD object.
+ * @param[in] parameterName            Indicate the parameter to set.
+ * @param[in] *pValue                  Is a pointer to the value to set
+ * 				       cast to void.
+ * 				       \n In the ::bdIMADpj_Parameter
+ * 				       declaration is indicated the real type of
+ * 				       the value, depending on the
+ * 				       <code>parameterName</code>.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise
+ * 				       return an error (refer to
+ * 				       §::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_setParameter(bdIMADpj bdIMADInstance,
+				bdIMADpj_Parameter parameterName, void *pValue);
+
+/**
+ * @brief Is used to get a parameter of the bdIMAD object pointed by the
+ * <code>pBdIMADInstance</code>.
+ * @param[in] bdIMADInstance           bdIMAD object.
+ * @param[in] parameterName            Indicate the parameter to get.
+ * @param[out] *pValue                 Is a pointer to the value to get cast
+ * 				       to void. \n In the
+ * 				       ::bdIMADpj_Parameter declaration is
+ * 				       indicated the real type of the value,
+ * 				       depending on the
+ * 				       <code>parameterName</code>.
+ * @return                             ::BD_PJ_OK if the function has been
+ * 				       performed successfully, otherwise return
+ * 				       an error (refer to ::bdIMADpj_Status).
+ */
+BDIMADPJ_API bdIMADpj_Status bdIMADpj_getParameter(bdIMADpj bdIMADInstance,
+				bdIMADpj_Parameter parameterName, void *pValue);
+
+
+#ifdef __cplusplus
+}
+#endif
+/**
+ * @}
+ */
+
+#endif //BD_IMAD_PJ_H__
