* #27232: jni: added pjproject checkout as regular git content

We will remove it once the next release of pjsip (with Android support)
comes out and is merged into SFLphone.
diff --git a/jni/pjproject-android/.svn/pristine/ad/ad2dafb3d167ceefba0d9a2efd56524ae4dfec6c.svn-base b/jni/pjproject-android/.svn/pristine/ad/ad2dafb3d167ceefba0d9a2efd56524ae4dfec6c.svn-base
new file mode 100644
index 0000000..07d4973
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ad/ad2dafb3d167ceefba0d9a2efd56524ae4dfec6c.svn-base
@@ -0,0 +1,2109 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <pjmedia-audiodev/audiodev_imp.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+#include <pj/os.h>
+
+#if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO
+
+#include "TargetConditionals.h"
+#if TARGET_OS_IPHONE
+    #define COREAUDIO_MAC 0
+#else
+    #define COREAUDIO_MAC 1
+#endif
+
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioConverter.h>
+#if COREAUDIO_MAC
+    #include <CoreAudio/CoreAudio.h>
+#else
+    #include <AudioToolbox/AudioServices.h>
+
+    #define AudioDeviceID unsigned
+
+    /**
+     * As in iOS SDK 4 or later, audio route change property listener is
+     * no longer necessary. Just make surethat your application can receive
+     * remote control events by adding the code:
+     *     [[UIApplication sharedApplication] 
+     *      beginReceivingRemoteControlEvents];
+     * Otherwise audio route change (such as headset plug/unplug) will not be
+     * processed while your application is in the background mode.
+     */
+    #define USE_AUDIO_ROUTE_CHANGE_PROP_LISTENER 0
+
+#endif
+
+/* For Mac OS 10.5.x and earlier */
+#if AUDIO_UNIT_VERSION < 1060
+    #define AudioComponent Component
+    #define AudioComponentDescription ComponentDescription
+    #define AudioComponentInstance ComponentInstance
+    #define AudioComponentFindNext FindNextComponent
+    #define AudioComponentInstanceNew OpenAComponent
+    #define AudioComponentInstanceDispose CloseComponent
+#endif
+
+
+#define THIS_FILE		"coreaudio_dev.c"
+
+/* coreaudio device info */
+struct coreaudio_dev_info
+{
+    pjmedia_aud_dev_info	 info;
+    AudioDeviceID		 dev_id;
+};
+
+/* linked list of streams */
+struct stream_list
+{
+    PJ_DECL_LIST_MEMBER(struct stream_list);
+    struct coreaudio_stream	*stream;
+};
+
+/* coreaudio factory */
+struct coreaudio_factory
+{
+    pjmedia_aud_dev_factory	 base;
+    pj_pool_t			*base_pool;
+    pj_pool_t			*pool;
+    pj_pool_factory		*pf;
+    pj_mutex_t			*mutex;
+
+    unsigned			 dev_count;
+    struct coreaudio_dev_info	*dev_info;
+
+    AudioComponent		 io_comp;
+    struct stream_list		 streams;
+};
+
+/* Sound stream. */
+struct coreaudio_stream
+{
+    pjmedia_aud_stream	 	 base;   	 /**< Base stream  	  */
+    pjmedia_aud_param	 	 param;		 /**< Settings	          */
+    pj_pool_t			*pool;           /**< Memory pool.        */
+    struct coreaudio_factory	*cf;
+    struct stream_list		 list_entry;
+
+    pjmedia_aud_rec_cb   	 rec_cb;         /**< Capture callback.   */
+    pjmedia_aud_play_cb  	 play_cb;        /**< Playback callback.  */
+    void                	*user_data;      /**< Application data.   */
+
+    pj_timestamp	 	 play_timestamp;
+    pj_timestamp	 	 rec_timestamp;
+
+    pj_int16_t			*rec_buf;
+    unsigned		 	 rec_buf_count;
+    pj_int16_t			*play_buf;
+    unsigned		 	 play_buf_count;
+
+    pj_bool_t			 interrupted;
+    pj_bool_t		 	 quit_flag;
+    pj_bool_t			 running;
+
+    pj_bool_t		 	 rec_thread_initialized;
+    pj_thread_desc	 	 rec_thread_desc;
+    pj_thread_t			*rec_thread;
+
+    pj_bool_t		 	 play_thread_initialized;
+    pj_thread_desc	 	 play_thread_desc;
+    pj_thread_t			*play_thread;
+
+    AudioUnit		 	 io_units[2];
+    AudioStreamBasicDescription  streamFormat;
+    AudioBufferList		*audio_buf;
+
+    AudioConverterRef            resample;
+    pj_int16_t			*resample_buf;
+    void			*resample_buf_ptr;
+    unsigned		 	 resample_buf_count;
+    unsigned		 	 resample_buf_size;
+};
+
+/* Static variable */
+static struct coreaudio_factory *cf_instance = NULL;
+
+/* Prototypes */
+static pj_status_t ca_factory_init(pjmedia_aud_dev_factory *f);
+static pj_status_t ca_factory_destroy(pjmedia_aud_dev_factory *f);
+static pj_status_t ca_factory_refresh(pjmedia_aud_dev_factory *f);
+static unsigned    ca_factory_get_dev_count(pjmedia_aud_dev_factory *f);
+static pj_status_t ca_factory_get_dev_info(pjmedia_aud_dev_factory *f,
+					   unsigned index,
+					   pjmedia_aud_dev_info *info);
+static pj_status_t ca_factory_default_param(pjmedia_aud_dev_factory *f,
+					    unsigned index,
+					    pjmedia_aud_param *param);
+static pj_status_t ca_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 ca_stream_get_param(pjmedia_aud_stream *strm,
+				       pjmedia_aud_param *param);
+static pj_status_t ca_stream_get_cap(pjmedia_aud_stream *strm,
+				     pjmedia_aud_dev_cap cap,
+				     void *value);
+static pj_status_t ca_stream_set_cap(pjmedia_aud_stream *strm,
+				     pjmedia_aud_dev_cap cap,
+				     const void *value);
+static pj_status_t ca_stream_start(pjmedia_aud_stream *strm);
+static pj_status_t ca_stream_stop(pjmedia_aud_stream *strm);
+static pj_status_t ca_stream_destroy(pjmedia_aud_stream *strm);
+static pj_status_t create_audio_unit(AudioComponent io_comp,
+				     AudioDeviceID dev_id,
+				     pjmedia_dir dir,
+				     struct coreaudio_stream *strm,
+				     AudioUnit *io_unit);
+#if !COREAUDIO_MAC
+static void interruptionListener(void *inClientData, UInt32 inInterruption);
+static void propListener(void *                 inClientData,
+                         AudioSessionPropertyID inID,
+                         UInt32                 inDataSize,
+                         const void *           inData);
+#endif
+
+/* Operations */
+static pjmedia_aud_dev_factory_op factory_op =
+{
+    &ca_factory_init,
+    &ca_factory_destroy,
+    &ca_factory_get_dev_count,
+    &ca_factory_get_dev_info,
+    &ca_factory_default_param,
+    &ca_factory_create_stream,
+    &ca_factory_refresh
+};
+
+static pjmedia_aud_stream_op stream_op =
+{
+    &ca_stream_get_param,
+    &ca_stream_get_cap,
+    &ca_stream_set_cap,
+    &ca_stream_start,
+    &ca_stream_stop,
+    &ca_stream_destroy
+};
+
+
+/****************************************************************************
+ * Factory operations
+ */
+/*
+ * Init coreaudio audio driver.
+ */
+pjmedia_aud_dev_factory* pjmedia_coreaudio_factory(pj_pool_factory *pf)
+{
+    struct coreaudio_factory *f;
+    pj_pool_t *pool;
+
+    pool = pj_pool_create(pf, "core audio base", 1000, 1000, NULL);
+    f = PJ_POOL_ZALLOC_T(pool, struct coreaudio_factory);
+    f->pf = pf;
+    f->base_pool = pool;
+    f->base.op = &factory_op;
+
+    return &f->base;
+}
+
+
+/* API: init factory */
+static pj_status_t ca_factory_init(pjmedia_aud_dev_factory *f)
+{
+    struct coreaudio_factory *cf = (struct coreaudio_factory*)f;
+    AudioComponentDescription desc;
+    pj_status_t status;
+#if !COREAUDIO_MAC
+    unsigned i;
+    OSStatus ostatus;
+#endif
+
+    pj_list_init(&cf->streams);
+    status = pj_mutex_create_recursive(cf->base_pool,
+				       "coreaudio",
+				       &cf->mutex);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    desc.componentType = kAudioUnitType_Output;
+#if COREAUDIO_MAC
+    desc.componentSubType = kAudioUnitSubType_HALOutput;
+#else
+    desc.componentSubType = kAudioUnitSubType_RemoteIO;
+#endif
+    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+    desc.componentFlags = 0;
+    desc.componentFlagsMask = 0;
+
+    cf->io_comp = AudioComponentFindNext(NULL, &desc);
+    if (cf->io_comp == NULL)
+	return PJMEDIA_EAUD_INIT; // cannot find IO unit;
+
+    status = ca_factory_refresh(f);
+    if (status != PJ_SUCCESS)
+	return status;
+
+#if !COREAUDIO_MAC
+    cf->pool = pj_pool_create(cf->pf, "core audio", 1000, 1000, NULL);
+    cf->dev_count = 1;
+    cf->dev_info = (struct coreaudio_dev_info*)
+   		   pj_pool_calloc(cf->pool, cf->dev_count,
+   		   sizeof(struct coreaudio_dev_info));
+    for (i = 0; i < cf->dev_count; i++) {
+ 	struct coreaudio_dev_info *cdi;
+
+ 	cdi = &cf->dev_info[i];
+ 	pj_bzero(cdi, sizeof(*cdi));
+ 	cdi->dev_id = 0;
+ 	strcpy(cdi->info.name, "iPhone IO device");
+ 	strcpy(cdi->info.driver, "apple");
+ 	cdi->info.input_count = 1;
+ 	cdi->info.output_count = 1;
+ 	cdi->info.default_samples_per_sec = 8000;
+
+	/* Set the device capabilities here */
+ 	cdi->info.caps = PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
+			 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY |
+			 PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING |
+			 PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE |
+			 PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE |
+			 PJMEDIA_AUD_DEV_CAP_EC;
+ 	cdi->info.routes = PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER |
+			   PJMEDIA_AUD_DEV_ROUTE_EARPIECE |
+			   PJMEDIA_AUD_DEV_ROUTE_BLUETOOTH;
+
+	PJ_LOG(4, (THIS_FILE, " dev_id %d: %s  (in=%d, out=%d) %dHz",
+		   i,
+		   cdi->info.name,
+		   cdi->info.input_count,
+		   cdi->info.output_count,
+		   cdi->info.default_samples_per_sec));
+    }
+
+    /* Initialize the Audio Session */
+    ostatus = AudioSessionInitialize(NULL, NULL, interruptionListener, NULL);
+    if (ostatus != kAudioSessionNoError) {
+	PJ_LOG(4, (THIS_FILE,
+		   "Warning: cannot initialize audio session services (%i)",
+		   ostatus));
+    }
+
+    /* Listen for audio routing change notifications. */
+#if USE_AUDIO_ROUTE_CHANGE_PROP_LISTENER != 0
+    ostatus = AudioSessionAddPropertyListener(
+	          kAudioSessionProperty_AudioRouteChange,
+		  propListener, cf);
+    if (ostatus != kAudioSessionNoError) {
+	PJ_LOG(4, (THIS_FILE,
+		   "Warning: cannot listen for audio route change "
+		   "notifications (%i)", ostatus));
+    }
+#endif
+
+    cf_instance = cf;
+#endif
+
+    PJ_LOG(4, (THIS_FILE, "core audio initialized"));
+
+    return PJ_SUCCESS;
+}
+
+/* API: destroy factory */
+static pj_status_t ca_factory_destroy(pjmedia_aud_dev_factory *f)
+{
+    struct coreaudio_factory *cf = (struct coreaudio_factory*)f;
+    pj_pool_t *pool;
+
+    pj_assert(cf);
+    pj_assert(cf->base_pool);
+    pj_assert(pj_list_empty(&cf->streams));
+
+#if !COREAUDIO_MAC
+#if USE_AUDIO_ROUTE_CHANGE_PROP_LISTENER != 0
+    AudioSessionRemovePropertyListenerWithUserData(
+        kAudioSessionProperty_AudioRouteChange, propListener, cf);
+#endif
+#endif
+    
+    if (cf->pool) {
+	pj_pool_release(cf->pool);
+	cf->pool = NULL;
+    }
+
+    if (cf->mutex) {
+	pj_mutex_lock(cf->mutex);
+	cf_instance = NULL;
+	pj_mutex_unlock(cf->mutex);
+	pj_mutex_destroy(cf->mutex);
+	cf->mutex = NULL;
+    }
+
+    pool = cf->base_pool;
+    cf->base_pool = NULL;
+    pj_pool_release(pool);
+
+    return PJ_SUCCESS;
+}
+
+/* API: refresh the device list */
+static pj_status_t ca_factory_refresh(pjmedia_aud_dev_factory *f)
+{
+#if !COREAUDIO_MAC
+    /* iPhone doesn't support refreshing the device list */
+    PJ_UNUSED_ARG(f);
+    return PJ_SUCCESS;
+#else
+    struct coreaudio_factory *cf = (struct coreaudio_factory*)f;
+    unsigned i;
+    unsigned dev_count;
+    AudioObjectPropertyAddress addr;
+    AudioDeviceID *dev_ids;
+    UInt32 buf_size, dev_size, size = sizeof(AudioDeviceID);
+    AudioBufferList *buf = NULL;
+    OSStatus ostatus;
+
+    if (cf->pool != NULL) {
+	pj_pool_release(cf->pool);
+	cf->pool = NULL;
+    }
+
+    cf->dev_count = 0;
+    cf->pool = pj_pool_create(cf->pf, "core audio", 1000, 1000, NULL);
+
+    /* Find out how many audio devices there are */
+    addr.mSelector = kAudioHardwarePropertyDevices;
+    addr.mScope = kAudioObjectPropertyScopeGlobal;
+    addr.mElement = kAudioObjectPropertyElementMaster;
+    ostatus = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr,
+                                             0, NULL, &dev_size);
+    if (ostatus != noErr) {
+	dev_size = 0;
+    }
+
+    /* Calculate the number of audio devices available */
+    dev_count = dev_size / size;
+    if (dev_count==0) {
+  	PJ_LOG(4,(THIS_FILE, "core audio found no sound devices"));
+  	/* Enabling this will cause pjsua-lib initialization to fail when
+  	 * there is no sound device installed in the system, even when pjsua
+  	 * has been run with --null-audio. Moreover, it might be better to
+  	 * think that the core audio backend initialization is successful,
+  	 * regardless there is no audio device installed, as later application
+  	 * can check it using get_dev_count().
+  	return PJMEDIA_EAUD_NODEV;
+  	 */
+  	return PJ_SUCCESS;
+    }
+    PJ_LOG(4, (THIS_FILE, "core audio detected %d devices",
+	       dev_count));
+
+    /* Get all the audio device IDs */
+    dev_ids = (AudioDeviceID *)pj_pool_calloc(cf->pool, dev_size, size);
+    if (!dev_ids)
+	return PJ_ENOMEM;
+    pj_bzero(dev_ids, dev_count);
+    ostatus = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr,
+					 0, NULL,
+				         &dev_size, (void *)dev_ids);
+    if (ostatus != noErr ) {
+	/* This should not happen since we have successfully retrieved
+	 * the property data size before
+	 */
+	return PJMEDIA_EAUD_INIT;
+    }
+    
+    if (dev_size > 1) {
+	AudioDeviceID dev_id = kAudioObjectUnknown;
+	unsigned idx = 0;
+	
+	/* Find default audio input device */
+	addr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+	addr.mScope = kAudioObjectPropertyScopeGlobal;
+	addr.mElement = kAudioObjectPropertyElementMaster;
+	size = sizeof(dev_id);
+	
+	ostatus = AudioObjectGetPropertyData(kAudioObjectSystemObject,
+					     &addr, 0, NULL,
+					     &size, (void *)&dev_id);
+	if (ostatus == noErr && dev_id != dev_ids[idx]) {
+	    AudioDeviceID temp_id = dev_ids[idx];
+	    
+	    for (i = idx + 1; i < dev_size; i++) {
+		if (dev_ids[i] == dev_id) {
+		    dev_ids[idx++] = dev_id;
+		    dev_ids[i] = temp_id;
+		    break;
+		}
+	    }
+	}
+
+	/* Find default audio output device */
+	addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;	
+	ostatus = AudioObjectGetPropertyData(kAudioObjectSystemObject,
+					     &addr, 0, NULL,
+					     &size, (void *)&dev_id);
+	if (ostatus == noErr && dev_id != dev_ids[idx]) {
+	    AudioDeviceID temp_id = dev_ids[idx];
+	    
+	    for (i = idx + 1; i < dev_size; i++) {
+		if (dev_ids[i] == dev_id) {
+		    dev_ids[idx] = dev_id;
+		    dev_ids[i] = temp_id;
+		    break;
+		}
+	    }
+	}
+    }
+
+    /* Build the devices' info */
+    cf->dev_info = (struct coreaudio_dev_info*)
+  		   pj_pool_calloc(cf->pool, dev_count,
+  		   sizeof(struct coreaudio_dev_info));
+    buf_size = 0;
+    for (i = 0; i < dev_count; i++) {
+	struct coreaudio_dev_info *cdi;
+	Float64 sampleRate;
+
+	cdi = &cf->dev_info[i];
+	pj_bzero(cdi, sizeof(*cdi));
+	cdi->dev_id = dev_ids[i];
+
+	/* Get device name */
+	addr.mSelector = kAudioDevicePropertyDeviceName;
+	addr.mScope = kAudioObjectPropertyScopeGlobal;
+	addr.mElement = kAudioObjectPropertyElementMaster;
+	size = sizeof(cdi->info.name);
+	AudioObjectGetPropertyData(cdi->dev_id, &addr,
+				   0, NULL,
+			           &size, (void *)cdi->info.name);
+
+	strcpy(cdi->info.driver, "core audio");
+
+        /* Get the number of input channels */
+	addr.mSelector = kAudioDevicePropertyStreamConfiguration;
+	addr.mScope = kAudioDevicePropertyScopeInput;
+	size = 0;
+	ostatus = AudioObjectGetPropertyDataSize(cdi->dev_id, &addr,
+	                                         0, NULL, &size);
+	if (ostatus == noErr && size > 0) {
+
+	    if (size > buf_size) {
+		buf = pj_pool_alloc(cf->pool, size);
+		buf_size = size;
+	    }
+	    if (buf) {
+		UInt32 idx;
+
+		/* Get the input stream configuration */
+		ostatus = AudioObjectGetPropertyData(cdi->dev_id, &addr,
+						     0, NULL,
+						     &size, buf);
+		if (ostatus == noErr) {
+		    /* Count the total number of input channels in
+		     * the stream
+		     */
+		    for (idx = 0; idx < buf->mNumberBuffers; idx++) {
+			cdi->info.input_count +=
+			    buf->mBuffers[idx].mNumberChannels;
+		    }
+		}
+	    }
+	}
+
+        /* Get the number of output channels */
+	addr.mScope = kAudioDevicePropertyScopeOutput;
+	size = 0;
+	ostatus = AudioObjectGetPropertyDataSize(cdi->dev_id, &addr,
+	                                         0, NULL, &size);
+	if (ostatus == noErr && size > 0) {
+
+	    if (size > buf_size) {
+		buf = pj_pool_alloc(cf->pool, size);
+		buf_size = size;
+	    }
+	    if (buf) {
+		UInt32 idx;
+
+		/* Get the output stream configuration */
+		ostatus = AudioObjectGetPropertyData(cdi->dev_id, &addr,
+						     0, NULL,
+						     &size, buf);
+		if (ostatus == noErr) {
+		    /* Count the total number of output channels in
+		     * the stream
+		     */
+		    for (idx = 0; idx < buf->mNumberBuffers; idx++) {
+			cdi->info.output_count +=
+			    buf->mBuffers[idx].mNumberChannels;
+		    }
+		}
+	    }
+	}
+
+	/* Get default sample rate */
+	addr.mSelector = kAudioDevicePropertyNominalSampleRate;
+	addr.mScope = kAudioObjectPropertyScopeGlobal;
+	size = sizeof(Float64);
+	ostatus = AudioObjectGetPropertyData (cdi->dev_id, &addr,
+		                              0, NULL,
+		                              &size, &sampleRate);
+	cdi->info.default_samples_per_sec = (ostatus == noErr ?
+					    sampleRate:
+					    16000);
+
+	/* Set device capabilities here */
+	if (cdi->info.input_count > 0) {
+	    cdi->info.caps |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
+	}
+	if (cdi->info.output_count > 0) {
+	    cdi->info.caps |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
+	    addr.mSelector = kAudioDevicePropertyVolumeScalar;
+	    addr.mScope = kAudioDevicePropertyScopeOutput;
+	    if (AudioObjectHasProperty(cdi->dev_id, &addr)) {
+		cdi->info.caps |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
+	    }
+	}
+
+	cf->dev_count++;
+
+	PJ_LOG(4, (THIS_FILE, " dev_id %d: %s  (in=%d, out=%d) %dHz",
+	       i,
+	       cdi->info.name,
+	       cdi->info.input_count,
+	       cdi->info.output_count,
+	       cdi->info.default_samples_per_sec));
+    }
+
+    return PJ_SUCCESS;
+#endif
+}
+
+/* API: get number of devices */
+static unsigned ca_factory_get_dev_count(pjmedia_aud_dev_factory *f)
+{
+    struct coreaudio_factory *cf = (struct coreaudio_factory*)f;
+    return cf->dev_count;
+}
+
+/* API: get device info */
+static pj_status_t ca_factory_get_dev_info(pjmedia_aud_dev_factory *f,
+					   unsigned index,
+					   pjmedia_aud_dev_info *info)
+{
+    struct coreaudio_factory *cf = (struct coreaudio_factory*)f;
+
+    PJ_ASSERT_RETURN(index < cf->dev_count, PJMEDIA_EAUD_INVDEV);
+
+    pj_memcpy(info, &cf->dev_info[index].info, sizeof(*info));
+
+    return PJ_SUCCESS;
+}
+
+/* API: create default device parameter */
+static pj_status_t ca_factory_default_param(pjmedia_aud_dev_factory *f,
+					    unsigned index,
+					    pjmedia_aud_param *param)
+{
+    struct coreaudio_factory *cf = (struct coreaudio_factory*)f;
+    struct coreaudio_dev_info *di = &cf->dev_info[index];
+
+    PJ_ASSERT_RETURN(index < cf->dev_count, PJMEDIA_EAUD_INVDEV);
+
+    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;
+    } else if (di->info.input_count) {
+	param->dir = PJMEDIA_DIR_CAPTURE;
+	param->rec_id = index;
+	param->play_id = PJMEDIA_AUD_INVALID_DEV;
+    } else if (di->info.output_count) {
+	param->dir = PJMEDIA_DIR_PLAYBACK;
+	param->play_id = index;
+	param->rec_id = PJMEDIA_AUD_INVALID_DEV;
+    } else {
+	return PJMEDIA_EAUD_INVDEV;
+    }
+
+    /* Set the mandatory settings here */
+    param->clock_rate = di->info.default_samples_per_sec;
+    param->channel_count = 1;
+    param->samples_per_frame = di->info.default_samples_per_sec * 20 / 1000;
+    param->bits_per_sample = 16;
+
+    /* Set the param for device capabilities here */
+    param->flags = PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
+		   PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
+    param->input_latency_ms = PJMEDIA_SND_DEFAULT_REC_LATENCY;
+    param->output_latency_ms = PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
+
+    return PJ_SUCCESS;
+}
+
+OSStatus resampleProc(AudioConverterRef             inAudioConverter,
+		      UInt32                        *ioNumberDataPackets,
+		      AudioBufferList               *ioData,
+		      AudioStreamPacketDescription  **outDataPacketDescription,
+		      void                          *inUserData)
+{
+    struct coreaudio_stream *strm = (struct coreaudio_stream*)inUserData;
+
+    if (*ioNumberDataPackets > strm->resample_buf_size)
+	*ioNumberDataPackets = strm->resample_buf_size;
+
+    ioData->mNumberBuffers = 1;
+    ioData->mBuffers[0].mNumberChannels = strm->streamFormat.mChannelsPerFrame;
+    ioData->mBuffers[0].mData = strm->resample_buf_ptr;
+    ioData->mBuffers[0].mDataByteSize = *ioNumberDataPackets *
+					strm->streamFormat.mChannelsPerFrame *
+					strm->param.bits_per_sample >> 3;
+
+    return noErr;
+}
+
+static OSStatus resample_callback(void                       *inRefCon,
+				  AudioUnitRenderActionFlags *ioActionFlags,
+				  const AudioTimeStamp       *inTimeStamp,
+				  UInt32                      inBusNumber,
+				  UInt32                      inNumberFrames,
+				  AudioBufferList            *ioData)
+{
+    struct coreaudio_stream *strm = (struct coreaudio_stream*)inRefCon;
+    OSStatus ostatus;
+    pj_status_t status = 0;
+    unsigned nsamples;
+    AudioBufferList *buf = strm->audio_buf;
+    pj_int16_t *input;
+    UInt32 resampleSize;
+
+    pj_assert(!strm->quit_flag);
+
+    /* Known cases of callback's thread:
+     * - The thread may be changed in the middle of a session
+     *   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("ca_rec", strm->rec_thread_desc,
+				    &strm->rec_thread);
+	strm->rec_thread_initialized = 1;
+	PJ_LOG(5,(THIS_FILE, "Recorder thread started, (%i frames)", 
+		  inNumberFrames));
+    }
+
+    buf->mBuffers[0].mData = NULL;
+    buf->mBuffers[0].mDataByteSize = inNumberFrames *
+				     strm->streamFormat.mChannelsPerFrame;
+    /* Render the unit to get input data */
+    ostatus = AudioUnitRender(strm->io_units[0],
+			      ioActionFlags,
+			      inTimeStamp,
+			      inBusNumber,
+			      inNumberFrames,
+			      buf);
+
+    if (ostatus != noErr) {
+	PJ_LOG(5, (THIS_FILE, "Core audio unit render error %i", ostatus));
+	goto on_break;
+    }
+    input = (pj_int16_t *)buf->mBuffers[0].mData;
+
+    resampleSize = strm->resample_buf_size;
+    nsamples = inNumberFrames * strm->param.channel_count +
+	       strm->resample_buf_count;
+
+    if (nsamples >= resampleSize) {
+	pjmedia_frame frame;
+	UInt32 resampleOutput = strm->param.samples_per_frame /
+				strm->streamFormat.mChannelsPerFrame;
+	AudioBufferList ab;
+
+	frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+	frame.buf = (void*) strm->rec_buf;
+	frame.size = strm->param.samples_per_frame *
+		     strm->param.bits_per_sample >> 3;
+	frame.bit_info = 0;
+	
+	ab.mNumberBuffers = 1;
+	ab.mBuffers[0].mNumberChannels = strm->streamFormat.mChannelsPerFrame;
+	ab.mBuffers[0].mData = strm->rec_buf;
+	ab.mBuffers[0].mDataByteSize = frame.size;
+
+	/* If buffer is not empty, combine the buffer with the just incoming
+	 * samples, then call put_frame.
+	 */
+	if (strm->resample_buf_count) {
+	    unsigned chunk_count = resampleSize - strm->resample_buf_count;
+	    pjmedia_copy_samples(strm->resample_buf + strm->resample_buf_count,
+				 input, chunk_count);
+
+	    /* Do the resample */
+
+	    strm->resample_buf_ptr = strm->resample_buf;
+	    ostatus = AudioConverterFillComplexBuffer(strm->resample,
+						      resampleProc,
+						      strm,
+						      &resampleOutput,
+						      &ab,
+						      NULL);
+	    if (ostatus != noErr) {
+		goto on_break;
+	    }
+	    frame.timestamp.u64 = strm->rec_timestamp.u64;
+
+	    status = (*strm->rec_cb)(strm->user_data, &frame);
+
+	    input = input + chunk_count;
+	    nsamples -= resampleSize;
+	    strm->resample_buf_count = 0;
+	    strm->rec_timestamp.u64 += strm->param.samples_per_frame /
+				       strm->param.channel_count;
+	}
+	
+	
+ 	/* Give all frames we have */
+ 	while (nsamples >= resampleSize && status == 0) {
+ 	    frame.timestamp.u64 = strm->rec_timestamp.u64;
+	    
+	    /* Do the resample */
+	    strm->resample_buf_ptr = input;
+	    ab.mBuffers[0].mDataByteSize = frame.size;
+	    resampleOutput = strm->param.samples_per_frame /
+			     strm->streamFormat.mChannelsPerFrame;
+	    ostatus = AudioConverterFillComplexBuffer(strm->resample,
+						      resampleProc,
+						      strm,
+						      &resampleOutput,
+						      &ab,
+						      NULL);
+	    if (ostatus != noErr) {
+		goto on_break;
+	    }	    
+	    
+ 	    status = (*strm->rec_cb)(strm->user_data, &frame);
+	    
+ 	    input = (pj_int16_t*) input + resampleSize;
+ 	    nsamples -= resampleSize;
+ 	    strm->rec_timestamp.u64 += strm->param.samples_per_frame /
+				       strm->param.channel_count;
+ 	}
+
+	/* Store the remaining samples into the buffer */
+	if (nsamples && status == 0) {
+	    strm->resample_buf_count = nsamples;
+	    pjmedia_copy_samples(strm->resample_buf, input,
+				 nsamples);
+	}
+
+    } else {
+	/* Not enough samples, let's just store them in the buffer */
+	pjmedia_copy_samples(strm->resample_buf + strm->resample_buf_count,
+			     input,
+			     inNumberFrames * strm->param.channel_count);
+	strm->resample_buf_count += inNumberFrames *
+				    strm->param.channel_count;
+    }
+
+    return noErr;
+
+on_break:
+    return -1;
+}
+
+static OSStatus input_callback(void                       *inRefCon,
+                               AudioUnitRenderActionFlags *ioActionFlags,
+                               const AudioTimeStamp       *inTimeStamp,
+                               UInt32                      inBusNumber,
+                               UInt32                      inNumberFrames,
+                               AudioBufferList            *ioData)
+{
+    struct coreaudio_stream *strm = (struct coreaudio_stream*)inRefCon;
+    OSStatus ostatus;
+    pj_status_t status = 0;
+    unsigned nsamples;
+    AudioBufferList *buf = strm->audio_buf;
+    pj_int16_t *input;
+
+    pj_assert(!strm->quit_flag);
+
+    /* Known cases of callback's thread:
+     * - The thread may be changed in the middle of a session
+     *   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("ca_rec", strm->rec_thread_desc,
+				    &strm->rec_thread);
+	strm->rec_thread_initialized = 1;
+	PJ_LOG(5,(THIS_FILE, "Recorder thread started, (%i frames)",
+		  inNumberFrames));
+    }
+
+    buf->mBuffers[0].mData = NULL;
+    buf->mBuffers[0].mDataByteSize = inNumberFrames *
+				     strm->streamFormat.mChannelsPerFrame;
+    /* Render the unit to get input data */
+    ostatus = AudioUnitRender(strm->io_units[0],
+			      ioActionFlags,
+			      inTimeStamp,
+			      inBusNumber,
+			      inNumberFrames,
+			      buf);
+
+    if (ostatus != noErr) {
+	PJ_LOG(5, (THIS_FILE, "Core audio unit render error %i", ostatus));
+	goto on_break;
+    }
+    input = (pj_int16_t *)buf->mBuffers[0].mData;
+
+    /* Calculate number of samples we've got */
+    nsamples = inNumberFrames * strm->param.channel_count +
+	       strm->rec_buf_count;
+    if (nsamples >= strm->param.samples_per_frame) {
+	pjmedia_frame frame;
+
+	frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+	frame.size = strm->param.samples_per_frame *
+		     strm->param.bits_per_sample >> 3;
+	frame.bit_info = 0;
+
+ 	/* 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->param.samples_per_frame - strm->rec_buf_count;
+ 	    pjmedia_copy_samples(strm->rec_buf + strm->rec_buf_count,
+ 				 input, chunk_count);
+
+ 	    frame.buf = (void*) strm->rec_buf;
+ 	    frame.timestamp.u64 = strm->rec_timestamp.u64;
+
+ 	    status = (*strm->rec_cb)(strm->user_data, &frame);
+
+ 	    input = input + chunk_count;
+ 	    nsamples -= strm->param.samples_per_frame;
+ 	    strm->rec_buf_count = 0;
+ 	    strm->rec_timestamp.u64 += strm->param.samples_per_frame /
+				       strm->param.channel_count;
+ 	}
+
+ 	/* Give all frames we have */
+ 	while (nsamples >= strm->param.samples_per_frame && status == 0) {
+ 	    frame.buf = (void*) input;
+ 	    frame.timestamp.u64 = strm->rec_timestamp.u64;
+
+ 	    status = (*strm->rec_cb)(strm->user_data, &frame);
+
+ 	    input = (pj_int16_t*) input + strm->param.samples_per_frame;
+ 	    nsamples -= strm->param.samples_per_frame;
+ 	    strm->rec_timestamp.u64 += strm->param.samples_per_frame /
+				       strm->param.channel_count;
+ 	}
+
+ 	/* Store the remaining samples into the buffer */
+ 	if (nsamples && status == 0) {
+ 	    strm->rec_buf_count = nsamples;
+ 	    pjmedia_copy_samples(strm->rec_buf, input,
+ 			         nsamples);
+ 	}
+
+     } else {
+ 	/* Not enough samples, let's just store them in the buffer */
+ 	pjmedia_copy_samples(strm->rec_buf + strm->rec_buf_count,
+ 			     input,
+ 			     inNumberFrames * strm->param.channel_count);
+ 	strm->rec_buf_count += inNumberFrames * strm->param.channel_count;
+     }
+
+    return noErr;
+
+on_break:
+    return -1;
+}
+
+static OSStatus output_renderer(void                       *inRefCon,
+                                AudioUnitRenderActionFlags *ioActionFlags,
+                                const AudioTimeStamp       *inTimeStamp,
+                                UInt32                      inBusNumber,
+                                UInt32                      inNumberFrames,
+                                AudioBufferList            *ioData)
+{
+    struct coreaudio_stream *stream = (struct coreaudio_stream*)inRefCon;
+    pj_status_t status = 0;
+    unsigned nsamples_req = inNumberFrames * stream->param.channel_count;
+    pj_int16_t *output = ioData->mBuffers[0].mData;
+
+    pj_assert(!stream->quit_flag);
+
+    /* Known cases of callback's thread:
+     * - The thread may be changed in the middle of a session
+     *   it happens when plugging/unplugging headphone.
+     * - The same thread may be reused in consecutive sessions. The first
+     *   session will leave TLS set, but release the TLS data address,
+     *   so the second session must re-register the callback's thread.
+     */
+    if (stream->play_thread_initialized == 0 || !pj_thread_is_registered())
+    {
+	pj_bzero(stream->play_thread_desc, sizeof(pj_thread_desc));
+	status = pj_thread_register("coreaudio", stream->play_thread_desc,
+				    &stream->play_thread);
+	stream->play_thread_initialized = 1;
+	PJ_LOG(5,(THIS_FILE, "Player thread started, (%i frames)",
+		  inNumberFrames));
+    }
+
+
+    /* Check if any buffered samples */
+    if (stream->play_buf_count) {
+	/* samples buffered >= requested by sound device */
+	if (stream->play_buf_count >= nsamples_req) {
+	    pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf,
+				 nsamples_req);
+	    stream->play_buf_count -= nsamples_req;
+	    pjmedia_move_samples(stream->play_buf,
+				 stream->play_buf + nsamples_req,
+				 stream->play_buf_count);
+	    nsamples_req = 0;
+
+	    return noErr;
+	}
+
+	/* samples buffered < requested by sound device */
+	pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf,
+			     stream->play_buf_count);
+	nsamples_req -= stream->play_buf_count;
+	output = (pj_int16_t*)output + stream->play_buf_count;
+	stream->play_buf_count = 0;
+    }
+
+    /* Fill output buffer as requested */
+    while (nsamples_req && status == 0) {
+	pjmedia_frame frame;
+
+	frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+	frame.size = stream->param.samples_per_frame *
+		     stream->param.bits_per_sample >> 3;
+	frame.timestamp.u64 = stream->play_timestamp.u64;
+	frame.bit_info = 0;
+
+	if (nsamples_req >= stream->param.samples_per_frame) {
+	    frame.buf = output;
+	    status = (*stream->play_cb)(stream->user_data, &frame);
+	    if (status != PJ_SUCCESS)
+		goto on_break;
+
+	    if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
+		pj_bzero(frame.buf, frame.size);
+
+	    nsamples_req -= stream->param.samples_per_frame;
+	    output = (pj_int16_t*)output + stream->param.samples_per_frame;
+	} else {
+	    frame.buf = stream->play_buf;
+	    status = (*stream->play_cb)(stream->user_data, &frame);
+	    if (status != PJ_SUCCESS)
+		goto on_break;
+
+	    if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO)
+		pj_bzero(frame.buf, frame.size);
+
+	    pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf,
+				 nsamples_req);
+	    stream->play_buf_count = stream->param.samples_per_frame -
+		                     nsamples_req;
+	    pjmedia_move_samples(stream->play_buf,
+				 stream->play_buf+nsamples_req,
+				 stream->play_buf_count);
+	    nsamples_req = 0;
+	}
+
+	stream->play_timestamp.u64 += stream->param.samples_per_frame /
+				      stream->param.channel_count;
+    }
+
+    return noErr;
+
+on_break:
+    return -1;
+}
+
+#if !COREAUDIO_MAC
+static void propListener(void 			*inClientData,
+			 AudioSessionPropertyID	inID,
+			 UInt32                 inDataSize,
+			 const void *           inData)
+{
+    struct coreaudio_factory *cf = (struct coreaudio_factory*)inClientData;
+    struct stream_list *it, *itBegin;
+    CFDictionaryRef routeDictionary;
+    CFNumberRef reason;
+    SInt32 reasonVal;
+    pj_assert(cf);
+
+    if (inID != kAudioSessionProperty_AudioRouteChange)
+	return;
+
+    routeDictionary = (CFDictionaryRef)inData;
+    reason = (CFNumberRef)
+	     CFDictionaryGetValue(
+	         routeDictionary, 
+		 CFSTR(kAudioSession_AudioRouteChangeKey_Reason));
+    CFNumberGetValue(reason, kCFNumberSInt32Type, &reasonVal);
+
+    if (reasonVal != kAudioSessionRouteChangeReason_OldDeviceUnavailable) {
+	PJ_LOG(3, (THIS_FILE, "ignoring audio route change..."));
+	return;
+    }
+
+    PJ_LOG(3, (THIS_FILE, "audio route changed"));
+
+    pj_mutex_lock(cf->mutex);
+    itBegin = &cf->streams;
+    for (it = itBegin->next; it != itBegin; it = it->next) {
+	if (it->stream->interrupted)
+	    continue;
+
+	/*
+	status = ca_stream_stop((pjmedia_aud_stream *)it->stream);
+	status = ca_stream_start((pjmedia_aud_stream *)it->stream);
+	if (status != PJ_SUCCESS) {
+	    PJ_LOG(3, (THIS_FILE,
+		       "Error: failed to restart the audio unit (%i)",
+		       status));
+	    continue;
+	}
+	PJ_LOG(3, (THIS_FILE, "core audio unit successfully restarted"));
+	*/
+    }
+    pj_mutex_unlock(cf->mutex);
+}
+
+static void interruptionListener(void *inClientData, UInt32 inInterruption)
+{
+    struct stream_list *it, *itBegin;
+    pj_status_t status;
+    pj_thread_desc thread_desc;
+    pj_thread_t *thread;
+    
+    /* Register the thread with PJLIB, this is must for any external threads
+     * which need to use the PJLIB framework.
+     */
+    if (!pj_thread_is_registered()) {
+	pj_bzero(thread_desc, sizeof(pj_thread_desc));
+	status = pj_thread_register("intListener", thread_desc, &thread);
+    }
+    
+    PJ_LOG(3, (THIS_FILE, "Session interrupted! --- %s ---",
+	   inInterruption == kAudioSessionBeginInterruption ?
+	   "Begin Interruption" : "End Interruption"));
+
+    if (!cf_instance)
+	return;
+    
+    pj_mutex_lock(cf_instance->mutex);
+    itBegin = &cf_instance->streams;
+    for (it = itBegin->next; it != itBegin; it = it->next) {
+	if (inInterruption == kAudioSessionEndInterruption &&
+	    it->stream->interrupted == PJ_TRUE)
+	{
+	    UInt32 audioCategory;
+	    OSStatus ostatus;
+
+	    /* Make sure that your application can receive remote control
+	     * events by adding the code:
+	     *     [[UIApplication sharedApplication] 
+	     *      beginReceivingRemoteControlEvents];
+	     * Otherwise audio unit will fail to restart while your
+	     * application is in the background mode.
+	     */
+	    /* Make sure we set the correct audio category before restarting */
+	    audioCategory = kAudioSessionCategory_PlayAndRecord;
+	    ostatus = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
+					      sizeof(audioCategory),
+					      &audioCategory);
+	    if (ostatus != kAudioSessionNoError) {
+		PJ_LOG(4, (THIS_FILE,
+			   "Warning: cannot set the audio session category (%i)",
+			   ostatus));
+	    }
+	    
+	    /* Restart the stream */
+	    status = ca_stream_start((pjmedia_aud_stream*)it->stream);
+	    if (status != PJ_SUCCESS) {
+		PJ_LOG(3, (THIS_FILE,
+			   "Error: failed to restart the audio unit (%i)",
+			   status));
+		continue;
+	    }
+	    PJ_LOG(3, (THIS_FILE, "core audio unit successfully resumed"
+		       " after interruption"));
+	} else if (inInterruption == kAudioSessionBeginInterruption &&
+		   it->stream->running == PJ_TRUE)
+	{
+	    status = ca_stream_stop((pjmedia_aud_stream*)it->stream);
+	    it->stream->interrupted = PJ_TRUE;
+	}
+    }
+    pj_mutex_unlock(cf_instance->mutex);
+}
+
+#endif
+
+#if COREAUDIO_MAC
+/* Internal: create audio converter for resampling the recorder device */
+static pj_status_t create_audio_resample(struct coreaudio_stream     *strm,
+					 AudioStreamBasicDescription *desc)
+{
+    OSStatus ostatus;
+
+    pj_assert(strm->streamFormat.mSampleRate != desc->mSampleRate);
+    pj_assert(NULL == strm->resample);
+    pj_assert(NULL == strm->resample_buf);
+
+    /* Create the audio converter */
+    ostatus = AudioConverterNew(desc, &strm->streamFormat, &strm->resample);
+    if (ostatus != noErr) {
+	return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+    }
+    
+    /*
+     * Allocate the buffer required to hold enough input data
+     */
+    strm->resample_buf_size =  (unsigned)(desc->mSampleRate *
+					  strm->param.samples_per_frame /
+					  strm->param.clock_rate);
+    strm->resample_buf = (pj_int16_t*)
+			 pj_pool_alloc(strm->pool,
+				       strm->resample_buf_size *
+				       strm->param.bits_per_sample >> 3);
+    if (!strm->resample_buf)
+	return PJ_ENOMEM;
+    strm->resample_buf_count = 0;
+
+    return PJ_SUCCESS;
+}
+#endif
+
+/* Internal: create audio unit for recorder/playback device */
+static pj_status_t create_audio_unit(AudioComponent io_comp,
+				     AudioDeviceID dev_id,
+				     pjmedia_dir dir,
+				     struct coreaudio_stream *strm,
+				     AudioUnit *io_unit)
+{
+    OSStatus ostatus;
+#if !COREAUDIO_MAC
+    UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
+    /* We want to be able to open playback and recording streams */
+    ostatus = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,
+				      sizeof(audioCategory),
+				      &audioCategory);
+    if (ostatus != kAudioSessionNoError) {
+	PJ_LOG(4, (THIS_FILE,
+		   "Warning: cannot set the audio session category (%i)",
+		   ostatus));
+    }    
+#endif
+    
+    /* Create an audio unit to interface with the device */
+    ostatus = AudioComponentInstanceNew(io_comp, io_unit);
+    if (ostatus != noErr) {
+	return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+    }
+
+    /* Set audio unit's properties for capture device */
+    if (dir & PJMEDIA_DIR_CAPTURE) {
+	UInt32 enable = 1;
+
+	/* Enable input */
+	ostatus = AudioUnitSetProperty(*io_unit,
+	                               kAudioOutputUnitProperty_EnableIO,
+	                               kAudioUnitScope_Input,
+	                               1,
+	                               &enable,
+	                               sizeof(enable));
+	if (ostatus != noErr) {
+	    PJ_LOG(4, (THIS_FILE,
+		   "Warning: cannot enable IO of capture device %d",
+		   dev_id));
+	}
+
+	/* Disable output */
+	if (!(dir & PJMEDIA_DIR_PLAYBACK)) {
+	    enable = 0;
+	    ostatus = AudioUnitSetProperty(*io_unit,
+					   kAudioOutputUnitProperty_EnableIO,
+					   kAudioUnitScope_Output,
+					   0,
+					   &enable,
+					   sizeof(enable));
+	    if (ostatus != noErr) {
+		PJ_LOG(4, (THIS_FILE,
+		       "Warning: cannot disable IO of capture device %d",
+		       dev_id));
+	    }
+	}
+    }
+
+    /* Set audio unit's properties for playback device */
+    if (dir & PJMEDIA_DIR_PLAYBACK) {
+	UInt32 enable = 1;
+
+	/* Enable output */
+	ostatus = AudioUnitSetProperty(*io_unit,
+	                               kAudioOutputUnitProperty_EnableIO,
+	                               kAudioUnitScope_Output,
+	                               0,
+	                               &enable,
+	                               sizeof(enable));
+	if (ostatus != noErr) {
+	    PJ_LOG(4, (THIS_FILE,
+		   "Warning: cannot enable IO of playback device %d",
+		   dev_id));
+	}
+
+    }
+
+#if COREAUDIO_MAC
+    PJ_LOG(5, (THIS_FILE, "Opening device %d", dev_id));
+    ostatus = AudioUnitSetProperty(*io_unit,
+			           kAudioOutputUnitProperty_CurrentDevice,
+			           kAudioUnitScope_Global,
+			           0,
+			           &dev_id,
+			           sizeof(dev_id));
+    if (ostatus != noErr) {
+	return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+    }
+#endif
+
+    if (dir & PJMEDIA_DIR_CAPTURE) {
+#if COREAUDIO_MAC
+	AudioStreamBasicDescription deviceFormat;
+	UInt32 size;
+
+	/*
+	 * Keep the sample rate from the device, otherwise we will confuse
+	 * AUHAL
+	 */
+	size = sizeof(AudioStreamBasicDescription);
+	ostatus = AudioUnitGetProperty(*io_unit,
+				       kAudioUnitProperty_StreamFormat,
+				       kAudioUnitScope_Input,
+				       1,
+				       &deviceFormat,
+				       &size);
+	if (ostatus != noErr) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+	strm->streamFormat.mSampleRate = deviceFormat.mSampleRate;
+#endif
+
+	/* When setting the stream format, we have to make sure the sample
+	 * rate is supported. Setting an unsupported sample rate will cause
+	 * AudioUnitRender() to fail later.
+	 */
+	ostatus = AudioUnitSetProperty(*io_unit,
+				       kAudioUnitProperty_StreamFormat,
+				       kAudioUnitScope_Output,
+				       1,
+				       &strm->streamFormat,
+				       sizeof(strm->streamFormat));
+	if (ostatus != noErr) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+
+#if COREAUDIO_MAC
+	strm->streamFormat.mSampleRate = strm->param.clock_rate;
+	size = sizeof(AudioStreamBasicDescription);
+	ostatus = AudioUnitGetProperty (*io_unit,
+					kAudioUnitProperty_StreamFormat,
+					kAudioUnitScope_Output,
+					1,
+					&deviceFormat,
+					&size);
+	if (ostatus == noErr) {
+	    if (strm->streamFormat.mSampleRate != deviceFormat.mSampleRate) {
+		pj_status_t rc = create_audio_resample(strm, &deviceFormat);
+		if (PJ_SUCCESS != rc)
+		    return rc;
+	    }
+	} else {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+#endif
+    }
+
+    if (dir & PJMEDIA_DIR_PLAYBACK) {
+	AURenderCallbackStruct output_cb;
+
+	/* Set the stream format */
+	ostatus = AudioUnitSetProperty(*io_unit,
+	                               kAudioUnitProperty_StreamFormat,
+	                               kAudioUnitScope_Input,
+	                               0,
+	                               &strm->streamFormat,
+	                               sizeof(strm->streamFormat));
+	if (ostatus != noErr) {
+	    PJ_LOG(4, (THIS_FILE,
+		   "Warning: cannot set playback stream format of dev %d",
+		   dev_id));
+	}
+
+	/* Set render callback */
+	output_cb.inputProc = output_renderer;
+	output_cb.inputProcRefCon = strm;
+	ostatus = AudioUnitSetProperty(*io_unit,
+				       kAudioUnitProperty_SetRenderCallback,
+				       kAudioUnitScope_Input,
+				       0,
+				       &output_cb,
+				       sizeof(output_cb));
+	if (ostatus != noErr) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+
+	/* Allocate playback buffer */
+	strm->play_buf = (pj_int16_t*)pj_pool_alloc(strm->pool,
+			 strm->param.samples_per_frame *
+			 strm->param.bits_per_sample >> 3);
+	if (!strm->play_buf)
+	    return PJ_ENOMEM;
+	strm->play_buf_count = 0;
+    }
+
+    if (dir & PJMEDIA_DIR_CAPTURE) {
+	AURenderCallbackStruct input_cb;
+#if COREAUDIO_MAC
+	AudioBuffer *ab;
+	UInt32 size, buf_size;
+#endif
+
+	/* Set input callback */
+	input_cb.inputProc = strm->resample ? resample_callback :
+			     input_callback;
+	input_cb.inputProcRefCon = strm;
+	ostatus = AudioUnitSetProperty(
+		      *io_unit,
+		      kAudioOutputUnitProperty_SetInputCallback,
+		      kAudioUnitScope_Global,
+		      0,
+		      &input_cb,
+		      sizeof(input_cb));
+	if (ostatus != noErr) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+
+#if COREAUDIO_MAC
+	/* Get device's buffer frame size */
+	size = sizeof(UInt32);
+	ostatus = AudioUnitGetProperty(*io_unit,
+		                       kAudioDevicePropertyBufferFrameSize,
+		                       kAudioUnitScope_Global,
+		                       0,
+		                       &buf_size,
+		                       &size);
+	if (ostatus != noErr)
+	{
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+
+	/* Allocate audio buffer */
+	strm->audio_buf = (AudioBufferList*)pj_pool_alloc(strm->pool,
+		          sizeof(AudioBufferList) + sizeof(AudioBuffer));
+	if (!strm->audio_buf)
+	    return PJ_ENOMEM;
+
+	strm->audio_buf->mNumberBuffers = 1;
+	ab = &strm->audio_buf->mBuffers[0];
+	ab->mNumberChannels = strm->streamFormat.mChannelsPerFrame;
+	ab->mDataByteSize = buf_size * ab->mNumberChannels *
+			    strm->param.bits_per_sample >> 3;
+	ab->mData = pj_pool_alloc(strm->pool,
+				  ab->mDataByteSize);
+	if (!ab->mData)
+	    return PJ_ENOMEM;
+
+#else
+	/* We will let AudioUnitRender() to allocate the buffer
+	 * for us later
+	 */
+	strm->audio_buf = (AudioBufferList*)pj_pool_alloc(strm->pool,
+		          sizeof(AudioBufferList) + sizeof(AudioBuffer));
+	if (!strm->audio_buf)
+	    return PJ_ENOMEM;
+
+	strm->audio_buf->mNumberBuffers = 1;
+	strm->audio_buf->mBuffers[0].mNumberChannels =
+		strm->streamFormat.mChannelsPerFrame;
+	
+#endif
+
+	/* Allocate recording buffer */
+	strm->rec_buf = (pj_int16_t*)pj_pool_alloc(strm->pool,
+			strm->param.samples_per_frame *
+			strm->param.bits_per_sample >> 3);
+	if (!strm->rec_buf)
+	    return PJ_ENOMEM;
+	strm->rec_buf_count = 0;
+    }
+
+    /* Initialize the audio unit */
+    ostatus = AudioUnitInitialize(*io_unit);
+    if (ostatus != noErr) {
+ 	return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+    }
+
+    return PJ_SUCCESS;
+}
+
+/* API: create stream */
+static pj_status_t ca_factory_create_stream(pjmedia_aud_dev_factory *f,
+					    const pjmedia_aud_param *param,
+					    pjmedia_aud_rec_cb rec_cb,
+					    pjmedia_aud_play_cb play_cb,
+					    void *user_data,
+					    pjmedia_aud_stream **p_aud_strm)
+{
+    struct coreaudio_factory *cf = (struct coreaudio_factory*)f;
+    pj_pool_t *pool;
+    struct coreaudio_stream *strm;
+    pj_status_t status;
+
+    /* Create and Initialize stream descriptor */
+    pool = pj_pool_create(cf->pf, "coreaudio-dev", 1000, 1000, NULL);
+    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
+
+    strm = PJ_POOL_ZALLOC_T(pool, struct coreaudio_stream);
+    pj_list_init(&strm->list_entry);
+    strm->list_entry.stream = strm;
+    strm->cf = cf;
+    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;
+
+    /* Set the stream format */
+    strm->streamFormat.mSampleRate       = param->clock_rate;
+    strm->streamFormat.mFormatID         = kAudioFormatLinearPCM;
+    strm->streamFormat.mFormatFlags      = kLinearPCMFormatFlagIsSignedInteger
+  					   | kLinearPCMFormatFlagIsPacked;
+    strm->streamFormat.mBitsPerChannel   = strm->param.bits_per_sample;
+    strm->streamFormat.mChannelsPerFrame = param->channel_count;
+    strm->streamFormat.mBytesPerFrame    = strm->streamFormat.mChannelsPerFrame
+	                                   * strm->param.bits_per_sample >> 3;
+    strm->streamFormat.mFramesPerPacket  = 1;
+    strm->streamFormat.mBytesPerPacket   = strm->streamFormat.mBytesPerFrame *
+					   strm->streamFormat.mFramesPerPacket;
+
+    /* Apply input/output routes settings before we create the audio units */
+    if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE) {
+	ca_stream_set_cap(&strm->base,
+		          PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE,
+		          &param->input_route);
+    }
+    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE) {
+	ca_stream_set_cap(&strm->base,
+		          PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
+		          &param->output_route);
+    }
+    if (param->flags & PJMEDIA_AUD_DEV_CAP_EC) {
+	ca_stream_set_cap(&strm->base,
+		          PJMEDIA_AUD_DEV_CAP_EC,
+		          &param->ec_enabled);
+    } else {
+	pj_bool_t ec = PJ_FALSE;
+	ca_stream_set_cap(&strm->base,
+		          PJMEDIA_AUD_DEV_CAP_EC, &ec);
+    }
+
+    strm->io_units[0] = strm->io_units[1] = NULL;
+    if (param->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK &&
+	param->rec_id == param->play_id)
+    {
+	/* If both input and output are on the same device, only create
+	 * one audio unit to interface with the device.
+	 */
+	status = create_audio_unit(cf->io_comp,
+		                   cf->dev_info[param->rec_id].dev_id,
+		                   param->dir, strm, &strm->io_units[0]);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+    } else {
+	unsigned nunits = 0;
+
+	if (param->dir & PJMEDIA_DIR_CAPTURE) {
+	    status = create_audio_unit(cf->io_comp,
+				       cf->dev_info[param->rec_id].dev_id,
+				       PJMEDIA_DIR_CAPTURE,
+				       strm, &strm->io_units[nunits++]);
+	    if (status != PJ_SUCCESS)
+		goto on_error;
+	}
+	if (param->dir & PJMEDIA_DIR_PLAYBACK) {
+
+	    status = create_audio_unit(cf->io_comp,
+				       cf->dev_info[param->play_id].dev_id,
+				       PJMEDIA_DIR_PLAYBACK,
+				       strm, &strm->io_units[nunits++]);
+	    if (status != PJ_SUCCESS)
+		goto on_error;
+	}
+    }
+
+    /* Apply the remaining settings */
+    if (param->flags & PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY) {
+	ca_stream_get_cap(&strm->base,
+		          PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
+		          &strm->param.input_latency_ms);
+    }
+    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY) {
+	ca_stream_get_cap(&strm->base,
+		          PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
+		          &strm->param.output_latency_ms);
+    }
+    if (param->flags & PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) {
+	ca_stream_set_cap(&strm->base,
+		          PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
+		          &param->output_vol);
+    }
+
+    pj_mutex_lock(strm->cf->mutex);
+    pj_assert(pj_list_empty(&strm->list_entry));
+    pj_list_insert_after(&strm->cf->streams, &strm->list_entry);
+    pj_mutex_unlock(strm->cf->mutex);
+
+    /* Done */
+    strm->base.op = &stream_op;
+    *p_aud_strm = &strm->base;
+
+    return PJ_SUCCESS;
+
+ on_error:
+    ca_stream_destroy((pjmedia_aud_stream *)strm);
+    return status;
+}
+
+/* API: Get stream info. */
+static pj_status_t ca_stream_get_param(pjmedia_aud_stream *s,
+				       pjmedia_aud_param *pi)
+{
+    struct coreaudio_stream *strm = (struct coreaudio_stream*)s;
+
+    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
+
+    pj_memcpy(pi, &strm->param, sizeof(*pi));
+
+    /* Update the device capabilities' values */
+    if (ca_stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY,
+		          &pi->input_latency_ms) == PJ_SUCCESS)
+    {
+    	pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY;
+    }
+    if (ca_stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY,
+			  &pi->output_latency_ms) == PJ_SUCCESS)
+    {
+	pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY;
+    }
+    if (ca_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;
+    }
+    if (ca_stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE,
+			  &pi->input_route) == PJ_SUCCESS)
+    {
+        pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE;
+    }
+    if (ca_stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
+			  &pi->output_route) == PJ_SUCCESS)
+    {
+        pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE;
+    }
+    if (ca_stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_EC,
+			  &pi->ec_enabled) == PJ_SUCCESS)
+    {
+        pi->flags |= PJMEDIA_AUD_DEV_CAP_EC;
+    }
+
+    return PJ_SUCCESS;
+}
+
+/* API: get capability */
+static pj_status_t ca_stream_get_cap(pjmedia_aud_stream *s,
+				     pjmedia_aud_dev_cap cap,
+				     void *pval)
+{
+    struct coreaudio_stream *strm = (struct coreaudio_stream*)s;
+
+    PJ_UNUSED_ARG(strm);
+
+    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
+
+    if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY &&
+	(strm->param.dir & PJMEDIA_DIR_CAPTURE))
+    {
+#if COREAUDIO_MAC
+	UInt32 latency, size = sizeof(UInt32);
+
+	/* Recording latency */
+	if (AudioUnitGetProperty (strm->io_units[0],
+				  kAudioDevicePropertyLatency,
+				  kAudioUnitScope_Input,
+				  1,
+				  &latency,
+				  &size) == noErr)
+	{
+	    UInt32 latency2;
+	    if (AudioUnitGetProperty (strm->io_units[0],
+				      kAudioDevicePropertyBufferFrameSize,
+				      kAudioUnitScope_Input,
+				      1,
+				      &latency2,
+				      &size) == noErr)
+	    {
+		strm->param.input_latency_ms = (latency + latency2) * 1000 /
+					       strm->param.clock_rate;
+		strm->param.input_latency_ms++;
+	    }
+	}
+#else
+	Float32 latency, latency2;
+	UInt32 size = sizeof(Float32);
+
+	if ((AudioSessionGetProperty(
+	    kAudioSessionProperty_CurrentHardwareInputLatency,
+	    &size, &latency) == kAudioSessionNoError) &&
+	    (AudioSessionGetProperty(
+	    kAudioSessionProperty_CurrentHardwareIOBufferDuration,
+	    &size, &latency2) == kAudioSessionNoError))
+	{
+	    strm->param.input_latency_ms = (unsigned)
+					   ((latency + latency2) * 1000);
+	    strm->param.input_latency_ms++;
+	}
+#endif
+
+	*(unsigned*)pval = strm->param.input_latency_ms;
+	return PJ_SUCCESS;
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY  &&
+	       (strm->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+#if COREAUDIO_MAC
+	UInt32 latency, size = sizeof(UInt32);
+	AudioUnit *io_unit = strm->io_units[1] ? &strm->io_units[1] :
+			     &strm->io_units[0];
+
+	/* Playback latency */
+	if (AudioUnitGetProperty (*io_unit,
+				  kAudioDevicePropertyLatency,
+				  kAudioUnitScope_Output,
+				  0,
+				  &latency,
+				  &size) == noErr)
+	{
+	    UInt32 latency2;
+	    if (AudioUnitGetProperty (*io_unit,
+				      kAudioDevicePropertyBufferFrameSize,
+				      kAudioUnitScope_Output,
+				      0,
+				      &latency2,
+				      &size) == noErr)
+	    {
+		strm->param.output_latency_ms = (latency + latency2) * 1000 /
+						strm->param.clock_rate;
+		strm->param.output_latency_ms++;
+	    }
+	}
+#else
+	Float32 latency, latency2;
+	UInt32 size = sizeof(Float32);
+
+	if ((AudioSessionGetProperty(
+	    kAudioSessionProperty_CurrentHardwareOutputLatency,
+	    &size, &latency) == kAudioSessionNoError) &&
+	    (AudioSessionGetProperty(
+	    kAudioSessionProperty_CurrentHardwareIOBufferDuration,
+	    &size, &latency2) == kAudioSessionNoError))
+	{
+	    strm->param.output_latency_ms = (unsigned)
+					    ((latency + latency2) * 1000);
+	    strm->param.output_latency_ms++;
+	}
+#endif
+	*(unsigned*)pval = (++strm->param.output_latency_ms * 2);
+	return PJ_SUCCESS;
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING &&
+	       (strm->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+	OSStatus ostatus;
+	Float32 volume;
+	UInt32 size = sizeof(Float32);
+
+	/* Output volume setting */
+#if COREAUDIO_MAC
+	ostatus = AudioUnitGetProperty (strm->io_units[1] ? strm->io_units[1] :
+					strm->io_units[0],
+					kAudioDevicePropertyVolumeScalar,
+	                                kAudioUnitScope_Output,
+	                                0,
+	                                &volume,
+	                                &size);
+	if (ostatus != noErr)
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+#else
+	ostatus = AudioSessionGetProperty(
+		  kAudioSessionProperty_CurrentHardwareOutputVolume,
+		  &size, &volume);
+	if (ostatus != kAudioSessionNoError) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+#endif
+
+	*(unsigned*)pval = (unsigned)(volume * 100);
+	return PJ_SUCCESS;
+#if !COREAUDIO_MAC
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE &&
+	       (strm->param.dir & PJMEDIA_DIR_CAPTURE))
+    {
+	UInt32 btooth, size = sizeof(UInt32);
+	OSStatus ostatus;
+
+	ostatus = AudioSessionGetProperty (
+	    kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,
+	    &size, &btooth);
+	if (ostatus != kAudioSessionNoError) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+
+	*(pjmedia_aud_dev_route*)pval = btooth?
+		                        PJMEDIA_AUD_DEV_ROUTE_BLUETOOTH:
+					PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
+	return PJ_SUCCESS;
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE &&
+	       (strm->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+	CFStringRef route;
+	UInt32 size = sizeof(CFStringRef);
+	OSStatus ostatus;
+
+	ostatus = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
+					   &size, &route);
+	if (ostatus != kAudioSessionNoError) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+
+	if (!route) {
+	    *(pjmedia_aud_dev_route*)pval = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
+	} else if (CFStringHasPrefix(route, CFSTR("Headset"))) {
+	    *(pjmedia_aud_dev_route*)pval = PJMEDIA_AUD_DEV_ROUTE_EARPIECE;
+	} else {
+	    *(pjmedia_aud_dev_route*)pval = PJMEDIA_AUD_DEV_ROUTE_DEFAULT;
+	}
+
+	CFRelease(route);
+
+	return PJ_SUCCESS;
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_EC) {
+	AudioComponentDescription desc;
+	OSStatus ostatus;
+
+	ostatus = AudioComponentGetDescription(strm->cf->io_comp, &desc);
+	if (ostatus != noErr) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+
+	*(pj_bool_t*)pval = (desc.componentSubType ==
+		            kAudioUnitSubType_VoiceProcessingIO);
+	return PJ_SUCCESS;
+#endif
+    } else {
+	return PJMEDIA_EAUD_INVCAP;
+    }
+}
+
+/* API: set capability */
+static pj_status_t ca_stream_set_cap(pjmedia_aud_stream *s,
+				     pjmedia_aud_dev_cap cap,
+				     const void *pval)
+{
+    struct coreaudio_stream *strm = (struct coreaudio_stream*)s;
+
+    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
+
+#if COREAUDIO_MAC
+    if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING &&
+	(strm->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+	OSStatus ostatus;
+	Float32 volume = *(unsigned*)pval;
+
+	/* Output volume setting */
+	volume /= 100.0;
+	ostatus = AudioUnitSetProperty (strm->io_units[1] ? strm->io_units[1] :
+					strm->io_units[0],
+					kAudioDevicePropertyVolumeScalar,
+	                                kAudioUnitScope_Output,
+	                                0,
+	                                &volume,
+	                                sizeof(Float32));
+	if (ostatus != noErr) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+	strm->param.output_vol = *(unsigned*)pval;
+	return PJ_SUCCESS;
+    }
+
+#else
+
+    if ((cap==PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY &&
+	 (strm->param.dir & PJMEDIA_DIR_CAPTURE)) ||
+	(cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY &&
+	 (strm->param.dir & PJMEDIA_DIR_PLAYBACK)))
+    {
+	Float32 bufferDuration = *(unsigned *)pval;
+	OSStatus ostatus;
+	unsigned latency;
+	
+	/* For low-latency audio streaming, you can set this value to
+	 * as low as 5 ms (the default is 23ms). However, lowering the
+	 * latency may cause a decrease in audio quality.
+	 */
+	bufferDuration /= 1000;
+	ostatus = AudioSessionSetProperty(
+		      kAudioSessionProperty_PreferredHardwareIOBufferDuration,
+		      sizeof(bufferDuration), &bufferDuration);
+	if (ostatus != kAudioSessionNoError) {
+	    PJ_LOG(4, (THIS_FILE,
+		       "Error: cannot set the preferred buffer duration (%i)",
+		       ostatus));
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+	
+	ca_stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY, &latency);
+	ca_stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY, &latency);
+	
+	return PJ_SUCCESS;
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_ROUTE &&
+	       (strm->param.dir & PJMEDIA_DIR_CAPTURE))
+    {
+	UInt32 btooth = *(pjmedia_aud_dev_route*)pval ==
+		        PJMEDIA_AUD_DEV_ROUTE_BLUETOOTH ? 1 : 0;
+	OSStatus ostatus;
+
+	ostatus = AudioSessionSetProperty (
+	    kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,
+	    sizeof(btooth), &btooth);
+	if (ostatus != kAudioSessionNoError) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+	strm->param.input_route = *(pjmedia_aud_dev_route*)pval;
+	return PJ_SUCCESS;
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE &&
+	       (strm->param.dir & PJMEDIA_DIR_PLAYBACK))
+    {
+	OSStatus ostatus;
+	UInt32 route = *(pjmedia_aud_dev_route*)pval ==
+		       PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER ?
+		       kAudioSessionOverrideAudioRoute_Speaker :
+		       kAudioSessionOverrideAudioRoute_None;
+
+	ostatus = AudioSessionSetProperty (
+	    kAudioSessionProperty_OverrideAudioRoute,
+	    sizeof(route), &route);
+	if (ostatus != kAudioSessionNoError) {
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+	strm->param.output_route = *(pjmedia_aud_dev_route*)pval;
+	return PJ_SUCCESS;
+    } else if (cap==PJMEDIA_AUD_DEV_CAP_EC) {
+	AudioComponentDescription desc;
+	AudioComponent io_comp;
+
+	desc.componentType = kAudioUnitType_Output;
+	desc.componentSubType = (*(pj_bool_t*)pval)?
+				kAudioUnitSubType_VoiceProcessingIO :
+				kAudioUnitSubType_RemoteIO;
+	desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+	desc.componentFlags = 0;
+	desc.componentFlagsMask = 0;
+
+	io_comp = AudioComponentFindNext(NULL, &desc);
+	if (io_comp == NULL)
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(-1);
+	strm->cf->io_comp = io_comp;
+	strm->param.ec_enabled = *(pj_bool_t*)pval;
+
+        PJ_LOG(4, (THIS_FILE, "Using %s audio unit", 
+                              (desc.componentSubType ==
+                               kAudioUnitSubType_RemoteIO? "RemoteIO":
+                               "VoiceProcessingIO")));
+        
+	return PJ_SUCCESS;
+    }
+#endif
+
+    return PJMEDIA_EAUD_INVCAP;
+}
+
+/* API: Start stream. */
+static pj_status_t ca_stream_start(pjmedia_aud_stream *strm)
+{
+    struct coreaudio_stream *stream = (struct coreaudio_stream*)strm;
+    OSStatus ostatus;
+    UInt32 i;
+
+    if (stream->running)
+	return PJ_SUCCESS;
+
+    stream->quit_flag = 0;
+    stream->interrupted = PJ_FALSE;
+    stream->rec_buf_count = 0;
+    stream->play_buf_count = 0;
+    stream->resample_buf_count = 0;
+
+    if (stream->resample) {
+	ostatus = AudioConverterReset(stream->resample);
+	if (ostatus != noErr)
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+    }
+
+#if !COREAUDIO_MAC
+    AudioSessionSetActive(true);
+#endif
+    
+    for (i = 0; i < 2; i++) {
+	if (stream->io_units[i] == NULL) break;
+	ostatus = AudioOutputUnitStart(stream->io_units[i]);
+	if (ostatus != noErr) {
+	    if (i == 1)
+		AudioOutputUnitStop(stream->io_units[0]);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+    }
+
+    stream->running = PJ_TRUE;
+
+    PJ_LOG(4, (THIS_FILE, "core audio stream started"));
+
+    return PJ_SUCCESS;
+}
+
+/* API: Stop stream. */
+static pj_status_t ca_stream_stop(pjmedia_aud_stream *strm)
+{
+    struct coreaudio_stream *stream = (struct coreaudio_stream*)strm;
+    OSStatus ostatus;
+    unsigned i;
+    int should_deactivate;
+    struct stream_list *it, *itBegin;
+
+    if (!stream->running)
+	return PJ_SUCCESS;
+
+    for (i = 0; i < 2; i++) {
+	if (stream->io_units[i] == NULL) break;
+	ostatus = AudioOutputUnitStop(stream->io_units[i]);
+	if (ostatus != noErr) {
+	    if (i == 0 && stream->io_units[1])
+		AudioOutputUnitStop(stream->io_units[1]);
+	    return PJMEDIA_AUDIODEV_ERRNO_FROM_COREAUDIO(ostatus);
+	}
+    }
+
+    /* Check whether we need to deactivate the audio session. */
+    pj_mutex_lock(stream->cf->mutex);
+    pj_assert(!pj_list_empty(&stream->cf->streams));
+    pj_assert(!pj_list_empty(&stream->list_entry));
+    stream->running = PJ_FALSE;
+    should_deactivate = PJ_TRUE;
+    itBegin = &stream->cf->streams;
+    for (it = itBegin->next; it != itBegin; it = it->next) {
+	if (it->stream->running) {
+	    should_deactivate = PJ_FALSE;
+	    break;
+	}
+    }
+    pj_mutex_unlock(stream->cf->mutex);
+
+#if !COREAUDIO_MAC
+    if (should_deactivate)
+	AudioSessionSetActive(false);
+#endif
+
+    stream->quit_flag = 1;
+    stream->play_thread_initialized = 0;
+    stream->rec_thread_initialized = 0;
+    pj_bzero(stream->rec_thread_desc, sizeof(pj_thread_desc));
+    pj_bzero(stream->play_thread_desc, sizeof(pj_thread_desc));
+
+    PJ_LOG(4, (THIS_FILE, "core audio stream stopped"));
+
+    return PJ_SUCCESS;
+}
+
+
+/* API: Destroy stream. */
+static pj_status_t ca_stream_destroy(pjmedia_aud_stream *strm)
+{
+    struct coreaudio_stream *stream = (struct coreaudio_stream*)strm;
+    unsigned i;
+
+    PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL);
+
+    ca_stream_stop(strm);
+
+    for (i = 0; i < 2; i++) {
+	if (stream->io_units[i]) {
+	    AudioUnitUninitialize(stream->io_units[i]);
+	    AudioComponentInstanceDispose(stream->io_units[i]);
+	    stream->io_units[i] = NULL;
+	}
+    }
+
+    if (stream->resample)
+	AudioConverterDispose(stream->resample);
+
+    pj_mutex_lock(stream->cf->mutex);
+    if (!pj_list_empty(&stream->list_entry))
+	pj_list_erase(&stream->list_entry);
+    pj_mutex_unlock(stream->cf->mutex);
+
+    pj_pool_release(stream->pool);
+
+    return PJ_SUCCESS;
+}
+
+#endif	/* PJMEDIA_AUDIO_DEV_HAS_COREAUDIO */
diff --git a/jni/pjproject-android/.svn/pristine/ad/ad7b4ac1916178ae5dea50d0869d867971c6ca94.svn-base b/jni/pjproject-android/.svn/pristine/ad/ad7b4ac1916178ae5dea50d0869d867971c6ca94.svn-base
new file mode 100644
index 0000000..6428d97
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ad/ad7b4ac1916178ae5dea50d0869d867971c6ca94.svn-base
@@ -0,0 +1,298 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjnath/stun_msg.h>
+#include <pjnath/errno.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+#include <pj/string.h>
+
+#if PJ_LOG_MAX_LEVEL > 0
+
+
+#define APPLY()		if (len < 1 || len >= (end-p)) \
+			    goto on_return; \
+			p += len
+
+static int print_binary(char *buffer, unsigned length,
+			const pj_uint8_t *data, unsigned data_len)
+{
+    unsigned i;
+
+    if (length < data_len * 2 + 8)
+	return -1;
+
+    pj_ansi_sprintf(buffer, ", data=");
+    buffer += 7;
+
+    for (i=0; i<data_len; ++i) {
+	pj_ansi_sprintf(buffer, "%02x", (*data) & 0xFF);
+	buffer += 2;
+	data++;
+    }
+
+    pj_ansi_sprintf(buffer, "\n");
+    buffer++;
+
+    return data_len * 2 + 8;
+}
+
+static int print_attr(char *buffer, unsigned length,
+		      const pj_stun_attr_hdr *ahdr)
+{
+    char *p = buffer, *end = buffer + length;
+    const char *attr_name = pj_stun_get_attr_name(ahdr->type);
+    char attr_buf[32];
+    int len;
+
+    if (*attr_name == '?') {
+	pj_ansi_snprintf(attr_buf, sizeof(attr_buf), "Attr 0x%x", 
+			 ahdr->type);
+	attr_name = attr_buf;
+    }
+
+    len = pj_ansi_snprintf(p, end-p,
+			   "  %s: length=%d",
+			   attr_name,
+			   (int)ahdr->length);
+    APPLY();
+
+
+    switch (ahdr->type) {
+    case PJ_STUN_ATTR_MAPPED_ADDR:
+    case PJ_STUN_ATTR_RESPONSE_ADDR:
+    case PJ_STUN_ATTR_SOURCE_ADDR:
+    case PJ_STUN_ATTR_CHANGED_ADDR:
+    case PJ_STUN_ATTR_REFLECTED_FROM:
+    case PJ_STUN_ATTR_XOR_PEER_ADDR:
+    case PJ_STUN_ATTR_XOR_RELAYED_ADDR:
+    case PJ_STUN_ATTR_XOR_MAPPED_ADDR:
+    case PJ_STUN_ATTR_XOR_REFLECTED_FROM:
+    case PJ_STUN_ATTR_ALTERNATE_SERVER:
+	{
+	    const pj_stun_sockaddr_attr *attr;
+
+	    attr = (const pj_stun_sockaddr_attr*)ahdr;
+
+	    if (attr->sockaddr.addr.sa_family == pj_AF_INET()) {
+		len = pj_ansi_snprintf(p, end-p,
+				       ", IPv4 addr=%s:%d\n",
+				       pj_inet_ntoa(attr->sockaddr.ipv4.sin_addr),
+				       pj_ntohs(attr->sockaddr.ipv4.sin_port));
+
+	    } else if (attr->sockaddr.addr.sa_family == pj_AF_INET6()) {
+		len = pj_ansi_snprintf(p, end-p,
+				       ", IPv6 addr present\n");
+	    } else {
+		len = pj_ansi_snprintf(p, end-p,
+				       ", INVALID ADDRESS FAMILY!\n");
+	    }
+	    APPLY();
+	}
+	break;
+
+    case PJ_STUN_ATTR_CHANNEL_NUMBER:
+	{
+	    const pj_stun_uint_attr *attr;
+
+	    attr = (const pj_stun_uint_attr*)ahdr;
+	    len = pj_ansi_snprintf(p, end-p,
+				   ", chnum=%u (0x%x)\n",
+				   (int)PJ_STUN_GET_CH_NB(attr->value),
+				   (int)PJ_STUN_GET_CH_NB(attr->value));
+	    APPLY();
+	}
+	break;
+
+    case PJ_STUN_ATTR_CHANGE_REQUEST:
+    case PJ_STUN_ATTR_LIFETIME:
+    case PJ_STUN_ATTR_BANDWIDTH:
+    case PJ_STUN_ATTR_REQ_ADDR_TYPE:
+    case PJ_STUN_ATTR_EVEN_PORT:
+    case PJ_STUN_ATTR_REQ_TRANSPORT:
+    case PJ_STUN_ATTR_TIMER_VAL:
+    case PJ_STUN_ATTR_PRIORITY:
+    case PJ_STUN_ATTR_FINGERPRINT:
+    case PJ_STUN_ATTR_REFRESH_INTERVAL:
+    case PJ_STUN_ATTR_ICMP:
+	{
+	    const pj_stun_uint_attr *attr;
+
+	    attr = (const pj_stun_uint_attr*)ahdr;
+	    len = pj_ansi_snprintf(p, end-p,
+				   ", value=%u (0x%x)\n",
+				   (pj_uint32_t)attr->value,
+				   (pj_uint32_t)attr->value);
+	    APPLY();
+	}
+	break;
+
+    case PJ_STUN_ATTR_USERNAME:
+    case PJ_STUN_ATTR_PASSWORD:
+    case PJ_STUN_ATTR_REALM:
+    case PJ_STUN_ATTR_NONCE:
+    case PJ_STUN_ATTR_SOFTWARE:
+	{
+	    const pj_stun_string_attr *attr;
+
+	    attr = (pj_stun_string_attr*)ahdr;
+	    len = pj_ansi_snprintf(p, end-p,
+				   ", value=\"%.*s\"\n",
+				   (int)attr->value.slen,
+				   attr->value.ptr);
+	    APPLY();
+	}
+	break;
+
+    case PJ_STUN_ATTR_ERROR_CODE:
+	{
+	    const pj_stun_errcode_attr *attr;
+
+	    attr = (const pj_stun_errcode_attr*) ahdr;
+	    len = pj_ansi_snprintf(p, end-p,
+				   ", err_code=%d, reason=\"%.*s\"\n",
+				   attr->err_code,
+				   (int)attr->reason.slen,
+				   attr->reason.ptr);
+	    APPLY();
+	}
+	break;
+
+    case PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES:
+	{
+	    const pj_stun_unknown_attr *attr;
+	    unsigned j;
+
+	    attr = (const pj_stun_unknown_attr*) ahdr;
+
+	    len = pj_ansi_snprintf(p, end-p,
+				   ", unknown list:");
+	    APPLY();
+
+	    for (j=0; j<attr->attr_count; ++j) {
+		len = pj_ansi_snprintf(p, end-p,
+				       " %d",
+				       (int)attr->attrs[j]);
+		APPLY();
+	    }
+	}
+	break;
+
+    case PJ_STUN_ATTR_MESSAGE_INTEGRITY:
+	{
+	    const pj_stun_msgint_attr *attr;
+
+	    attr = (const pj_stun_msgint_attr*) ahdr;
+	    len = print_binary(p, (unsigned)(end-p), attr->hmac, 20);
+	    APPLY();
+	}
+	break;
+
+    case PJ_STUN_ATTR_DATA:
+	{
+	    const pj_stun_binary_attr *attr;
+
+	    attr = (const pj_stun_binary_attr*) ahdr;
+	    len = print_binary(p, (unsigned)(end-p), attr->data, attr->length);
+	    APPLY();
+	}
+	break;
+    case PJ_STUN_ATTR_ICE_CONTROLLED:
+    case PJ_STUN_ATTR_ICE_CONTROLLING:
+    case PJ_STUN_ATTR_RESERVATION_TOKEN:
+	{
+	    const pj_stun_uint64_attr *attr;
+	    pj_uint8_t data[8];
+	    int i;
+
+	    attr = (const pj_stun_uint64_attr*) ahdr;
+
+	    for (i=0; i<8; ++i)
+		data[i] = ((const pj_uint8_t*)&attr->value)[7-i];
+
+	    len = print_binary(p, (unsigned)(end-p), data, 8);
+	    APPLY();
+	}
+	break;
+    case PJ_STUN_ATTR_USE_CANDIDATE:
+    case PJ_STUN_ATTR_DONT_FRAGMENT:
+    default:
+	len = pj_ansi_snprintf(p, end-p, "\n");
+	APPLY();
+	break;
+    }
+
+    return (int)(p-buffer);
+
+on_return:
+    return len;
+}
+
+
+/*
+ * Dump STUN message to a printable string output.
+ */
+PJ_DEF(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
+			       char *buffer,
+			       unsigned length,
+			       unsigned *printed_len)
+{
+    char *p, *end;
+    int len;
+    unsigned i;
+
+    PJ_ASSERT_RETURN(msg && buffer && length, NULL);
+
+    PJ_CHECK_STACK();
+    
+    p = buffer;
+    end = buffer + length;
+
+    len = pj_ansi_snprintf(p, end-p, "STUN %s %s\n",
+			   pj_stun_get_method_name(msg->hdr.type),
+			   pj_stun_get_class_name(msg->hdr.type));
+    APPLY();
+
+    len = pj_ansi_snprintf(p, end-p, 
+			   " Hdr: length=%d, magic=%08x, tsx_id=%08x%08x%08x\n"
+			   " Attributes:\n",
+			   msg->hdr.length,
+			   msg->hdr.magic,
+			   *(pj_uint32_t*)&msg->hdr.tsx_id[0],
+			   *(pj_uint32_t*)&msg->hdr.tsx_id[4],
+			   *(pj_uint32_t*)&msg->hdr.tsx_id[8]);
+    APPLY();
+
+    for (i=0; i<msg->attr_count; ++i) {
+	len = print_attr(p, (unsigned)(end-p), msg->attr[i]);
+	APPLY();
+    }
+
+on_return:
+    *p = '\0';
+    if (printed_len)
+	*printed_len = (unsigned)(p-buffer);
+    return buffer;
+
+#undef APPLY
+}
+
+
+#endif	/* PJ_LOG_MAX_LEVEL > 0 */
+
diff --git a/jni/pjproject-android/.svn/pristine/ad/ad90a2706a74f2155fe59e9a2fea062e86e81447.svn-base b/jni/pjproject-android/.svn/pristine/ad/ad90a2706a74f2155fe59e9a2fea062e86e81447.svn-base
new file mode 100644
index 0000000..bc45da8
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ad/ad90a2706a74f2155fe59e9a2fea062e86e81447.svn-base
@@ -0,0 +1,964 @@
+ Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+
+ This program is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 2 of the License, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see http://www.gnu.org/licenses/.
+
+
+Getting Started: Building and Using PJSIP and PJMEDIA
+
+   [Last Update: $Date: 2007-02-02 20:42:44 +0000 (Fri, 02 Feb 2007) $]
+
+                                                   Print Friendly Page
+     _________________________________________________________________
+
+   This article describes how to download, customize, build, and use the open
+   source PJSIP and PJMEDIA SIP and media stack. The online (and HTML) version
+   of this file can be downloaded from http://www.pjsip.org/using.htm
+
+
+Quick Info
+     _________________________________________________________________
+
+   Building with GNU tools (Linux, *BSD, MacOS X, mingw, etc.)
+          Generally these should be all that are needed to build the libraries,
+          applications, and samples:
+
+   $ ./configure
+   $ make dep && make clean && make
+
+   Building Win32 Target with Microsoft Visual Studio
+          Generally we can just do these steps:
+
+         1. Visual Studio 6: open pjproject.dsw workspace,
+         2. Visual Studio 2005: open pjproject-vs8.sln solution,
+         3. Create an empty pjlib/include/pj/config_site.h, and
+         4. build the pjsua application.
+
+   Building for Windows Mobile
+          Generally these are all that are needed:
+
+         1. Open pjsip-apps/build/wince-evc4/wince_demos.vcw EVC4 workspace,
+         2. Create an empty pjlib/include/pj/config_site.h, and
+         3. build the pjsua_wince application.
+
+   Invoking Older Build System (e.g. for RTEMS)
+          Generally these should be all that are needed to build the libraries,
+          applications, and samples:
+
+   $ ./configure-legacy
+   $ make dep && make clean && make
+
+   Locating Output Binaries/Libraries
+          Libraries will be put in lib directory, and binaries will be put in
+          bin directory, under each projects.
+
+   Running the Applications
+          After successful build, you can try running pjsua application on
+          pjsip-apps/bin   directory.   PJSUA  manual  can  be  found  in
+          http://www.pjsip.org/pjsua.htm page.
+
+
+Table of Contents:
+     _________________________________________________________________
+
+   1. Getting the Source Distribution
+
+     1.1 Getting the Release tarball
+
+     1.2 Getting from Subversion trunk
+
+     1.3 Source Directories Layout
+
+   2. Build Preparation
+
+     2.1 config_site.h file
+
+     2.2 Disk Space Requirements
+
+   3.  Building Linux, *nix, *BSD, and MacOS X Targets with GNU Build
+   Systems
+
+     3.1 Supported Targets
+
+     3.2 Requirements
+
+     3.3 Running configure
+
+     3.4 Running make
+
+     3.5 Cross Compilation
+
+     3.6 Build Customizations
+
+   4. Building for Windows Targets with Microsoft Visual Studio
+
+     4.1 Requirements
+
+     4.2 Building the Projects
+
+     4.3 Debugging the Sample Application
+
+   5. Building for Windows Mobile Targets (Windows CE/WinCE/PDA/SmartPhone)
+
+     5.1 Requirements
+
+     5.2 Building the Projects
+
+   6. Older PJLIB Build System for Non-Autoconf Targets (e.g. RTEMS)
+
+     6.1 Supported Targets
+
+     6.2 Invoking the Build System
+
+   7. Running the Applications
+
+     7.1 pjsua
+
+     7.2 Sample Applications
+
+     7.3 pjlib-test
+
+     7.4 pjsip-test
+
+   8. Using PJPROJECT with Applications
+
+
+   Appendix I: Common Problems/Frequently Asked Question (FAQ)
+
+     I.1 fatal error C1083: Cannot open include file: 'pj/config_site.h':
+   No such file or directory
+
+
+1. Getting the Source Code Distribution
+     _________________________________________________________________
+
+   All libraries (PJLIB, PJLIB-UTIL, PJSIP, PJMEDIA, and PJMEDIA-CODEC) are
+   currently distributed under a single source tree, collectively named as
+   PJPROJECT or just PJ libraries. These libraries can be obtained by either
+   downloading the release tarball or getting them from the Subversion trunk.
+
+
+1.1 Getting the Release tarball
+     _________________________________________________________________
+
+   Getting the released tarball is a convenient way to obtain stable version of
+   PJPROJECT. The tarball may not contain the latest features or bug-fixes, but
+   normally it is considered more stable as each will be tested more rigorously
+   before released.
+
+   The   latest   released   tarball   can   be   downloaded   from   the
+   http://www.pjsip.org/download.htm.
+
+
+1.2 Getting from Subversion trunk
+     _________________________________________________________________
+
+   PJPROJECT  Subversion  repository  will always contain the latest/most
+   up-to-date version of the sources. Normally the Subversion repository is
+   always kept in a "good" state. However, there's always a chance that things
+   break  and  the  tree  doesn't  build  correctly (particularly for the
+   "not-so-popular" targets), so please consult the mailing list should there
+   be any problems.
+
+   Using Subversion also has benefits of keeping the local copy of the source
+   up to date with the main PJ source tree and to easily track the changes made
+   to the local copy, if any.
+
+
+What is Subversion
+
+   Subversion (SVN) is Open Source version control system similar to CVS.
+   Subversion homepage is in http://subversion.tigris.org/
+
+
+Getting Subversion Client
+
+   A Subversion (SVN) client is needed to download the PJ source files from
+   pjsip.org  SVN  tree.  SVN  client  binaries  can  be  downloaded from
+   http://subversion.tigris.org/, and the program should be available for
+   Windows, Linux, MacOS X, and many more platforms.
+
+
+Getting the Source for The First Time
+
+   Once Subversion client is installed, we can use these commands to initially
+   retrieve the latest sources from the Subversion trunk:
+
+
+
+   $ svn co http://svn.pjproject.net/repos/pjproject/trunk pjproject
+   $ cd pjproject
+
+
+Keeping The Local Copy Up-to-Date
+
+   Once sources have been downloaded, we can keep the local copy up to date by
+   periodically synchronizing the local source with the latest revision from
+   the  PJ's  Subversion  trunk. The mailing list provides best source of
+   information about the availability of new updates in the trunk.
+
+   To  update  the  local  copy  with the latest changes in the main PJ's
+   repository:
+
+
+
+   $ cd pjproject
+   $ svn update
+
+
+Tracking Local and Remote Changes
+
+   To see what files have been changed locally:
+
+
+
+   $ cd pjproject
+   $ svn status
+
+   The above command only compares local file against the original local copy,
+   so it doesn't require Internet connection while performing the check.
+
+   To see both what files have been changed locally and what files have been
+   updated in the PJ's Subversion repository:
+
+
+
+   $ cd pjproject
+   $ svn status -u
+
+   Note that this command requires active Internet connection to query the
+   status of PJPROJECT's source repository.
+
+
+1.3 Source Directories Layout
+     _________________________________________________________________
+
+Top-Level Directory Layout
+
+   The top-level directories (denoted as $TOP here) in the source distribution
+   contains the following sub-directories:
+
+   $TOP/build
+          Contains makefiles that are common for all projects.
+
+   $TOP/pjlib
+          Contains  header  and  source files of PJLIB. PJLIB is the base
+          portability  and  framework  library which is used by all other
+          libraries
+
+   $TOP/pjlib-util
+          Contains  PJLIB-UTIL  header and source files. PJLIB-UTIL is an
+          auxiliary library that contains utility functions such as scanner,
+          XML, STUN, MD5 algorithm, getopt() implementation, etc.
+
+   $TOP/pjmedia
+          Contains PJMEDIA and PJMEDIA-CODEC header and source files. The
+          sources of various codecs (such as GSM, Speex, and iLBC) can be found
+          under this directory.
+
+   $TOP/pjsip
+          Contains PJSIP header and source files.
+
+   $TOP/pjsip-apps
+          Contains source code for PJSUA and various sample applications.
+
+
+Individual Directory Inside Each Project
+
+   Each library directory further contains these sub-directories:
+
+   bin
+          Contains binaries produced by the build process.
+
+   build
+          Contains build scripts/makefiles, project files, project workspace,
+          etc. to build the project. In particular, it contains one Makefile
+          file  to  build the project with GNU build systems, and a *.dsw
+          workspace file to build the library with Microsoft Visual Studio 6 or
+          later.
+
+   build/output
+          The build/output directory contains the object files and other files
+          generated by the build process. To support building multiple targets
+          with a single source tree, each build target will occupy a different
+          subdirectory under this directory.
+
+   build/wince-evc4
+          This directory contains the project/workspace files to build Windows
+          CE/WinCE version of the project using Microsoft Embedded Visual C++
+          4.
+
+   build/wince-evc4/output
+          This directory contains the library, executable, and object files
+          generated by Windows Mobile build process.
+
+   docs
+          Contains Doxygen configuration file (doxygen.cfg) to generate online
+          documentation from the source files. The output documentation will be
+          put in this directory as well (for example, docs/html directory for
+          the HTML files).
+
+          (to generate Doxygen documentation from the source tree, just run
+          "doxygen docs/doxygen.cfg" in the individual project directory. The
+          generated files will reside in docs directory).
+
+   include
+          Contains the header files for the project.
+
+   lib
+          Contains libraries produced by the build process.
+
+   src
+          Contains the source files of the project.
+
+
+2. Build Preparation
+     _________________________________________________________________
+
+2.1 Create config_site.h file
+     _________________________________________________________________
+
+   Before source files can be built, the pjlib/include/pj/config_site.h file
+   must be created (it can just be an empty file).
+
+   Note:
+          When the Makefile based build system is used, this process is taken
+          care by the Makefiles. But when non-Makefile based build system (such
+          as Visual Studio) is used, the config_site.h file must be created
+          manually.
+
+
+What is config_site.h File
+
+   The pjlib/include/pj/config_site.h contains local customizations to the
+   libraries.
+
+   All customizations should be put in this file instead of modifying PJ's
+   files, because if PJ's files get modified, then those modified files will
+   not be updated the next time the source is synchronized. Or in other case,
+   the local modification may be overwritten with the fresh copy from the SVN.
+
+   Putting the local customization to the config_site.h solves this problem,
+   because this file is not included in the version control, so it will never
+   be overwritten by "svn update" command.
+
+   Please find list of configuration macros that can be overriden from these
+   files:
+     * PJLIB Configuration (the pjlib/config.h file)
+     * PJLIB-UTIL Configuration (the pjlib-util/config.h file)
+     * PJMEDIA Configuration (the pjmedia/config.h file)
+     * PJSIP Configuration (the pjsip/sip_config.h file)
+
+   A     sample    config_site.h    file    is    also    available    in
+   pjlib/include/config_site_sample.h.
+
+
+Creating config_site.h file
+
+   The simplest way is just to create an empty file, to use whetever default
+   values set by the libraries.
+
+   Another way to create the config_site.h file is to write something like the
+   following:
+
+
+   // Uncomment to get minimum footprint (suitable for 1-2 concurrent calls
+   only)
+   //#define PJ_CONFIG_MINIMAL_SIZE
+   // Uncomment to get maximum performance
+   //#define PJ_CONFIG_MAXIMUM_SPEED
+   #include <pj/config_site_sample.h>
+
+
+2.2 Disk Space Requirements
+     _________________________________________________________________
+
+   The building process needs:
+   about 50-60 MB of disk space to store the uncompressed source files, and
+     * about 30-50 MB of additional space for building each target
+
+   (Visual Studio Debug and Release are considered as separate targets)
+
+
+3. Building Linux, *nix, *BSD, and MacOS X Targets with GNU Build Systems
+     _________________________________________________________________
+
+3.1 Supported Targets
+     _________________________________________________________________
+
+   The  new,  autoconf  based  GNU  build system can be used to build the
+   libraries/applications for the following targets:
+     * Linux/uC-Linux (i386, Opteron, Itanium, MIPS, PowerPC, etc.),
+     * MacOS X (PowerPC),
+     * mingw (i386),
+     * FreeBSD and maybe other BSD's (i386, Opteron, etc.),
+     * RTEMS with cross compilation (ARM, powerpc),
+     * etc.
+
+
+3.2 Requirements
+     _________________________________________________________________
+
+   In order to use PJ's GNU build system, these typical GNU tools are needed:
+     * GNU make (other make will not work),
+     * GNU binutils for the target, and
+     * GNU gcc for the target.
+     * OpenSSL header files/libraries (optional) if TLS support is wanted.
+
+   In addition, the appropriate "SDK" must be installed for the particular
+   target (this could just be a libc and the appropriate system abstraction
+   library such as Posix).
+
+   The build system is known to work on the following hosts:
+     * Linux, many types of distributions.
+     * MacOS X 10.2
+     * mingw (Win2K, XP)
+     * FreeBSD (must use gmake instead of make)
+
+   Building Win32 applications with Cygwin is currently not supported by the
+   autoconf script (there is some Windows header conflicts), but one can still
+   use the old configure script by calling ./configure-legacy. More over,
+   cross-compilations might also work with Cygwin.
+
+
+3.3 Running configure
+     _________________________________________________________________
+
+Using Default Settings
+
+   Run  "./configure"  without  any  options to let the script detect the
+   appropriate settings for the host:
+
+
+
+   $ cd pjproject
+   $ ./configure
+   ...
+
+   Notes:
+          The default settings build the libraries in "release" mode, with
+          default CFLAGS set to "-O2 -DNDEBUG". To change the default CFLAGS,
+          we can use the usual "./configure CFLAGS='-g'" construct.
+
+    Features Customization
+
+   With the new autoconf based build system, most configuration/customization
+   can be specified as configure arguments. The list of customizable features
+   can be viewed by running "./configure --help" command:
+
+
+
+   $ cd pjproject
+   $ ./configure --help
+   ...
+   Optional Features:
+   --disable-floating-point	Disable floating point where possible
+   --disable-sound 		Exclude sound (i.e. use null sound)
+   --disable-small-filter 	Exclude small filter in resampling
+   --disable-large-filter 	Exclude large filter in resampling
+   --disable-g711-plc 		Exclude G.711 Annex A PLC
+   --disable-speex-aec 		Exclude Speex Acoustic Echo Canceller/AEC
+   --disable-g711-codec 	Exclude G.711 codecs from the build
+   --disable-l16-codec 		Exclude Linear/L16 codec family from the build
+   --disable-gsm-codec 		Exclude GSM codec in the build
+   --disable-speex-codec 	Exclude Speex codecs in the build
+   --disable-ilbc-codec 	Exclude iLBC codec in the build
+   --disable-tls Force excluding TLS support (default is autodetected based on
+   OpenSSL availability)
+   ...
+
+    Configuring Debug Version and Other Customizations
+
+   The configure script accepts standard customization, which details can be
+   obtained by executing ./configure --help.
+
+   Below is an example of specifying CFLAGS in configure:
+
+
+
+   $ ./configure CFLAGS="-O3 -DNDEBUG -msoft-float -fno-builtin"
+   ...
+
+    Configuring TLS Support
+
+   By default, TLS support is configured based on the availability of OpenSSL
+   header files and libraries. If OpenSSL is available at the default include
+   and library path locations, TLS will be enabled by the configure script.
+
+   You  can explicitly disable TLS support by giving the configure script
+   --disable-tls option.
+
+
+  3.4 Cross Compilation
+     _________________________________________________________________
+
+   Cross compilation should be supported, using the usual autoconf syntax:
+
+
+
+   $ ./configure --host=arm-elf-linux
+   ...
+
+   Since cross-compilation is not tested as often as the "normal" build, please
+   watch for the ./configure output for incorrect settings (well ideally this
+   should be done for normal build too).
+
+   Please refer to Porting Guide for further information about porting PJ
+   software.
+
+
+  3.5 Running make
+     _________________________________________________________________
+
+   Once the configure script completes successfully, start the build process by
+   invoking these commands:
+
+
+
+   $ cd pjproject
+   $ make dep
+   $ make
+
+   Note:
+          gmake may need to be specified instead of make for some hosts, to
+          invoke GNU make instead of the native make.
+
+
+   Description of all make targets supported by the Makefile's:
+
+   all
+          The default (or first) target to build the libraries/binaries.
+
+   dep, depend
+          Build dependencies rule from the source files.
+
+   clean
+          Clean  the object files for current target, but keep the output
+          library/binary files intact.
+
+   distclean, realclean
+          Remove  all  generated  files (object, libraries, binaries, and
+          dependency files) for current target.
+
+
+   Note:
+          make can be invoked either in the top-level PJ directory or in build
+          directory under each project to build only the particular project.
+
+
+  3.6 Build Customizations
+     _________________________________________________________________
+
+   Build features can be customized by specifying the options when running
+   ./configure as described in Running Configure above.
+
+   In addition, additional CFLAGS and LDFLAGS options can be put in user.mak
+   file in PJ root directory (this file may need to be created if it doesn't
+   exist). Below is a sample of user.mak file contents:
+
+
+
+   export CFLAGS += -msoft-float -fno-builtin
+   export LDFLAGS +=
+
+
+4. Building for Windows Targets with Microsoft Visual Studio
+     _________________________________________________________________
+
+  4.1 Requirements
+     _________________________________________________________________
+
+   The Microsoft Visual Studio based project files can be used with one of the
+   following:
+
+     * Microsoft Visual Studio 6,
+     * Microsoft Visual Studio .NET 2002,
+     * Microsoft Visual Studio .NET 2003,
+     * Microsoft Visual C++ 2005 (including Express edition),
+
+   In addition, the following SDK's are needed:
+     * Platform SDK, if you're using Visual Studio 2005 Express (tested with
+       Platform SDK for Windows Server 2003 SP1),
+     * DirectX SDK (tested with DirectX version 8 and 9),
+     * OpenSSL development kit would be needed if TLS support is wanted, or
+       otherwise this is optional.
+
+   For the host, the following are required:
+     * Windows NT, 2000, XP, 2003, or later ,
+     * Windows 95/98 should work too, but this has not been tested,
+     * Sufficient amount of RAM for the build process (at least 256MB).
+
+
+    Enabling TLS Support with OpenSSL
+
+   If  TLS  support  is wanted, then OpenSSL SDK must be installed in the
+   development host.
+
+   To install OpenSSL SDK from the Win32 binary distribution:
+    1. Install OpenSSL SDK to any folder (e.g. C:\OpenSSL)
+    2. Add OpenSSL DLL location to the system PATH.
+    3. Add OpenSSL include path to Visual Studio includes search directory.
+       Make sure that OpenSSL header files can be accessed from the program
+       with #include <openssl/ssl.h> construct.
+    4. Add OpenSSL library path to Visual Studio library search directory. Make
+       sure the following libraries are accessible:
+          + For Debug build: libeay32MTd and ssleay32MTd.
+          + For Release build: libeay32MT and ssleay32MT.
+
+   Then to enable TLS transport support in PJSIP, just add
+
+     #define PJSIP_HAS_TLS_TRANSPORT 1
+
+   in your pj/config_site.h. When this macro is defined, OpenSSL libraries will
+   be automatically linked to the application via the #pragma construct in
+   sip_transport_tls_ossl.c file.
+
+
+  4.2 Building the Projects
+     _________________________________________________________________
+
+   Follow the steps below to build the libraries/application using Visual
+   Studio:
+    1. For Visual Studio 6: open pjproject.dsw workspace file.
+    2. For Visual Studio 8 (VS 2005): open pjproject-vs8.sln solution file.
+    3. Set pjsua as Active Project.
+    4. Select Debug or Release build as appropriate.
+    5. Build the project. This will build pjsua application and all libraries
+       needed by pjsua.
+    6. After  successful  build,  the pjsua application will be placed in
+       pjsip-apps/bin directory, and the libraries in lib directory under each
+       projects.
+
+   To build the samples:
+    1. (Still using the same workspace)
+    2. Set samples project as Active Project
+    3. Select Debug or Release build as appropriate.
+    4. Build the project. This will build all sample applications and all
+       libraries needed.
+    5. After  successful build, the sample applications will be placed in
+       pjsip-apps/bin/samples directory, and the libraries in lib directory
+       under each projects.
+
+  4.3 Debugging the Sample Application
+     _________________________________________________________________
+
+   The sample applications are build using Samples.mak makefile, therefore it
+   is  difficult  to  setup  debugging session in Visual Studio for these
+   applications. To solve this issue, the pjsip_apps workspace contain one
+   project  called  sample_debug  which  can  be used to debug the sample
+   application.
+
+   To setup debugging using sample_debug project:
+    1. (Still using pjsip_apps workspace)
+    2. Set sample_debug project as Active Project
+    3. Edit debug.c file inside this project.
+    4. Modify the #include line to include the particular sample application to
+       debug
+    5. Select Debug build.
+    6. Build and debug the project.
+
+
+5. Building for Windows Mobile Targets (Windows CE/WinCE/PDA/SmartPhone)
+     _________________________________________________________________
+
+   PJ supports building SIP and media stacks and applications for Windows
+   Mobile targets. A very simple WinCE SIP user agent (with media) application
+   is provided just as proof of concept that the port works.
+
+  5.1 Requirements
+     _________________________________________________________________
+
+   One of the following development tools is needed to build SIP and media
+   components for Windows Mobile:
+     * Microsoft Embedded Visual C++ 4 with appropriate SDKs, or
+     * Microsoft Visual Studio 2005 for Windows Mobile with appropriate SDKs.
+
+   Note that VS2005 is not directly supported (as I don't have the tools), but
+   it is reported to work (I assumed that VS2005 for Windows Mobile can import
+   EVC4 workspace file).
+
+  5.2 Building the Projects
+     _________________________________________________________________
+
+   The Windows Mobile port is included in the main source distribution. Please
+   follow  the  following  steps  to build the WinCE libraries and sample
+   application:
+    1. Open pjsip-apps/build/wince-evc4/wince_demos.vcw workspace file. If
+       later version of EVC4 is being used, this may cause the workspace file
+       to be converted to the appropriate format.
+    2. Select pjsua_wince project as the Active Project.
+    3. Select the appropriate SDK (for example Pocket PC 2003 SDK or SmartPhone
+       2003 SDK)
+    4. Select the appropriate configuration (for example, Win32 (WCE Emulator
+       Debug) to debug the program in emulator, or other configurations such as
+       ARMV4, MIPS, SH3, SH4, or whatever suitable for the device)
+    5. Select the appropriate device (Emulator or the actual Device).
+    6. Build the project. This will build the sample WinCE application and all
+       libraries (SIP, Media, etc.) needed by this application.
+
+   Notes
+
+          + If the config_site.h includes config_site_sample.h file, then
+            there are certain configuration in config_site_sample.h that get
+            activated for Windows CE targets. Please make sure that these
+            configurations are suitable for the application.
+          + The libraries, binaries and object files produced by the build
+            process are located under build/wince-evc4/output directory of each
+            projects.
+
+
+6. Older PJLIB Build System for Non-Autoconf Targets (e.g. RTEMS)
+     _________________________________________________________________
+
+   The old PJLIB build system can still be used for building PJ libraries, for
+   example for RTEMS target. Please see the Porting PJLIB page in PJLIB
+   Reference documentation for information on how to support new target using
+   this build system.
+
+  6.1 Supported Targets
+     _________________________________________________________________
+
+   The older build system supports building PJ libraries for the following
+   operating systems:
+     * RTEMS
+     * Linux
+     * MacOS X
+     * Cygwin and Mingw
+
+   And it supports the following target architectures:
+     * i386, x86_64, itanium
+     * ARM
+     * mips
+     * powerpc
+     * mpc860
+     * etc.
+
+   For other targets, specific files need to be added to the build system,
+   please see the Porting PJLIB page in PJLIB Reference documentation for
+   details.
+
+  6.2 Invoking the Build System
+     _________________________________________________________________
+
+   To invoke the older build system, run the following:
+
+
+
+   $ cd pjproject
+   $ ./configure-legacy
+   $ make dep && make clean && make
+
+
+
+7. Running the Applications
+     _________________________________________________________________
+
+   Upon successful build, the output libraries (PJLIB, PJLIB-UTIL, PJMEDIA,
+   PJSIP, etc.) are put under ./lib sub-directory under each project directory.
+   In addition, some applications may also be built, and such applications will
+   be put in ./bin sub-directory under each project directory.
+
+
+  7.1 pjsua
+     _________________________________________________________________
+
+   pjsua is the reference implementation for both PJSIP and PJMEDIA stack, and
+   is  the  main target of the build system. Upon successful build, pjsua
+   application will be put in pjsip-apps/bin directory.
+
+   pjsua manual can be found in pjsua Manual Page.
+
+
+  7.2 Sample Applications
+     _________________________________________________________________
+
+   Sample applications will be built with the Makefile build system. For Visual
+   Studio, you have to build the samples manually by selecting and building the
+   Samples project inside pjsip-apps/build/pjsip_apps.dsw project workspace.
+
+   Upon   successful   build,   the   sample   applications  are  put  in
+   pjsip-apps/bin/samples directory.
+
+   The  sample applications are described in PJMEDIA Samples Page and
+   PJSIP Samples Page in the website.
+
+
+  7.3 pjlib-test
+     _________________________________________________________________
+
+   pjlib-test contains comprehensive tests for testing PJLIB functionality.
+   This application will only be built when the Makefile build system is used;
+   with  Visual  Studio, one has to open pjlib.dsw project in pjlib/build
+   directory to build this application.
+
+   If  you're  porting PJLIB to new target, it is recommended to run this
+   application to make sure that all functionalities works as expected.
+
+
+  7.4 pjsip-test
+     _________________________________________________________________
+
+   pjsip-test contains codes for testing various SIP functionalities in PJSIP
+   and also to benchmark static performance metrics such as message parsing per
+   second.
+
+
+
+8. Using PJPROJECT with Applications
+     _________________________________________________________________
+
+   Regardless of the build system being used, the following tasks are normally
+   needed to be done in order to build application to use PJSIP and PJMEDIA:
+    1. Put these include directories in the include search path:
+          + pjlib/include
+          + pjlib-util/include
+          + pjmedia/include
+          + pjsip/include
+    2. Put these library directories in the library search path:
+          + pjlib/lib
+          + pjlib-util/lib
+          + pjmedia/lib
+          + pjsip/lib
+    3. Include the relevant PJ header files in the application source file. For
+       example, using these would include ALL APIs exported by PJ:
+
+      #include <pjlib.h>
+      #include <pjlib-util.h>
+      #include <pjsip.h>
+      #include <pjsip_ua.h>
+      #include <pjsip_simple.h>
+      #include <pjsua.h>
+      #include <pjmedia.h>
+      #include <pjmedia-codec.h>
+       (Note: the documentation of the relevant libraries should say which
+       header files should be included to get the declaration of the APIs).
+    4. Declare the OS macros.
+          + For Windows applications built with Visual Studio, we need to
+            declare PJ_WIN32=1 macro in the project settings (declaring the
+            macro in the source file may not be sufficient).
+          + For Windows Mobile applications build with Visual C++, we need to
+            declare PJ_WIN32_WINCE=1 macro in the project settings.
+          + For  GNU build system/autoconf based build system, we need to
+            declare PJ_AUTOCONF=1 macro when compiling the applications.
+       (Note: the old PJ build system requires declaring the target processor
+       with PJ_M_XXX=1 macro, but this has been made obsolete. The target
+       processor  will  be  detected  from compiler's predefined macro by
+       pjlib/config.h file).
+    5. Link with the appropriate PJ libraries. The following libraries will
+       need to be included in the library link specifications:
+
+        pjlib
+                Base library used by all libraries.
+
+        pjlib-util
+                Auxiliary library containing scanner, XML, STUN, MD5, getopt,
+                etc, used by the SIP and media stack.
+
+        pjsip
+                SIP core stack library.
+
+        pjsip-ua
+                SIP user agent library containing INVITE session, call
+                transfer, client registration, etc.
+
+        pjsip-simple
+                SIP SIMPLE library for base event framework, presence, instant
+                messaging, etc.
+
+        pjsua
+                High level SIP UA library, combining SIP and media stack into
+                high-level easy to use API.
+
+        pjmedia
+                The media framework.
+
+        pjmedia-codec
+                Container library for various codecs such as GSM, Speex, and
+                iLBC.
+
+
+   Note: the actual library names will be appended with the target name and the
+   build configuration. For example:
+
+        For Visual Studio builds
+                The actual library names will look like
+                pjlib-i386-win32-vc6-debug.lib,
+                pjlib-i386-win32-vc6-release.lib, etc., depending on whether we
+                are building the Debug or Release version of the library.
+
+                An easier way to link with the libraries is to include PJ
+                project files in the workspace, and to configure project
+                dependencies so that the application depends on the PJ
+                libraries. This way, we don't need to manually add each PJ
+                libraries to the input library file specification, since VS
+                will automatically link the dependency libraries with the
+                application.
+
+        For Windows Mobile builds
+                Unfortunately the PJ libraries built for Windows Mobile will
+                not be placed in the usual lib directory, but rather under the
+                output directory under build/wince-evc4 project directory.
+
+                An easier way to link with the libraries is to include PJ
+                project files in the workspace, and to configure project
+                dependencies so that the application depends on the PJ
+                libraries. This way, we don't need to manually add each PJ
+                libraries to the input library file specification, since VS
+                will automatically link the dependency libraries with the
+                application.
+
+        For GNU builds
+                Application's Makefile can get the PJ library suffix by
+                including PJ's build.mak file from the root PJ directory (the
+                suffix is contained in TARGET_NAME variable). For example, to
+                link with PJLIB and PJMEDIA, we can use this syntax in the
+                LDFLAGS: "-lpj-$(TARGET_NAME) -lpjmedia-$(TARGET_NAME)"
+
+
+    6. Link with system spesific libraries:
+
+        Windows
+                Add (among other things): wsock32.lib, ws2_32.lib, ole32.lib,
+                dsound.lib
+
+        Linux, *nix, *BSD
+                Add (among other things): '-lpthread -lm' (at least).
+
+        MacOS X
+                Add (among other things): '-framework CoreAudio -lpthread -lm'.
+
+
+Appendix I: Common Problems/Frequently Asked Question (FAQ)
+     _________________________________________________________________
+
+  I.1 fatal error C1083: Cannot open include file: 'pj/config_site.h': No such
+  file or directory
+
+   This error normally occurs when the config_site.h file has not been created.
+   This file needs to be created manually (an empty file is sufficient). Please
+   follow the Build Preparation instructions above to create this file.
+
+
+
+
+
+
+
+
+     _________________________________________________________________
+
+   Feedback:
+          Thanks for using PJ libraries and for reading this document. Please
+          send feedbacks or general comments to <bennylp at pjsip dot org>.
+
diff --git a/jni/pjproject-android/.svn/pristine/ad/ad9ca3f4b9c198a02c701f6ddd5bb9322fac4bf6.svn-base b/jni/pjproject-android/.svn/pristine/ad/ad9ca3f4b9c198a02c701f6ddd5bb9322fac4bf6.svn-base
new file mode 100644
index 0000000..c95561f
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ad/ad9ca3f4b9c198a02c701f6ddd5bb9322fac4bf6.svn-base
@@ -0,0 +1,24 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+/*
+ * This file is a C++ wrapper, see ticket #886 for details.
+ */
+
+#include "pool.c"
diff --git a/jni/pjproject-android/.svn/pristine/ad/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc.svn-base b/jni/pjproject-android/.svn/pristine/ad/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc.svn-base
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/ad/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc.svn-base
@@ -0,0 +1 @@
+