* #36737: switch back to svn repo, remove assert in sip_transaction.c
diff --git a/jni/pjproject-android/.svn/pristine/49/4974e03b1fe9d2535d13852c5c2d31dddecd8fd2.svn-base b/jni/pjproject-android/.svn/pristine/49/4974e03b1fe9d2535d13852c5c2d31dddecd8fd2.svn-base
new file mode 100644
index 0000000..2c741e4
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/49/4974e03b1fe9d2535d13852c5c2d31dddecd8fd2.svn-base
@@ -0,0 +1,35 @@
+# $Id$
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=ice-ufrag:1234
+a=ice-pwd:5678
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=candidate:XX 1 UDP 1234 127.0.0.1 4000 typ host
+a=candidate:YY 2 UDP 1234 127.0.0.1 4001 typ host
+"""
+
+args = "--null-audio --use-ice --auto-answer 200 --max-calls 1"
+include = ["a=ice-ufrag",			# must have ICE
+	   "a=candidate:[0-9a-zA-Z]+ 2 UDP"	# must have RTCP component
+	   ]		   	
+exclude = [
+	   "ice-mismatch"		     	# must not mismatch
+	  ]
+
+sendto_cfg = sip.SendtoCfg( "caller sends two components without a=rtcp line", 
+			    pjsua_args=args, sdp=sdp, resp_code=200, 
+			    resp_inc=include, resp_exc=exclude,
+			    enable_buffer = True)
+
diff --git a/jni/pjproject-android/.svn/pristine/49/4995bd2698d43a8dcd2f041a39573fd8d8565668.svn-base b/jni/pjproject-android/.svn/pristine/49/4995bd2698d43a8dcd2f041a39573fd8d8565668.svn-base
new file mode 100644
index 0000000..929fc21
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/49/4995bd2698d43a8dcd2f041a39573fd8d8565668.svn-base
@@ -0,0 +1,547 @@
+ /**

+ * @file bdIMADpj.h

+ * @brief bdSound IMproved Audio Device for PJSIP.

+ */

+ 

+/**

+ * @defgroup bd_IMAD bdIMADpj bdSound IMproved Audio Device for PJSIP.

+ * @ingroup audio_device_api

+ * 

+ * <b>bdSound IMproved Audio Device</b> is a multiplatform audio interface

+ * created to integrate in <b>PJSIP</b> library with no effort.

+ * \n Porting <b>bdIMADpj</b> across the main operating systems is

+ * straightforward, without the need of change a single line of code.

+ *

+ *    - <b>Features</b>

+ *       - Echo cancellation (Full Duplex)

+ *       - Noise reduction

+ *       - Automatic Gain Control

+ *       - Audio Enhancement

+ *

+ *    - <b>Supported operating systems</b>

+ *       - Windows

+ *       - Android

+ *       - MacOS X

+ *       - iOS

+ *       - Linux / Alsa

+ *

+ *    - <b>Supported platforms</b>

+ *       - x86

+ *       - x64

+ *       - ARM Cortex-A8/A9/A15 with NEON

+ * 

+ * Visit <a href="http:/www.bdsound.com" target="new">bdSound</a> for updated

+ * features, supported operating systems and platforms.

+ * 

+ * <b>Using PJSIP with bdIMAD audio device</b>

+ * 

+ *    - <b>Integration</b>

+ *    \n Using <b>bdIMAD</b> within <b>PJSIP</b> is simple:

+ *       -# Request for bdIMADpj library to

+ *       <a href="http:/www.bdsound.com" target="new">bdSound</a>:

+ *        bdSound will provide instruction to integrate the library depending on

+ *        the platform / O.S. / toolchain;

+ *       -# Add the <code>bdimad_dev.c</code> file to

+ *       <code>pjmedia/src/pjmedia-audiodev</code> folder;

+ *       -# Enable the bdIMAD audio device defining the periferal in the

+ *       <code>pj/config_site.h</code> and disabling all other devices:

+ *       <pre>

+ *       #define PJMEDIA_AUDIO_DEV_HAS_BDIMAD 1

+ *       </pre>

+ *

+ *    - <b>Usage</b>

+ *    \n There are only a couple of things the customer have to pay attention on

+ *    §when using bdIMAD library.

+ *

+ *       - <b>Initialization</b>

+ *       \n Since the bdIMAD library provide itself the echo cancellation

+ *       and the latency management, is necessary to disable these features

+ *       in the PJSIP librariy applications.

+ *       \n For example in PJSUA sample application there is the need

+ *       to provide the following commands:

+ *       <pre>

+ *       --ec-tail=0

+ *       --no-vad

+ *       --capture-lat=0

+ *       --playback-lat=0

+ *       </pre>

+ * 

+ *       - <b>Supported set capability</b>

+ *          - <code>PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING</code>

+ *          \n Setting speaker volume.

+ *          - <code>PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING</code>

+ *          \n Setting michrophone volume.

+ *          - <code>PJMEDIA_AUD_DEV_CAP_EC</code>

+ *          \n Enable/disable echo cancellation.

+ *

+ * For additional information visit

+ * <a href="http:/www.bdsound.com" target="new">www.bdsound.com</a>

+ * or write to info@bdsound.com

+ *

+ * @author bdSound

+ * @version   1.0.1

+ * @copyright 2012 bdSound srl. All rights reserved.

+ *

+ */

+

+/**        

+ * @defgroup groupFunction Functions      

+ * @ingroup bd_IMAD  

+ * 

+ * Functions defined in bdIMAD.

+ */

+

+/**        

+ * @defgroup groupCallback Callbacks      

+ * @ingroup bd_IMAD    

+ * 

+ * Callbacks defined in bdIMAD.

+ */

+ 

+/**        

+ * @defgroup groupStructEnum Structs and Enums       

+ * @ingroup bd_IMAD   

+ * 

+ * Struct and Enum defined in bdIMAD.

+ */

+

+#ifndef BD_IMAD_PJ_H__

+#define BD_IMAD_PJ_H__

+  

+/**

+ * @brief Macro for Windows DLL Support.

+ */

+ 

+#ifdef _BDIMADPJ_EXPORTDLL

+	#ifdef WIN32

+		#define BDIMADPJ_API __declspec(dllexport)

+	#else

+		#define BDIMADPJ_API __attribute__((visibility("default")))	

+	#endif

+#else

+	#define BDIMADPJ_API

+#endif

+

+#define BD_IMAD_CAPTURE_DEVICES      1

+#define BD_IMAD_PLAYBACK_DEVICES     0

+#define BD_IMAD_DIAGNOSTIC_ENABLE    1

+#define BD_IMAD_DIAGNOSTIC_DISABLE   0

+

+#define BD_IMAD_BITS_X_SAMPLE	     16                  /**< Bits per sample */

+

+typedef void* bdIMADpj;

+

+/**

+ * @addtogroup groupCallback

+ * @{

+ */

+

+/**

+ * @brief Callback used to fill the playback buffer of bdIMAD.

+ * The function is called by bdIMAD each time are required sample to be played.

+ * @param[in] *buffer                  pointer to the buffer with the audio

+ * 				       samples to be played(short type).

+ * @param[in] nSamples                 number of samples required.

+ * @param[in] user_data                pointer to the user data structure

+ * 				       defined in the bdIMADpj_Setting_t

+ * 				       structure.

+ * @return none.

+ */

+

+typedef int (* cb_fillPlayBackB_t) (void *buffer, int nSamples,

+				    void *user_data);

+

+/**

+ * @brief Callback used to retrive the caputre buffer of bdIMAD. The function

+ * is called by bdIMAD each time processed mic samples are available.

+ * @param[out] *buffer                 pointer to the buffer with the audio

+ * 				       samples to download(short type).

+ * @param[in] nSamples                 number of samples processed to download.

+ * @param[in] user_data                pointer to the user data structure

+ *                                     defined in the MainSet structure.

+ * @return none.

+ */

+

+typedef void (* cb_emptyCaptureB_t) (void *buffer, int nSamples,

+				     void *user_data);

+/**

+ * @}

+ */

+

+/**

+ * @addtogroup groupStructEnum

+ * @{

+ */

+ 

+/**

+ * @brief Error status returned by some functions in the library.

+ */

+

+typedef enum bdIMADpj_Status{

+    /**< No error. */

+    BD_PJ_OK                                     = 0,

+    /**< Watch bdIMADpj_Warnings_t structure to find the warnings. */

+    BD_PJ_WARN_BDIMAD_WARNING_ASSERTED           = 1,

+    /**< Error not identified. */

+    BD_PJ_ERROR_GENERIC                          = 2,

+    /**< The pointer passed is NULL. */

+    BD_PJ_ERROR_NULL_POINTER                     = 3,

+    /**< Allocation procedure failed. */

+    BD_PJ_ERROR_ALLOCATION                       = 4,

+    /**< The parameter is not existent or the set/get function is not active. */

+    BD_PJ_ERROR_PARAMETER_NOT_FOUND              = 5,

+    /**< No capture device found. */

+    BD_PJ_ERROR_IMAD_NONE_CAPTURE_DEV            = 10,

+    /**< No play device found. */

+    BD_PJ_ERROR_IMAD_NONE_PLAY_DEV               = 11,

+    /**< Frame size not allowed. */

+    BD_PJ_ERROR_IMAD_FRAME_SIZE                  = 12,

+    /**< Sample frequency not allowed. */

+    BD_PJ_ERROR_IMAD_SAMPLE_FREQ                 = 13,

+    /**< Samples missing. */

+    BD_PJ_ERROR_IMAD_MISSING_SAMPLES             = 14,

+    /**< Device list is empty. */

+    BD_PJ_ERROR_IMAD_DEVICE_LIST_EMPTY           = 15,

+    /**< Library not authorized, entering demo mode. */

+    BD_PJ_ERROR_IMAD_LIB_NOT_AUTHORIZED          = 16,

+    /**< The input channel memory has not been allocated. */

+    BD_PJ_ERROR_IMAD_INPUT_CH_NOT_ALLOCATED      = 17,

+    /**< The library has expired, entering demo mode. */

+    BD_PJ_ERROR_IMAD_LICENSE_EXPIRED             = 18,

+    /**< Open of capture device failed. */

+    BD_PJ_ERROR_IMAD_OPEN_CAPTURE_DEV_FAILED     = 19,

+    /**< Open of play device failed.  */

+    BD_PJ_ERROR_IMAD_OPEN_PLAY_DEV_FAILED        = 20,

+    /**< Start of play device failed. */

+    BD_PJ_ERROR_IMAD_START_PLAY_DEV_FAILED       = 21,

+    /**< Start of capture device failed. */

+    BD_PJ_ERROR_IMAD_START_CAPTURE_DEV_FAILED    = 22,

+    /**< Start of time process failed. */

+    BD_PJ_ERROR_IMAD_START_TIME_PROCESS_FAILED   = 23,

+    /**< Start of thread process failed. */

+    BD_PJ_ERROR_IMAD_THREAD_PROCESS_FAILED       = 24,

+    /**< No volume control available. */

+    BD_PJ_ERROR_IMAD_NO_VOL_CONTROL_AVAILABLE    = 25,

+} bdIMADpj_Status;

+

+/**

+ * @brief Parameter to pass to set and get parameter functions. 

+ *

+ * For each enumeration are defined the data type and the supported operations

+ * on that parameter (set and get).

+ */

+   

+typedef enum bdIMADpj_Parameter{

+    /**< int*   \n set/get \n 1 enable / 0 disable echo cancellation. */

+    BD_PARAM_IMAD_PJ_AEC_ENABLE                 = 1,

+    /**< int*   \n set/get \n 1 enable / 0 disable microphone control

+     * (when possible). */

+    BD_PARAM_IMAD_PJ_MIC_CONTROL_ENABLE         = 2,

+    /**< int*   \n set/get \n 1 ebable / 0 disable noise reduction. */

+    BD_PARAM_IMAD_PJ_NOISE_REDUCTION_ENABLE     = 3,

+    /**< int*   \n set     \n number of channel to reset. Used to reset

+     * the input channel statistics. To be used when the same channel

+     * is assigned to another partecipant. */

+    BD_PARAM_IMAD_PJ_RESET_STATISTIC_IN_CH      = 4,

+    /**< float* \n set/get \n 0.0f -> 1.0f volume of

+     * the microphone(when possible). */

+    BD_PARAM_IMAD_PJ_MIC_VOLUME                 = 5,

+    /**< int*   \n set/get \n 0 mute / 1 not mute on microphone

+     * (when possible). */

+    BD_PARAM_IMAD_PJ_MIC_MUTE                   = 6,

+    /**< float* \n set/get \n 0.0f -> 1.0f volume of the speaker. */

+    BD_PARAM_IMAD_PJ_SPK_VOLUME                 = 7,

+    /**< int*   \n set/get \n 0 mute / 1 not mute on speaker. */

+    BD_PARAM_IMAD_PJ_SPK_MUTE                   = 8,

+} bdIMADpj_Parameter;

+

+

+/**

+ * @brief Instance structure for the information regarding the aec engine.

+ */

+

+typedef struct bdIMADpj_Setting_t{

+    /**< Sample frequency (8kHz or 16kHz). */

+    int                 SamplingFrequency;

+    /**< Audio buffer managed by the aec bdIMAD functions.

+     * (from 16ms to 80ms, 16ms recommended). */

+    int                 FrameSize_ms;

+    /**< Points to the validation functions in the validation library. */

+    void                *validate;

+    /**< Points to the the callback function used for filling

+     * the playback buffer of bdIMAD. */

+    cb_fillPlayBackB_t  cb_fillPlayBackBuffer;

+    /**< Points to user data to pass to the callback. */

+    void                *cb_fillPlayBackBuffer_user_data;

+    /**< Points to the callback function used for retreive the processed

+     * audio present in the capture buffer of bdIMAD. */

+    cb_emptyCaptureB_t  cb_emptyCaptureBuffer;

+    /**< Points to user data to pass to the callback. */

+    void                *cb_emptyCaptureBuffer_user_data;

+    /**< Is a wide char pointer to the capture device name. */

+    wchar_t             *CaptureDevice;

+    /**< Is a wide char pointer to the play device name. */

+    wchar_t             *PlayDevice;

+    /**< True to enable diagnostic, false to disable. */

+    int 	            DiagnosticEnable;

+    /**< Directory which will contains the files generated for diagnostic. */

+    wchar_t             *DiagnosticFolderPath;

+    /**< Is an auxiliary settings pointer used internally by bdIMAD. */

+    void                *bdIMADwr_SettingsData;

+} bdIMADpj_Setting_t;

+

+/**

+ * @brief Instance structure for the warnings generated by the initialization

+ * functions.

+ */

+

+typedef struct bdIMADpj_Warnings_t{

+    /**< The capture device indicated can't be opened, has been selected

+     * the default capture device. */

+    int DefaultCaptureDeviceAutomaticallySelected;

+    /**< The capture device opened has not volume control. */

+    int CaptureDeviceWithoutVolumeControl;

+    /**< The play device indicated can't be opened, has been selected

+     * the default play device. */

+    int DefaultPlayDeviceAutomaticallySelected;

+    /**< The number of channel requested is out of range. The number of

+     * channel opened is equal to the maximum. */

+    int NumberOfChannelsOutOfRange;

+    /**< The diagnostic files could not be saved. */

+    int DiagnosticSaveNotAllowed;

+    /**< The nlp level requested is not allowed, it has been automatically

+     * changed to the default value. */

+    int nlpLevelChangeSettting;

+    /**< No capture device is present. Anyway the bdSES has been

+     * istantiated only for playback. */

+    int NoCaptureDevicePresent;

+    /**< The cpu is not adapt to run the aec engine, the aec has been disabled.

+     * This appens for very old cpu like pentium III. */

+    int oldCPUdetected_AECdisable;

+    /**< Windows Direct Sound error. */

+    long directSoundError;

+    /**< Windows Direct Sound volume error. */

+    long directSoundLevel;

+    /**< No play device is present. Anyway the bdSES has been istantiated

+     * only for capture. */

+    int NoPlayDevicePresent;

+} bdIMADpj_Warnings_t;

+

+/**

+ * @brief Instance structure for the library version

+ */

+

+typedef struct bdIMADpj_libVersion_t{

+    int     major;                                /**< major version. */

+    int	    minor;                                /**< minor version. */

+    int	    build;                                /**< build number. */

+    char    *name;                                /**< name "bdIMADpj ver.X". */

+    char    *version;                             /**< beta, RC, release. */

+    char    *buildDate;                           /**< build date. */

+} bdIMADpj_libVersion_t;

+

+/**

+ * @}

+ */

+

+

+

+/**

+ * @addtogroup groupFunction

+ * @{

+ */

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+/**

+ * @brief Must be used to allocate and set to default parameter the memory

+ * for the bdIMAD.

+ *

+ * The function generate a structure bdIMADpj_Setting_t filled with the

+ * default settings.

+ * \n The user can change this settings according to the need and then

+ * launch the ::bdIMADpj_InitAEC.

+ * \n The function generate also a warning structure (::bdIMADpj_Warnings_t)

+ * that could be used in ::bdIMADpj_InitAEC to handle eventual warnings.

+ * @param[out] **ppSettings            Points to the pointer of the

+ *                                     allocated ::bdIMADpj_Setting_t.

+ * @param[out] **ppWarningMessages     Points to the pointer of the

+ *                                     allocated ::bdIMADpj_Warnings_t.

+ * @return                             ::BD_PJ_OK if the function has been

+ *                                     performed successfully, otherwise return

+ *                                     an error (refer to ::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_CreateStructures(

+				    bdIMADpj_Setting_t **ppSettings,

+				    bdIMADpj_Warnings_t **ppWarningMessages);

+

+/**

+ * @brief Is used to free the memory for the ::bdIMADpj_Setting_t structure and

+ * ::bdIMADpj_Warnings_t structure allocated with

+ * the ::bdIMADpj_CreateStructures.

+ * @param[in] **ppSettings             Pointer to a memory location filled

+ * 				       with the address of the

+ * 				       ::bdIMADpj_Setting_t structure to free.

+ * This address will be set to NULL.

+ * @param[in] **ppWarningMessages      Pointer to a memory location filled

+ * 				       with the address of the allocated

+ * 				       ::bdIMADpj_Warnings_t structure to free.

+ * 				       This address will be set to NULL.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise return

+ * 				       an error (refer to ::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_FreeStructures(

+				    bdIMADpj_Setting_t **ppSettings,

+				    bdIMADpj_Warnings_t **ppWarningMessages);

+

+/**

+ * @brief Is used to initialize the memory for bdIMAD with the settings

+ * contained in the <code>ppSettings</code>.

+ * @param[out] *pBdIMADInstance        Is the pointer to the bdIMAD object.

+ * @param[in] **ppSettings             Pointer to pointer to a

+ * 				       ::bdIMADpj_Setting_t structure, filled

+ * 				       with initialization settings to be

+ * 				       applied to the bdIMAD.

+ *                                     \n Note, the <code>pBdIMADInstance</code>

+ *                                     is modified with the applied settings.

+ * @param[out] **ppWarningMessages     Pointer to pointer to a

+ * 				       ::bdIMADpj_Warnings_t sructure,

+ * 				       which reports the warnings after the

+ * 				       initialization.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise return

+ * 				       an error (refer to ::bdIMADpj_Status).

+ *                                     \n If the error is

+ *                                     ::BD_PJ_WARN_BDIMAD_WARNING_ASSERTED

+ *                                     the init has been performed with success,

+ *                                     but with a different settings

+ *                                     respect to the ones required.

+ *                                     This mainly happens if the audio

+ *                                     device opened is different to the

+ *                                     one requested.

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_InitAEC(bdIMADpj *pBdIMADInstance,

+				      bdIMADpj_Setting_t **ppSettings,

+				      bdIMADpj_Warnings_t **ppWarningMessages);

+

+/**

+ * @brief Is used to free the bdIMAD object pointed by the

+ * <code>pBdIMADInstance</code>.

+ * @param[in] *pBdIMADInstance         Pointer to the bdIMAD object to free.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise return

+ * 				       an error (refer to ::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_FreeAEC(bdIMADpj *pBdIMADInstance);

+

+/**

+ * @brief Is used to make a list of capure and play devices available

+ * on the system.

+ * @param[in] captureDevice            Set to 1 to get the list of capture

+ * 				       devices. Set to 0 to get the list of

+ * 				       play devices.

+ * @param[in] **deviceName             Pointer to pointer to a wide char

+ * 				       containing the names of capture/play

+ * 				       devices.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise return

+ * 				       an error (refer to ::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_getDeviceName(int captureDevice,

+						    wchar_t **deviceName);

+

+/**

+ * @brief Is used to freeze the bdIMAD, stopping the audio playback

+ * and recording.

+ * @param[in] bdIMADInstance           bdIMAD object.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise

+ * 				       return an error (refer to

+ * 				       ::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_stop(bdIMADpj bdIMADInstance);

+

+/**

+ * @brief Is used to put back in play the audio after it has been stopped by the

+ * ::bdIMADpj_stop functions.

+ * @param[in] bdIMADInstance           bdIMAD object.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise

+ * 				       return an error (refer to

+ * 				       ::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_run(bdIMADpj bdIMADInstance);

+

+/**

+ * @brief Print on a standard output the warning messages.

+ * @param[in] *pWarningMessages        Pointer to the warning structure

+ * 				       to be printed.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise

+ * 				       return an error

+ * 				       (refer to ::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_DisplayWarnings(

+					bdIMADpj_Warnings_t *pWarningMessages);

+

+/**

+ * @brief Clear the warning structure after being read.

+ * @param[out] **ppWarningMessages     Pointer to pointer to the warning

+ * 				       structure to be cleared.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise

+ * 				       return an error (refer to

+ * 				       ::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_ClearAllWarnings(

+				       bdIMADpj_Warnings_t **ppWarningMessages);

+

+/**

+ * @brief Is used to set a parameter of the bdIMAD object pointed by the

+ * <code>pBdIMADInstance</code>.

+ * @param[in] bdIMADInstance           bdIMAD object.

+ * @param[in] parameterName            Indicate the parameter to set.

+ * @param[in] *pValue                  Is a pointer to the value to set

+ * 				       cast to void.

+ * 				       \n In the ::bdIMADpj_Parameter

+ * 				       declaration is indicated the real type of

+ * 				       the value, depending on the

+ * 				       <code>parameterName</code>.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise

+ * 				       return an error (refer to

+ * 				       §::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_setParameter(bdIMADpj bdIMADInstance,

+				bdIMADpj_Parameter parameterName, void *pValue);

+

+/**

+ * @brief Is used to get a parameter of the bdIMAD object pointed by the

+ * <code>pBdIMADInstance</code>.

+ * @param[in] bdIMADInstance           bdIMAD object.

+ * @param[in] parameterName            Indicate the parameter to get.

+ * @param[out] *pValue                 Is a pointer to the value to get cast

+ * 				       to void. \n In the

+ * 				       ::bdIMADpj_Parameter declaration is

+ * 				       indicated the real type of the value,

+ * 				       depending on the

+ * 				       <code>parameterName</code>.

+ * @return                             ::BD_PJ_OK if the function has been

+ * 				       performed successfully, otherwise return

+ * 				       an error (refer to ::bdIMADpj_Status).

+ */

+BDIMADPJ_API bdIMADpj_Status bdIMADpj_getParameter(bdIMADpj bdIMADInstance,

+				bdIMADpj_Parameter parameterName, void *pValue);

+

+

+#ifdef __cplusplus

+}

+#endif

+/**

+ * @}

+ */

+

+#endif //BD_IMAD_PJ_H__

diff --git a/jni/pjproject-android/.svn/pristine/49/499d59e0e9859840f9f6361ec06f87181e5ef446.svn-base b/jni/pjproject-android/.svn/pristine/49/499d59e0e9859840f9f6361ec06f87181e5ef446.svn-base
new file mode 100644
index 0000000..645ed39
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/49/499d59e0e9859840f9f6361ec06f87181e5ef446.svn-base
@@ -0,0 +1,1196 @@
+/* $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 <pjmedia-audiodev/audiodev_imp.h>
+#include <pjmedia-audiodev/errno.h>
+#include <pjmedia/alaw_ulaw.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+#include <pj/math.h>
+#include <pj/os.h>
+#include <pj/string.h>
+
+#if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
+
+/*
+ * This file provides sound implementation for Symbian Audio Streaming
+ * device. Application using this sound abstraction must link with:
+ *  - mediaclientaudiostream.lib, and
+ *  - mediaclientaudioinputstream.lib 
+ */
+#include <mda/common/audio.h>
+#include <mdaaudiooutputstream.h>
+#include <mdaaudioinputstream.h>
+
+
+#define THIS_FILE			"symb_mda_dev.c"
+#define BITS_PER_SAMPLE			16
+#define BYTES_PER_SAMPLE		(BITS_PER_SAMPLE/8)
+
+
+#if 1
+#   define TRACE_(st) PJ_LOG(3, st)
+#else
+#   define TRACE_(st)
+#endif
+
+
+/* MDA factory */
+struct mda_factory
+{
+    pjmedia_aud_dev_factory	 base;
+    pj_pool_t			*pool;
+    pj_pool_factory		*pf;
+    pjmedia_aud_dev_info	 dev_info;
+};
+
+/* Forward declaration of internal engine. */
+class CPjAudioInputEngine;
+class CPjAudioOutputEngine;
+
+/* MDA stream. */
+struct mda_stream
+{
+    // Base
+    pjmedia_aud_stream	 base;			/**< Base class.	*/
+    
+    // Pool
+    pj_pool_t		*pool;			/**< Memory pool.       */
+
+    // Common settings.
+    pjmedia_aud_param param;		/**< Stream param.	*/
+
+    // Audio engine
+    CPjAudioInputEngine	*in_engine;		/**< Record engine.	*/
+    CPjAudioOutputEngine *out_engine;		/**< Playback engine.	*/
+};
+
+
+/* Prototypes */
+static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
+static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
+static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f);
+static unsigned    factory_get_dev_count(pjmedia_aud_dev_factory *f);
+static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, 
+					unsigned index,
+					pjmedia_aud_dev_info *info);
+static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
+					 unsigned index,
+					 pjmedia_aud_param *param);
+static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
+					 const pjmedia_aud_param *param,
+					 pjmedia_aud_rec_cb rec_cb,
+					 pjmedia_aud_play_cb play_cb,
+					 void *user_data,
+					 pjmedia_aud_stream **p_aud_strm);
+
+static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
+				    pjmedia_aud_param *param);
+static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
+				  pjmedia_aud_dev_cap cap,
+				  void *value);
+static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
+				  pjmedia_aud_dev_cap cap,
+				  const void *value);
+static pj_status_t stream_start(pjmedia_aud_stream *strm);
+static pj_status_t stream_stop(pjmedia_aud_stream *strm);
+static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
+
+
+/* Operations */
+static pjmedia_aud_dev_factory_op factory_op =
+{
+    &factory_init,
+    &factory_destroy,
+    &factory_get_dev_count,
+    &factory_get_dev_info,
+    &factory_default_param,
+    &factory_create_stream,
+    &factory_refresh
+};
+
+static pjmedia_aud_stream_op stream_op = 
+{
+    &stream_get_param,
+    &stream_get_cap,
+    &stream_set_cap,
+    &stream_start,
+    &stream_stop,
+    &stream_destroy
+};
+
+
+/*
+ * Convert clock rate to Symbian's TMdaAudioDataSettings capability.
+ */
+static TInt get_clock_rate_cap(unsigned clock_rate)
+{
+    switch (clock_rate) {
+    case 8000:  return TMdaAudioDataSettings::ESampleRate8000Hz;
+    case 11025: return TMdaAudioDataSettings::ESampleRate11025Hz;
+    case 12000: return TMdaAudioDataSettings::ESampleRate12000Hz;
+    case 16000: return TMdaAudioDataSettings::ESampleRate16000Hz;
+    case 22050: return TMdaAudioDataSettings::ESampleRate22050Hz;
+    case 24000: return TMdaAudioDataSettings::ESampleRate24000Hz;
+    case 32000: return TMdaAudioDataSettings::ESampleRate32000Hz;
+    case 44100: return TMdaAudioDataSettings::ESampleRate44100Hz;
+    case 48000: return TMdaAudioDataSettings::ESampleRate48000Hz;
+    case 64000: return TMdaAudioDataSettings::ESampleRate64000Hz;
+    case 96000: return TMdaAudioDataSettings::ESampleRate96000Hz;
+    default:
+	return 0;
+    }
+}
+
+/*
+ * Convert number of channels into Symbian's TMdaAudioDataSettings capability.
+ */
+static TInt get_channel_cap(unsigned channel_count)
+{
+    switch (channel_count) {
+    case 1: return TMdaAudioDataSettings::EChannelsMono;
+    case 2: return TMdaAudioDataSettings::EChannelsStereo;
+    default:
+	return 0;
+    }
+}
+
+/*
+ * Utility: print sound device error
+ */
+static void snd_perror(const char *title, TInt rc) 
+{
+    PJ_LOG(1,(THIS_FILE, "%s: error code %d", title, rc));
+}
+ 
+//////////////////////////////////////////////////////////////////////////////
+//
+
+/*
+ * Implementation: Symbian Input Stream.
+ */
+class CPjAudioInputEngine : public CBase, MMdaAudioInputStreamCallback
+{
+public:
+    enum State
+    {
+	STATE_INACTIVE,
+	STATE_ACTIVE,
+    };
+
+    ~CPjAudioInputEngine();
+
+    static CPjAudioInputEngine *NewL(struct mda_stream *parent_strm,
+				     pjmedia_aud_rec_cb rec_cb,
+				     void *user_data);
+
+    static CPjAudioInputEngine *NewLC(struct mda_stream *parent_strm,
+				      pjmedia_aud_rec_cb rec_cb,
+				      void *user_data);
+
+    pj_status_t StartRecord();
+    void Stop();
+
+    pj_status_t SetGain(TInt gain) { 
+	if (iInputStream_) { 
+	    iInputStream_->SetGain(gain);
+	    return PJ_SUCCESS;
+	} else
+	    return PJ_EINVALIDOP;
+    }
+    
+    TInt GetGain() { 
+	if (iInputStream_) { 
+	    return iInputStream_->Gain();
+	} else
+	    return PJ_EINVALIDOP;
+    }
+
+    TInt GetMaxGain() { 
+	if (iInputStream_) { 
+	    return iInputStream_->MaxGain();
+	} else
+	    return PJ_EINVALIDOP;
+    }
+    
+private:
+    State		     state_;
+    struct mda_stream	    *parentStrm_;
+    pjmedia_aud_rec_cb	     recCb_;
+    void		    *userData_;
+    CMdaAudioInputStream    *iInputStream_;
+    HBufC8		    *iStreamBuffer_;
+    TPtr8		     iFramePtr_;
+    TInt		     lastError_;
+    pj_uint32_t		     timeStamp_;
+    CActiveSchedulerWait     startAsw_;
+
+    // cache variable
+    // to avoid calculating frame length repeatedly
+    TInt		     frameLen_;
+    
+    // sometimes recorded size != requested framesize, so let's
+    // provide a buffer to make sure the rec callback returning
+    // framesize as requested.
+    TUint8		    *frameRecBuf_;
+    TInt		     frameRecBufLen_;
+
+    CPjAudioInputEngine(struct mda_stream *parent_strm,
+	    pjmedia_aud_rec_cb rec_cb,
+			void *user_data);
+    void ConstructL();
+    TPtr8 & GetFrame();
+    
+public:
+    virtual void MaiscOpenComplete(TInt aError);
+    virtual void MaiscBufferCopied(TInt aError, const TDesC8 &aBuffer);
+    virtual void MaiscRecordComplete(TInt aError);
+
+};
+
+
+CPjAudioInputEngine::CPjAudioInputEngine(struct mda_stream *parent_strm,
+					 pjmedia_aud_rec_cb rec_cb,
+					 void *user_data)
+    : state_(STATE_INACTIVE), parentStrm_(parent_strm), 
+      recCb_(rec_cb), userData_(user_data), 
+      iInputStream_(NULL), iStreamBuffer_(NULL), iFramePtr_(0, 0),
+      lastError_(KErrNone), timeStamp_(0),
+      frameLen_(parent_strm->param.samples_per_frame * 
+	        BYTES_PER_SAMPLE),
+      frameRecBuf_(NULL), frameRecBufLen_(0)
+{
+}
+
+CPjAudioInputEngine::~CPjAudioInputEngine()
+{
+    Stop();
+
+    delete iStreamBuffer_;
+    iStreamBuffer_ = NULL;
+    
+    delete [] frameRecBuf_;
+    frameRecBuf_ = NULL;
+    frameRecBufLen_ = 0;
+}
+
+void CPjAudioInputEngine::ConstructL()
+{
+    iStreamBuffer_ = HBufC8::NewL(frameLen_);
+    CleanupStack::PushL(iStreamBuffer_);
+
+    frameRecBuf_ = new TUint8[frameLen_*2];
+    CleanupStack::PushL(frameRecBuf_);
+}
+
+CPjAudioInputEngine *CPjAudioInputEngine::NewLC(struct mda_stream *parent,
+						pjmedia_aud_rec_cb rec_cb,
+					        void *user_data)
+{
+    CPjAudioInputEngine* self = new (ELeave) CPjAudioInputEngine(parent,
+								 rec_cb, 
+								 user_data);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+}
+
+CPjAudioInputEngine *CPjAudioInputEngine::NewL(struct mda_stream *parent,
+					       pjmedia_aud_rec_cb rec_cb,
+					       void *user_data)
+{
+    CPjAudioInputEngine *self = NewLC(parent, rec_cb, user_data);
+    CleanupStack::Pop(self->frameRecBuf_);
+    CleanupStack::Pop(self->iStreamBuffer_);
+    CleanupStack::Pop(self);
+    return self;
+}
+
+
+pj_status_t CPjAudioInputEngine::StartRecord()
+{
+
+    // Ignore command if recording is in progress.
+    if (state_ == STATE_ACTIVE)
+	return PJ_SUCCESS;
+
+    // According to Nokia's AudioStream example, some 2nd Edition, FP2 devices
+    // (such as Nokia 6630) require the stream to be reconstructed each time 
+    // before calling Open() - otherwise the callback never gets called.
+    // For uniform behavior, lets just delete/re-create the stream for all
+    // devices.
+
+    // Destroy existing stream.
+    if (iInputStream_) delete iInputStream_;
+    iInputStream_ = NULL;
+
+    // Create the stream.
+    TRAPD(err, iInputStream_ = CMdaAudioInputStream::NewL(*this));
+    if (err != KErrNone)
+	return PJ_RETURN_OS_ERROR(err);
+
+    // Initialize settings.
+    TMdaAudioDataSettings iStreamSettings;
+    iStreamSettings.iChannels = 
+			    get_channel_cap(parentStrm_->param.channel_count);
+    iStreamSettings.iSampleRate = 
+			    get_clock_rate_cap(parentStrm_->param.clock_rate);
+
+    pj_assert(iStreamSettings.iChannels != 0 && 
+	      iStreamSettings.iSampleRate != 0);
+
+    PJ_LOG(4,(THIS_FILE, "Opening sound device for capture, "
+    		         "clock rate=%d, channel count=%d..",
+    		         parentStrm_->param.clock_rate, 
+    		         parentStrm_->param.channel_count));
+    
+    // Open stream.
+    lastError_ = KRequestPending;
+    iInputStream_->Open(&iStreamSettings);
+    
+#if defined(PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START) && \
+    PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START != 0
+    
+    startAsw_.Start();
+    
+#endif
+    
+    // Success
+    PJ_LOG(4,(THIS_FILE, "Sound capture started."));
+    return PJ_SUCCESS;
+}
+
+
+void CPjAudioInputEngine::Stop()
+{
+    // If capture is in progress, stop it.
+    if (iInputStream_ && state_ == STATE_ACTIVE) {
+    	lastError_ = KRequestPending;
+    	iInputStream_->Stop();
+
+	// Wait until it's actually stopped
+    	while (lastError_ == KRequestPending)
+	    pj_symbianos_poll(-1, 100);
+    }
+
+    if (iInputStream_) {
+	delete iInputStream_;
+	iInputStream_ = NULL;
+    }
+    
+    if (startAsw_.IsStarted()) {
+	startAsw_.AsyncStop();
+    }
+    
+    state_ = STATE_INACTIVE;
+}
+
+
+TPtr8 & CPjAudioInputEngine::GetFrame() 
+{
+    //iStreamBuffer_->Des().FillZ(frameLen_);
+    iFramePtr_.Set((TUint8*)(iStreamBuffer_->Ptr()), frameLen_, frameLen_);
+    return iFramePtr_;
+}
+
+void CPjAudioInputEngine::MaiscOpenComplete(TInt aError)
+{
+    if (startAsw_.IsStarted()) {
+	startAsw_.AsyncStop();
+    }
+    
+    lastError_ = aError;
+    if (aError != KErrNone) {
+        snd_perror("Error in MaiscOpenComplete()", aError);
+    	return;
+    }
+
+    /* Apply input volume setting if specified */
+    if (parentStrm_->param.flags & 
+        PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING) 
+    {
+        stream_set_cap(&parentStrm_->base,
+                       PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING, 
+                       &parentStrm_->param.input_vol);
+    }
+
+    // set stream priority to normal and time sensitive
+    iInputStream_->SetPriority(EPriorityNormal, 
+    			       EMdaPriorityPreferenceTime);				
+
+    // Read the first frame.
+    TPtr8 & frm = GetFrame();
+    TRAPD(err2, iInputStream_->ReadL(frm));
+    if (err2) {
+    	PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
+	lastError_ = err2;
+	return;
+    }
+
+    // input stream opened succesfully, set status to Active
+    state_ = STATE_ACTIVE;
+}
+
+void CPjAudioInputEngine::MaiscBufferCopied(TInt aError, 
+					    const TDesC8 &aBuffer)
+{
+    lastError_ = aError;
+    if (aError != KErrNone) {
+    	snd_perror("Error in MaiscBufferCopied()", aError);
+	return;
+    }
+
+    if (frameRecBufLen_ || aBuffer.Length() < frameLen_) {
+	pj_memcpy(frameRecBuf_ + frameRecBufLen_, (void*) aBuffer.Ptr(), aBuffer.Length());
+	frameRecBufLen_ += aBuffer.Length();
+    }
+
+    if (frameRecBufLen_) {
+    	while (frameRecBufLen_ >= frameLen_) {
+    	    pjmedia_frame f;
+    	    
+    	    f.type = PJMEDIA_FRAME_TYPE_AUDIO;
+    	    f.buf = frameRecBuf_;
+    	    f.size = frameLen_;
+    	    f.timestamp.u32.lo = timeStamp_;
+    	    f.bit_info = 0;
+    	    
+    	    // Call the callback.
+	    recCb_(userData_, &f);
+	    // Increment timestamp.
+	    timeStamp_ += parentStrm_->param.samples_per_frame;
+
+	    frameRecBufLen_ -= frameLen_;
+	    pj_memmove(frameRecBuf_, frameRecBuf_+frameLen_, frameRecBufLen_);
+    	}
+    } else {
+	pjmedia_frame f;
+	
+	f.type = PJMEDIA_FRAME_TYPE_AUDIO;
+	f.buf = (void*)aBuffer.Ptr();
+	f.size = aBuffer.Length();
+	f.timestamp.u32.lo = timeStamp_;
+	f.bit_info = 0;
+	
+	// Call the callback.
+	recCb_(userData_, &f);
+	
+	// Increment timestamp.
+	timeStamp_ += parentStrm_->param.samples_per_frame;
+    }
+
+    // Record next frame
+    TPtr8 & frm = GetFrame();
+    TRAPD(err2, iInputStream_->ReadL(frm));
+    if (err2) {
+    	PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
+    }
+}
+
+
+void CPjAudioInputEngine::MaiscRecordComplete(TInt aError)
+{
+    lastError_ = aError;
+    state_ = STATE_INACTIVE;
+    if (aError != KErrNone && aError != KErrCancel) {
+    	snd_perror("Error in MaiscRecordComplete()", aError);
+    }
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+
+/*
+ * Implementation: Symbian Output Stream.
+ */
+
+class CPjAudioOutputEngine : public CBase, MMdaAudioOutputStreamCallback
+{
+public:
+    enum State
+    {
+	STATE_INACTIVE,
+	STATE_ACTIVE,
+    };
+
+    ~CPjAudioOutputEngine();
+
+    static CPjAudioOutputEngine *NewL(struct mda_stream *parent_strm,
+				      pjmedia_aud_play_cb play_cb,
+				      void *user_data);
+
+    static CPjAudioOutputEngine *NewLC(struct mda_stream *parent_strm,
+				       pjmedia_aud_play_cb rec_cb,
+				       void *user_data);
+
+    pj_status_t StartPlay();
+    void Stop();
+
+    pj_status_t SetVolume(TInt vol) { 
+	if (iOutputStream_) { 
+	    iOutputStream_->SetVolume(vol);
+	    return PJ_SUCCESS;
+	} else
+	    return PJ_EINVALIDOP;
+    }
+    
+    TInt GetVolume() { 
+	if (iOutputStream_) { 
+	    return iOutputStream_->Volume();
+	} else
+	    return PJ_EINVALIDOP;
+    }
+
+    TInt GetMaxVolume() { 
+	if (iOutputStream_) { 
+	    return iOutputStream_->MaxVolume();
+	} else
+	    return PJ_EINVALIDOP;
+    }
+
+private:
+    State		     state_;
+    struct mda_stream	    *parentStrm_;
+    pjmedia_aud_play_cb	     playCb_;
+    void		    *userData_;
+    CMdaAudioOutputStream   *iOutputStream_;
+    TUint8		    *frameBuf_;
+    unsigned		     frameBufSize_;
+    TPtrC8		     frame_;
+    TInt		     lastError_;
+    unsigned		     timestamp_;
+    CActiveSchedulerWait     startAsw_;
+
+    CPjAudioOutputEngine(struct mda_stream *parent_strm,
+			 pjmedia_aud_play_cb play_cb,
+			 void *user_data);
+    void ConstructL();
+
+    virtual void MaoscOpenComplete(TInt aError);
+    virtual void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
+    virtual void MaoscPlayComplete(TInt aError);
+};
+
+
+CPjAudioOutputEngine::CPjAudioOutputEngine(struct mda_stream *parent_strm,
+					   pjmedia_aud_play_cb play_cb,
+					   void *user_data) 
+: state_(STATE_INACTIVE), parentStrm_(parent_strm), playCb_(play_cb), 
+  userData_(user_data), iOutputStream_(NULL), frameBuf_(NULL),
+  lastError_(KErrNone), timestamp_(0)
+{
+}
+
+
+void CPjAudioOutputEngine::ConstructL()
+{
+    frameBufSize_ = parentStrm_->param.samples_per_frame *
+		    BYTES_PER_SAMPLE;
+    frameBuf_ = new TUint8[frameBufSize_];
+}
+
+CPjAudioOutputEngine::~CPjAudioOutputEngine()
+{
+    Stop();
+    delete [] frameBuf_;	
+}
+
+CPjAudioOutputEngine *
+CPjAudioOutputEngine::NewLC(struct mda_stream *parent_strm,
+			    pjmedia_aud_play_cb play_cb,
+			    void *user_data)
+{
+    CPjAudioOutputEngine* self = new (ELeave) CPjAudioOutputEngine(parent_strm,
+								   play_cb, 
+								   user_data);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    return self;
+}
+
+CPjAudioOutputEngine *
+CPjAudioOutputEngine::NewL(struct mda_stream *parent_strm,
+			   pjmedia_aud_play_cb play_cb,
+			   void *user_data)
+{
+    CPjAudioOutputEngine *self = NewLC(parent_strm, play_cb, user_data);
+    CleanupStack::Pop(self);
+    return self;
+}
+
+pj_status_t CPjAudioOutputEngine::StartPlay()
+{
+    // Ignore command if playing is in progress.
+    if (state_ == STATE_ACTIVE)
+	return PJ_SUCCESS;
+    
+    // Destroy existing stream.
+    if (iOutputStream_) delete iOutputStream_;
+    iOutputStream_ = NULL;
+    
+    // Create the stream
+    TRAPD(err, iOutputStream_ = CMdaAudioOutputStream::NewL(*this));
+    if (err != KErrNone)
+	return PJ_RETURN_OS_ERROR(err);
+    
+    // Initialize settings.
+    TMdaAudioDataSettings iStreamSettings;
+    iStreamSettings.iChannels = 
+			    get_channel_cap(parentStrm_->param.channel_count);
+    iStreamSettings.iSampleRate = 
+			    get_clock_rate_cap(parentStrm_->param.clock_rate);
+
+    pj_assert(iStreamSettings.iChannels != 0 && 
+	      iStreamSettings.iSampleRate != 0);
+    
+    PJ_LOG(4,(THIS_FILE, "Opening sound device for playback, "
+    		         "clock rate=%d, channel count=%d..",
+    		         parentStrm_->param.clock_rate, 
+    		         parentStrm_->param.channel_count));
+
+    // Open stream.
+    lastError_ = KRequestPending;
+    iOutputStream_->Open(&iStreamSettings);
+    
+#if defined(PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START) && \
+    PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START != 0
+    
+    startAsw_.Start();
+    
+#endif
+
+    // Success
+    PJ_LOG(4,(THIS_FILE, "Sound playback started"));
+    return PJ_SUCCESS;
+
+}
+
+void CPjAudioOutputEngine::Stop()
+{
+    // Stop stream if it's playing
+    if (iOutputStream_ && state_ != STATE_INACTIVE) {
+    	lastError_ = KRequestPending;
+    	iOutputStream_->Stop();
+
+	// Wait until it's actually stopped
+    	while (lastError_ == KRequestPending)
+	    pj_symbianos_poll(-1, 100);
+    }
+    
+    if (iOutputStream_) {	
+	delete iOutputStream_;
+	iOutputStream_ = NULL;
+    }
+    
+    if (startAsw_.IsStarted()) {
+	startAsw_.AsyncStop();
+    }
+    
+    state_ = STATE_INACTIVE;
+}
+
+void CPjAudioOutputEngine::MaoscOpenComplete(TInt aError)
+{
+    if (startAsw_.IsStarted()) {
+	startAsw_.AsyncStop();
+    }
+
+    lastError_ = aError;
+    
+    if (aError==KErrNone) {
+	// set stream properties, 16bit 8KHz mono
+	TMdaAudioDataSettings iSettings;
+	iSettings.iChannels = 
+			get_channel_cap(parentStrm_->param.channel_count);
+	iSettings.iSampleRate = 
+			get_clock_rate_cap(parentStrm_->param.clock_rate);
+
+	iOutputStream_->SetAudioPropertiesL(iSettings.iSampleRate, 
+					    iSettings.iChannels);
+
+        /* Apply output volume setting if specified */
+        if (parentStrm_->param.flags & 
+            PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING) 
+        {
+            stream_set_cap(&parentStrm_->base,
+                           PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, 
+                           &parentStrm_->param.output_vol);
+        } else {
+            // set volume to 1/2th of stream max volume
+            iOutputStream_->SetVolume(iOutputStream_->MaxVolume()/2);
+        }
+	
+	// set stream priority to normal and time sensitive
+	iOutputStream_->SetPriority(EPriorityNormal, 
+				    EMdaPriorityPreferenceTime);				
+
+	// Call callback to retrieve frame from upstream.
+	pjmedia_frame f;
+	pj_status_t status;
+	
+	f.type = PJMEDIA_FRAME_TYPE_AUDIO;
+	f.buf = frameBuf_;
+	f.size = frameBufSize_;
+	f.timestamp.u32.lo = timestamp_;
+	f.bit_info = 0;
+
+	status = playCb_(this->userData_, &f);
+	if (status != PJ_SUCCESS) {
+	    this->Stop();
+	    return;
+	}
+
+	if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
+	    pj_bzero(frameBuf_, frameBufSize_);
+	
+	// Increment timestamp.
+	timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
+
+	// issue WriteL() to write the first audio data block, 
+	// subsequent calls to WriteL() will be issued in 
+	// MMdaAudioOutputStreamCallback::MaoscBufferCopied() 
+	// until whole data buffer is written.
+	frame_.Set(frameBuf_, frameBufSize_);
+	iOutputStream_->WriteL(frame_);
+
+	// output stream opened succesfully, set status to Active
+	state_ = STATE_ACTIVE;
+    } else {
+    	snd_perror("Error in MaoscOpenComplete()", aError);
+    }
+}
+
+void CPjAudioOutputEngine::MaoscBufferCopied(TInt aError, 
+					     const TDesC8& aBuffer)
+{
+    PJ_UNUSED_ARG(aBuffer);
+
+    if (aError==KErrNone) {
+    	// Buffer successfully written, feed another one.
+
+	// Call callback to retrieve frame from upstream.
+	pjmedia_frame f;
+	pj_status_t status;
+	
+	f.type = PJMEDIA_FRAME_TYPE_AUDIO;
+	f.buf = frameBuf_;
+	f.size = frameBufSize_;
+	f.timestamp.u32.lo = timestamp_;
+	f.bit_info = 0;
+
+	status = playCb_(this->userData_, &f);
+	if (status != PJ_SUCCESS) {
+	    this->Stop();
+	    return;
+	}
+
+	if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
+	    pj_bzero(frameBuf_, frameBufSize_);
+	
+	// Increment timestamp.
+	timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
+
+	// Write to playback stream.
+	frame_.Set(frameBuf_, frameBufSize_);
+	iOutputStream_->WriteL(frame_);
+
+    } else if (aError==KErrAbort) {
+	// playing was aborted, due to call to CMdaAudioOutputStream::Stop()
+	state_ = STATE_INACTIVE;
+    } else  {
+	// error writing data to output
+	lastError_ = aError;
+	state_ = STATE_INACTIVE;
+	snd_perror("Error in MaoscBufferCopied()", aError);
+    }
+}
+
+void CPjAudioOutputEngine::MaoscPlayComplete(TInt aError)
+{
+    lastError_ = aError;
+    state_ = STATE_INACTIVE;
+    if (aError != KErrNone && aError != KErrCancel) {
+    	snd_perror("Error in MaoscPlayComplete()", aError);
+    }
+}
+
+/****************************************************************************
+ * Factory operations
+ */
+
+/*
+ * C compatible declaration of MDA factory.
+ */
+PJ_BEGIN_DECL
+PJ_DECL(pjmedia_aud_dev_factory*) pjmedia_symb_mda_factory(pj_pool_factory *pf);
+PJ_END_DECL
+
+/*
+ * Init Symbian audio driver.
+ */
+pjmedia_aud_dev_factory* pjmedia_symb_mda_factory(pj_pool_factory *pf)
+{
+    struct mda_factory *f;
+    pj_pool_t *pool;
+
+    pool = pj_pool_create(pf, "symb_aud", 1000, 1000, NULL);
+    f = PJ_POOL_ZALLOC_T(pool, struct mda_factory);
+    f->pf = pf;
+    f->pool = pool;
+    f->base.op = &factory_op;
+
+    return &f->base;
+}
+
+/* API: init factory */
+static pj_status_t factory_init(pjmedia_aud_dev_factory *f)
+{
+    struct mda_factory *af = (struct mda_factory*)f;
+
+    pj_ansi_strcpy(af->dev_info.name, "Symbian Audio");
+    af->dev_info.default_samples_per_sec = 8000;
+    af->dev_info.caps = PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING |
+			PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
+    af->dev_info.input_count = 1;
+    af->dev_info.output_count = 1;
+
+    PJ_LOG(4, (THIS_FILE, "Symb Mda initialized"));
+
+    return PJ_SUCCESS;
+}
+
+/* API: destroy factory */
+static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f)
+{
+    struct mda_factory *af = (struct mda_factory*)f;
+    pj_pool_t *pool = af->pool;
+
+    af->pool = NULL;
+    pj_pool_release(pool);
+
+    PJ_LOG(4, (THIS_FILE, "Symbian Mda destroyed"));
+    
+    return PJ_SUCCESS;
+}
+
+/* API: refresh the device list */
+static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f)
+{
+    PJ_UNUSED_ARG(f);
+    return PJ_ENOTSUP;
+}
+
+/* API: get number of devices */
+static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f)
+{
+    PJ_UNUSED_ARG(f);
+    return 1;
+}
+
+/* API: get device info */
+static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, 
+					unsigned index,
+					pjmedia_aud_dev_info *info)
+{
+    struct mda_factory *af = (struct mda_factory*)f;
+
+    PJ_ASSERT_RETURN(index == 0, PJMEDIA_EAUD_INVDEV);
+
+    pj_memcpy(info, &af->dev_info, sizeof(*info));
+
+    return PJ_SUCCESS;
+}
+
+/* API: create default device parameter */
+static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
+					 unsigned index,
+					 pjmedia_aud_param *param)
+{
+    struct mda_factory *af = (struct mda_factory*)f;
+
+    PJ_ASSERT_RETURN(index == 0, PJMEDIA_EAUD_INVDEV);
+
+    pj_bzero(param, sizeof(*param));
+    param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
+    param->rec_id = index;
+    param->play_id = index;
+    param->clock_rate = af->dev_info.default_samples_per_sec;
+    param->channel_count = 1;
+    param->samples_per_frame = af->dev_info.default_samples_per_sec * 20 / 1000;
+    param->bits_per_sample = BITS_PER_SAMPLE;
+    // Don't set the flags without specifying the flags value.
+    //param->flags = af->dev_info.caps;
+
+    return PJ_SUCCESS;
+}
+
+
+/* API: create stream */
+static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
+					 const pjmedia_aud_param *param,
+					 pjmedia_aud_rec_cb rec_cb,
+					 pjmedia_aud_play_cb play_cb,
+					 void *user_data,
+					 pjmedia_aud_stream **p_aud_strm)
+{
+    struct mda_factory *mf = (struct mda_factory*)f;
+    pj_pool_t *pool;
+    struct mda_stream *strm;
+
+    /* Can only support 16bits per sample raw PCM format. */
+    PJ_ASSERT_RETURN(param->bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);
+    PJ_ASSERT_RETURN((param->flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT)==0 ||
+		     param->ext_fmt.id == PJMEDIA_FORMAT_L16,
+		     PJ_ENOTSUP);
+    
+    /* It seems that MDA recorder only supports for mono channel. */
+    PJ_ASSERT_RETURN(param->channel_count == 1, PJ_EINVAL);
+
+    /* Create and Initialize stream descriptor */
+    pool = pj_pool_create(mf->pf, "symb_aud_dev", 1000, 1000, NULL);
+    PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
+
+    strm = PJ_POOL_ZALLOC_T(pool, struct mda_stream);
+    strm->pool = pool;
+    strm->param = *param;
+
+    // Create the output stream.
+    if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
+	TRAPD(err, strm->out_engine = CPjAudioOutputEngine::NewL(strm, play_cb,
+								 user_data));
+	if (err != KErrNone) {
+	    pj_pool_release(pool);	
+	    return PJ_RETURN_OS_ERROR(err);
+	}
+    }
+
+    // Create the input stream.
+    if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
+	TRAPD(err, strm->in_engine = CPjAudioInputEngine::NewL(strm, rec_cb, 
+							       user_data));
+	if (err != KErrNone) {
+	    strm->in_engine = NULL;
+	    delete strm->out_engine;
+	    strm->out_engine = NULL;
+	    pj_pool_release(pool);	
+	    return PJ_RETURN_OS_ERROR(err);
+	}
+    }
+	
+    /* Done */
+    strm->base.op = &stream_op;
+    *p_aud_strm = &strm->base;
+
+    return PJ_SUCCESS;
+}
+
+/* API: Get stream info. */
+static pj_status_t stream_get_param(pjmedia_aud_stream *s,
+				    pjmedia_aud_param *pi)
+{
+    struct mda_stream *strm = (struct mda_stream*)s;
+
+    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
+
+    pj_memcpy(pi, &strm->param, sizeof(*pi));
+    
+    /* Update the output volume setting */
+    if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
+		       &pi->output_vol) == PJ_SUCCESS)
+    {
+	pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
+    }
+    
+    /* Update the input volume setting */
+    if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
+		       &pi->input_vol) == PJ_SUCCESS)
+    {
+	pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING;
+    }
+    
+    return PJ_SUCCESS;
+}
+
+/* API: get capability */
+static pj_status_t stream_get_cap(pjmedia_aud_stream *s,
+				  pjmedia_aud_dev_cap cap,
+				  void *pval)
+{
+    struct mda_stream *strm = (struct mda_stream*)s;
+    pj_status_t status = PJ_ENOTSUP;
+
+    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
+
+    switch (cap) {
+    case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
+	if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
+	    PJ_ASSERT_RETURN(strm->in_engine, PJ_EINVAL);
+	    
+	    TInt max_gain = strm->in_engine->GetMaxGain();
+	    TInt gain = strm->in_engine->GetGain();
+	    
+	    if (max_gain > 0 && gain >= 0) {
+		*(unsigned*)pval = gain * 100 / max_gain; 
+		status = PJ_SUCCESS;
+	    } else {
+		status = PJMEDIA_EAUD_NOTREADY;
+	    }
+	}
+	break;
+    case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
+	if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
+	    PJ_ASSERT_RETURN(strm->out_engine, PJ_EINVAL);
+	    
+	    TInt max_vol = strm->out_engine->GetMaxVolume();
+	    TInt vol = strm->out_engine->GetVolume();
+	    
+	    if (max_vol > 0 && vol >= 0) {
+		*(unsigned*)pval = vol * 100 / max_vol; 
+		status = PJ_SUCCESS;
+	    } else {
+		status = PJMEDIA_EAUD_NOTREADY;
+	    }
+	}
+	break;
+    default:
+	break;
+    }
+    
+    return status;
+}
+
+/* API: set capability */
+static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
+				  pjmedia_aud_dev_cap cap,
+				  const void *pval)
+{
+    struct mda_stream *strm = (struct mda_stream*)s;
+    pj_status_t status = PJ_ENOTSUP;
+
+    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
+
+    switch (cap) {
+    case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
+	if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
+	    PJ_ASSERT_RETURN(strm->in_engine, PJ_EINVAL);
+	    
+	    TInt max_gain = strm->in_engine->GetMaxGain();
+	    if (max_gain > 0) {
+		TInt gain;
+		
+		gain = *(unsigned*)pval * max_gain / 100;
+		status = strm->in_engine->SetGain(gain);
+	    } else {
+		status = PJMEDIA_EAUD_NOTREADY;
+	    }
+	}
+	break;
+    case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
+	if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
+	    PJ_ASSERT_RETURN(strm->out_engine, PJ_EINVAL);
+	    
+	    TInt max_vol = strm->out_engine->GetMaxVolume();
+	    if (max_vol > 0) {
+		TInt vol;
+		
+		vol = *(unsigned*)pval * max_vol / 100;
+		status = strm->out_engine->SetVolume(vol);
+	    } else {
+		status = PJMEDIA_EAUD_NOTREADY;
+	    }
+	}
+	break;
+    default:
+	break;
+    }
+    
+    return status;
+}
+
+/* API: Start stream. */
+static pj_status_t stream_start(pjmedia_aud_stream *strm)
+{
+    struct mda_stream *stream = (struct mda_stream*)strm;
+
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    if (stream->out_engine) {
+	pj_status_t status;
+    	status = stream->out_engine->StartPlay();
+    	if (status != PJ_SUCCESS)
+    	    return status;
+    }
+    
+    if (stream->in_engine) {
+	pj_status_t status;
+    	status = stream->in_engine->StartRecord();
+    	if (status != PJ_SUCCESS)
+    	    return status;
+    }
+
+    return PJ_SUCCESS;
+}
+
+/* API: Stop stream. */
+static pj_status_t stream_stop(pjmedia_aud_stream *strm)
+{
+    struct mda_stream *stream = (struct mda_stream*)strm;
+
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    if (stream->in_engine) {
+    	stream->in_engine->Stop();
+    }
+    	
+    if (stream->out_engine) {
+    	stream->out_engine->Stop();
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/* API: Destroy stream. */
+static pj_status_t stream_destroy(pjmedia_aud_stream *strm)
+{
+    struct mda_stream *stream = (struct mda_stream*)strm;
+
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    stream_stop(strm);
+
+    delete stream->in_engine;
+    stream->in_engine = NULL;
+
+    delete stream->out_engine;
+    stream->out_engine = NULL;
+
+    pj_pool_t *pool;
+    pool = stream->pool;
+    if (pool) {
+    	stream->pool = NULL;
+    	pj_pool_release(pool);
+    }
+
+    return PJ_SUCCESS;
+}
+
+#endif /* PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA */
diff --git a/jni/pjproject-android/.svn/pristine/49/499d6eeec0a295cb60c54eea1df8be9f397918d8.svn-base b/jni/pjproject-android/.svn/pristine/49/499d6eeec0a295cb60c54eea1df8be9f397918d8.svn-base
new file mode 100644
index 0000000..ca907ba
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/49/499d6eeec0a295cb60c54eea1df8be9f397918d8.svn-base
@@ -0,0 +1,1447 @@
+/* $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 <pjsip-ua/sip_regc.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_parser.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_transaction.h>
+#include <pjsip/sip_event.h>
+#include <pjsip/sip_util.h>
+#include <pjsip/sip_auth_msg.h>
+#include <pjsip/sip_errno.h>
+#include <pj/assert.h>
+#include <pj/guid.h>
+#include <pj/lock.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pj/log.h>
+#include <pj/rand.h>
+#include <pj/string.h>
+
+
+#define REFRESH_TIMER		1
+#define DELAY_BEFORE_REFRESH    PJSIP_REGISTER_CLIENT_DELAY_BEFORE_REFRESH
+#define THIS_FILE		"sip_reg.c"
+
+/* Outgoing transaction timeout when server sends 100 but never replies
+ * with final response. Value is in MILISECONDS!
+ */
+#define REGC_TSX_TIMEOUT	33000
+
+enum { NOEXP = 0x1FFFFFFF };
+
+static const pj_str_t XUID_PARAM_NAME = { "x-uid", 5 };
+
+
+/* Current/pending operation */
+enum regc_op
+{
+    REGC_IDLE,
+    REGC_REGISTERING,
+    REGC_UNREGISTERING
+};
+
+/**
+ * SIP client registration structure.
+ */
+struct pjsip_regc
+{
+    pj_pool_t			*pool;
+    pjsip_endpoint		*endpt;
+    pj_lock_t			*lock;
+    pj_bool_t			 _delete_flag;
+    pj_bool_t			 has_tsx;
+    pj_atomic_t			*busy_ctr;
+    enum regc_op		 current_op;
+
+    pj_bool_t			 add_xuid_param;
+
+    void			*token;
+    pjsip_regc_cb		*cb;
+    pjsip_regc_tsx_cb           *tsx_cb;
+
+    pj_str_t			 str_srv_url;
+    pjsip_uri			*srv_url;
+    pjsip_cid_hdr		*cid_hdr;
+    pjsip_cseq_hdr		*cseq_hdr;
+    pj_str_t			 from_uri;
+    pjsip_from_hdr		*from_hdr;
+    pjsip_to_hdr		*to_hdr;
+    pjsip_contact_hdr		 contact_hdr_list;
+    pjsip_contact_hdr		 removed_contact_hdr_list;
+    pjsip_expires_hdr		*expires_hdr;
+    pj_uint32_t			 expires;
+    pj_uint32_t			 delay_before_refresh;
+    pjsip_route_hdr		 route_set;
+    pjsip_hdr			 hdr_list;
+    pjsip_host_port              via_addr;
+    const void                  *via_tp;
+
+    /* Authorization sessions. */
+    pjsip_auth_clt_sess		 auth_sess;
+
+    /* Auto refresh registration. */
+    pj_bool_t			 auto_reg;
+    pj_time_val			 last_reg;
+    pj_time_val			 next_reg;
+    pj_timer_entry		 timer;
+
+    /* Transport selector */
+    pjsip_tpselector		 tp_sel;
+
+    /* Last transport used. We acquire the transport to keep
+     * it open.
+     */
+    pjsip_transport		*last_transport;
+};
+
+
+PJ_DEF(pj_status_t) pjsip_regc_create( pjsip_endpoint *endpt, void *token,
+				       pjsip_regc_cb *cb,
+				       pjsip_regc **p_regc)
+{
+    pj_pool_t *pool;
+    pjsip_regc *regc;
+    pj_status_t status;
+
+    /* Verify arguments. */
+    PJ_ASSERT_RETURN(endpt && cb && p_regc, PJ_EINVAL);
+
+    pool = pjsip_endpt_create_pool(endpt, "regc%p", 1024, 1024);
+    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
+
+    regc = PJ_POOL_ZALLOC_T(pool, pjsip_regc);
+
+    regc->pool = pool;
+    regc->endpt = endpt;
+    regc->token = token;
+    regc->cb = cb;
+    regc->expires = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;
+    regc->add_xuid_param = pjsip_cfg()->regc.add_xuid_param;
+
+    status = pj_lock_create_recursive_mutex(pool, pool->obj_name, 
+					    &regc->lock);
+    if (status != PJ_SUCCESS) {
+	pj_pool_release(pool);
+	return status;
+    }
+
+    status = pj_atomic_create(pool, 0, &regc->busy_ctr);
+    if (status != PJ_SUCCESS) {
+	pj_lock_destroy(regc->lock);
+	pj_pool_release(pool);
+	return status;
+    }
+
+    status = pjsip_auth_clt_init(&regc->auth_sess, endpt, regc->pool, 0);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pj_list_init(&regc->route_set);
+    pj_list_init(&regc->hdr_list);
+    pj_list_init(&regc->contact_hdr_list);
+    pj_list_init(&regc->removed_contact_hdr_list);
+
+    /* Done */
+    *p_regc = regc;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_destroy(pjsip_regc *regc)
+{
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+
+    pj_lock_acquire(regc->lock);
+    if (regc->has_tsx || pj_atomic_get(regc->busy_ctr) != 0) {
+	regc->_delete_flag = 1;
+	regc->cb = NULL;
+	pj_lock_release(regc->lock);
+    } else {
+	pjsip_tpselector_dec_ref(&regc->tp_sel);
+	if (regc->last_transport) {
+	    pjsip_transport_dec_ref(regc->last_transport);
+	    regc->last_transport = NULL;
+	}
+	if (regc->timer.id != 0) {
+	    pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
+	    regc->timer.id = 0;
+	}
+	pj_atomic_destroy(regc->busy_ctr);
+	pj_lock_release(regc->lock);
+	pj_lock_destroy(regc->lock);
+	regc->lock = NULL;
+	pjsip_endpt_release_pool(regc->endpt, regc->pool);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_get_info( pjsip_regc *regc,
+					 pjsip_regc_info *info )
+{
+    PJ_ASSERT_RETURN(regc && info, PJ_EINVAL);
+
+    pj_lock_acquire(regc->lock);
+
+    info->server_uri = regc->str_srv_url;
+    info->client_uri = regc->from_uri;
+    info->is_busy = (pj_atomic_get(regc->busy_ctr) || regc->has_tsx);
+    info->auto_reg = regc->auto_reg;
+    info->interval = regc->expires;
+    info->transport = regc->last_transport;
+    
+    if (regc->has_tsx)
+	info->next_reg = 0;
+    else if (regc->auto_reg == 0)
+	info->next_reg = 0;
+    else if (regc->expires < 0)
+	info->next_reg = regc->expires;
+    else {
+	pj_time_val now, next_reg;
+
+	next_reg = regc->next_reg;
+	pj_gettimeofday(&now);
+	PJ_TIME_VAL_SUB(next_reg, now);
+	info->next_reg = next_reg.sec;
+    }
+
+    pj_lock_release(regc->lock);
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc)
+{
+    return regc->pool;
+}
+
+static void set_expires( pjsip_regc *regc, pj_uint32_t expires)
+{
+    if (expires != regc->expires) {
+	regc->expires_hdr = pjsip_expires_hdr_create(regc->pool, expires);
+    } else {
+	regc->expires_hdr = NULL;
+    }
+}
+
+
+static pj_status_t set_contact( pjsip_regc *regc,
+			        int contact_cnt,
+				const pj_str_t contact[] )
+{
+    const pj_str_t CONTACT = { "Contact", 7 };
+    pjsip_contact_hdr *h;
+    int i;
+    
+    /* Save existing contact list to removed_contact_hdr_list and
+     * clear contact_hdr_list.
+     */
+    pj_list_merge_last(&regc->removed_contact_hdr_list, 
+		       &regc->contact_hdr_list);
+
+    /* Set the expiration of Contacts in to removed_contact_hdr_list 
+     * zero.
+     */
+    h = regc->removed_contact_hdr_list.next;
+    while (h != &regc->removed_contact_hdr_list) {
+	h->expires = 0;
+	h = h->next;
+    }
+
+    /* Process new contacts */
+    for (i=0; i<contact_cnt; ++i) {
+	pjsip_contact_hdr *hdr;
+	pj_str_t tmp;
+
+	pj_strdup_with_null(regc->pool, &tmp, &contact[i]);
+	hdr = (pjsip_contact_hdr*)
+              pjsip_parse_hdr(regc->pool, &CONTACT, tmp.ptr, tmp.slen, NULL);
+	if (hdr == NULL) {
+	    PJ_LOG(4,(THIS_FILE, "Invalid Contact: \"%.*s\"", 
+		     (int)tmp.slen, tmp.ptr));
+	    return PJSIP_EINVALIDURI;
+	}
+
+	/* Find the new contact in old contact list. If found, remove
+	 * the old header from the old header list.
+	 */
+	h = regc->removed_contact_hdr_list.next;
+	while (h != &regc->removed_contact_hdr_list) {
+	    int rc;
+
+	    rc = pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, 
+			       h->uri, hdr->uri);
+	    if (rc == 0) {
+		/* Match */
+		pj_list_erase(h);
+		break;
+	    }
+
+	    h = h->next;
+	}
+
+	/* If add_xuid_param option is enabled and Contact URI is sip/sips,
+	 * add xuid parameter to assist matching the Contact URI in the 
+	 * REGISTER response later.
+	 */
+	if (regc->add_xuid_param && (PJSIP_URI_SCHEME_IS_SIP(hdr->uri) ||
+				     PJSIP_URI_SCHEME_IS_SIPS(hdr->uri))) 
+	{
+	    pjsip_param *xuid_param;
+	    pjsip_sip_uri *sip_uri;
+
+	    xuid_param = PJ_POOL_ZALLOC_T(regc->pool, pjsip_param);
+	    xuid_param->name = XUID_PARAM_NAME;
+	    pj_create_unique_string(regc->pool, &xuid_param->value);
+
+	    sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(hdr->uri);
+	    pj_list_push_back(&sip_uri->other_param, xuid_param);
+	}
+
+	pj_list_push_back(&regc->contact_hdr_list, hdr);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_init( pjsip_regc *regc,
+				     const pj_str_t *srv_url,
+				     const pj_str_t *from_url,
+				     const pj_str_t *to_url,
+				     int contact_cnt,
+				     const pj_str_t contact[],
+				     pj_uint32_t expires)
+{
+    pj_str_t tmp;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(regc && srv_url && from_url && to_url && 
+		     expires, PJ_EINVAL);
+
+    /* Copy server URL. */
+    pj_strdup_with_null(regc->pool, &regc->str_srv_url, srv_url);
+
+    /* Set server URL. */
+    tmp = regc->str_srv_url;
+    regc->srv_url = pjsip_parse_uri( regc->pool, tmp.ptr, tmp.slen, 0);
+    if (regc->srv_url == NULL) {
+	return PJSIP_EINVALIDURI;
+    }
+
+    /* Set "From" header. */
+    pj_strdup_with_null(regc->pool, &regc->from_uri, from_url);
+    tmp = regc->from_uri;
+    regc->from_hdr = pjsip_from_hdr_create(regc->pool);
+    regc->from_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen, 
+					  PJSIP_PARSE_URI_AS_NAMEADDR);
+    if (!regc->from_hdr->uri) {
+	PJ_LOG(4,(THIS_FILE, "regc: invalid source URI %.*s", 
+		  from_url->slen, from_url->ptr));
+	return PJSIP_EINVALIDURI;
+    }
+
+    /* Set "To" header. */
+    pj_strdup_with_null(regc->pool, &tmp, to_url);
+    regc->to_hdr = pjsip_to_hdr_create(regc->pool);
+    regc->to_hdr->uri = pjsip_parse_uri(regc->pool, tmp.ptr, tmp.slen, 
+					PJSIP_PARSE_URI_AS_NAMEADDR);
+    if (!regc->to_hdr->uri) {
+	PJ_LOG(4,(THIS_FILE, "regc: invalid target URI %.*s", to_url->slen, to_url->ptr));
+	return PJSIP_EINVALIDURI;
+    }
+
+
+    /* Set "Contact" header. */
+    status = set_contact( regc, contact_cnt, contact);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Set "Expires" header, if required. */
+    set_expires( regc, expires);
+    regc->delay_before_refresh = DELAY_BEFORE_REFRESH;
+
+    /* Set "Call-ID" header. */
+    regc->cid_hdr = pjsip_cid_hdr_create(regc->pool);
+    pj_create_unique_string(regc->pool, &regc->cid_hdr->id);
+
+    /* Set "CSeq" header. */
+    regc->cseq_hdr = pjsip_cseq_hdr_create(regc->pool);
+    regc->cseq_hdr->cseq = pj_rand() % 0xFFFF;
+    pjsip_method_set( &regc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
+
+    /* Done. */
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc,
+						int count,
+						const pjsip_cred_info cred[] )
+{
+    PJ_ASSERT_RETURN(regc && count && cred, PJ_EINVAL);
+    return pjsip_auth_clt_set_credentials(&regc->auth_sess, count, cred);
+}
+
+PJ_DEF(pj_status_t) pjsip_regc_set_prefs( pjsip_regc *regc,
+					  const pjsip_auth_clt_pref *pref)
+{
+    PJ_ASSERT_RETURN(regc && pref, PJ_EINVAL);
+    return pjsip_auth_clt_set_prefs(&regc->auth_sess, pref);
+}
+
+PJ_DEF(pj_status_t) pjsip_regc_set_route_set( pjsip_regc *regc,
+					      const pjsip_route_hdr *route_set)
+{
+    const pjsip_route_hdr *chdr;
+
+    PJ_ASSERT_RETURN(regc && route_set, PJ_EINVAL);
+
+    pj_list_init(&regc->route_set);
+
+    chdr = route_set->next;
+    while (chdr != route_set) {
+	pj_list_push_back(&regc->route_set, pjsip_hdr_clone(regc->pool, chdr));
+	chdr = chdr->next;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Bind client registration to a specific transport/listener. 
+ */
+PJ_DEF(pj_status_t) pjsip_regc_set_transport( pjsip_regc *regc,
+					      const pjsip_tpselector *sel)
+{
+    PJ_ASSERT_RETURN(regc && sel, PJ_EINVAL);
+
+    pjsip_tpselector_dec_ref(&regc->tp_sel);
+    pj_memcpy(&regc->tp_sel, sel, sizeof(*sel));
+    pjsip_tpselector_add_ref(&regc->tp_sel);
+
+    return PJ_SUCCESS;
+}
+
+/* Release transport */
+PJ_DEF(pj_status_t) pjsip_regc_release_transport(pjsip_regc *regc)
+{
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+    if (regc->last_transport) {
+	pjsip_transport_dec_ref(regc->last_transport);
+	regc->last_transport = NULL;
+    }
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_add_headers( pjsip_regc *regc,
+					    const pjsip_hdr *hdr_list)
+{
+    const pjsip_hdr *hdr;
+
+    PJ_ASSERT_RETURN(regc && hdr_list, PJ_EINVAL);
+
+    //This is "add" operation, so don't remove headers.
+    //pj_list_init(&regc->hdr_list);
+
+    hdr = hdr_list->next;
+    while (hdr != hdr_list) {
+	pj_list_push_back(&regc->hdr_list, pjsip_hdr_clone(regc->pool, hdr));
+	hdr = hdr->next;
+    }
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t create_request(pjsip_regc *regc, 
+				  pjsip_tx_data **p_tdata)
+{
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+
+    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+
+    /* Create the request. */
+    status = pjsip_endpt_create_request_from_hdr( regc->endpt, 
+						  pjsip_get_register_method(),
+						  regc->srv_url,
+						  regc->from_hdr,
+						  regc->to_hdr,
+						  NULL,
+						  regc->cid_hdr,
+						  regc->cseq_hdr->cseq,
+						  NULL,
+						  &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Add cached authorization headers. */
+    pjsip_auth_clt_init_req( &regc->auth_sess, tdata );
+
+    /* Add Route headers from route set, ideally after Via header */
+    if (!pj_list_empty(&regc->route_set)) {
+	pjsip_hdr *route_pos;
+	const pjsip_route_hdr *route;
+
+	route_pos = (pjsip_hdr*)
+		    pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
+	if (!route_pos)
+	    route_pos = &tdata->msg->hdr;
+
+	route = regc->route_set.next;
+	while (route != &regc->route_set) {
+	    pjsip_hdr *new_hdr = (pjsip_hdr*)
+				 pjsip_hdr_shallow_clone(tdata->pool, route);
+	    pj_list_insert_after(route_pos, new_hdr);
+	    route_pos = new_hdr;
+	    route = route->next;
+	}
+    }
+
+    /* Add additional request headers */
+    if (!pj_list_empty(&regc->hdr_list)) {
+	const pjsip_hdr *hdr;
+
+	hdr = regc->hdr_list.next;
+	while (hdr != &regc->hdr_list) {
+	    pjsip_hdr *new_hdr = (pjsip_hdr*)
+				 pjsip_hdr_shallow_clone(tdata->pool, hdr);
+	    pjsip_msg_add_hdr(tdata->msg, new_hdr);
+	    hdr = hdr->next;
+	}
+    }
+
+    /* Done. */
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg,
+					pjsip_tx_data **p_tdata)
+{
+    pjsip_msg *msg;
+    pjsip_contact_hdr *hdr;
+    const pjsip_hdr *h_allow;
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+
+    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+
+    pj_lock_acquire(regc->lock);
+
+    status = create_request(regc, &tdata);
+    if (status != PJ_SUCCESS) {
+	pj_lock_release(regc->lock);
+	return status;
+    }
+
+    msg = tdata->msg;
+
+    /* Add Contact headers. */
+    hdr = regc->contact_hdr_list.next;
+    while (hdr != &regc->contact_hdr_list) {
+	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
+			       pjsip_hdr_shallow_clone(tdata->pool, hdr));
+	hdr = hdr->next;
+    }
+
+    /* Also add bindings which are to be removed */
+    while (!pj_list_empty(&regc->removed_contact_hdr_list)) {
+	hdr = regc->removed_contact_hdr_list.next;
+	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
+			       pjsip_hdr_clone(tdata->pool, hdr));
+	pj_list_erase(hdr);
+    }
+    
+
+    if (regc->expires_hdr)
+	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
+			       pjsip_hdr_shallow_clone(tdata->pool,
+						       regc->expires_hdr));
+
+    if (regc->timer.id != 0) {
+	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
+	regc->timer.id = 0;
+    }
+
+    /* Add Allow header (http://trac.pjsip.org/repos/ticket/1039) */
+    h_allow = pjsip_endpt_get_capability(regc->endpt, PJSIP_H_ALLOW, NULL);
+    if (h_allow) {
+	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
+			       pjsip_hdr_shallow_clone(tdata->pool, h_allow));
+
+    }
+
+    regc->auto_reg = autoreg;
+
+    pj_lock_release(regc->lock);
+
+    /* Done */
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_unregister(pjsip_regc *regc,
+					  pjsip_tx_data **p_tdata)
+{
+    pjsip_tx_data *tdata;
+    pjsip_msg *msg;
+    pjsip_hdr *hdr;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+
+    pj_lock_acquire(regc->lock);
+
+    if (regc->timer.id != 0) {
+	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
+	regc->timer.id = 0;
+    }
+
+    status = create_request(regc, &tdata);
+    if (status != PJ_SUCCESS) {
+	pj_lock_release(regc->lock);
+	return status;
+    }
+
+    msg = tdata->msg;
+
+    /* Add Contact headers. */
+    hdr = (pjsip_hdr*)regc->contact_hdr_list.next;
+    while ((void*)hdr != (void*)&regc->contact_hdr_list) {
+	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
+			       pjsip_hdr_shallow_clone(tdata->pool, hdr));
+	hdr = hdr->next;
+    }
+
+    /* Also add bindings which are to be removed */
+    while (!pj_list_empty(&regc->removed_contact_hdr_list)) {
+	hdr = (pjsip_hdr*)regc->removed_contact_hdr_list.next;
+	pjsip_msg_add_hdr(msg, (pjsip_hdr*)
+			       pjsip_hdr_clone(tdata->pool, hdr));
+	pj_list_erase(hdr);
+    }
+
+    /* Add Expires:0 header */
+    hdr = (pjsip_hdr*) pjsip_expires_hdr_create(tdata->pool, 0);
+    pjsip_msg_add_hdr(msg, hdr);
+
+    pj_lock_release(regc->lock);
+
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t) pjsip_regc_unregister_all(pjsip_regc *regc,
+					      pjsip_tx_data **p_tdata)
+{
+    pjsip_tx_data *tdata;
+    pjsip_contact_hdr *hcontact;
+    pjsip_hdr *hdr;
+    pjsip_msg *msg;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
+
+    pj_lock_acquire(regc->lock);
+
+    if (regc->timer.id != 0) {
+	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
+	regc->timer.id = 0;
+    }
+
+    status = create_request(regc, &tdata);
+    if (status != PJ_SUCCESS) {
+	pj_lock_release(regc->lock);
+	return status;
+    }
+
+    msg = tdata->msg;
+
+    /* Clear removed_contact_hdr_list */
+    pj_list_init(&regc->removed_contact_hdr_list);
+
+    /* Add Contact:* header */
+    hcontact = pjsip_contact_hdr_create(tdata->pool);
+    hcontact->star = 1;
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)hcontact);
+    
+    /* Add Expires:0 header */
+    hdr = (pjsip_hdr*) pjsip_expires_hdr_create(tdata->pool, 0);
+    pjsip_msg_add_hdr(msg, hdr);
+
+    pj_lock_release(regc->lock);
+
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_update_contact(  pjsip_regc *regc,
+					        int contact_cnt,
+						const pj_str_t contact[] )
+{
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+
+    pj_lock_acquire(regc->lock);
+    status = set_contact( regc, contact_cnt, contact );
+    pj_lock_release(regc->lock);
+
+    return status;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_update_expires(  pjsip_regc *regc,
+					        pj_uint32_t expires )
+{
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+
+    pj_lock_acquire(regc->lock);
+    set_expires( regc, expires );
+    pj_lock_release(regc->lock);
+
+    return PJ_SUCCESS;
+}
+
+static void cbparam_init( struct pjsip_regc_cbparam *cbparam,
+                          pjsip_regc *regc, 
+                          pj_status_t status, int st_code, 
+			  const pj_str_t *reason,
+			  pjsip_rx_data *rdata, pj_int32_t expiration,
+			  int contact_cnt, pjsip_contact_hdr *contact[])
+{
+    cbparam->regc = regc;
+    cbparam->token = regc->token;
+    cbparam->status = status;
+    cbparam->code = st_code;
+    cbparam->reason = *reason;
+    cbparam->rdata = rdata;
+    cbparam->contact_cnt = contact_cnt;
+    cbparam->expiration = expiration;
+    if (contact_cnt) {
+	pj_memcpy( cbparam->contact, contact, 
+		   contact_cnt*sizeof(pjsip_contact_hdr*));
+    }
+}
+
+static void call_callback(pjsip_regc *regc, pj_status_t status, int st_code, 
+			  const pj_str_t *reason,
+			  pjsip_rx_data *rdata, pj_int32_t expiration,
+			  int contact_cnt, pjsip_contact_hdr *contact[])
+{
+    struct pjsip_regc_cbparam cbparam;
+
+    if (!regc->cb)
+	return;
+
+    cbparam_init(&cbparam, regc, status, st_code, reason, rdata, expiration,
+                 contact_cnt, contact);
+    (*regc->cb)(&cbparam);
+}
+
+static void regc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
+				   struct pj_timer_entry *entry)
+{
+    pjsip_regc *regc = (pjsip_regc*) entry->user_data;
+    pjsip_tx_data *tdata;
+    pj_status_t status;
+    
+    PJ_UNUSED_ARG(timer_heap);
+
+    /* Temporarily increase busy flag to prevent regc from being deleted
+     * in pjsip_regc_send() or in the callback
+     */
+    pj_atomic_inc(regc->busy_ctr);
+
+    entry->id = 0;
+    status = pjsip_regc_register(regc, 1, &tdata);
+    if (status == PJ_SUCCESS) {
+	status = pjsip_regc_send(regc, tdata);
+    } 
+    
+    if (status != PJ_SUCCESS && regc->cb) {
+	char errmsg[PJ_ERR_MSG_SIZE];
+	pj_str_t reason = pj_strerror(status, errmsg, sizeof(errmsg));
+	call_callback(regc, status, 400, &reason, NULL, -1, 0, NULL);
+    }
+
+    /* Delete the record if user destroy regc during the callback. */
+    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) {
+	pjsip_regc_destroy(regc);
+    }
+}
+
+static void schedule_registration ( pjsip_regc *regc, pj_int32_t expiration )
+{
+    if (regc->auto_reg && expiration > 0) {
+        pj_time_val delay = { 0, 0};
+
+        pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(regc->endpt),
+                                       &regc->timer, 0);
+
+        delay.sec = expiration - regc->delay_before_refresh;
+        if (regc->expires != PJSIP_REGC_EXPIRATION_NOT_SPECIFIED && 
+            delay.sec > (pj_int32_t)regc->expires) 
+        {
+            delay.sec = regc->expires;
+        }
+        if (delay.sec < DELAY_BEFORE_REFRESH) 
+            delay.sec = DELAY_BEFORE_REFRESH;
+        regc->timer.cb = &regc_refresh_timer_cb;
+        regc->timer.id = REFRESH_TIMER;
+        regc->timer.user_data = regc;
+        pjsip_endpt_schedule_timer( regc->endpt, &regc->timer, &delay);
+        pj_gettimeofday(&regc->last_reg);
+        regc->next_reg = regc->last_reg;
+        regc->next_reg.sec += delay.sec;
+    }
+}
+
+PJ_DEF(pj_status_t) pjsip_regc_set_reg_tsx_cb( pjsip_regc *regc,
+				               pjsip_regc_tsx_cb *tsx_cb)
+{
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+    regc->tsx_cb = tsx_cb;
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_regc_set_via_sent_by( pjsip_regc *regc,
+				                pjsip_host_port *via_addr,
+                                                pjsip_transport *via_tp)
+{
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+
+    if (!via_addr)
+        pj_bzero(&regc->via_addr, sizeof(regc->via_addr));
+    else {
+        if (pj_strcmp(&regc->via_addr.host, &via_addr->host))
+            pj_strdup(regc->pool, &regc->via_addr.host, &via_addr->host);
+        regc->via_addr.port = via_addr->port;
+    }
+    regc->via_tp = via_tp;
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pj_status_t)
+pjsip_regc_set_delay_before_refresh( pjsip_regc *regc,
+				     pj_uint32_t delay )
+{
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+
+    if (delay > regc->expires)
+        return PJ_ETOOBIG;
+
+    pj_lock_acquire(regc->lock);
+
+    if (regc->delay_before_refresh != delay)
+    {
+        regc->delay_before_refresh = delay;
+
+        if (regc->timer.id != 0) {
+            /* Cancel registration timer */
+            pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
+            regc->timer.id = 0;
+
+            /* Schedule next registration */
+            schedule_registration(regc, regc->expires);
+        }
+    }
+
+    pj_lock_release(regc->lock);
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_int32_t calculate_response_expiration(const pjsip_regc *regc,
+					        const pjsip_rx_data *rdata,
+						unsigned *contact_cnt,
+						unsigned max_contact,
+						pjsip_contact_hdr *contacts[])
+{
+    pj_int32_t expiration = NOEXP;
+    const pjsip_msg *msg = rdata->msg_info.msg;
+    const pjsip_hdr *hdr;
+
+    /* Enumerate all Contact headers in the response */
+    *contact_cnt = 0;
+    for (hdr=msg->hdr.next; hdr!=&msg->hdr; hdr=hdr->next) {
+	if (hdr->type == PJSIP_H_CONTACT && 
+	    *contact_cnt < max_contact) 
+	{
+	    contacts[*contact_cnt] = (pjsip_contact_hdr*)hdr;
+	    ++(*contact_cnt);
+	}
+    }
+
+    if (regc->current_op == REGC_REGISTERING) {
+	pj_bool_t has_our_contact = PJ_FALSE;
+	const pjsip_expires_hdr *expires;
+
+	/* Get Expires header */
+	expires = (const pjsip_expires_hdr*)
+		  pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
+
+	/* Try to find the Contact URIs that we register, in the response
+	 * to get the expires value. We'll try both with comparing the URI
+	 * and comparing the extension param only.
+	 */
+	if (pjsip_cfg()->regc.check_contact || regc->add_xuid_param) {
+	    unsigned i;
+	    for (i=0; i<*contact_cnt; ++i) {
+		const pjsip_contact_hdr *our_hdr;
+
+		our_hdr = (const pjsip_contact_hdr*) 
+			  regc->contact_hdr_list.next;
+
+		/* Match with our Contact header(s) */
+		while ((void*)our_hdr != (void*)&regc->contact_hdr_list) {
+
+		    const pjsip_uri *uri1, *uri2;
+		    pj_bool_t matched = PJ_FALSE;
+
+		    /* Exclude the display name when comparing the URI 
+		     * since server may not return it.
+		     */
+		    uri1 = (const pjsip_uri*)
+			   pjsip_uri_get_uri(contacts[i]->uri);
+		    uri2 = (const pjsip_uri*)
+			   pjsip_uri_get_uri(our_hdr->uri);
+
+		    /* First try with exact matching, according to RFC 3261
+		     * Section 19.1.4 URI Comparison
+		     */
+		    if (pjsip_cfg()->regc.check_contact) {
+			matched = pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR,
+						uri1, uri2)==0;
+		    }
+
+		    /* If no match is found, try with matching the extension
+		     * parameter only if extension parameter was added.
+		     */
+		    if (!matched && regc->add_xuid_param &&
+			(PJSIP_URI_SCHEME_IS_SIP(uri1) ||
+			 PJSIP_URI_SCHEME_IS_SIPS(uri1)) && 
+			(PJSIP_URI_SCHEME_IS_SIP(uri2) ||
+			 PJSIP_URI_SCHEME_IS_SIPS(uri2))) 
+		    {
+			const pjsip_sip_uri *sip_uri1, *sip_uri2;
+			const pjsip_param *p1, *p2;
+		
+			sip_uri1 = (const pjsip_sip_uri*)uri1;
+			sip_uri2 = (const pjsip_sip_uri*)uri2;
+
+			p1 = pjsip_param_cfind(&sip_uri1->other_param,
+					       &XUID_PARAM_NAME);
+			p2 = pjsip_param_cfind(&sip_uri2->other_param,
+					       &XUID_PARAM_NAME);
+			matched = p1 && p2 &&
+				  pj_strcmp(&p1->value, &p2->value)==0;
+
+		    }
+
+		    if (matched) {
+			has_our_contact = PJ_TRUE;
+
+			if (contacts[i]->expires >= 0 && 
+			    contacts[i]->expires < expiration) 
+			{
+			    /* Get the lowest expiration time. */
+			    expiration = contacts[i]->expires;
+			}
+
+			break;
+		    }
+
+		    our_hdr = our_hdr->next;
+
+		} /* while ((void.. */
+
+	    }  /* for (i=.. */
+
+	    /* If matching Contact header(s) are found but the
+	     * header doesn't contain expires parameter, get the
+	     * expiration value from the Expires header. And
+	     * if Expires header is not present, get the expiration
+	     * value from the request.
+	     */
+	    if (has_our_contact && expiration == NOEXP) {
+		if (expires) {
+		    expiration = expires->ivalue;
+		} else if (regc->expires_hdr) {
+		    expiration = regc->expires_hdr->ivalue;
+		} else {
+		    /* We didn't request explicit expiration value,
+		     * and server doesn't specify it either. This 
+		     * shouldn't happen unless we have a broken
+		     * registrar.
+		     */
+		    expiration = 3600;
+		}
+	    }
+
+	}
+
+	/* If we still couldn't get matching Contact header(s), it means
+	 * there must be something wrong with the  registrar (e.g. it may
+	 * have modified the URI's in the response, which is prohibited).
+	 */
+	if (expiration==NOEXP) {
+	    /* If the number of Contact headers in the response matches 
+	     * ours, they're all probably ours. Get the expiration
+	     * from there if this is the case, or from Expires header
+	     * if we don't have exact Contact header count, or
+	     * from the request as the last resort.
+	     */
+	    pj_size_t our_contact_cnt;
+
+	    our_contact_cnt = pj_list_size(&regc->contact_hdr_list);
+
+	    if (*contact_cnt == our_contact_cnt && *contact_cnt &&
+		contacts[0]->expires >= 0) 
+	    {
+		expiration = contacts[0]->expires;
+	    } else if (expires)
+		expiration = expires->ivalue;
+	    else if (regc->expires_hdr)
+		expiration = regc->expires_hdr->ivalue;
+	    else
+		expiration = 3600;
+	}
+
+    } else {
+	/* Just assume that the unregistration has been successful. */
+	expiration = 0;
+    }
+
+    /* Must have expiration value by now */
+    pj_assert(expiration != NOEXP);
+
+    return expiration;
+}
+
+static void regc_tsx_callback(void *token, pjsip_event *event)
+{
+    pj_status_t status;
+    pjsip_regc *regc = (pjsip_regc*) token;
+    pjsip_transaction *tsx = event->body.tsx_state.tsx;
+    pj_bool_t handled = PJ_TRUE;
+    pj_bool_t update_contact = PJ_FALSE;
+
+    pj_atomic_inc(regc->busy_ctr);
+    pj_lock_acquire(regc->lock);
+
+    /* Decrement pending transaction counter. */
+    pj_assert(regc->has_tsx);
+    regc->has_tsx = PJ_FALSE;
+
+    /* Add reference to the transport */
+    if (tsx->transport != regc->last_transport) {
+	if (regc->last_transport) {
+	    pjsip_transport_dec_ref(regc->last_transport);
+	    regc->last_transport = NULL;
+	}
+
+	if (tsx->transport) {
+	    regc->last_transport = tsx->transport;
+	    pjsip_transport_add_ref(regc->last_transport);
+	}
+    }
+
+    if (regc->_delete_flag == 0 && regc->tsx_cb &&
+        regc->current_op == REGC_REGISTERING)
+    {
+        struct pjsip_regc_tsx_cb_param param;
+
+        param.contact_cnt = -1;
+        cbparam_init(&param.cbparam, regc, PJ_SUCCESS, tsx->status_code,
+		     &tsx->status_text,
+                     (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ? 
+	              event->body.tsx_state.src.rdata : NULL,
+                     -1, 0, NULL);
+
+        /* Call regc tsx callback before handling any response */
+        pj_lock_release(regc->lock);
+        (*regc->tsx_cb)(&param);
+        pj_lock_acquire(regc->lock);
+
+        if (param.contact_cnt >= 0) {
+            /* Since we receive non-2xx response, it means that (some) contact
+             * bindings haven't been established so we can safely remove these
+             * contact headers. This is to avoid removing non-existent contact
+             * bindings later.
+             */
+            if (tsx->status_code/100 != 2) {
+                pjsip_contact_hdr *h;
+
+	        h = regc->contact_hdr_list.next;
+	        while (h != &regc->contact_hdr_list) {
+                    pjsip_contact_hdr *next = h->next;
+
+                    if (h->expires == -1) {
+                        pj_list_erase(h);
+                    }
+                    h = next;
+                }
+	    }
+
+            /* Update contact address */
+            pjsip_regc_update_contact(regc, param.contact_cnt, param.contact);
+            update_contact = PJ_TRUE;
+        }
+    }
+
+    /* Handle 401/407 challenge (even when _delete_flag is set) */
+    if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
+	tsx->status_code == PJSIP_SC_UNAUTHORIZED)
+    {
+	pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
+	pjsip_tx_data *tdata;
+
+	/* reset current op */
+	regc->current_op = REGC_IDLE;
+
+        if (update_contact) {
+            pjsip_msg *msg;
+            pjsip_hdr *hdr, *ins_hdr;
+            pjsip_contact_hdr *chdr;
+
+            /* Delete Contact headers, but we shouldn't delete headers
+             * which are supposed to remove contact bindings since
+             * we cannot reconstruct those headers.
+             */
+            msg = tsx->last_tx->msg;
+            hdr = msg->hdr.next;
+            ins_hdr = &msg->hdr;
+            while (hdr != &msg->hdr) {
+                pjsip_hdr *next = hdr->next;
+
+                if (hdr->type == PJSIP_H_CONTACT) {
+                    chdr = (pjsip_contact_hdr *)hdr;
+                    if (chdr->expires != 0) {
+                        pj_list_erase(hdr);
+                        ins_hdr = next;
+                    }
+                }
+                hdr = next;
+            }
+
+            /* Add Contact headers. */
+            chdr = regc->contact_hdr_list.next;
+            while (chdr != &regc->contact_hdr_list) {
+	        pj_list_insert_before(ins_hdr, (pjsip_hdr*)
+                    pjsip_hdr_shallow_clone(tsx->last_tx->pool, chdr));
+	        chdr = chdr->next;
+            }
+
+            /* Also add bindings which are to be removed */
+            while (!pj_list_empty(&regc->removed_contact_hdr_list)) {
+	        chdr = regc->removed_contact_hdr_list.next;
+	        pj_list_insert_before(ins_hdr, (pjsip_hdr*)
+                    pjsip_hdr_clone(tsx->last_tx->pool, chdr));
+	        pj_list_erase(chdr);
+            }
+        }
+
+        status = pjsip_auth_clt_reinit_req( &regc->auth_sess,
+					    rdata, 
+					    tsx->last_tx,  
+					    &tdata);
+
+	if (status == PJ_SUCCESS) {
+	    status = pjsip_regc_send(regc, tdata);
+	}
+	
+	if (status != PJ_SUCCESS) {
+
+	    /* Only call callback if application is still interested
+	     * in it.
+	     */
+	    if (regc->_delete_flag == 0) {
+		/* Should be safe to release the lock temporarily.
+		 * We do this to avoid deadlock. 
+		 */
+		pj_lock_release(regc->lock);
+		call_callback(regc, status, tsx->status_code, 
+			      &rdata->msg_info.msg->line.status.reason,
+			      rdata, -1, 0, NULL);
+		pj_lock_acquire(regc->lock);
+	    }
+	}
+
+    } else if (regc->_delete_flag) {
+
+	/* User has called pjsip_regc_destroy(), so don't call callback. 
+	 * This regc will be destroyed later in this function.
+	 */
+
+	/* Just reset current op */
+	regc->current_op = REGC_IDLE;
+
+    } else if (tsx->status_code == PJSIP_SC_INTERVAL_TOO_BRIEF &&
+	       regc->current_op == REGC_REGISTERING)
+    {
+	/* Handle 423 response automatically:
+	 *  - set requested expiration to Min-Expires header, ONLY IF
+	 *    the original request is a registration (as opposed to
+	 *    unregistration) and the requested expiration was indeed
+	 *    lower than Min-Expires)
+	 *  - resend the request
+	 */
+	pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
+	pjsip_min_expires_hdr *me_hdr;
+	pjsip_tx_data *tdata;
+	pj_int32_t min_exp;
+
+	/* reset current op */
+	regc->current_op = REGC_IDLE;
+
+	/* Update requested expiration */
+	me_hdr = (pjsip_min_expires_hdr*)
+		 pjsip_msg_find_hdr(rdata->msg_info.msg,
+				    PJSIP_H_MIN_EXPIRES, NULL);
+	if (me_hdr) {
+	    min_exp = me_hdr->ivalue;
+	} else {
+	    /* Broken server, Min-Expires doesn't exist.
+	     * Just guestimate then, BUT ONLY if if this is the
+	     * first time we received such response.
+	     */
+	    enum {
+		/* Note: changing this value would require changing couple of
+		 *       Python test scripts.
+		 */
+		UNSPECIFIED_MIN_EXPIRES = 3601
+	    };
+	    if (!regc->expires_hdr ||
+		 regc->expires_hdr->ivalue != UNSPECIFIED_MIN_EXPIRES)
+	    {
+		min_exp = UNSPECIFIED_MIN_EXPIRES;
+	    } else {
+		handled = PJ_FALSE;
+		PJ_LOG(4,(THIS_FILE, "Registration failed: 423 response "
+				     "without Min-Expires header is invalid"));
+		goto handle_err;
+	    }
+	}
+
+	if (regc->expires_hdr && regc->expires_hdr->ivalue >= min_exp) {
+	    /* But we already send with greater expiration time, why does
+	     * the server send us with 423? Oh well, just fail the request.
+	     */
+	    handled = PJ_FALSE;
+	    PJ_LOG(4,(THIS_FILE, "Registration failed: invalid "
+			         "Min-Expires header value in response"));
+	    goto handle_err;
+	}
+
+	set_expires(regc, min_exp);
+
+	status = pjsip_regc_register(regc, regc->auto_reg, &tdata);
+	if (status == PJ_SUCCESS) {
+	    status = pjsip_regc_send(regc, tdata);
+	}
+
+	if (status != PJ_SUCCESS) {
+	    /* Only call callback if application is still interested
+	     * in it.
+	     */
+	    if (!regc->_delete_flag) {
+		/* Should be safe to release the lock temporarily.
+		 * We do this to avoid deadlock.
+		 */
+		pj_lock_release(regc->lock);
+		call_callback(regc, status, tsx->status_code,
+			      &rdata->msg_info.msg->line.status.reason,
+			      rdata, -1, 0, NULL);
+		pj_lock_acquire(regc->lock);
+	    }
+	}
+
+    } else {
+	handled = PJ_FALSE;
+    }
+
+handle_err:
+    if (!handled) {
+	pjsip_rx_data *rdata;
+	pj_int32_t expiration = NOEXP;
+	unsigned contact_cnt = 0;
+	pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT];
+
+	if (tsx->status_code/100 == 2) {
+
+	    rdata = event->body.tsx_state.src.rdata;
+
+	    /* Calculate expiration */
+	    expiration = calculate_response_expiration(regc, rdata, 
+						       &contact_cnt,
+						       PJSIP_REGC_MAX_CONTACT,
+						       contact);
+
+	    /* Schedule next registration */
+            schedule_registration(regc, expiration);
+
+	} else {
+	    rdata = (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ? 
+			event->body.tsx_state.src.rdata : NULL;
+	}
+
+	/* Update registration */
+	if (expiration==NOEXP) expiration=-1;
+	regc->expires = expiration;
+
+	/* Mark operation as complete */
+	regc->current_op = REGC_IDLE;
+
+	/* Call callback. */
+	/* Should be safe to release the lock temporarily.
+	 * We do this to avoid deadlock. 
+	 */
+	pj_lock_release(regc->lock);
+	call_callback(regc, PJ_SUCCESS, tsx->status_code, 
+		      (rdata ? &rdata->msg_info.msg->line.status.reason 
+			: &tsx->status_text),
+		      rdata, expiration, 
+		      contact_cnt, contact);
+	pj_lock_acquire(regc->lock);
+    }
+
+    pj_lock_release(regc->lock);
+
+    /* Delete the record if user destroy regc during the callback. */
+    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) {
+	pjsip_regc_destroy(regc);
+    }
+}
+
+PJ_DEF(pj_status_t) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
+{
+    pj_status_t status;
+    pjsip_cseq_hdr *cseq_hdr;
+    pjsip_expires_hdr *expires_hdr;
+    pj_uint32_t cseq;
+
+    pj_atomic_inc(regc->busy_ctr);
+    pj_lock_acquire(regc->lock);
+
+    /* Make sure we don't have pending transaction. */
+    if (regc->has_tsx) {
+	PJ_LOG(4,(THIS_FILE, "Unable to send request, regc has another "
+			     "transaction pending"));
+	pjsip_tx_data_dec_ref( tdata );
+	pj_lock_release(regc->lock);
+	pj_atomic_dec(regc->busy_ctr);
+	return PJSIP_EBUSY;
+    }
+
+    pj_assert(regc->current_op == REGC_IDLE);
+
+    /* Invalidate message buffer. */
+    pjsip_tx_data_invalidate_msg(tdata);
+
+    /* Increment CSeq */
+    cseq = ++regc->cseq_hdr->cseq;
+    cseq_hdr = (pjsip_cseq_hdr*)
+	       pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
+    cseq_hdr->cseq = cseq;
+
+    /* Find Expires header */
+    expires_hdr = (pjsip_expires_hdr*)
+		  pjsip_msg_find_hdr(tdata->msg, PJSIP_H_EXPIRES, NULL);
+
+    /* Bind to transport selector */
+    pjsip_tx_data_set_transport(tdata, &regc->tp_sel);
+
+    regc->has_tsx = PJ_TRUE;
+
+    /* Set current operation based on the value of Expires header */
+    if (expires_hdr && expires_hdr->ivalue==0)
+	regc->current_op = REGC_UNREGISTERING;
+    else
+	regc->current_op = REGC_REGISTERING;
+
+    /* Prevent deletion of tdata, e.g: when something wrong in sending,
+     * we need tdata to retrieve the transport.
+     */
+    pjsip_tx_data_add_ref(tdata);
+
+    /* If via_addr is set, use this address for the Via header. */
+    if (regc->via_addr.host.slen > 0) {
+        tdata->via_addr = regc->via_addr;
+        tdata->via_tp = regc->via_tp;
+    }
+
+    /* Need to unlock the regc temporarily while sending the message to
+     * prevent deadlock (https://trac.pjsip.org/repos/ticket/1247).
+     * It should be safe to do this since the regc's refcount has been
+     * incremented.
+     */
+    pj_lock_release(regc->lock);
+
+    /* Now send the message */
+    status = pjsip_endpt_send_request(regc->endpt, tdata, REGC_TSX_TIMEOUT,
+				      regc, &regc_tsx_callback);
+    if (status!=PJ_SUCCESS) {
+	PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
+    }
+
+    /* Reacquire the lock */
+    pj_lock_acquire(regc->lock);
+
+    /* Get last transport used and add reference to it */
+    if (tdata->tp_info.transport != regc->last_transport &&
+	status==PJ_SUCCESS)
+    {
+	if (regc->last_transport) {
+	    pjsip_transport_dec_ref(regc->last_transport);
+	    regc->last_transport = NULL;
+	}
+
+	if (tdata->tp_info.transport) {
+	    regc->last_transport = tdata->tp_info.transport;
+	    pjsip_transport_add_ref(regc->last_transport);
+	}
+    }
+
+    /* Release tdata */
+    pjsip_tx_data_dec_ref(tdata);
+
+    pj_lock_release(regc->lock);
+
+    /* Delete the record if user destroy regc during the callback. */
+    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) {
+	pjsip_regc_destroy(regc);
+    }
+
+    return status;
+}
+
+
diff --git a/jni/pjproject-android/.svn/pristine/49/49baa624266f6ebb133c25569a86b2881dc915aa.svn-base b/jni/pjproject-android/.svn/pristine/49/49baa624266f6ebb133c25569a86b2881dc915aa.svn-base
new file mode 100644
index 0000000..9dbb118
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/49/49baa624266f6ebb133c25569a86b2881dc915aa.svn-base
@@ -0,0 +1,19 @@
+; symsndtest.pkg

+

+; Languages

+&EN

+

+; Header

+#{"symsndtest"},(0xA000000E), 0, 1, 1

+

+; Platform compatibility

+[0x101F7961], *, *, *, {"Series60ProductID"}

+

+; vendor

+%{"PJSIP"}

+:"PJSIP"

+

+; Target

+"$(EPOCROOT)Epoc32\release\$(PLATFORM)\$(TARGET)\symsndtest.exe"-"!:\sys\bin\symsndtest.exe"

+"$(EPOCROOT)Epoc32\data\z\private\10003a3f\apps\symsndtest_reg.rSC"-"!:\private\10003a3f\import\apps\symsndtest_reg.rSC"

+

diff --git a/jni/pjproject-android/.svn/pristine/49/49f03cdcb2c809e5d7ad1bfb9a5511ff968018b8.svn-base b/jni/pjproject-android/.svn/pristine/49/49f03cdcb2c809e5d7ad1bfb9a5511ff968018b8.svn-base
new file mode 100644
index 0000000..255ac44
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/49/49f03cdcb2c809e5d7ad1bfb9a5511ff968018b8.svn-base
@@ -0,0 +1 @@
+#include "../../../portaudio/src/hostapi/oss/pa_unix_oss.c"