Applying license to pjproject

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@49 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjlib-util/include/pjlib-util.h b/pjlib-util/include/pjlib-util.h
index 69989ca..8efac78 100644
--- a/pjlib-util/include/pjlib-util.h
+++ b/pjlib-util/include/pjlib-util.h
@@ -1,3 +1,24 @@
+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #include <pjlib-util/md5.h>

 #include <pjlib-util/scanner.h>

 #include <pjlib-util/stun.h>

diff --git a/pjlib-util/include/pjlib-util/md5.h b/pjlib-util/include/pjlib-util/md5.h
index 8f3f614..ce27b6a 100644
--- a/pjlib-util/include/pjlib-util/md5.h
+++ b/pjlib-util/include/pjlib-util/md5.h
@@ -1,94 +1,115 @@
-/* $Id$
- *
- */
-/*
-  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  L. Peter Deutsch
-  ghost@aladdin.com
-
- */
-/* $Id$ */
-/*
-  Independent implementation of MD5 (RFC 1321).
-
-  This code implements the MD5 Algorithm defined in RFC 1321, whose
-  text is available at
-	http://www.ietf.org/rfc/rfc1321.txt
-  The code is derived from the text of the RFC, including the test suite
-  (section A.5) but excluding the rest of Appendix A.  It does not include
-  any code or documentation that is identified in the RFC as being
-  copyrighted.
-
-  The original and principal author of md5.h is L. Peter Deutsch
-  <ghost@aladdin.com>.  Other authors are noted in the change history
-  that follows (in reverse chronological order):
-
-  2002-04-13 lpd Removed support for non-ANSI compilers; removed
-	references to Ghostscript; clarified derivation from RFC 1321;
-	now handles byte order either statically or dynamically.
-  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
-  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
-	added conditionalization for C++ compilation from Martin
-	Purschke <purschke@bnl.gov>.
-  1999-05-03 lpd Original version.
- */
-
-#ifndef md5_INCLUDED
-#  define md5_INCLUDED
-
-/*
- * This package supports both compile-time and run-time determination of CPU
- * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
- * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
- * defined as non-zero, the code will be compiled to run only on big-endian
- * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
- * run on either big- or little-endian CPUs, but will run slightly less
- * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
- */
-
-typedef unsigned char md5_byte_t; /* 8-bit byte */
-typedef unsigned long md5_word_t; /* 32-bit word */
-
-/** Define the state of the MD5 Algorithm. */
-typedef struct md5_state_s {
-    md5_word_t count[2];	/**< message length in bits, lsw first */
-    md5_word_t abcd[4];		/**< digest buffer */
-    md5_byte_t buf[64];		/**< accumulate block */
-} md5_state_t;
-
-#ifdef __cplusplus
-extern "C" 
-{
-#endif
-
-/** Initialize the algorithm. */
-void md5_init(md5_state_t *pms);
-
-/** Append a string to the message. */
-void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
-
-/** Finish the message and return the digest. */
-void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
-
-#ifdef __cplusplus
-}  /* end extern "C" */
-#endif
-
-#endif /* md5_INCLUDED */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/*

+  Copyright (C) 1999, 2002 Aladdin Enterprises.  All rights reserved.

+

+  This software is provided 'as-is', without any express or implied

+  warranty.  In no event will the authors be held liable for any damages

+  arising from the use of this software.

+

+  Permission is granted to anyone to use this software for any purpose,

+  including commercial applications, and to alter it and redistribute it

+  freely, subject to the following restrictions:

+

+  1. The origin of this software must not be misrepresented; you must not

+     claim that you wrote the original software. If you use this software

+     in a product, an acknowledgment in the product documentation would be

+     appreciated but is not required.

+  2. Altered source versions must be plainly marked as such, and must not be

+     misrepresented as being the original software.

+  3. This notice may not be removed or altered from any source distribution.

+

+  L. Peter Deutsch

+  ghost@aladdin.com

+

+ */

+/* $Id$ */

+/*

+  Independent implementation of MD5 (RFC 1321).

+

+  This code implements the MD5 Algorithm defined in RFC 1321, whose

+  text is available at

+	http://www.ietf.org/rfc/rfc1321.txt

+  The code is derived from the text of the RFC, including the test suite

+  (section A.5) but excluding the rest of Appendix A.  It does not include

+  any code or documentation that is identified in the RFC as being

+  copyrighted.

+

+  The original and principal author of md5.h is L. Peter Deutsch

+  <ghost@aladdin.com>.  Other authors are noted in the change history

+  that follows (in reverse chronological order):

+

+  2002-04-13 lpd Removed support for non-ANSI compilers; removed

+	references to Ghostscript; clarified derivation from RFC 1321;

+	now handles byte order either statically or dynamically.

+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.

+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);

+	added conditionalization for C++ compilation from Martin

+	Purschke <purschke@bnl.gov>.

+  1999-05-03 lpd Original version.

+ */

+

+#ifndef md5_INCLUDED

+#  define md5_INCLUDED

+

+/*

+ * This package supports both compile-time and run-time determination of CPU

+ * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be

+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is

+ * defined as non-zero, the code will be compiled to run only on big-endian

+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to

+ * run on either big- or little-endian CPUs, but will run slightly less

+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.

+ */

+

+typedef unsigned char md5_byte_t; /* 8-bit byte */

+typedef unsigned long md5_word_t; /* 32-bit word */

+

+/** Define the state of the MD5 Algorithm. */

+typedef struct md5_state_s {

+    md5_word_t count[2];	/**< message length in bits, lsw first */

+    md5_word_t abcd[4];		/**< digest buffer */

+    md5_byte_t buf[64];		/**< accumulate block */

+} md5_state_t;

+

+#ifdef __cplusplus

+extern "C" 

+{

+#endif

+

+/** Initialize the algorithm. */

+void md5_init(md5_state_t *pms);

+

+/** Append a string to the message. */

+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);

+

+/** Finish the message and return the digest. */

+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);

+

+#ifdef __cplusplus

+}  /* end extern "C" */

+#endif

+

+#endif /* md5_INCLUDED */

diff --git a/pjlib-util/include/pjlib-util/scanner.h b/pjlib-util/include/pjlib-util/scanner.h
index 711eeed..a949143 100644
--- a/pjlib-util/include/pjlib-util/scanner.h
+++ b/pjlib-util/include/pjlib-util/scanner.h
@@ -1,26 +1,47 @@
-/* $Id$
- */
-#ifndef __PJ_SCANNER_H__
-#define __PJ_SCANNER_H__
-
-/**
- * @file scanner.h
- * @brief Text Scanning.
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_SCAN Text Scanning
- * @ingroup PJ_MISC
- * @brief
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_SCANNER_H__

+#define __PJ_SCANNER_H__

+

+/**

+ * @file scanner.h

+ * @brief Text Scanning.

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_SCAN Text Scanning

+ * @ingroup PJ_MISC

+ * @brief

  * Text scanning utility.

  *

- * @{
- */
-
+ * @{

+ */

+

 /**

  * This describes the type of individual character specification in

  * #pj_cis_buf_t. Basicly the number of bits here

@@ -28,28 +49,28 @@
 #ifndef PJ_CIS_ELEM_TYPE

 #   define PJ_CIS_ELEM_TYPE pj_uint32_t

 #endif

-
-/**
- * This describes the type of individual character specification in
- * #pj_cis_buf_t.
- */
-typedef PJ_CIS_ELEM_TYPE pj_cis_elem_t;
+

+/**

+ * This describes the type of individual character specification in

+ * #pj_cis_buf_t.

+ */

+typedef PJ_CIS_ELEM_TYPE pj_cis_elem_t;

 

 /**

  * Maximum number of input specification in a buffer.

  * Effectively this means the number of bits in pj_cis_elem_t.

  */

 #define PJ_CIS_MAX_INDEX   (sizeof(pj_cis_elem_t) << 3)

-
-/**
- * The scanner input specification buffer.
- */
+

+/**

+ * The scanner input specification buffer.

+ */

 typedef struct pj_cis_buf_t

 {

     pj_cis_elem_t    cis_buf[256];  /**< Must be 256 (not 128)! */

     pj_cis_elem_t    use_mask;      /**< To keep used indexes.  */

 } pj_cis_buf_t;

-
+

 /**

  * Character input specification.

  */

@@ -58,13 +79,13 @@
     pj_cis_elem_t   *cis_buf;       /**< Pointer to buffer.     */

     int              cis_id;        /**< Id.                    */

 } pj_cis_t;

-
-/**
+

+/**

  * Initialize scanner input specification buffer.

- *
- * @param cs_buf    The scanner character specification.
- */
-PJ_DECL(void) pj_cis_buf_init(pj_cis_buf_t *cs_buf);
+ *

+ * @param cs_buf    The scanner character specification.

+ */

+PJ_DECL(void) pj_cis_buf_init(pj_cis_buf_t *cs_buf);

 

 /**

  * Create a new input specification.

@@ -90,15 +111,15 @@
  *                  specifications in the buffer.

  */

 PJ_DECL(pj_status_t) pj_cis_dup(pj_cis_t *new_cis, pj_cis_t *existing);

-
-/**
+

+/**

  * Set the membership of the specified character.

  * Note that this is a macro, and arguments may be evaluated more than once.

- *
- * @param cis       Pointer to character input specification.
- * @param c         The character.
- */
-#define PJ_CIS_SET(cis,c)   ((cis)->cis_buf[(c)] |= (1 << (cis)->cis_id))
+ *

+ * @param cis       Pointer to character input specification.

+ * @param c         The character.

+ */

+#define PJ_CIS_SET(cis,c)   ((cis)->cis_buf[(c)] |= (1 << (cis)->cis_id))

 

 /**

  * Remove the membership of the specified character.

@@ -117,395 +138,395 @@
  * @param c         The character.

  */

 #define PJ_CIS_ISSET(cis,c) ((cis)->cis_buf[c] & (1 << (cis)->cis_id))

-
-/**
- * Add the characters in the specified range '[cstart, cend)' to the 
+

+/**

+ * Add the characters in the specified range '[cstart, cend)' to the 

  * specification (the last character itself ('cend') is not added).

- *
- * @param cis       The scanner character specification.
- * @param cstart    The first character in the range.
- * @param cend      The next character after the last character in the range.
- */
-PJ_DECL(void) pj_cis_add_range( pj_cis_t *cis, int cstart, int cend);
-
-/**
+ *

+ * @param cis       The scanner character specification.

+ * @param cstart    The first character in the range.

+ * @param cend      The next character after the last character in the range.

+ */

+PJ_DECL(void) pj_cis_add_range( pj_cis_t *cis, int cstart, int cend);

+

+/**

  * Add alphabetic characters to the specification.

- *
- * @param cis       The scanner character specification.
- */
-PJ_DECL(void) pj_cis_add_alpha( pj_cis_t *cis);
-
-/**
+ *

+ * @param cis       The scanner character specification.

+ */

+PJ_DECL(void) pj_cis_add_alpha( pj_cis_t *cis);

+

+/**

  * Add numeric characters to the specification.

- *
- * @param cis       The scanner character specification.
- */
-PJ_DECL(void) pj_cis_add_num( pj_cis_t *cis);
-
-/**
+ *

+ * @param cis       The scanner character specification.

+ */

+PJ_DECL(void) pj_cis_add_num( pj_cis_t *cis);

+

+/**

  * Add the characters in the string to the specification.

- *
- * @param cis       The scanner character specification.
- * @param str       The string.
- */
-PJ_DECL(void) pj_cis_add_str( pj_cis_t *cis, const char *str);
-
-/**
+ *

+ * @param cis       The scanner character specification.

+ * @param str       The string.

+ */

+PJ_DECL(void) pj_cis_add_str( pj_cis_t *cis, const char *str);

+

+/**

  * Delete characters in the specified range from the specification.

- *
- * @param cis       The scanner character specification.
- * @param cstart    The first character in the range.
- * @param cend      The next character after the last character in the range.
- */
-PJ_DECL(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend);
-
-/**
+ *

+ * @param cis       The scanner character specification.

+ * @param cstart    The first character in the range.

+ * @param cend      The next character after the last character in the range.

+ */

+PJ_DECL(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend);

+

+/**

  * Delete characters in the specified string from the specification.

- *
- * @param cis       The scanner character specification.
- * @param str       The string.
- */
-PJ_DECL(void) pj_cis_del_str( pj_cis_t *cis, const char *str);
-
-/**
+ *

+ * @param cis       The scanner character specification.

+ * @param str       The string.

+ */

+PJ_DECL(void) pj_cis_del_str( pj_cis_t *cis, const char *str);

+

+/**

  * Invert specification.

- *
- * @param cis       The scanner character specification.
- */
-PJ_DECL(void) pj_cis_invert( pj_cis_t *cis );
-
-/**
+ *

+ * @param cis       The scanner character specification.

+ */

+PJ_DECL(void) pj_cis_invert( pj_cis_t *cis );

+

+/**

  * Check whether the specified character belongs to the specification.

- *
- * @param cis       The scanner character specification.
- * @param c         The character to check for matching.
- */
-PJ_INLINE(int) pj_cis_match( const pj_cis_t *cis, int c )
-{
-    return PJ_CIS_ISSET(cis, c);
-}
-
-
-/**
- * Flags for scanner.
- */
-enum
-{
-    /** This flags specifies that the scanner should automatically skip
-	whitespaces 
-     */
-    PJ_SCAN_AUTOSKIP_WS = 1,
-
-    /** This flags specifies that the scanner should automatically skip
-        SIP header continuation. This flag implies PJ_SCAN_AUTOSKIP_WS.
-     */
-    PJ_SCAN_AUTOSKIP_WS_HEADER = 3,
-
-    /** Auto-skip new lines.
-     */
-    PJ_SCAN_AUTOSKIP_NEWLINE = 4,
-};
-
-
-/* Forward decl. */
-struct pj_scanner;
-
-
-/**
- * The callback function type to be called by the scanner when it encounters
+ *

+ * @param cis       The scanner character specification.

+ * @param c         The character to check for matching.

+ */

+PJ_INLINE(int) pj_cis_match( const pj_cis_t *cis, int c )

+{

+    return PJ_CIS_ISSET(cis, c);

+}

+

+

+/**

+ * Flags for scanner.

+ */

+enum

+{

+    /** This flags specifies that the scanner should automatically skip

+	whitespaces 

+     */

+    PJ_SCAN_AUTOSKIP_WS = 1,

+

+    /** This flags specifies that the scanner should automatically skip

+        SIP header continuation. This flag implies PJ_SCAN_AUTOSKIP_WS.

+     */

+    PJ_SCAN_AUTOSKIP_WS_HEADER = 3,

+

+    /** Auto-skip new lines.

+     */

+    PJ_SCAN_AUTOSKIP_NEWLINE = 4,

+};

+

+

+/* Forward decl. */

+struct pj_scanner;

+

+

+/**

+ * The callback function type to be called by the scanner when it encounters

  * syntax error.

- *
- * @param scanner       The scanner instance that calls the callback .
- */
-typedef void (*pj_syn_err_func_ptr)(struct pj_scanner *scanner);
-
-
-/**
- * The text scanner structure.
- */
-typedef struct pj_scanner
-{
-    char *begin;        /**< Start of input buffer. */
-    char *end;          /**< End of input buffer.   */
-    char *curptr;       /**< Current pointer.       */
-    int  line;          /**< Current line.          */
-    int  col;           /**< Current column.        */
-    int  skip_ws;       /**< Skip whitespace flag.  */
-    pj_syn_err_func_ptr callback;   /**< Syntax error callback. */
-} pj_scanner;
-
-
-/**
- * This structure can be used by application to store the state of the parser,
- * so that the scanner state can be rollback to this state when necessary.
- */
-typedef struct pj_scan_state
-{
-    char *curptr;       /**< Current scanner's pointer. */
-    int   line;         /**< Current line.      */
-    int   col;          /**< Current column.    */
-} pj_scan_state;
-
-
-/**
- * Initialize the scanner. Note that the input string buffer must have
- * length at least buflen+1 because the scanner will NULL terminate the
- * string during initialization.
- *
- * @param scanner   The scanner to be initialized.
- * @param bufstart  The input buffer to scan. Note that buffer[buflen] will be 
- *		    filled with NULL char until scanner is destroyed, so
- *		    the actual buffer length must be at least buflen+1.
- * @param buflen    The length of the input buffer, which normally is
- *		    strlen(bufstart).
- * @param options   Zero, or combination of PJ_SCAN_AUTOSKIP_WS or
- *		    PJ_SCAN_AUTOSKIP_WS_HEADER
- * @param callback  Callback to be called when the scanner encounters syntax
- *		    error condition.
- */
-PJ_DECL(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, 
-			    unsigned options,
-			    pj_syn_err_func_ptr callback );
-
-
-/** 
- * Call this function when application has finished using the scanner.
- *
- * @param scanner   The scanner.
- */
-PJ_DECL(void) pj_scan_fini( pj_scanner *scanner );
-
-
-/** 
- * Determine whether the EOF condition for the scanner has been met.
- *
- * @param scanner   The scanner.
- *
- * @return Non-zero if scanner is EOF.
- */
-PJ_INLINE(int) pj_scan_is_eof( const pj_scanner *scanner)
-{
-    return scanner->curptr >= scanner->end;
-}
-
-
-/** 
- * Peek strings in current position according to parameter spec, and return
- * the strings in parameter out. The current scanner position will not be
- * moved. If the scanner is already in EOF state, syntax error callback will
- * be called thrown.
- *
- * @param scanner   The scanner.
- * @param spec	    The spec to match input string.
- * @param out	    String to store the result.
- *
- * @return the character right after the peek-ed position or zero if there's
- *	   no more characters.
- */
-PJ_DECL(int) pj_scan_peek( pj_scanner *scanner,
-			   const pj_cis_t *spec, pj_str_t *out);
-
-
-/** 
- * Peek len characters in current position, and return them in out parameter.
- * Note that whitespaces or newlines will be returned as it is, regardless
- * of PJ_SCAN_AUTOSKIP_WS settings. If the character left is less than len, 
- * syntax error callback will be called.
- *
- * @param scanner   The scanner.
- * @param len	    Length to peek.
- * @param out	    String to store the result.
- *
- * @return the character right after the peek-ed position or zero if there's
- *	   no more characters.
- */
-PJ_DECL(int) pj_scan_peek_n( pj_scanner *scanner,
-			     pj_size_t len, pj_str_t *out);
-
-
-/** 
- * Peek strings in current position until spec is matched, and return
- * the strings in parameter out. The current scanner position will not be
- * moved. If the scanner is already in EOF state, syntax error callback will
- * be called.
- *
- * @param scanner   The scanner.
- * @param spec	    The peeking will stop when the input match this spec.
- * @param out	    String to store the result.
- *
- * @return the character right after the peek-ed position.
- */
-PJ_DECL(int) pj_scan_peek_until( pj_scanner *scanner,
-				 const pj_cis_t *spec, 
-				 pj_str_t *out);
-
-
-/** 
- * Get characters from the buffer according to the spec, and return them
- * in out parameter. The scanner will attempt to get as many characters as
- * possible as long as the spec matches. If the first character doesn't
- * match the spec, or scanner is already in EOF when this function is called,
- * an exception will be thrown.
- *
- * @param scanner   The scanner.
- * @param spec	    The spec to match input string.
- * @param out	    String to store the result.
- */
-PJ_DECL(void) pj_scan_get( pj_scanner *scanner,
-			   const pj_cis_t *spec, pj_str_t *out);
-
-
-/** 
- * Get characters between quotes. If current input doesn't match begin_quote,
- * syntax error will be thrown.
- *
- * @param scanner	The scanner.
- * @param begin_quote	The character to begin the quote.
- * @param end_quote	The character to end the quote.
- * @param out		String to store the result.
- */
-PJ_DECL(void) pj_scan_get_quote( pj_scanner *scanner,
-				  int begin_quote, int end_quote, 
-				  pj_str_t *out);
-
-/** 
- * Get N characters from the scanner.
- *
- * @param scanner   The scanner.
- * @param N	    Number of characters to get.
- * @param out	    String to store the result.
- */
-PJ_DECL(void) pj_scan_get_n( pj_scanner *scanner,
-			     unsigned N, pj_str_t *out);
-
-
-/** 
- * Get one character from the scanner.
- *
- * @param scanner   The scanner.
- *
- * @return The character.
- */
-PJ_DECL(int) pj_scan_get_char( pj_scanner *scanner );
-
-
-/** 
- * Get a newline from the scanner. A newline is defined as '\\n', or '\\r', or
- * "\\r\\n". If current input is not newline, syntax error will be thrown.
- *
- * @param scanner   The scanner.
- */
-PJ_DECL(void) pj_scan_get_newline( pj_scanner *scanner );
-
-
-/** 
- * Get characters from the scanner and move the scanner position until the
- * current character matches the spec.
- *
- * @param scanner   The scanner.
- * @param spec	    Get until the input match this spec.
- * @param out	    String to store the result.
- */
-PJ_DECL(void) pj_scan_get_until( pj_scanner *scanner,
-				 const pj_cis_t *spec, pj_str_t *out);
-
-
-/** 
- * Get characters from the scanner and move the scanner position until the
- * current character matches until_char.
- *
- * @param scanner	The scanner.
- * @param until_char    Get until the input match this character.
- * @param out		String to store the result.
- */
-PJ_DECL(void) pj_scan_get_until_ch( pj_scanner *scanner, 
-				    int until_char, pj_str_t *out);
-
-
-/** 
- * Get characters from the scanner and move the scanner position until the
- * current character matches until_char.
- *
- * @param scanner	The scanner.
- * @param until_spec	Get until the input match any of these characters.
- * @param out		String to store the result.
- */
-PJ_DECL(void) pj_scan_get_until_chr( pj_scanner *scanner,
-				     const char *until_spec, pj_str_t *out);
-
-/** 
- * Advance the scanner N characters, and skip whitespace
- * if necessary.
- *
- * @param scanner   The scanner.
- * @param N	    Number of characters to skip.
- * @param skip	    Flag to specify whether whitespace should be skipped
- *		    after skipping the characters.
- */
-PJ_DECL(void) pj_scan_advance_n( pj_scanner *scanner,
-				 unsigned N, pj_bool_t skip);
-
-
-/** 
- * Compare string in current position with the specified string.
- * 
- * @param scanner   The scanner.
- * @param s	    The string to compare with.
- * @param len	    Length of the string to compare.
- *
- * @return zero, <0, or >0 (just like strcmp()).
- */
-PJ_DECL(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len);
-
-
-/** 
- * Case-less string comparison of current position with the specified
- * string.
- *
- * @param scanner   The scanner.
- * @param s	    The string to compare with.
- * @param len	    Length of the string to compare with.
- *
- * @return zero, <0, or >0 (just like strcmp()).
- */
-PJ_DECL(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len);
-
-
-/** 
- * Manually skip whitespaces according to flag that was specified when
- * the scanner was initialized.
- *
- * @param scanner   The scanner.
- */
-PJ_DECL(void) pj_scan_skip_whitespace( pj_scanner *scanner );
-
-
-/** 
- * Save the full scanner state.
- *
- * @param scanner   The scanner.
- * @param state	    Variable to store scanner's state.
- */
-PJ_DECL(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state);
-
-
-/** 
- * Restore the full scanner state.
- * Note that this would not restore the string if application has modified
- * it. This will only restore the scanner scanning position.
- *
- * @param scanner   The scanner.
- * @param state	    State of the scanner.
- */
-PJ_DECL(void) pj_scan_restore_state( pj_scanner *scanner, 
-				      pj_scan_state *state);
-
-/**
- * @}
- */
-
-
-PJ_END_DECL
-
-#endif
-
+ *

+ * @param scanner       The scanner instance that calls the callback .

+ */

+typedef void (*pj_syn_err_func_ptr)(struct pj_scanner *scanner);

+

+

+/**

+ * The text scanner structure.

+ */

+typedef struct pj_scanner

+{

+    char *begin;        /**< Start of input buffer. */

+    char *end;          /**< End of input buffer.   */

+    char *curptr;       /**< Current pointer.       */

+    int  line;          /**< Current line.          */

+    int  col;           /**< Current column.        */

+    int  skip_ws;       /**< Skip whitespace flag.  */

+    pj_syn_err_func_ptr callback;   /**< Syntax error callback. */

+} pj_scanner;

+

+

+/**

+ * This structure can be used by application to store the state of the parser,

+ * so that the scanner state can be rollback to this state when necessary.

+ */

+typedef struct pj_scan_state

+{

+    char *curptr;       /**< Current scanner's pointer. */

+    int   line;         /**< Current line.      */

+    int   col;          /**< Current column.    */

+} pj_scan_state;

+

+

+/**

+ * Initialize the scanner. Note that the input string buffer must have

+ * length at least buflen+1 because the scanner will NULL terminate the

+ * string during initialization.

+ *

+ * @param scanner   The scanner to be initialized.

+ * @param bufstart  The input buffer to scan. Note that buffer[buflen] will be 

+ *		    filled with NULL char until scanner is destroyed, so

+ *		    the actual buffer length must be at least buflen+1.

+ * @param buflen    The length of the input buffer, which normally is

+ *		    strlen(bufstart).

+ * @param options   Zero, or combination of PJ_SCAN_AUTOSKIP_WS or

+ *		    PJ_SCAN_AUTOSKIP_WS_HEADER

+ * @param callback  Callback to be called when the scanner encounters syntax

+ *		    error condition.

+ */

+PJ_DECL(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, 

+			    unsigned options,

+			    pj_syn_err_func_ptr callback );

+

+

+/** 

+ * Call this function when application has finished using the scanner.

+ *

+ * @param scanner   The scanner.

+ */

+PJ_DECL(void) pj_scan_fini( pj_scanner *scanner );

+

+

+/** 

+ * Determine whether the EOF condition for the scanner has been met.

+ *

+ * @param scanner   The scanner.

+ *

+ * @return Non-zero if scanner is EOF.

+ */

+PJ_INLINE(int) pj_scan_is_eof( const pj_scanner *scanner)

+{

+    return scanner->curptr >= scanner->end;

+}

+

+

+/** 

+ * Peek strings in current position according to parameter spec, and return

+ * the strings in parameter out. The current scanner position will not be

+ * moved. If the scanner is already in EOF state, syntax error callback will

+ * be called thrown.

+ *

+ * @param scanner   The scanner.

+ * @param spec	    The spec to match input string.

+ * @param out	    String to store the result.

+ *

+ * @return the character right after the peek-ed position or zero if there's

+ *	   no more characters.

+ */

+PJ_DECL(int) pj_scan_peek( pj_scanner *scanner,

+			   const pj_cis_t *spec, pj_str_t *out);

+

+

+/** 

+ * Peek len characters in current position, and return them in out parameter.

+ * Note that whitespaces or newlines will be returned as it is, regardless

+ * of PJ_SCAN_AUTOSKIP_WS settings. If the character left is less than len, 

+ * syntax error callback will be called.

+ *

+ * @param scanner   The scanner.

+ * @param len	    Length to peek.

+ * @param out	    String to store the result.

+ *

+ * @return the character right after the peek-ed position or zero if there's

+ *	   no more characters.

+ */

+PJ_DECL(int) pj_scan_peek_n( pj_scanner *scanner,

+			     pj_size_t len, pj_str_t *out);

+

+

+/** 

+ * Peek strings in current position until spec is matched, and return

+ * the strings in parameter out. The current scanner position will not be

+ * moved. If the scanner is already in EOF state, syntax error callback will

+ * be called.

+ *

+ * @param scanner   The scanner.

+ * @param spec	    The peeking will stop when the input match this spec.

+ * @param out	    String to store the result.

+ *

+ * @return the character right after the peek-ed position.

+ */

+PJ_DECL(int) pj_scan_peek_until( pj_scanner *scanner,

+				 const pj_cis_t *spec, 

+				 pj_str_t *out);

+

+

+/** 

+ * Get characters from the buffer according to the spec, and return them

+ * in out parameter. The scanner will attempt to get as many characters as

+ * possible as long as the spec matches. If the first character doesn't

+ * match the spec, or scanner is already in EOF when this function is called,

+ * an exception will be thrown.

+ *

+ * @param scanner   The scanner.

+ * @param spec	    The spec to match input string.

+ * @param out	    String to store the result.

+ */

+PJ_DECL(void) pj_scan_get( pj_scanner *scanner,

+			   const pj_cis_t *spec, pj_str_t *out);

+

+

+/** 

+ * Get characters between quotes. If current input doesn't match begin_quote,

+ * syntax error will be thrown.

+ *

+ * @param scanner	The scanner.

+ * @param begin_quote	The character to begin the quote.

+ * @param end_quote	The character to end the quote.

+ * @param out		String to store the result.

+ */

+PJ_DECL(void) pj_scan_get_quote( pj_scanner *scanner,

+				  int begin_quote, int end_quote, 

+				  pj_str_t *out);

+

+/** 

+ * Get N characters from the scanner.

+ *

+ * @param scanner   The scanner.

+ * @param N	    Number of characters to get.

+ * @param out	    String to store the result.

+ */

+PJ_DECL(void) pj_scan_get_n( pj_scanner *scanner,

+			     unsigned N, pj_str_t *out);

+

+

+/** 

+ * Get one character from the scanner.

+ *

+ * @param scanner   The scanner.

+ *

+ * @return The character.

+ */

+PJ_DECL(int) pj_scan_get_char( pj_scanner *scanner );

+

+

+/** 

+ * Get a newline from the scanner. A newline is defined as '\\n', or '\\r', or

+ * "\\r\\n". If current input is not newline, syntax error will be thrown.

+ *

+ * @param scanner   The scanner.

+ */

+PJ_DECL(void) pj_scan_get_newline( pj_scanner *scanner );

+

+

+/** 

+ * Get characters from the scanner and move the scanner position until the

+ * current character matches the spec.

+ *

+ * @param scanner   The scanner.

+ * @param spec	    Get until the input match this spec.

+ * @param out	    String to store the result.

+ */

+PJ_DECL(void) pj_scan_get_until( pj_scanner *scanner,

+				 const pj_cis_t *spec, pj_str_t *out);

+

+

+/** 

+ * Get characters from the scanner and move the scanner position until the

+ * current character matches until_char.

+ *

+ * @param scanner	The scanner.

+ * @param until_char    Get until the input match this character.

+ * @param out		String to store the result.

+ */

+PJ_DECL(void) pj_scan_get_until_ch( pj_scanner *scanner, 

+				    int until_char, pj_str_t *out);

+

+

+/** 

+ * Get characters from the scanner and move the scanner position until the

+ * current character matches until_char.

+ *

+ * @param scanner	The scanner.

+ * @param until_spec	Get until the input match any of these characters.

+ * @param out		String to store the result.

+ */

+PJ_DECL(void) pj_scan_get_until_chr( pj_scanner *scanner,

+				     const char *until_spec, pj_str_t *out);

+

+/** 

+ * Advance the scanner N characters, and skip whitespace

+ * if necessary.

+ *

+ * @param scanner   The scanner.

+ * @param N	    Number of characters to skip.

+ * @param skip	    Flag to specify whether whitespace should be skipped

+ *		    after skipping the characters.

+ */

+PJ_DECL(void) pj_scan_advance_n( pj_scanner *scanner,

+				 unsigned N, pj_bool_t skip);

+

+

+/** 

+ * Compare string in current position with the specified string.

+ * 

+ * @param scanner   The scanner.

+ * @param s	    The string to compare with.

+ * @param len	    Length of the string to compare.

+ *

+ * @return zero, <0, or >0 (just like strcmp()).

+ */

+PJ_DECL(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len);

+

+

+/** 

+ * Case-less string comparison of current position with the specified

+ * string.

+ *

+ * @param scanner   The scanner.

+ * @param s	    The string to compare with.

+ * @param len	    Length of the string to compare with.

+ *

+ * @return zero, <0, or >0 (just like strcmp()).

+ */

+PJ_DECL(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len);

+

+

+/** 

+ * Manually skip whitespaces according to flag that was specified when

+ * the scanner was initialized.

+ *

+ * @param scanner   The scanner.

+ */

+PJ_DECL(void) pj_scan_skip_whitespace( pj_scanner *scanner );

+

+

+/** 

+ * Save the full scanner state.

+ *

+ * @param scanner   The scanner.

+ * @param state	    Variable to store scanner's state.

+ */

+PJ_DECL(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state);

+

+

+/** 

+ * Restore the full scanner state.

+ * Note that this would not restore the string if application has modified

+ * it. This will only restore the scanner scanning position.

+ *

+ * @param scanner   The scanner.

+ * @param state	    State of the scanner.

+ */

+PJ_DECL(void) pj_scan_restore_state( pj_scanner *scanner, 

+				      pj_scan_state *state);

+

+/**

+ * @}

+ */

+

+

+PJ_END_DECL

+

+#endif

+

diff --git a/pjlib-util/include/pjlib-util/stun.h b/pjlib-util/include/pjlib-util/stun.h
index 90c20ec..d2065e7 100644
--- a/pjlib-util/include/pjlib-util/stun.h
+++ b/pjlib-util/include/pjlib-util/stun.h
@@ -1,123 +1,144 @@
-#ifndef __PJ_STUN_H__
-#define __PJ_STUN_H__
-
-#include <pj/types.h>
-#include <pj/sock.h>
-
-PJ_BEGIN_DECL
-
-#define PJ_STUN_MAX_ATTR    16
-
-typedef enum pj_stun_msg_type
-{
-    PJ_STUN_BINDING_REQUEST		    = 0x0001,
-    PJ_STUN_BINDING_RESPONSE		    = 0x0101,
-    PJ_STUN_BINDING_ERROR_RESPONSE	    = 0x0111,
-    PJ_STUN_SHARED_SECRET_REQUEST	    = 0x0002,
-    PJ_STUN_SHARED_SECRET_RESPONSE	    = 0x0102,
-    PJ_STUN_SHARED_SECRET_ERROR_RESPONSE    = 0x0112
-} pj_stun_msg_type;
-
-typedef enum pj_stun_attr_type
-{
-    PJ_STUN_ATTR_MAPPED_ADDR = 1,
-    PJ_STUN_ATTR_RESPONSE_ADDR,
-    PJ_STUN_ATTR_CHANGE_REQUEST,
-    PJ_STUN_ATTR_SOURCE_ADDR,
-    PJ_STUN_ATTR_CHANGED_ADDR,
-    PJ_STUN_ATTR_USERNAME,
-    PJ_STUN_ATTR_PASSWORD,
-    PJ_STUN_ATTR_MESSAGE_INTEGRITY,
-    PJ_STUN_ATTR_ERROR_CODE,
-    PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES,
-    PJ_STUN_ATTR_REFLECTED_FORM
-} pj_stun_attr_type;
-
-typedef struct pj_stun_msg_hdr
-{
-    pj_uint16_t		type;
-    pj_uint16_t		length;
-    pj_uint32_t		tsx[4];
-} pj_stun_msg_hdr;
-
-typedef struct pj_stun_attr_hdr
-{
-    pj_uint16_t		type;
-    pj_uint16_t		length;
-} pj_stun_attr_hdr;
-
-typedef struct pj_stun_mapped_addr_attr
-{
-    pj_stun_attr_hdr	hdr;
-    pj_uint8_t		ignored;
-    pj_uint8_t		family;
-    pj_uint16_t		port;
-    pj_uint32_t		addr;
-} pj_stun_mapped_addr_attr;
-
-typedef pj_stun_mapped_addr_attr pj_stun_response_addr_attr;
-typedef pj_stun_mapped_addr_attr pj_stun_changed_addr_attr;
-typedef pj_stun_mapped_addr_attr pj_stun_src_addr_attr;
-typedef pj_stun_mapped_addr_attr pj_stun_reflected_form_attr;
-
-typedef struct pj_stun_change_request_attr
-{
-    pj_stun_attr_hdr	hdr;
-    pj_uint32_t		value;
-} pj_stun_change_request_attr;
-
-typedef struct pj_stun_username_attr
-{
-    pj_stun_attr_hdr	hdr;
-    pj_uint32_t		value[1];
-} pj_stun_username_attr;
-
-typedef pj_stun_username_attr pj_stun_password_attr;
-
-typedef struct pj_stun_error_code_attr
-{
-    pj_stun_attr_hdr	hdr;
-    pj_uint16_t		ignored;
-    pj_uint8_t		err_class;
-    pj_uint8_t		number;
-    char		reason[4];
-} pj_stun_error_code_attr;
-
-typedef struct pj_stun_msg
-{
-    pj_stun_msg_hdr    *hdr;
-    int			attr_count;
-    pj_stun_attr_hdr   *attr[PJ_STUN_MAX_ATTR];
-} pj_stun_msg;
-
-/* STUN message API (stun.c). */
-
-PJ_DECL(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, 
-					      void **msg, pj_size_t *len,
-					      pj_uint32_t id_hi,
-					      pj_uint32_t id_lo);
-PJ_DECL(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len,
-				        pj_stun_msg *msg);
-PJ_DECL(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t);
-
-/* STUN simple client API (stun_client.c) */
-enum pj_stun_err_code {
-    PJ_STUN_ERR_MEMORY		= (-2),
-    PJ_STUN_ERR_RESOLVE		= (-3),
-    PJ_STUN_ERR_TRANSPORT	= (-4),
-    PJ_STUN_ERR_INVALID_MSG	= (-5),
-    PJ_STUN_ERR_NO_RESPONSE	= (-6),
-    PJ_STUN_ERR_SYMETRIC	= (-7),
-};
-
-PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf,
-					      int sock_cnt, pj_sock_t sock[],
-					      const pj_str_t *srv1, int port1,
-					      const pj_str_t *srv2, int port2,
-					      pj_sockaddr_in mapped_addr[]);
-PJ_DECL(const char*) pj_stun_get_err_msg(pj_status_t status);
-
-PJ_END_DECL
-
-#endif	/* __PJ_STUN_H__ */
-
+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_STUN_H__

+#define __PJ_STUN_H__

+

+#include <pj/types.h>

+#include <pj/sock.h>

+

+PJ_BEGIN_DECL

+

+#define PJ_STUN_MAX_ATTR    16

+

+typedef enum pj_stun_msg_type

+{

+    PJ_STUN_BINDING_REQUEST		    = 0x0001,

+    PJ_STUN_BINDING_RESPONSE		    = 0x0101,

+    PJ_STUN_BINDING_ERROR_RESPONSE	    = 0x0111,

+    PJ_STUN_SHARED_SECRET_REQUEST	    = 0x0002,

+    PJ_STUN_SHARED_SECRET_RESPONSE	    = 0x0102,

+    PJ_STUN_SHARED_SECRET_ERROR_RESPONSE    = 0x0112

+} pj_stun_msg_type;

+

+typedef enum pj_stun_attr_type

+{

+    PJ_STUN_ATTR_MAPPED_ADDR = 1,

+    PJ_STUN_ATTR_RESPONSE_ADDR,

+    PJ_STUN_ATTR_CHANGE_REQUEST,

+    PJ_STUN_ATTR_SOURCE_ADDR,

+    PJ_STUN_ATTR_CHANGED_ADDR,

+    PJ_STUN_ATTR_USERNAME,

+    PJ_STUN_ATTR_PASSWORD,

+    PJ_STUN_ATTR_MESSAGE_INTEGRITY,

+    PJ_STUN_ATTR_ERROR_CODE,

+    PJ_STUN_ATTR_UNKNOWN_ATTRIBUTES,

+    PJ_STUN_ATTR_REFLECTED_FORM

+} pj_stun_attr_type;

+

+typedef struct pj_stun_msg_hdr

+{

+    pj_uint16_t		type;

+    pj_uint16_t		length;

+    pj_uint32_t		tsx[4];

+} pj_stun_msg_hdr;

+

+typedef struct pj_stun_attr_hdr

+{

+    pj_uint16_t		type;

+    pj_uint16_t		length;

+} pj_stun_attr_hdr;

+

+typedef struct pj_stun_mapped_addr_attr

+{

+    pj_stun_attr_hdr	hdr;

+    pj_uint8_t		ignored;

+    pj_uint8_t		family;

+    pj_uint16_t		port;

+    pj_uint32_t		addr;

+} pj_stun_mapped_addr_attr;

+

+typedef pj_stun_mapped_addr_attr pj_stun_response_addr_attr;

+typedef pj_stun_mapped_addr_attr pj_stun_changed_addr_attr;

+typedef pj_stun_mapped_addr_attr pj_stun_src_addr_attr;

+typedef pj_stun_mapped_addr_attr pj_stun_reflected_form_attr;

+

+typedef struct pj_stun_change_request_attr

+{

+    pj_stun_attr_hdr	hdr;

+    pj_uint32_t		value;

+} pj_stun_change_request_attr;

+

+typedef struct pj_stun_username_attr

+{

+    pj_stun_attr_hdr	hdr;

+    pj_uint32_t		value[1];

+} pj_stun_username_attr;

+

+typedef pj_stun_username_attr pj_stun_password_attr;

+

+typedef struct pj_stun_error_code_attr

+{

+    pj_stun_attr_hdr	hdr;

+    pj_uint16_t		ignored;

+    pj_uint8_t		err_class;

+    pj_uint8_t		number;

+    char		reason[4];

+} pj_stun_error_code_attr;

+

+typedef struct pj_stun_msg

+{

+    pj_stun_msg_hdr    *hdr;

+    int			attr_count;

+    pj_stun_attr_hdr   *attr[PJ_STUN_MAX_ATTR];

+} pj_stun_msg;

+

+/* STUN message API (stun.c). */

+

+PJ_DECL(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, 

+					      void **msg, pj_size_t *len,

+					      pj_uint32_t id_hi,

+					      pj_uint32_t id_lo);

+PJ_DECL(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len,

+				        pj_stun_msg *msg);

+PJ_DECL(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t);

+

+/* STUN simple client API (stun_client.c) */

+enum pj_stun_err_code {

+    PJ_STUN_ERR_MEMORY		= (-2),

+    PJ_STUN_ERR_RESOLVE		= (-3),

+    PJ_STUN_ERR_TRANSPORT	= (-4),

+    PJ_STUN_ERR_INVALID_MSG	= (-5),

+    PJ_STUN_ERR_NO_RESPONSE	= (-6),

+    PJ_STUN_ERR_SYMETRIC	= (-7),

+};

+

+PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf,

+					      int sock_cnt, pj_sock_t sock[],

+					      const pj_str_t *srv1, int port1,

+					      const pj_str_t *srv2, int port2,

+					      pj_sockaddr_in mapped_addr[]);

+PJ_DECL(const char*) pj_stun_get_err_msg(pj_status_t status);

+

+PJ_END_DECL

+

+#endif	/* __PJ_STUN_H__ */

+

diff --git a/pjlib-util/include/pjlib-util/xml.h b/pjlib-util/include/pjlib-util/xml.h
index fd7978a..e0ebb4c 100644
--- a/pjlib-util/include/pjlib-util/xml.h
+++ b/pjlib-util/include/pjlib-util/xml.h
@@ -1,157 +1,178 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_XML_H__
-#define __PJ_XML_H__
-
-/**
- * @file xml.h
- * @brief PJLIB XML Parser/Helper.
- */
-
-#include <pj/types.h>
-#include <pj/list.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_XML XML Parser/Helper.
- * @ingroup PJ
- * @{
- */
-
-/** Typedef for XML attribute. */
-typedef struct pj_xml_attr pj_xml_attr;
-
-/** Typedef for XML nodes. */
-typedef struct pj_xml_node pj_xml_node;
-
-/** This structure declares XML attribute. */
-struct pj_xml_attr
-{
-    PJ_DECL_LIST_MEMBER(pj_xml_attr);   /**< Standard list elements.    */
-    pj_str_t	name;	                /**< Attribute name.            */
-    pj_str_t	value;	                /**< Attribute value.           */
-};
-
-/** This structure describes XML node head inside XML node structure.
- */
-typedef struct pj_xml_node_head
-{
-    PJ_DECL_LIST_MEMBER(pj_xml_node);   /**< Standard list elements.    */
-} pj_xml_node_head;
-
-/** This structure describes XML node. */
-struct pj_xml_node
-{
-    PJ_DECL_LIST_MEMBER(pj_xml_node);   /**< List @a prev and @a next member */
-    pj_str_t		name;		/**< Node name.                      */
-    pj_xml_attr		attr_head;      /**< Attribute list.                 */
-    pj_xml_node_head	node_head;      /**< Node list.                      */
-    pj_str_t		content;	/**< Node content.                   */
-};
-
-/**
- * Parse XML message into XML document with a single root node. The parser
- * is capable of parsing XML processing instruction construct ("<?") and 
- * XML comments ("<!--"), however such constructs will be ignored and will not 
- * be included in the resulted XML node tree.
- *
- * @param pool	    Pool to allocate memory from.
- * @param msg	    The XML message to parse.
- * @param len	    The length of the message.
- *
- * @return	    XML root node, or NULL if the XML document can not be parsed.
- */
-PJ_DECL(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len);
-
-
-/**
- * Print XML into XML message. Note that the function WILL NOT NULL terminate
- * the output.
- *
- * @param node	    The XML node to print.
- * @param buf	    Buffer to hold the output message.
- * @param len	    The length of the buffer.
- * @param prolog    If set to nonzero, will print XML prolog ("<?xml..")
- *
- * @return	    The size of the printed message, or -1 if there is not 
- *		    sufficient space in the buffer to print the message.
- */
-PJ_DECL(int) pj_xml_print( const pj_xml_node *node, char *buf, pj_size_t len,
-			   pj_bool_t include_prolog);
-
-/**
- * Add node to another node.
- *
- * @param parent    Parent node.
- * @param node	    Node to be added to parent.
- */
-PJ_DECL(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node );
-
-
-/**
- * Add attribute to a node.
- *
- * @param node	    Node.
- * @param attr	    Attribute to add to node.
- */
-PJ_DECL(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr );
-
-/**
- * Find first node with the specified name.
- *
- * @param parent    Parent node.
- * @param name	    Node name to find.
- *
- * @return	    XML node found or NULL.
- */
-PJ_DECL(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name);
-
-/**
- * Find first node with the specified name.
- *
- * @param parent    Parent node.
- * @param name	    Node name to find.
- *
- * @return	    XML node found or NULL.
- */
-PJ_DECL(pj_xml_node*) pj_xml_find_next_node(pj_xml_node *parent, pj_xml_node *node,
-					    const pj_str_t *name);
-
-/**
- * Find first attribute within a node with the specified name and optional value.
- *
- * @param node	    XML Node.
- * @param name	    Attribute name to find.
- * @param value	    Optional value to match.
- *
- * @return	    XML attribute found, or NULL.
- */
-PJ_DECL(pj_xml_attr*) pj_xml_find_attr(pj_xml_node *node, const pj_str_t *name,
-				       const pj_str_t *value);
-
-
-/**
- * Find a direct child node with the specified name and match the function.
- *
- * @param node	    Parent node.
- * @param name	    Optional name.
- * @param data	    Data to be passed to matching function.
- * @param match	    Optional matching function.
- *
- * @return	    The first matched node, or NULL.
- */
-PJ_DECL(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name,
-				   const void *data, 
-				   pj_bool_t (*match)(pj_xml_node *, const void*));
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJ_XML_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_XML_H__

+#define __PJ_XML_H__

+

+/**

+ * @file xml.h

+ * @brief PJLIB XML Parser/Helper.

+ */

+

+#include <pj/types.h>

+#include <pj/list.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_XML XML Parser/Helper.

+ * @ingroup PJ

+ * @{

+ */

+

+/** Typedef for XML attribute. */

+typedef struct pj_xml_attr pj_xml_attr;

+

+/** Typedef for XML nodes. */

+typedef struct pj_xml_node pj_xml_node;

+

+/** This structure declares XML attribute. */

+struct pj_xml_attr

+{

+    PJ_DECL_LIST_MEMBER(pj_xml_attr);   /**< Standard list elements.    */

+    pj_str_t	name;	                /**< Attribute name.            */

+    pj_str_t	value;	                /**< Attribute value.           */

+};

+

+/** This structure describes XML node head inside XML node structure.

+ */

+typedef struct pj_xml_node_head

+{

+    PJ_DECL_LIST_MEMBER(pj_xml_node);   /**< Standard list elements.    */

+} pj_xml_node_head;

+

+/** This structure describes XML node. */

+struct pj_xml_node

+{

+    PJ_DECL_LIST_MEMBER(pj_xml_node);   /**< List @a prev and @a next member */

+    pj_str_t		name;		/**< Node name.                      */

+    pj_xml_attr		attr_head;      /**< Attribute list.                 */

+    pj_xml_node_head	node_head;      /**< Node list.                      */

+    pj_str_t		content;	/**< Node content.                   */

+};

+

+/**

+ * Parse XML message into XML document with a single root node. The parser

+ * is capable of parsing XML processing instruction construct ("<?") and 

+ * XML comments ("<!--"), however such constructs will be ignored and will not 

+ * be included in the resulted XML node tree.

+ *

+ * @param pool	    Pool to allocate memory from.

+ * @param msg	    The XML message to parse.

+ * @param len	    The length of the message.

+ *

+ * @return	    XML root node, or NULL if the XML document can not be parsed.

+ */

+PJ_DECL(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len);

+

+

+/**

+ * Print XML into XML message. Note that the function WILL NOT NULL terminate

+ * the output.

+ *

+ * @param node	    The XML node to print.

+ * @param buf	    Buffer to hold the output message.

+ * @param len	    The length of the buffer.

+ * @param prolog    If set to nonzero, will print XML prolog ("<?xml..")

+ *

+ * @return	    The size of the printed message, or -1 if there is not 

+ *		    sufficient space in the buffer to print the message.

+ */

+PJ_DECL(int) pj_xml_print( const pj_xml_node *node, char *buf, pj_size_t len,

+			   pj_bool_t include_prolog);

+

+/**

+ * Add node to another node.

+ *

+ * @param parent    Parent node.

+ * @param node	    Node to be added to parent.

+ */

+PJ_DECL(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node );

+

+

+/**

+ * Add attribute to a node.

+ *

+ * @param node	    Node.

+ * @param attr	    Attribute to add to node.

+ */

+PJ_DECL(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr );

+

+/**

+ * Find first node with the specified name.

+ *

+ * @param parent    Parent node.

+ * @param name	    Node name to find.

+ *

+ * @return	    XML node found or NULL.

+ */

+PJ_DECL(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name);

+

+/**

+ * Find first node with the specified name.

+ *

+ * @param parent    Parent node.

+ * @param name	    Node name to find.

+ *

+ * @return	    XML node found or NULL.

+ */

+PJ_DECL(pj_xml_node*) pj_xml_find_next_node(pj_xml_node *parent, pj_xml_node *node,

+					    const pj_str_t *name);

+

+/**

+ * Find first attribute within a node with the specified name and optional value.

+ *

+ * @param node	    XML Node.

+ * @param name	    Attribute name to find.

+ * @param value	    Optional value to match.

+ *

+ * @return	    XML attribute found, or NULL.

+ */

+PJ_DECL(pj_xml_attr*) pj_xml_find_attr(pj_xml_node *node, const pj_str_t *name,

+				       const pj_str_t *value);

+

+

+/**

+ * Find a direct child node with the specified name and match the function.

+ *

+ * @param node	    Parent node.

+ * @param name	    Optional name.

+ * @param data	    Data to be passed to matching function.

+ * @param match	    Optional matching function.

+ *

+ * @return	    The first matched node, or NULL.

+ */

+PJ_DECL(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name,

+				   const void *data, 

+				   pj_bool_t (*match)(pj_xml_node *, const void*));

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJ_XML_H__ */

diff --git a/pjlib-util/src/pjlib-util-test/main.c b/pjlib-util/src/pjlib-util-test/main.c
index 3a57258..beb0c06 100644
--- a/pjlib-util/src/pjlib-util-test/main.c
+++ b/pjlib-util/src/pjlib-util-test/main.c
@@ -1,3 +1,24 @@
+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #include "test.h"

 

 #if defined(PJ_SUNOS) && PJ_SUNOS!=0

diff --git a/pjlib-util/src/pjlib-util-test/test.c b/pjlib-util/src/pjlib-util-test/test.c
index 4502728..06194ad 100644
--- a/pjlib-util/src/pjlib-util-test/test.c
+++ b/pjlib-util/src/pjlib-util-test/test.c
@@ -1,3 +1,24 @@
+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #include "test.h"

 #include <pjlib.h>

 

diff --git a/pjlib-util/src/pjlib-util-test/test.h b/pjlib-util/src/pjlib-util-test/test.h
index 2545bd7..3b098dc 100644
--- a/pjlib-util/src/pjlib-util-test/test.h
+++ b/pjlib-util/src/pjlib-util-test/test.h
@@ -1,3 +1,24 @@
+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #include <pj/types.h>

 

 #define INCLUDE_XML_TEST	1

diff --git a/pjlib-util/src/pjlib-util-test/xml.c b/pjlib-util/src/pjlib-util-test/xml.c
index d4e2274..440e0ae 100644
--- a/pjlib-util/src/pjlib-util-test/xml.c
+++ b/pjlib-util/src/pjlib-util-test/xml.c
@@ -1,129 +1,150 @@
-/* $Id$
- */
-#include "test.h"
-
-
-#if INCLUDE_XML_TEST
-
-#include <pjlib-util/xml.h>
-#include <pjlib.h>
-
-#define THIS_FILE   "xml_test"
-
-static const char *xml_doc[] =
-{
-"   <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
-"   <p:pidf-full xmlns=\"urn:ietf:params:xml:ns:pidf\"\n"
-"          xmlns:p=\"urn:ietf:params:xml:ns:pidf-diff\"\n"
-"          xmlns:r=\"urn:ietf:params:xml:ns:pidf:rpid\"\n"
-"          xmlns:c=\"urn:ietf:params:xml:ns:pidf:caps\"\n"
-"          entity=\"pres:someone@example.com\"\n"
-"          version=\"567\">\n"
-"\n"
-"    <tuple id=\"sg89ae\">\n"
-"     <status>\n"
-"      <basic>open</basic>\n"
-"      <r:relationship>assistant</r:relationship>\n"
-"     </status>\n"
-"     <c:servcaps>\n"
-"      <c:audio>true</c:audio>\n"
-"      <c:video>false</c:video>\n"
-"      <c:message>true</c:message>\n"
-"     </c:servcaps>\n"
-"     <contact priority=\"0.8\">tel:09012345678</contact>\n"
-"    </tuple>\n"
-"\n"
-"    <tuple id=\"cg231jcr\">\n"
-"     <status>\n"
-"      <basic>open</basic>\n"
-"     </status>\n"
-"     <contact priority=\"1.0\">im:pep@example.com</contact>\n"
-"    </tuple>\n"
-"\n"
-"    <tuple id=\"r1230d\">\n"
-"     <status>\n"
-"      <basic>closed</basic>\n"
-"      <r:activity>meeting</r:activity>\n"
-"     </status>\n"
-"     <r:homepage>http://example.com/~pep/</r:homepage>\n"
-"     <r:icon>http://example.com/~pep/icon.gif</r:icon>\n"
-"     <r:card>http://example.com/~pep/card.vcd</r:card>\n"
-"     <contact priority=\"0.9\">sip:pep@example.com</contact>\n"
-"    </tuple>\n"
-"\n"
-"    <note xml:lang=\"en\">Full state presence document</note>\n"
-"\n"
-"    <r:person>\n"
-"     <r:status>\n"
-"      <r:activities>\n"
-"       <r:on-the-phone/>\n"
-"       <r:busy/>\n"
-"      </r:activities>\n"
-"     </r:status>\n"
-"    </r:person>\n"
-"\n"
-"    <r:device id=\"urn:esn:600b40c7\">\n"
-"     <r:status>\n"
-"      <c:devcaps>\n"
-"       <c:mobility>\n"
-"        <c:supported>\n"
-"         <c:mobile/>\n"
-"        </c:supported>\n"
-"       </c:mobility>\n"
-"      </c:devcaps>\n"
-"     </r:status>\n"
-"    </r:device>\n"
-"\n"
-"   </p:pidf-full>\n"
-}
-;
-
-static int xml_parse_print_test(const char *doc)
-{
-    pj_str_t msg;
-    pj_pool_t *pool;
-    pj_xml_node *root;
-    char *output;
-    int output_len;
-
-    pool = pj_pool_create(mem, "xml", 4096, 1024, NULL);
-    pj_strdup2(pool, &msg, doc);
-    root = pj_xml_parse(pool, msg.ptr, msg.slen);
-    if (!root) {
-	PJ_LOG(1, (THIS_FILE, "  Error: unable to parse XML"));
-	return -10;
-    }
-
-    output = (char*)pj_pool_alloc(pool, msg.slen + 512);
-    pj_memset(output, 0, msg.slen+512);
-    output_len = pj_xml_print(root, output, msg.slen+512, PJ_TRUE);
-    if (output_len < 1) {
-	PJ_LOG(1, (THIS_FILE, "  Error: buffer too small to print XML file"));
-	return -20;
-    }
-    output[output_len] = '\0';
-
-
-    pj_pool_release(pool);
-    return 0;
-}
-
-int xml_test()
-{
-    unsigned i;
-    for (i=0; i<sizeof(xml_doc)/sizeof(xml_doc[0]); ++i) {
-	int status;
-	if ((status=xml_parse_print_test(xml_doc[i])) != 0)
-	    return status;
-    }
-    return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_xml_test;
-#endif	/* INCLUDE_XML_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+

+#if INCLUDE_XML_TEST

+

+#include <pjlib-util/xml.h>

+#include <pjlib.h>

+

+#define THIS_FILE   "xml_test"

+

+static const char *xml_doc[] =

+{

+"   <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"

+"   <p:pidf-full xmlns=\"urn:ietf:params:xml:ns:pidf\"\n"

+"          xmlns:p=\"urn:ietf:params:xml:ns:pidf-diff\"\n"

+"          xmlns:r=\"urn:ietf:params:xml:ns:pidf:rpid\"\n"

+"          xmlns:c=\"urn:ietf:params:xml:ns:pidf:caps\"\n"

+"          entity=\"pres:someone@example.com\"\n"

+"          version=\"567\">\n"

+"\n"

+"    <tuple id=\"sg89ae\">\n"

+"     <status>\n"

+"      <basic>open</basic>\n"

+"      <r:relationship>assistant</r:relationship>\n"

+"     </status>\n"

+"     <c:servcaps>\n"

+"      <c:audio>true</c:audio>\n"

+"      <c:video>false</c:video>\n"

+"      <c:message>true</c:message>\n"

+"     </c:servcaps>\n"

+"     <contact priority=\"0.8\">tel:09012345678</contact>\n"

+"    </tuple>\n"

+"\n"

+"    <tuple id=\"cg231jcr\">\n"

+"     <status>\n"

+"      <basic>open</basic>\n"

+"     </status>\n"

+"     <contact priority=\"1.0\">im:pep@example.com</contact>\n"

+"    </tuple>\n"

+"\n"

+"    <tuple id=\"r1230d\">\n"

+"     <status>\n"

+"      <basic>closed</basic>\n"

+"      <r:activity>meeting</r:activity>\n"

+"     </status>\n"

+"     <r:homepage>http://example.com/~pep/</r:homepage>\n"

+"     <r:icon>http://example.com/~pep/icon.gif</r:icon>\n"

+"     <r:card>http://example.com/~pep/card.vcd</r:card>\n"

+"     <contact priority=\"0.9\">sip:pep@example.com</contact>\n"

+"    </tuple>\n"

+"\n"

+"    <note xml:lang=\"en\">Full state presence document</note>\n"

+"\n"

+"    <r:person>\n"

+"     <r:status>\n"

+"      <r:activities>\n"

+"       <r:on-the-phone/>\n"

+"       <r:busy/>\n"

+"      </r:activities>\n"

+"     </r:status>\n"

+"    </r:person>\n"

+"\n"

+"    <r:device id=\"urn:esn:600b40c7\">\n"

+"     <r:status>\n"

+"      <c:devcaps>\n"

+"       <c:mobility>\n"

+"        <c:supported>\n"

+"         <c:mobile/>\n"

+"        </c:supported>\n"

+"       </c:mobility>\n"

+"      </c:devcaps>\n"

+"     </r:status>\n"

+"    </r:device>\n"

+"\n"

+"   </p:pidf-full>\n"

+}

+;

+

+static int xml_parse_print_test(const char *doc)

+{

+    pj_str_t msg;

+    pj_pool_t *pool;

+    pj_xml_node *root;

+    char *output;

+    int output_len;

+

+    pool = pj_pool_create(mem, "xml", 4096, 1024, NULL);

+    pj_strdup2(pool, &msg, doc);

+    root = pj_xml_parse(pool, msg.ptr, msg.slen);

+    if (!root) {

+	PJ_LOG(1, (THIS_FILE, "  Error: unable to parse XML"));

+	return -10;

+    }

+

+    output = (char*)pj_pool_alloc(pool, msg.slen + 512);

+    pj_memset(output, 0, msg.slen+512);

+    output_len = pj_xml_print(root, output, msg.slen+512, PJ_TRUE);

+    if (output_len < 1) {

+	PJ_LOG(1, (THIS_FILE, "  Error: buffer too small to print XML file"));

+	return -20;

+    }

+    output[output_len] = '\0';

+

+

+    pj_pool_release(pool);

+    return 0;

+}

+

+int xml_test()

+{

+    unsigned i;

+    for (i=0; i<sizeof(xml_doc)/sizeof(xml_doc[0]); ++i) {

+	int status;

+	if ((status=xml_parse_print_test(xml_doc[i])) != 0)

+	    return status;

+    }

+    return 0;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_xml_test;

+#endif	/* INCLUDE_XML_TEST */

+

+

diff --git a/pjlib-util/src/pjlib-util/md5.c b/pjlib-util/src/pjlib-util/md5.c
index 10a903d..b5a1cbc 100644
--- a/pjlib-util/src/pjlib-util/md5.c
+++ b/pjlib-util/src/pjlib-util/md5.c
@@ -1,406 +1,427 @@
-/* $Id$
- */
-/*
-  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-
-  L. Peter Deutsch
-  ghost@aladdin.com
-
- */
-/* Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp */
-/*
-  Independent implementation of MD5 (RFC 1321).
-
-  This code implements the MD5 Algorithm defined in RFC 1321, whose
-  text is available at
-	http://www.ietf.org/rfc/rfc1321.txt
-  The code is derived from the text of the RFC, including the test suite
-  (section A.5) but excluding the rest of Appendix A.  It does not include
-  any code or documentation that is identified in the RFC as being
-  copyrighted.
-
-  The original and principal author of md5.c is L. Peter Deutsch
-  <ghost@aladdin.com>.  Other authors are noted in the change history
-  that follows (in reverse chronological order):
-
-  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
-	either statically or dynamically; added missing #include <string.h>
-	in library.
-  2002-03-11 lpd Corrected argument list for main(), and added int return
-	type, in test program and T value program.
-  2002-02-21 lpd Added missing #include <stdio.h> in test program.
-  2000-07-03 lpd Patched to eliminate warnings about "constant is
-	unsigned in ANSI C, signed in traditional"; made test program
-	self-checking.
-  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
-  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
-  1999-05-03 lpd Original version.
- */
-
-#include <pjlib-util/md5.h>
-#include <pj/string.h>
-#include <pj/os.h>
-
-#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */
-
-/*
-#ifdef ARCH_IS_BIG_ENDIAN
-#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
-#else
-#  define BYTE_ORDER 0
-#endif
-*/
-/* pjlib: */
-#include <pj/config.h>
-#if PJ_IS_LITTLE_ENDIAN
-#  define BYTE_ORDER -1
-#elif PJ_IS_BIG_ENDIAN
-#  define BYTE_ORDER 1
-#else
-#  error Endianess is not known!
-#endif
-
-
-#define T_MASK ((md5_word_t)~0)
-#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
-#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
-#define T3    0x242070db
-#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
-#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
-#define T6    0x4787c62a
-#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
-#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
-#define T9    0x698098d8
-#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
-#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
-#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
-#define T13    0x6b901122
-#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
-#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
-#define T16    0x49b40821
-#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
-#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
-#define T19    0x265e5a51
-#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
-#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
-#define T22    0x02441453
-#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
-#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
-#define T25    0x21e1cde6
-#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
-#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
-#define T28    0x455a14ed
-#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
-#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
-#define T31    0x676f02d9
-#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
-#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
-#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
-#define T35    0x6d9d6122
-#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
-#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
-#define T38    0x4bdecfa9
-#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
-#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
-#define T41    0x289b7ec6
-#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
-#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
-#define T44    0x04881d05
-#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
-#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
-#define T47    0x1fa27cf8
-#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
-#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
-#define T50    0x432aff97
-#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
-#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
-#define T53    0x655b59c3
-#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
-#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
-#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
-#define T57    0x6fa87e4f
-#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
-#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
-#define T60    0x4e0811a1
-#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
-#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
-#define T63    0x2ad7d2bb
-#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
-
-
-static void
-md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
-{
-    md5_word_t
-	a = pms->abcd[0], b = pms->abcd[1],
-	c = pms->abcd[2], d = pms->abcd[3];
-    md5_word_t t;
-#if BYTE_ORDER > 0
-    /* Define storage only for big-endian CPUs. */
-    md5_word_t X[16];
-#else
-    /* Define storage for little-endian or both types of CPUs. */
-    md5_word_t xbuf[16];
-    const md5_word_t *X;
-#endif
-
-    PJ_CHECK_STACK();
-
-    {
-#if BYTE_ORDER == 0
-	/*
-	 * Determine dynamically whether this is a big-endian or
-	 * little-endian machine, since we can use a more efficient
-	 * algorithm on the latter.
-	 */
-	static const int w = 1;
-
-	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
-#endif
-#if BYTE_ORDER <= 0		/* little-endian */
-	{
-	    /*
-	     * On little-endian machines, we can process properly aligned
-	     * data without copying it.
-	     */
-	    if (!((data - (const md5_byte_t *)0) & 3)) {
-		/* data are properly aligned */
-		X = (const md5_word_t *)data;
-	    } else {
-		/* not aligned */
-		memcpy(xbuf, data, 64);
-		X = xbuf;
-	    }
-	}
-#endif
-#if BYTE_ORDER == 0
-	else			/* dynamic big-endian */
-#endif
-#if BYTE_ORDER >= 0		/* big-endian */
-	{
-	    /*
-	     * On big-endian machines, we must arrange the bytes in the
-	     * right order.
-	     */
-	    const md5_byte_t *xp = data;
-	    int i;
-
-#  if BYTE_ORDER == 0
-	    X = xbuf;		/* (dynamic only) */
-#  else
-#    define xbuf X		/* (static only) */
-#  endif
-	    for (i = 0; i < 16; ++i, xp += 4)
-		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
-	}
-#endif
-    }
-
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
-    /* Round 1. */
-    /* Let [abcd k s i] denote the operation
-       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + F(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-    /* Do the following 16 operations. */
-    SET(a, b, c, d,  0,  7,  T1);
-    SET(d, a, b, c,  1, 12,  T2);
-    SET(c, d, a, b,  2, 17,  T3);
-    SET(b, c, d, a,  3, 22,  T4);
-    SET(a, b, c, d,  4,  7,  T5);
-    SET(d, a, b, c,  5, 12,  T6);
-    SET(c, d, a, b,  6, 17,  T7);
-    SET(b, c, d, a,  7, 22,  T8);
-    SET(a, b, c, d,  8,  7,  T9);
-    SET(d, a, b, c,  9, 12, T10);
-    SET(c, d, a, b, 10, 17, T11);
-    SET(b, c, d, a, 11, 22, T12);
-    SET(a, b, c, d, 12,  7, T13);
-    SET(d, a, b, c, 13, 12, T14);
-    SET(c, d, a, b, 14, 17, T15);
-    SET(b, c, d, a, 15, 22, T16);
-#undef SET
-
-     /* Round 2. */
-     /* Let [abcd k s i] denote the operation
-          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
-#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + G(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-     /* Do the following 16 operations. */
-    SET(a, b, c, d,  1,  5, T17);
-    SET(d, a, b, c,  6,  9, T18);
-    SET(c, d, a, b, 11, 14, T19);
-    SET(b, c, d, a,  0, 20, T20);
-    SET(a, b, c, d,  5,  5, T21);
-    SET(d, a, b, c, 10,  9, T22);
-    SET(c, d, a, b, 15, 14, T23);
-    SET(b, c, d, a,  4, 20, T24);
-    SET(a, b, c, d,  9,  5, T25);
-    SET(d, a, b, c, 14,  9, T26);
-    SET(c, d, a, b,  3, 14, T27);
-    SET(b, c, d, a,  8, 20, T28);
-    SET(a, b, c, d, 13,  5, T29);
-    SET(d, a, b, c,  2,  9, T30);
-    SET(c, d, a, b,  7, 14, T31);
-    SET(b, c, d, a, 12, 20, T32);
-#undef SET
-
-     /* Round 3. */
-     /* Let [abcd k s t] denote the operation
-          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + H(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-     /* Do the following 16 operations. */
-    SET(a, b, c, d,  5,  4, T33);
-    SET(d, a, b, c,  8, 11, T34);
-    SET(c, d, a, b, 11, 16, T35);
-    SET(b, c, d, a, 14, 23, T36);
-    SET(a, b, c, d,  1,  4, T37);
-    SET(d, a, b, c,  4, 11, T38);
-    SET(c, d, a, b,  7, 16, T39);
-    SET(b, c, d, a, 10, 23, T40);
-    SET(a, b, c, d, 13,  4, T41);
-    SET(d, a, b, c,  0, 11, T42);
-    SET(c, d, a, b,  3, 16, T43);
-    SET(b, c, d, a,  6, 23, T44);
-    SET(a, b, c, d,  9,  4, T45);
-    SET(d, a, b, c, 12, 11, T46);
-    SET(c, d, a, b, 15, 16, T47);
-    SET(b, c, d, a,  2, 23, T48);
-#undef SET
-
-     /* Round 4. */
-     /* Let [abcd k s t] denote the operation
-          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))
-#define SET(a, b, c, d, k, s, Ti)\
-  t = a + I(b,c,d) + X[k] + Ti;\
-  a = ROTATE_LEFT(t, s) + b
-     /* Do the following 16 operations. */
-    SET(a, b, c, d,  0,  6, T49);
-    SET(d, a, b, c,  7, 10, T50);
-    SET(c, d, a, b, 14, 15, T51);
-    SET(b, c, d, a,  5, 21, T52);
-    SET(a, b, c, d, 12,  6, T53);
-    SET(d, a, b, c,  3, 10, T54);
-    SET(c, d, a, b, 10, 15, T55);
-    SET(b, c, d, a,  1, 21, T56);
-    SET(a, b, c, d,  8,  6, T57);
-    SET(d, a, b, c, 15, 10, T58);
-    SET(c, d, a, b,  6, 15, T59);
-    SET(b, c, d, a, 13, 21, T60);
-    SET(a, b, c, d,  4,  6, T61);
-    SET(d, a, b, c, 11, 10, T62);
-    SET(c, d, a, b,  2, 15, T63);
-    SET(b, c, d, a,  9, 21, T64);
-#undef SET
-
-     /* Then perform the following additions. (That is increment each
-        of the four registers by the value it had before this block
-        was started.) */
-    pms->abcd[0] += a;
-    pms->abcd[1] += b;
-    pms->abcd[2] += c;
-    pms->abcd[3] += d;
-}
-
-void
-md5_init(md5_state_t *pms)
-{
-    PJ_CHECK_STACK();
-
-    pms->count[0] = pms->count[1] = 0;
-    pms->abcd[0] = 0x67452301;
-    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
-    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
-    pms->abcd[3] = 0x10325476;
-}
-
-void
-md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
-{
-    const md5_byte_t *p = data;
-    int left = nbytes;
-    int offset = (pms->count[0] >> 3) & 63;
-    md5_word_t nbits = (md5_word_t)(nbytes << 3);
-
-    PJ_CHECK_STACK();
-
-    if (nbytes <= 0)
-	return;
-
-    /* Update the message length. */
-    pms->count[1] += nbytes >> 29;
-    pms->count[0] += nbits;
-    if (pms->count[0] < nbits)
-	pms->count[1]++;
-
-    /* Process an initial partial block. */
-    if (offset) {
-	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
-
-	memcpy(pms->buf + offset, p, copy);
-	if (offset + copy < 64)
-	    return;
-	p += copy;
-	left -= copy;
-	md5_process(pms, pms->buf);
-    }
-
-    /* Process full blocks. */
-    for (; left >= 64; p += 64, left -= 64)
-	md5_process(pms, p);
-
-    /* Process a final partial block. */
-    if (left)
-	memcpy(pms->buf, p, left);
-}
-
-void
-md5_finish(md5_state_t *pms, md5_byte_t digest[16])
-{
-    static const md5_byte_t pad[64] = {
-	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-    };
-    md5_byte_t data[8];
-    int i;
-
-    PJ_CHECK_STACK();
-
-    /* Save the length before padding. */
-    for (i = 0; i < 8; ++i)
-	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
-    /* Pad to 56 bytes mod 64. */
-    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
-    /* Append the length. */
-    md5_append(pms, data, 8);
-    for (i = 0; i < 16; ++i)
-	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/*

+  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.

+

+  This software is provided 'as-is', without any express or implied

+  warranty.  In no event will the authors be held liable for any damages

+  arising from the use of this software.

+

+  Permission is granted to anyone to use this software for any purpose,

+  including commercial applications, and to alter it and redistribute it

+  freely, subject to the following restrictions:

+

+  1. The origin of this software must not be misrepresented; you must not

+     claim that you wrote the original software. If you use this software

+     in a product, an acknowledgment in the product documentation would be

+     appreciated but is not required.

+  2. Altered source versions must be plainly marked as such, and must not be

+     misrepresented as being the original software.

+  3. This notice may not be removed or altered from any source distribution.

+

+  L. Peter Deutsch

+  ghost@aladdin.com

+

+ */

+/* Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp */

+/*

+  Independent implementation of MD5 (RFC 1321).

+

+  This code implements the MD5 Algorithm defined in RFC 1321, whose

+  text is available at

+	http://www.ietf.org/rfc/rfc1321.txt

+  The code is derived from the text of the RFC, including the test suite

+  (section A.5) but excluding the rest of Appendix A.  It does not include

+  any code or documentation that is identified in the RFC as being

+  copyrighted.

+

+  The original and principal author of md5.c is L. Peter Deutsch

+  <ghost@aladdin.com>.  Other authors are noted in the change history

+  that follows (in reverse chronological order):

+

+  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order

+	either statically or dynamically; added missing #include <string.h>

+	in library.

+  2002-03-11 lpd Corrected argument list for main(), and added int return

+	type, in test program and T value program.

+  2002-02-21 lpd Added missing #include <stdio.h> in test program.

+  2000-07-03 lpd Patched to eliminate warnings about "constant is

+	unsigned in ANSI C, signed in traditional"; made test program

+	self-checking.

+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.

+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).

+  1999-05-03 lpd Original version.

+ */

+

+#include <pjlib-util/md5.h>

+#include <pj/string.h>

+#include <pj/os.h>

+

+#undef BYTE_ORDER	/* 1 = big-endian, -1 = little-endian, 0 = unknown */

+

+/*

+#ifdef ARCH_IS_BIG_ENDIAN

+#  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)

+#else

+#  define BYTE_ORDER 0

+#endif

+*/

+/* pjlib: */

+#include <pj/config.h>

+#if PJ_IS_LITTLE_ENDIAN

+#  define BYTE_ORDER -1

+#elif PJ_IS_BIG_ENDIAN

+#  define BYTE_ORDER 1

+#else

+#  error Endianess is not known!

+#endif

+

+

+#define T_MASK ((md5_word_t)~0)

+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)

+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)

+#define T3    0x242070db

+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)

+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)

+#define T6    0x4787c62a

+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)

+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)

+#define T9    0x698098d8

+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)

+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)

+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)

+#define T13    0x6b901122

+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)

+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)

+#define T16    0x49b40821

+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)

+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)

+#define T19    0x265e5a51

+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)

+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)

+#define T22    0x02441453

+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)

+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)

+#define T25    0x21e1cde6

+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)

+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)

+#define T28    0x455a14ed

+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)

+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)

+#define T31    0x676f02d9

+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)

+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)

+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)

+#define T35    0x6d9d6122

+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)

+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)

+#define T38    0x4bdecfa9

+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)

+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)

+#define T41    0x289b7ec6

+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)

+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)

+#define T44    0x04881d05

+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)

+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)

+#define T47    0x1fa27cf8

+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)

+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)

+#define T50    0x432aff97

+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)

+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)

+#define T53    0x655b59c3

+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)

+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)

+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)

+#define T57    0x6fa87e4f

+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)

+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)

+#define T60    0x4e0811a1

+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)

+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)

+#define T63    0x2ad7d2bb

+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)

+

+

+static void

+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)

+{

+    md5_word_t

+	a = pms->abcd[0], b = pms->abcd[1],

+	c = pms->abcd[2], d = pms->abcd[3];

+    md5_word_t t;

+#if BYTE_ORDER > 0

+    /* Define storage only for big-endian CPUs. */

+    md5_word_t X[16];

+#else

+    /* Define storage for little-endian or both types of CPUs. */

+    md5_word_t xbuf[16];

+    const md5_word_t *X;

+#endif

+

+    PJ_CHECK_STACK();

+

+    {

+#if BYTE_ORDER == 0

+	/*

+	 * Determine dynamically whether this is a big-endian or

+	 * little-endian machine, since we can use a more efficient

+	 * algorithm on the latter.

+	 */

+	static const int w = 1;

+

+	if (*((const md5_byte_t *)&w)) /* dynamic little-endian */

+#endif

+#if BYTE_ORDER <= 0		/* little-endian */

+	{

+	    /*

+	     * On little-endian machines, we can process properly aligned

+	     * data without copying it.

+	     */

+	    if (!((data - (const md5_byte_t *)0) & 3)) {

+		/* data are properly aligned */

+		X = (const md5_word_t *)data;

+	    } else {

+		/* not aligned */

+		memcpy(xbuf, data, 64);

+		X = xbuf;

+	    }

+	}

+#endif

+#if BYTE_ORDER == 0

+	else			/* dynamic big-endian */

+#endif

+#if BYTE_ORDER >= 0		/* big-endian */

+	{

+	    /*

+	     * On big-endian machines, we must arrange the bytes in the

+	     * right order.

+	     */

+	    const md5_byte_t *xp = data;

+	    int i;

+

+#  if BYTE_ORDER == 0

+	    X = xbuf;		/* (dynamic only) */

+#  else

+#    define xbuf X		/* (static only) */

+#  endif

+	    for (i = 0; i < 16; ++i, xp += 4)

+		xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);

+	}

+#endif

+    }

+

+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))

+

+    /* Round 1. */

+    /* Let [abcd k s i] denote the operation

+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */

+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))

+#define SET(a, b, c, d, k, s, Ti)\

+  t = a + F(b,c,d) + X[k] + Ti;\

+  a = ROTATE_LEFT(t, s) + b

+    /* Do the following 16 operations. */

+    SET(a, b, c, d,  0,  7,  T1);

+    SET(d, a, b, c,  1, 12,  T2);

+    SET(c, d, a, b,  2, 17,  T3);

+    SET(b, c, d, a,  3, 22,  T4);

+    SET(a, b, c, d,  4,  7,  T5);

+    SET(d, a, b, c,  5, 12,  T6);

+    SET(c, d, a, b,  6, 17,  T7);

+    SET(b, c, d, a,  7, 22,  T8);

+    SET(a, b, c, d,  8,  7,  T9);

+    SET(d, a, b, c,  9, 12, T10);

+    SET(c, d, a, b, 10, 17, T11);

+    SET(b, c, d, a, 11, 22, T12);

+    SET(a, b, c, d, 12,  7, T13);

+    SET(d, a, b, c, 13, 12, T14);

+    SET(c, d, a, b, 14, 17, T15);

+    SET(b, c, d, a, 15, 22, T16);

+#undef SET

+

+     /* Round 2. */

+     /* Let [abcd k s i] denote the operation

+          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */

+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))

+#define SET(a, b, c, d, k, s, Ti)\

+  t = a + G(b,c,d) + X[k] + Ti;\

+  a = ROTATE_LEFT(t, s) + b

+     /* Do the following 16 operations. */

+    SET(a, b, c, d,  1,  5, T17);

+    SET(d, a, b, c,  6,  9, T18);

+    SET(c, d, a, b, 11, 14, T19);

+    SET(b, c, d, a,  0, 20, T20);

+    SET(a, b, c, d,  5,  5, T21);

+    SET(d, a, b, c, 10,  9, T22);

+    SET(c, d, a, b, 15, 14, T23);

+    SET(b, c, d, a,  4, 20, T24);

+    SET(a, b, c, d,  9,  5, T25);

+    SET(d, a, b, c, 14,  9, T26);

+    SET(c, d, a, b,  3, 14, T27);

+    SET(b, c, d, a,  8, 20, T28);

+    SET(a, b, c, d, 13,  5, T29);

+    SET(d, a, b, c,  2,  9, T30);

+    SET(c, d, a, b,  7, 14, T31);

+    SET(b, c, d, a, 12, 20, T32);

+#undef SET

+

+     /* Round 3. */

+     /* Let [abcd k s t] denote the operation

+          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */

+#define H(x, y, z) ((x) ^ (y) ^ (z))

+#define SET(a, b, c, d, k, s, Ti)\

+  t = a + H(b,c,d) + X[k] + Ti;\

+  a = ROTATE_LEFT(t, s) + b

+     /* Do the following 16 operations. */

+    SET(a, b, c, d,  5,  4, T33);

+    SET(d, a, b, c,  8, 11, T34);

+    SET(c, d, a, b, 11, 16, T35);

+    SET(b, c, d, a, 14, 23, T36);

+    SET(a, b, c, d,  1,  4, T37);

+    SET(d, a, b, c,  4, 11, T38);

+    SET(c, d, a, b,  7, 16, T39);

+    SET(b, c, d, a, 10, 23, T40);

+    SET(a, b, c, d, 13,  4, T41);

+    SET(d, a, b, c,  0, 11, T42);

+    SET(c, d, a, b,  3, 16, T43);

+    SET(b, c, d, a,  6, 23, T44);

+    SET(a, b, c, d,  9,  4, T45);

+    SET(d, a, b, c, 12, 11, T46);

+    SET(c, d, a, b, 15, 16, T47);

+    SET(b, c, d, a,  2, 23, T48);

+#undef SET

+

+     /* Round 4. */

+     /* Let [abcd k s t] denote the operation

+          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */

+#define I(x, y, z) ((y) ^ ((x) | ~(z)))

+#define SET(a, b, c, d, k, s, Ti)\

+  t = a + I(b,c,d) + X[k] + Ti;\

+  a = ROTATE_LEFT(t, s) + b

+     /* Do the following 16 operations. */

+    SET(a, b, c, d,  0,  6, T49);

+    SET(d, a, b, c,  7, 10, T50);

+    SET(c, d, a, b, 14, 15, T51);

+    SET(b, c, d, a,  5, 21, T52);

+    SET(a, b, c, d, 12,  6, T53);

+    SET(d, a, b, c,  3, 10, T54);

+    SET(c, d, a, b, 10, 15, T55);

+    SET(b, c, d, a,  1, 21, T56);

+    SET(a, b, c, d,  8,  6, T57);

+    SET(d, a, b, c, 15, 10, T58);

+    SET(c, d, a, b,  6, 15, T59);

+    SET(b, c, d, a, 13, 21, T60);

+    SET(a, b, c, d,  4,  6, T61);

+    SET(d, a, b, c, 11, 10, T62);

+    SET(c, d, a, b,  2, 15, T63);

+    SET(b, c, d, a,  9, 21, T64);

+#undef SET

+

+     /* Then perform the following additions. (That is increment each

+        of the four registers by the value it had before this block

+        was started.) */

+    pms->abcd[0] += a;

+    pms->abcd[1] += b;

+    pms->abcd[2] += c;

+    pms->abcd[3] += d;

+}

+

+void

+md5_init(md5_state_t *pms)

+{

+    PJ_CHECK_STACK();

+

+    pms->count[0] = pms->count[1] = 0;

+    pms->abcd[0] = 0x67452301;

+    pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;

+    pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;

+    pms->abcd[3] = 0x10325476;

+}

+

+void

+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)

+{

+    const md5_byte_t *p = data;

+    int left = nbytes;

+    int offset = (pms->count[0] >> 3) & 63;

+    md5_word_t nbits = (md5_word_t)(nbytes << 3);

+

+    PJ_CHECK_STACK();

+

+    if (nbytes <= 0)

+	return;

+

+    /* Update the message length. */

+    pms->count[1] += nbytes >> 29;

+    pms->count[0] += nbits;

+    if (pms->count[0] < nbits)

+	pms->count[1]++;

+

+    /* Process an initial partial block. */

+    if (offset) {

+	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);

+

+	memcpy(pms->buf + offset, p, copy);

+	if (offset + copy < 64)

+	    return;

+	p += copy;

+	left -= copy;

+	md5_process(pms, pms->buf);

+    }

+

+    /* Process full blocks. */

+    for (; left >= 64; p += 64, left -= 64)

+	md5_process(pms, p);

+

+    /* Process a final partial block. */

+    if (left)

+	memcpy(pms->buf, p, left);

+}

+

+void

+md5_finish(md5_state_t *pms, md5_byte_t digest[16])

+{

+    static const md5_byte_t pad[64] = {

+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

+    };

+    md5_byte_t data[8];

+    int i;

+

+    PJ_CHECK_STACK();

+

+    /* Save the length before padding. */

+    for (i = 0; i < 8; ++i)

+	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));

+    /* Pad to 56 bytes mod 64. */

+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);

+    /* Append the length. */

+    md5_append(pms, data, 8);

+    for (i = 0; i < 16; ++i)

+	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));

+}

+

diff --git a/pjlib-util/src/pjlib-util/scanner.c b/pjlib-util/src/pjlib-util/scanner.c
index 0e753df..edd8de5 100644
--- a/pjlib-util/src/pjlib-util/scanner.c
+++ b/pjlib-util/src/pjlib-util/scanner.c
@@ -1,26 +1,47 @@
-/* $Id$
- */
-#include <pjlib-util/scanner.h>
-#include <pj/string.h>
-#include <pj/except.h>
-#include <pj/os.h>
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjlib-util/scanner.h>

+#include <pj/string.h>

+#include <pj/except.h>

+#include <pj/os.h>

 #include <pj/errno.h>

-
-#define PJ_SCAN_IS_SPACE(c)	((c)==' ' || (c)=='\t')
-#define PJ_SCAN_IS_NEWLINE(c)	((c)=='\r' || (c)=='\n')
-#define PJ_SCAN_CHECK_EOF(s)	(s != end)
-
-
-static void pj_scan_syntax_err(pj_scanner *scanner)
-{
-    (*scanner->callback)(scanner);
-}
-
-PJ_DEF(void) pj_cis_buf_init( pj_cis_buf_t *cis_buf)
-{
+

+#define PJ_SCAN_IS_SPACE(c)	((c)==' ' || (c)=='\t')

+#define PJ_SCAN_IS_NEWLINE(c)	((c)=='\r' || (c)=='\n')

+#define PJ_SCAN_CHECK_EOF(s)	(s != end)

+

+

+static void pj_scan_syntax_err(pj_scanner *scanner)

+{

+    (*scanner->callback)(scanner);

+}

+

+PJ_DEF(void) pj_cis_buf_init( pj_cis_buf_t *cis_buf)

+{

     pj_memset(cis_buf->cis_buf, 0, sizeof(cis_buf->cis_buf));

-    cis_buf->use_mask = 0;
-}
+    cis_buf->use_mask = 0;

+}

 

 PJ_DEF(pj_status_t) pj_cis_init(pj_cis_buf_t *cis_buf, pj_cis_t *cis)

 {

@@ -57,521 +78,521 @@
 

     return PJ_SUCCESS;

 }

-
-PJ_DEF(void) pj_cis_add_range(pj_cis_t *cis, int cstart, int cend)
-{
+

+PJ_DEF(void) pj_cis_add_range(pj_cis_t *cis, int cstart, int cend)

+{

     while (cstart != cend) {

-        PJ_CIS_SET(cis, cstart);
+        PJ_CIS_SET(cis, cstart);

 	++cstart;

-    }
-}
-
-PJ_DEF(void) pj_cis_add_alpha(pj_cis_t *cis)
-{
-    pj_cis_add_range( cis, 'a', 'z'+1);
-    pj_cis_add_range( cis, 'A', 'Z'+1);
-}
-
-PJ_DEF(void) pj_cis_add_num(pj_cis_t *cis)
-{
-    pj_cis_add_range( cis, '0', '9'+1);
-}
-
-PJ_DEF(void) pj_cis_add_str( pj_cis_t *cis, const char *str)
-{
-    while (*str) {
-        PJ_CIS_SET(cis, *str);
-	++str;
-    }
-}
-
-PJ_DEF(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend)
-{
-    while (cstart != cend) {
+    }

+}

+

+PJ_DEF(void) pj_cis_add_alpha(pj_cis_t *cis)

+{

+    pj_cis_add_range( cis, 'a', 'z'+1);

+    pj_cis_add_range( cis, 'A', 'Z'+1);

+}

+

+PJ_DEF(void) pj_cis_add_num(pj_cis_t *cis)

+{

+    pj_cis_add_range( cis, '0', '9'+1);

+}

+

+PJ_DEF(void) pj_cis_add_str( pj_cis_t *cis, const char *str)

+{

+    while (*str) {

+        PJ_CIS_SET(cis, *str);

+	++str;

+    }

+}

+

+PJ_DEF(void) pj_cis_del_range( pj_cis_t *cis, int cstart, int cend)

+{

+    while (cstart != cend) {

         PJ_CIS_CLR(cis, cstart);

         cstart++;

-    }
-}
-
-PJ_DEF(void) pj_cis_del_str( pj_cis_t *cis, const char *str)
-{
-    while (*str) {
-        PJ_CIS_CLR(cis, *str);
-	++str;
-    }
-}
-
-PJ_DEF(void) pj_cis_invert( pj_cis_t *cis )
-{
-    unsigned i;
-    for (i=0; i<256; ++i) {
+    }

+}

+

+PJ_DEF(void) pj_cis_del_str( pj_cis_t *cis, const char *str)

+{

+    while (*str) {

+        PJ_CIS_CLR(cis, *str);

+	++str;

+    }

+}

+

+PJ_DEF(void) pj_cis_invert( pj_cis_t *cis )

+{

+    unsigned i;

+    for (i=0; i<256; ++i) {

 	if (PJ_CIS_ISSET(cis,i))

             PJ_CIS_CLR(cis,i);

         else

-            PJ_CIS_SET(cis,i);
-    }
-}
-
-PJ_DEF(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, 
-			   unsigned options, pj_syn_err_func_ptr callback )
-{
-    PJ_CHECK_STACK();
-
-    scanner->begin = scanner->curptr = bufstart;
-    scanner->end = bufstart + buflen;
-    scanner->line = 1;
-    scanner->col = 1;
-    scanner->callback = callback;
-    scanner->skip_ws = options;
-
-    if (scanner->skip_ws) 
-	pj_scan_skip_whitespace(scanner);
-
-    scanner->col = scanner->curptr - scanner->begin + 1;
-}
-
-
-PJ_DEF(void) pj_scan_fini( pj_scanner *scanner )
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(scanner);
-}
-
-PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner )
-{
-    register char *s = scanner->curptr;
-
-    PJ_CHECK_STACK();
-
-    while (PJ_SCAN_IS_SPACE(*s)) {
-	++s;
-    }
-
-    if ((scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE) && PJ_SCAN_IS_NEWLINE(*s)) {
-	for (;;) {
-	    if (*s == '\r') {
-		++s;
-		if (*s == '\n') ++s;
-		++scanner->line;
-		scanner->col = 1;
-		scanner->curptr = s;
-	    } else if (*s == '\n') {
-		++s;
-		++scanner->line;
-		scanner->col = 1;
-		scanner->curptr = s;
-	    } else if (PJ_SCAN_IS_SPACE(*s)) {
-		do {
-		    ++s;
-		} while (PJ_SCAN_IS_SPACE(*s));
-	    } else {
-		break;
-	    }
-	}
-    }
-
-    if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==PJ_SCAN_AUTOSKIP_WS_HEADER) {
-	/* Check for header continuation. */
-	scanner->col += s - scanner->curptr;
-	scanner->curptr = s;
-
-	if (*s == '\r') {
-	    ++s;
-	}
-	if (*s == '\n') {
-	    ++s;
-	}
-	if (PJ_SCAN_IS_SPACE(*s)) {
-	    register char *t = s;
-	    do {
-		++t;
-	    } while (PJ_SCAN_IS_SPACE(*t));
-
-	    ++scanner->line;
-	    scanner->col = t-s;
-	    scanner->curptr = t;
-	}
-    } else {
-	scanner->col += s - scanner->curptr;
-	scanner->curptr = s;
-    }
-}
-
-PJ_DEF(int) pj_scan_peek( pj_scanner *scanner,
-			  const pj_cis_t *spec, pj_str_t *out)
-{
-    register char *s = scanner->curptr;
-    register char *end = scanner->end;
-
-    PJ_CHECK_STACK();
-
-    if (pj_scan_is_eof(scanner)) {
-	pj_scan_syntax_err(scanner);
-	return -1;
-    }
-
-    while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s))
-	++s;
-
-    pj_strset3(out, scanner->curptr, s);
-    return s < scanner->end ? *s : 0;
-}
-
-
-PJ_DEF(int) pj_scan_peek_n( pj_scanner *scanner,
-			     pj_size_t len, pj_str_t *out)
-{
-    char *endpos = scanner->curptr + len;
-
-    PJ_CHECK_STACK();
-
-    if (endpos > scanner->end) {
-	pj_scan_syntax_err(scanner);
-	return -1;
-    }
-
-    pj_strset(out, scanner->curptr, len);
-    return *endpos;
-}
-
-
-PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner,
-				const pj_cis_t *spec, 
-				pj_str_t *out)
-{
-    register char *s = scanner->curptr;
-    register char *end = scanner->end;
-
-    PJ_CHECK_STACK();
-
-    if (pj_scan_is_eof(scanner)) {
-	pj_scan_syntax_err(scanner);
-	return -1;
-    }
-
-    while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match( spec, *s))
-	++s;
-
-    pj_strset3(out, scanner->curptr, s);
-    return s!=scanner->end ? *s : 0;
-}
-
-
-PJ_DEF(void) pj_scan_get( pj_scanner *scanner,
-			  const pj_cis_t *spec, pj_str_t *out)
-{
-    register char *s = scanner->curptr;
-    register char *end = scanner->end;
-    char *start = s;
-
-    PJ_CHECK_STACK();
-
-    if (pj_scan_is_eof(scanner) || !pj_cis_match(spec, *s)) {
-	pj_scan_syntax_err(scanner);
-	return;
-    }
-
-    do {
-	++s;
-    } while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s));
-
-    pj_strset3(out, scanner->curptr, s);
-
-    scanner->col += (s - start);
-    scanner->curptr = s;
-
-    if (scanner->skip_ws) {
-	pj_scan_skip_whitespace(scanner);    
-    }
-}
-
-
-PJ_DEF(void) pj_scan_get_quote( pj_scanner *scanner,
-				 int begin_quote, int end_quote, 
-				 pj_str_t *out)
-{
-    register char *s = scanner->curptr;
-    register char *end = scanner->end;
-    char *start = s;
-    
-    PJ_CHECK_STACK();
-
-    /* Check and eat the begin_quote. */
-    if (*s != begin_quote) {
-	pj_scan_syntax_err(scanner);
-	return;
-    }
-    ++s;
-
-    /* Loop until end_quote is found. 
-     */
-    do {
-	/* loop until end_quote is found. */
-	do {
-	    ++s;
-	} while (s != end && *s != '\n' && *s != end_quote);
-
-	/* check that no backslash character precedes the end_quote. */
-	if (*s == end_quote) {
-	    if (*(s-1) == '\\') {
-		if (s-2 == scanner->begin) {
-		    break;
-		} else {
-		    char *q = s-2;
-		    char *r = s-2;
-
-		    while (r != scanner->begin && *r == '\\') {
-			--r;
-		    }
-		    /* break from main loop if we have odd number of backslashes */
-		    if (((unsigned)(q-r) & 0x01) == 1) {
-			break;
-		    }
-		}
-	    } else {
-		/* end_quote is not preceeded by backslash. break now. */
-		break;
-	    }
-	} else {
-	    /* loop ended by non-end_quote character. break now. */
-	    break;
-	}
-    } while (1);
-
-    /* Check and eat the end quote. */
-    if (*s != end_quote) {
-	pj_scan_syntax_err(scanner);
-	return;
-    }
-    ++s;
-
-    pj_strset3(out, scanner->curptr, s);
-
-    scanner->col += (s - start);
-    scanner->curptr = s;
-
-    if (scanner->skip_ws) {
-	pj_scan_skip_whitespace(scanner);
-    }
-}
-
-PJ_DEF(void) pj_scan_get_n( pj_scanner *scanner,
-			     unsigned N, pj_str_t *out)
-{
-    register char *s = scanner->curptr;
-    char *start = scanner->curptr;
-
-    PJ_CHECK_STACK();
-
-    if (scanner->curptr + N > scanner->end) {
-	pj_scan_syntax_err(scanner);
-	return;
-    }
-
-    pj_strset(out, s, N);
-    
-    s += N;
-    scanner->col += (s - start);
-    scanner->curptr = s;
-
-    if (scanner->skip_ws) {
-	pj_scan_skip_whitespace(scanner);
-    }
-}
-
-
-PJ_DEF(int) pj_scan_get_char( pj_scanner *scanner )
-{
-    char *start = scanner->curptr;
-    int chr = *start;
-
-    PJ_CHECK_STACK();
-
-    if (pj_scan_is_eof(scanner)) {
-	pj_scan_syntax_err(scanner);
-	return 0;
-    }
-
-    ++scanner->curptr;
-    scanner->col += (scanner->curptr - start);
-
-    if (scanner->skip_ws) {
-	pj_scan_skip_whitespace(scanner);
-    }
-    return chr;
-}
-
-
-PJ_DEF(void) pj_scan_get_newline( pj_scanner *scanner )
-{
-    PJ_CHECK_STACK();
-
-    if (!PJ_SCAN_IS_NEWLINE(*scanner->curptr)) {
-	pj_scan_syntax_err(scanner);
-	return;
-    }
-
-    if (*scanner->curptr == '\r') {
-	++scanner->curptr;
-    }
-    if (*scanner->curptr == '\n') {
-	++scanner->curptr;
-    }
-
-    ++scanner->line;
-    scanner->col = 1;
-
-    if (scanner->skip_ws) {
-	pj_scan_skip_whitespace(scanner);
-    }
-}
-
-
-PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner,
-				const pj_cis_t *spec, pj_str_t *out)
-{
-    register char *s = scanner->curptr;
-    register char *end = scanner->end;
-    char *start = s;
-
-    PJ_CHECK_STACK();
-
-    if (pj_scan_is_eof(scanner)) {
-	pj_scan_syntax_err(scanner);
-	return;
-    }
-
-    while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match(spec, *s)) {
-	++s;
-    }
-
-    pj_strset3(out, scanner->curptr, s);
-
-    scanner->col += (s - start);
-    scanner->curptr = s;
-
-    if (scanner->skip_ws) {
-	pj_scan_skip_whitespace(scanner);
-    }
-}
-
-
-PJ_DEF(void) pj_scan_get_until_ch( pj_scanner *scanner, 
-				   int until_char, pj_str_t *out)
-{
-    register char *s = scanner->curptr;
-    register char *end = scanner->end;
-    char *start = s;
-
-    PJ_CHECK_STACK();
-
-    if (pj_scan_is_eof(scanner)) {
-	pj_scan_syntax_err(scanner);
-	return;
-    }
-
-    while (PJ_SCAN_CHECK_EOF(s) && *s != until_char) {
-	++s;
-    }
-
-    pj_strset3(out, scanner->curptr, s);
-
-    scanner->col += (s - start);
-    scanner->curptr = s;
-
-    if (scanner->skip_ws) {
-	pj_scan_skip_whitespace(scanner);
-    }
-}
-
-
-PJ_DEF(void) pj_scan_get_until_chr( pj_scanner *scanner,
-				     const char *until_spec, pj_str_t *out)
-{
-    register char *s = scanner->curptr;
-    register char *end = scanner->end;
-    char *start = scanner->curptr;
-
-    PJ_CHECK_STACK();
-
-    if (pj_scan_is_eof(scanner)) {
-	pj_scan_syntax_err(scanner);
-	return;
-    }
-
-    while (PJ_SCAN_CHECK_EOF(s) && !strchr(until_spec, *s)) {
-	++s;
-    }
-
-    pj_strset3(out, scanner->curptr, s);
-
-    scanner->col += (s - start);
-    scanner->curptr = s;
-
-    if (scanner->skip_ws) {
-	pj_scan_skip_whitespace(scanner);
-    }
-}
-
-PJ_DEF(void) pj_scan_advance_n( pj_scanner *scanner,
-				 unsigned N, pj_bool_t skip_ws)
-{
-    char *start = scanner->curptr;
-
-    PJ_CHECK_STACK();
-
-    if (scanner->curptr + N > scanner->end) {
-	pj_scan_syntax_err(scanner);
-	return;
-    }
-
-    scanner->curptr += N;
-    scanner->col += (scanner->curptr - start);
-
-    if (skip_ws) {
-	pj_scan_skip_whitespace(scanner);
-    }
-}
-
-
-PJ_DEF(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len)
-{
-    if (scanner->curptr + len > scanner->end) {
-	pj_scan_syntax_err(scanner);
-	return -1;
-    }
-    return strncmp(scanner->curptr, s, len);
-}
-
-
-PJ_DEF(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len)
-{
-    if (scanner->curptr + len > scanner->end) {
-	pj_scan_syntax_err(scanner);
-	return -1;
-    }
-    return strnicmp(scanner->curptr, s, len);
-}
-
-
-PJ_DEF(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state)
-{
-    PJ_CHECK_STACK();
-
-    state->curptr = scanner->curptr;
-    state->line = scanner->line;
-    state->col = scanner->col;
-}
-
-
-PJ_DEF(void) pj_scan_restore_state( pj_scanner *scanner, 
-				     pj_scan_state *state)
-{
-    PJ_CHECK_STACK();
-
-    scanner->curptr = state->curptr;
-    scanner->line = state->line;
-    scanner->col = state->col;
-}
-
-
+            PJ_CIS_SET(cis,i);

+    }

+}

+

+PJ_DEF(void) pj_scan_init( pj_scanner *scanner, char *bufstart, int buflen, 

+			   unsigned options, pj_syn_err_func_ptr callback )

+{

+    PJ_CHECK_STACK();

+

+    scanner->begin = scanner->curptr = bufstart;

+    scanner->end = bufstart + buflen;

+    scanner->line = 1;

+    scanner->col = 1;

+    scanner->callback = callback;

+    scanner->skip_ws = options;

+

+    if (scanner->skip_ws) 

+	pj_scan_skip_whitespace(scanner);

+

+    scanner->col = scanner->curptr - scanner->begin + 1;

+}

+

+

+PJ_DEF(void) pj_scan_fini( pj_scanner *scanner )

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(scanner);

+}

+

+PJ_DEF(void) pj_scan_skip_whitespace( pj_scanner *scanner )

+{

+    register char *s = scanner->curptr;

+

+    PJ_CHECK_STACK();

+

+    while (PJ_SCAN_IS_SPACE(*s)) {

+	++s;

+    }

+

+    if ((scanner->skip_ws & PJ_SCAN_AUTOSKIP_NEWLINE) && PJ_SCAN_IS_NEWLINE(*s)) {

+	for (;;) {

+	    if (*s == '\r') {

+		++s;

+		if (*s == '\n') ++s;

+		++scanner->line;

+		scanner->col = 1;

+		scanner->curptr = s;

+	    } else if (*s == '\n') {

+		++s;

+		++scanner->line;

+		scanner->col = 1;

+		scanner->curptr = s;

+	    } else if (PJ_SCAN_IS_SPACE(*s)) {

+		do {

+		    ++s;

+		} while (PJ_SCAN_IS_SPACE(*s));

+	    } else {

+		break;

+	    }

+	}

+    }

+

+    if (PJ_SCAN_IS_NEWLINE(*s) && (scanner->skip_ws & PJ_SCAN_AUTOSKIP_WS_HEADER)==PJ_SCAN_AUTOSKIP_WS_HEADER) {

+	/* Check for header continuation. */

+	scanner->col += s - scanner->curptr;

+	scanner->curptr = s;

+

+	if (*s == '\r') {

+	    ++s;

+	}

+	if (*s == '\n') {

+	    ++s;

+	}

+	if (PJ_SCAN_IS_SPACE(*s)) {

+	    register char *t = s;

+	    do {

+		++t;

+	    } while (PJ_SCAN_IS_SPACE(*t));

+

+	    ++scanner->line;

+	    scanner->col = t-s;

+	    scanner->curptr = t;

+	}

+    } else {

+	scanner->col += s - scanner->curptr;

+	scanner->curptr = s;

+    }

+}

+

+PJ_DEF(int) pj_scan_peek( pj_scanner *scanner,

+			  const pj_cis_t *spec, pj_str_t *out)

+{

+    register char *s = scanner->curptr;

+    register char *end = scanner->end;

+

+    PJ_CHECK_STACK();

+

+    if (pj_scan_is_eof(scanner)) {

+	pj_scan_syntax_err(scanner);

+	return -1;

+    }

+

+    while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s))

+	++s;

+

+    pj_strset3(out, scanner->curptr, s);

+    return s < scanner->end ? *s : 0;

+}

+

+

+PJ_DEF(int) pj_scan_peek_n( pj_scanner *scanner,

+			     pj_size_t len, pj_str_t *out)

+{

+    char *endpos = scanner->curptr + len;

+

+    PJ_CHECK_STACK();

+

+    if (endpos > scanner->end) {

+	pj_scan_syntax_err(scanner);

+	return -1;

+    }

+

+    pj_strset(out, scanner->curptr, len);

+    return *endpos;

+}

+

+

+PJ_DEF(int) pj_scan_peek_until( pj_scanner *scanner,

+				const pj_cis_t *spec, 

+				pj_str_t *out)

+{

+    register char *s = scanner->curptr;

+    register char *end = scanner->end;

+

+    PJ_CHECK_STACK();

+

+    if (pj_scan_is_eof(scanner)) {

+	pj_scan_syntax_err(scanner);

+	return -1;

+    }

+

+    while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match( spec, *s))

+	++s;

+

+    pj_strset3(out, scanner->curptr, s);

+    return s!=scanner->end ? *s : 0;

+}

+

+

+PJ_DEF(void) pj_scan_get( pj_scanner *scanner,

+			  const pj_cis_t *spec, pj_str_t *out)

+{

+    register char *s = scanner->curptr;

+    register char *end = scanner->end;

+    char *start = s;

+

+    PJ_CHECK_STACK();

+

+    if (pj_scan_is_eof(scanner) || !pj_cis_match(spec, *s)) {

+	pj_scan_syntax_err(scanner);

+	return;

+    }

+

+    do {

+	++s;

+    } while (PJ_SCAN_CHECK_EOF(s) && pj_cis_match(spec, *s));

+

+    pj_strset3(out, scanner->curptr, s);

+

+    scanner->col += (s - start);

+    scanner->curptr = s;

+

+    if (scanner->skip_ws) {

+	pj_scan_skip_whitespace(scanner);    

+    }

+}

+

+

+PJ_DEF(void) pj_scan_get_quote( pj_scanner *scanner,

+				 int begin_quote, int end_quote, 

+				 pj_str_t *out)

+{

+    register char *s = scanner->curptr;

+    register char *end = scanner->end;

+    char *start = s;

+    

+    PJ_CHECK_STACK();

+

+    /* Check and eat the begin_quote. */

+    if (*s != begin_quote) {

+	pj_scan_syntax_err(scanner);

+	return;

+    }

+    ++s;

+

+    /* Loop until end_quote is found. 

+     */

+    do {

+	/* loop until end_quote is found. */

+	do {

+	    ++s;

+	} while (s != end && *s != '\n' && *s != end_quote);

+

+	/* check that no backslash character precedes the end_quote. */

+	if (*s == end_quote) {

+	    if (*(s-1) == '\\') {

+		if (s-2 == scanner->begin) {

+		    break;

+		} else {

+		    char *q = s-2;

+		    char *r = s-2;

+

+		    while (r != scanner->begin && *r == '\\') {

+			--r;

+		    }

+		    /* break from main loop if we have odd number of backslashes */

+		    if (((unsigned)(q-r) & 0x01) == 1) {

+			break;

+		    }

+		}

+	    } else {

+		/* end_quote is not preceeded by backslash. break now. */

+		break;

+	    }

+	} else {

+	    /* loop ended by non-end_quote character. break now. */

+	    break;

+	}

+    } while (1);

+

+    /* Check and eat the end quote. */

+    if (*s != end_quote) {

+	pj_scan_syntax_err(scanner);

+	return;

+    }

+    ++s;

+

+    pj_strset3(out, scanner->curptr, s);

+

+    scanner->col += (s - start);

+    scanner->curptr = s;

+

+    if (scanner->skip_ws) {

+	pj_scan_skip_whitespace(scanner);

+    }

+}

+

+PJ_DEF(void) pj_scan_get_n( pj_scanner *scanner,

+			     unsigned N, pj_str_t *out)

+{

+    register char *s = scanner->curptr;

+    char *start = scanner->curptr;

+

+    PJ_CHECK_STACK();

+

+    if (scanner->curptr + N > scanner->end) {

+	pj_scan_syntax_err(scanner);

+	return;

+    }

+

+    pj_strset(out, s, N);

+    

+    s += N;

+    scanner->col += (s - start);

+    scanner->curptr = s;

+

+    if (scanner->skip_ws) {

+	pj_scan_skip_whitespace(scanner);

+    }

+}

+

+

+PJ_DEF(int) pj_scan_get_char( pj_scanner *scanner )

+{

+    char *start = scanner->curptr;

+    int chr = *start;

+

+    PJ_CHECK_STACK();

+

+    if (pj_scan_is_eof(scanner)) {

+	pj_scan_syntax_err(scanner);

+	return 0;

+    }

+

+    ++scanner->curptr;

+    scanner->col += (scanner->curptr - start);

+

+    if (scanner->skip_ws) {

+	pj_scan_skip_whitespace(scanner);

+    }

+    return chr;

+}

+

+

+PJ_DEF(void) pj_scan_get_newline( pj_scanner *scanner )

+{

+    PJ_CHECK_STACK();

+

+    if (!PJ_SCAN_IS_NEWLINE(*scanner->curptr)) {

+	pj_scan_syntax_err(scanner);

+	return;

+    }

+

+    if (*scanner->curptr == '\r') {

+	++scanner->curptr;

+    }

+    if (*scanner->curptr == '\n') {

+	++scanner->curptr;

+    }

+

+    ++scanner->line;

+    scanner->col = 1;

+

+    if (scanner->skip_ws) {

+	pj_scan_skip_whitespace(scanner);

+    }

+}

+

+

+PJ_DEF(void) pj_scan_get_until( pj_scanner *scanner,

+				const pj_cis_t *spec, pj_str_t *out)

+{

+    register char *s = scanner->curptr;

+    register char *end = scanner->end;

+    char *start = s;

+

+    PJ_CHECK_STACK();

+

+    if (pj_scan_is_eof(scanner)) {

+	pj_scan_syntax_err(scanner);

+	return;

+    }

+

+    while (PJ_SCAN_CHECK_EOF(s) && !pj_cis_match(spec, *s)) {

+	++s;

+    }

+

+    pj_strset3(out, scanner->curptr, s);

+

+    scanner->col += (s - start);

+    scanner->curptr = s;

+

+    if (scanner->skip_ws) {

+	pj_scan_skip_whitespace(scanner);

+    }

+}

+

+

+PJ_DEF(void) pj_scan_get_until_ch( pj_scanner *scanner, 

+				   int until_char, pj_str_t *out)

+{

+    register char *s = scanner->curptr;

+    register char *end = scanner->end;

+    char *start = s;

+

+    PJ_CHECK_STACK();

+

+    if (pj_scan_is_eof(scanner)) {

+	pj_scan_syntax_err(scanner);

+	return;

+    }

+

+    while (PJ_SCAN_CHECK_EOF(s) && *s != until_char) {

+	++s;

+    }

+

+    pj_strset3(out, scanner->curptr, s);

+

+    scanner->col += (s - start);

+    scanner->curptr = s;

+

+    if (scanner->skip_ws) {

+	pj_scan_skip_whitespace(scanner);

+    }

+}

+

+

+PJ_DEF(void) pj_scan_get_until_chr( pj_scanner *scanner,

+				     const char *until_spec, pj_str_t *out)

+{

+    register char *s = scanner->curptr;

+    register char *end = scanner->end;

+    char *start = scanner->curptr;

+

+    PJ_CHECK_STACK();

+

+    if (pj_scan_is_eof(scanner)) {

+	pj_scan_syntax_err(scanner);

+	return;

+    }

+

+    while (PJ_SCAN_CHECK_EOF(s) && !strchr(until_spec, *s)) {

+	++s;

+    }

+

+    pj_strset3(out, scanner->curptr, s);

+

+    scanner->col += (s - start);

+    scanner->curptr = s;

+

+    if (scanner->skip_ws) {

+	pj_scan_skip_whitespace(scanner);

+    }

+}

+

+PJ_DEF(void) pj_scan_advance_n( pj_scanner *scanner,

+				 unsigned N, pj_bool_t skip_ws)

+{

+    char *start = scanner->curptr;

+

+    PJ_CHECK_STACK();

+

+    if (scanner->curptr + N > scanner->end) {

+	pj_scan_syntax_err(scanner);

+	return;

+    }

+

+    scanner->curptr += N;

+    scanner->col += (scanner->curptr - start);

+

+    if (skip_ws) {

+	pj_scan_skip_whitespace(scanner);

+    }

+}

+

+

+PJ_DEF(int) pj_scan_strcmp( pj_scanner *scanner, const char *s, int len)

+{

+    if (scanner->curptr + len > scanner->end) {

+	pj_scan_syntax_err(scanner);

+	return -1;

+    }

+    return strncmp(scanner->curptr, s, len);

+}

+

+

+PJ_DEF(int) pj_scan_stricmp( pj_scanner *scanner, const char *s, int len)

+{

+    if (scanner->curptr + len > scanner->end) {

+	pj_scan_syntax_err(scanner);

+	return -1;

+    }

+    return strnicmp(scanner->curptr, s, len);

+}

+

+

+PJ_DEF(void) pj_scan_save_state( pj_scanner *scanner, pj_scan_state *state)

+{

+    PJ_CHECK_STACK();

+

+    state->curptr = scanner->curptr;

+    state->line = scanner->line;

+    state->col = scanner->col;

+}

+

+

+PJ_DEF(void) pj_scan_restore_state( pj_scanner *scanner, 

+				     pj_scan_state *state)

+{

+    PJ_CHECK_STACK();

+

+    scanner->curptr = state->curptr;

+    scanner->line = state->line;

+    scanner->col = state->col;

+}

+

+

diff --git a/pjlib-util/src/pjlib-util/stun.c b/pjlib-util/src/pjlib-util/stun.c
index 4b41753..40566a6 100644
--- a/pjlib-util/src/pjlib-util/stun.c
+++ b/pjlib-util/src/pjlib-util/stun.c
@@ -1,113 +1,134 @@
-/* $Id$
- */
-#include <pjlib-util/stun.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/sock.h>
-#include <pj/os.h>
-
-#define THIS_FILE   "stun"
-
-PJ_DEF(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, 
-					     void **msg, pj_size_t *len,
-					     pj_uint32_t id_hi, 
-					     pj_uint32_t id_lo)
-{
-    pj_stun_msg_hdr *hdr;
-    
-    PJ_CHECK_STACK();
-
-    PJ_LOG(5,(THIS_FILE, "pj_stun_create_bind_req"));
-
-    hdr = pj_pool_calloc(pool, 1, sizeof(pj_stun_msg_hdr));
-    if (!hdr) {
-	PJ_LOG(5,(THIS_FILE, "Error allocating memory!"));
-	return -1;
-    }
-
-    hdr->type = pj_htons(PJ_STUN_BINDING_REQUEST);
-    hdr->tsx[2] = pj_htonl(id_hi);
-    hdr->tsx[3] = pj_htonl(id_lo);
-    *msg = hdr;
-    *len = sizeof(pj_stun_msg_hdr);
-
-    return 0;
-}
-
-PJ_DEF(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, 
-				       pj_stun_msg *msg)
-{
-    pj_uint16_t msg_type, msg_len;
-    char *p_attr;
-
-    PJ_CHECK_STACK();
-
-    PJ_LOG(5,(THIS_FILE, "pj_stun_parse_msg %p, len=%d", buf, len));
-
-    msg->hdr = (pj_stun_msg_hdr*)buf;
-    msg_type = pj_ntohs(msg->hdr->type);
-
-    switch (msg_type) {
-    case PJ_STUN_BINDING_REQUEST:
-    case PJ_STUN_BINDING_RESPONSE:
-    case PJ_STUN_BINDING_ERROR_RESPONSE:
-    case PJ_STUN_SHARED_SECRET_REQUEST:
-    case PJ_STUN_SHARED_SECRET_RESPONSE:
-    case PJ_STUN_SHARED_SECRET_ERROR_RESPONSE:
-	break;
-    default:
-	PJ_LOG(5,(THIS_FILE, "Error: unknown msg type %d", msg_type));
-	return -1;
-    }
-
-    msg_len = pj_ntohs(msg->hdr->length);
-    if (msg_len != len - sizeof(pj_stun_msg_hdr)) {
-	PJ_LOG(5,(THIS_FILE, "Error: invalid msg_len %d (expecting %d)", 
-			     msg_len, len - sizeof(pj_stun_msg_hdr)));
-	return -1;
-    }
-
-    msg->attr_count = 0;
-    p_attr = (char*)buf + sizeof(pj_stun_msg_hdr);
-
-    while (msg_len > 0) {
-	pj_stun_attr_hdr **attr = &msg->attr[msg->attr_count];
-	pj_uint32_t len;
-
-	*attr = (pj_stun_attr_hdr*)p_attr;
-	len = pj_ntohs((pj_uint16_t) ((*attr)->length)) + sizeof(pj_stun_attr_hdr);
-
-	if (msg_len < len) {
-	    PJ_LOG(5,(THIS_FILE, "Error: length mismatch in attr %d", 
-				 msg->attr_count));
-	    return -1;
-	}
-
-	if (pj_ntohs((*attr)->type) > PJ_STUN_ATTR_REFLECTED_FORM) {
-	    PJ_LOG(5,(THIS_FILE, "Error: invalid attr type %d in attr %d",
-				 pj_ntohs((*attr)->type), msg->attr_count));
-	    return -1;
-	}
-
-	msg_len = (pj_uint16_t)(msg_len - len);
-	p_attr += len;
-	++msg->attr_count;
-    }
-
-    return 0;
-}
-
-PJ_DEF(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t)
-{
-    int i;
-
-    PJ_CHECK_STACK();
-
-    for (i=0; i<msg->attr_count; ++i) {
-	pj_stun_attr_hdr *attr = msg->attr[i];
-	if (pj_ntohs(attr->type) == t)
-	    return attr;
-    }
-
-    return 0;
-}
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjlib-util/stun.h>

+#include <pj/pool.h>

+#include <pj/log.h>

+#include <pj/sock.h>

+#include <pj/os.h>

+

+#define THIS_FILE   "stun"

+

+PJ_DEF(pj_status_t) pj_stun_create_bind_req( pj_pool_t *pool, 

+					     void **msg, pj_size_t *len,

+					     pj_uint32_t id_hi, 

+					     pj_uint32_t id_lo)

+{

+    pj_stun_msg_hdr *hdr;

+    

+    PJ_CHECK_STACK();

+

+    PJ_LOG(5,(THIS_FILE, "pj_stun_create_bind_req"));

+

+    hdr = pj_pool_calloc(pool, 1, sizeof(pj_stun_msg_hdr));

+    if (!hdr) {

+	PJ_LOG(5,(THIS_FILE, "Error allocating memory!"));

+	return -1;

+    }

+

+    hdr->type = pj_htons(PJ_STUN_BINDING_REQUEST);

+    hdr->tsx[2] = pj_htonl(id_hi);

+    hdr->tsx[3] = pj_htonl(id_lo);

+    *msg = hdr;

+    *len = sizeof(pj_stun_msg_hdr);

+

+    return 0;

+}

+

+PJ_DEF(pj_status_t) pj_stun_parse_msg( void *buf, pj_size_t len, 

+				       pj_stun_msg *msg)

+{

+    pj_uint16_t msg_type, msg_len;

+    char *p_attr;

+

+    PJ_CHECK_STACK();

+

+    PJ_LOG(5,(THIS_FILE, "pj_stun_parse_msg %p, len=%d", buf, len));

+

+    msg->hdr = (pj_stun_msg_hdr*)buf;

+    msg_type = pj_ntohs(msg->hdr->type);

+

+    switch (msg_type) {

+    case PJ_STUN_BINDING_REQUEST:

+    case PJ_STUN_BINDING_RESPONSE:

+    case PJ_STUN_BINDING_ERROR_RESPONSE:

+    case PJ_STUN_SHARED_SECRET_REQUEST:

+    case PJ_STUN_SHARED_SECRET_RESPONSE:

+    case PJ_STUN_SHARED_SECRET_ERROR_RESPONSE:

+	break;

+    default:

+	PJ_LOG(5,(THIS_FILE, "Error: unknown msg type %d", msg_type));

+	return -1;

+    }

+

+    msg_len = pj_ntohs(msg->hdr->length);

+    if (msg_len != len - sizeof(pj_stun_msg_hdr)) {

+	PJ_LOG(5,(THIS_FILE, "Error: invalid msg_len %d (expecting %d)", 

+			     msg_len, len - sizeof(pj_stun_msg_hdr)));

+	return -1;

+    }

+

+    msg->attr_count = 0;

+    p_attr = (char*)buf + sizeof(pj_stun_msg_hdr);

+

+    while (msg_len > 0) {

+	pj_stun_attr_hdr **attr = &msg->attr[msg->attr_count];

+	pj_uint32_t len;

+

+	*attr = (pj_stun_attr_hdr*)p_attr;

+	len = pj_ntohs((pj_uint16_t) ((*attr)->length)) + sizeof(pj_stun_attr_hdr);

+

+	if (msg_len < len) {

+	    PJ_LOG(5,(THIS_FILE, "Error: length mismatch in attr %d", 

+				 msg->attr_count));

+	    return -1;

+	}

+

+	if (pj_ntohs((*attr)->type) > PJ_STUN_ATTR_REFLECTED_FORM) {

+	    PJ_LOG(5,(THIS_FILE, "Error: invalid attr type %d in attr %d",

+				 pj_ntohs((*attr)->type), msg->attr_count));

+	    return -1;

+	}

+

+	msg_len = (pj_uint16_t)(msg_len - len);

+	p_attr += len;

+	++msg->attr_count;

+    }

+

+    return 0;

+}

+

+PJ_DEF(void*) pj_stun_msg_find_attr( pj_stun_msg *msg, pj_stun_attr_type t)

+{

+    int i;

+

+    PJ_CHECK_STACK();

+

+    for (i=0; i<msg->attr_count; ++i) {

+	pj_stun_attr_hdr *attr = msg->attr[i];

+	if (pj_ntohs(attr->type) == t)

+	    return attr;

+    }

+

+    return 0;

+}

diff --git a/pjlib-util/src/pjlib-util/stun_client.c b/pjlib-util/src/pjlib-util/stun_client.c
index 6bfca13..5718532 100644
--- a/pjlib-util/src/pjlib-util/stun_client.c
+++ b/pjlib-util/src/pjlib-util/stun_client.c
@@ -1,261 +1,282 @@
-/* $Id$
- */
-#include <pjlib-util/stun.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/os.h>
-#include <pj/sock_select.h>
-
-enum { MAX_REQUEST = 3 };
-static int stun_timer[] = {1600, 1600, 1600 };
-
-#define THIS_FILE	"stunclient"
-#define LOG_ADDR(addr)	pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port)
-
-
-PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf,
-					      int sock_cnt, pj_sock_t sock[],
-					      const pj_str_t *srv1, int port1,
-					      const pj_str_t *srv2, int port2,
-					      pj_sockaddr_in mapped_addr[])
-{
-    pj_sockaddr_in srv_addr[2];
-    int i, j, rc, send_cnt = 0;
-    pj_pool_t *pool;
-    struct {
-	struct {
-	    pj_uint32_t	mapped_addr;
-	    pj_uint32_t	mapped_port;
-	} srv[2];
-    } *rec;
-    void       *out_msg;
-    pj_size_t	out_msg_len;
-    int wait_resp = 0;
-    int mapped_status = 0;
-
-    PJ_CHECK_STACK();
-
-    /* Create pool. */
-    pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL);
-    if (!pool) {
-	mapped_status = PJ_STUN_ERR_MEMORY; 
-	return -1;
-    }
-
-    /* Allocate client records */
-    rec = pj_pool_calloc(pool, sock_cnt, sizeof(*rec));
-    if (!rec) {
-	mapped_status = PJ_STUN_ERR_MEMORY; 
-	goto on_error;
-    }
-
-    /* Create the outgoing BIND REQUEST message template */
-    rc = pj_stun_create_bind_req( pool, &out_msg, &out_msg_len, 0, 0);
-    if (rc != 0) {
-	mapped_status = -1;
-	goto on_error;
-    }
-
-    /* Resolve servers. */
-    if (pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1) != 0) {
-	mapped_status = PJ_STUN_ERR_RESOLVE; 
-	goto on_error;
-    }
-    if (pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2) != 0) {
-	mapped_status = PJ_STUN_ERR_RESOLVE;
-	goto on_error;
-    }
-
-    /* Init mapped addresses to zero */
-    pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in));
-
-    /* Main retransmission loop. */
-    for (send_cnt=0; send_cnt<MAX_REQUEST; ++send_cnt) {
-	pj_time_val next_tx, now;
-	pj_fd_set_t r;
-	int select_rc;
-
-	PJ_LOG(4,(THIS_FILE, "STUN retransmit %d, wait_resp=%d", 
-			     send_cnt, wait_resp));
-
-	PJ_FD_ZERO(&r);
-
-	/* Send messages to servers that has not given us response. */
-	for (i=0; i<sock_cnt && mapped_status==0; ++i) {
-	    for (j=0; j<2 && mapped_status==0; ++j) {
-		pj_stun_msg_hdr *msg_hdr = out_msg;
-                pj_ssize_t sent_len;
-
-		if (rec[i].srv[j].mapped_port != 0)
-		    continue;
-
-		/* Modify message so that we can distinguish response. */
-		msg_hdr->tsx[2] = pj_htonl(i);
-		msg_hdr->tsx[3] = pj_htonl(j);
-
-		/* Send! */
-                sent_len = out_msg_len;
-		rc = pj_sock_sendto(sock[i], out_msg, &sent_len, 0,
-				    (pj_sockaddr_t*)&srv_addr[j], 
-				    sizeof(pj_sockaddr_in));
-		if (sent_len != (int)out_msg_len) {
-		    PJ_LOG(4,(THIS_FILE, 
-			      "Error sending STUN request to %s:%d",
-			      LOG_ADDR(srv_addr[j])));
-		    mapped_status = PJ_STUN_ERR_TRANSPORT; 
-		} else {
-		    ++wait_resp;
-		}
-	    }
-	}
-
-	/* All requests sent.
-	 * The loop below will wait for responses until all responses have
-	 * been received (i.e. wait_resp==0) or timeout occurs, which then
-	 * we'll go to the next retransmission iteration.
-	 */
-
-	/* Calculate time of next retransmission. */
-	pj_gettimeofday(&next_tx);
-	next_tx.sec += (stun_timer[send_cnt]/1000);
-	next_tx.msec += (stun_timer[send_cnt]%1000);
-	pj_time_val_normalize(&next_tx);
-
-	for (pj_gettimeofday(&now), select_rc=1; 
-	     mapped_status==0 && select_rc==1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); 
-	     pj_gettimeofday(&now)) 
-	{
-	    pj_time_val timeout;
-
-	    timeout = next_tx;
-	    PJ_TIME_VAL_SUB(timeout, now);
-
-	    for (i=0; i<sock_cnt; ++i) {
-		PJ_FD_SET(sock[i], &r);
-	    }
-
-	    select_rc = pj_sock_select(FD_SETSIZE, &r, NULL, NULL, &timeout);
-	    if (select_rc < 1)
-		continue;
-
-	    for (i=0; i<sock_cnt; ++i) {
-		int sock_idx, srv_idx;
-                pj_ssize_t len;
-		pj_stun_msg msg;
-		pj_sockaddr_in addr;
-		int addrlen = sizeof(addr);
-		pj_stun_mapped_addr_attr *attr;
-		char recv_buf[128];
-
-		if (!PJ_FD_ISSET(sock[i], &r))
-		    continue;
-
-                len = sizeof(recv_buf);
-		pj_sock_recvfrom( sock[i], recv_buf, 
-				  &len, 0,
-				  (pj_sockaddr_t*)&addr,
-				  &addrlen);
-
-		--wait_resp;
-
-		if (len < 1) {
-		    mapped_status = PJ_STUN_ERR_TRANSPORT; 
-		    continue;
-		}
-
-		if (pj_stun_parse_msg(recv_buf, len, &msg) != 0) {
-		    PJ_LOG(4,(THIS_FILE, 
-				"Error parsing STUN response from %s:%d",
-				LOG_ADDR(addr)));
-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
-		    continue;
-		}
-
-		sock_idx = pj_ntohl(msg.hdr->tsx[2]);
-		srv_idx = pj_ntohl(msg.hdr->tsx[3]);
-
-		if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) {
-		    PJ_LOG(4,(THIS_FILE, 
-				"Invalid transaction ID from %s:%d", 
-				LOG_ADDR(addr)));
-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
-		    continue;
-		}
-
-		if (pj_ntohs(msg.hdr->type) != PJ_STUN_BINDING_RESPONSE) {
-		    PJ_LOG(4,(THIS_FILE, 
-				"Non binding response %d from %s:%d", 
-				pj_ntohs(msg.hdr->type), LOG_ADDR(addr)));
-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
-		    continue;
-		}
-
-		if (pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_ERROR_CODE) != NULL) {
-		    PJ_LOG(4,(THIS_FILE, 
-				"Got STUN error attribute from %s:%d",
-				LOG_ADDR(addr)));
-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
-		    continue;
-		}
-
-		attr = (void*)pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_MAPPED_ADDR);
-		if (!attr) {
-		    PJ_LOG(4,(THIS_FILE,
-				"No mapped address in response from %s:%d",
-				LOG_ADDR(addr)));
-		    mapped_status = PJ_STUN_ERR_INVALID_MSG;
-		    continue;
-		}
-
-		rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr;
-		rec[sock_idx].srv[srv_idx].mapped_port = attr->port;
-	    }
-	}
-
-	/* The best scenario is if all requests have been replied.
-	 * Then we don't need to go to the next retransmission iteration.
-	 */
-	if (wait_resp <= 0)
-	    break;
-    }
-
-    for (i=0; i<sock_cnt && mapped_status==0; ++i) {
-	if (rec[i].srv[0].mapped_addr == rec[i].srv[1].mapped_addr &&
-	    rec[i].srv[0].mapped_port == rec[i].srv[1].mapped_port)
-	{
-	    mapped_addr[i].sin_family = PJ_AF_INET;
-	    mapped_addr[i].sin_addr.s_addr = rec[i].srv[0].mapped_addr;
-	    mapped_addr[i].sin_port = (pj_uint16_t)rec[i].srv[0].mapped_port;
-
-	    if (rec[i].srv[0].mapped_addr == 0 || rec[i].srv[0].mapped_port == 0) {
-		mapped_status = PJ_STUN_ERR_NO_RESPONSE;
-	    }
-	} else {
-	    mapped_status = PJ_STUN_ERR_SYMETRIC;
-	}
-    }
-
-    pj_pool_release(pool);
-
-    return mapped_status;
-
-on_error:
-    if (pool) pj_pool_release(pool);
-    return -1;
-}
-
-PJ_DEF(const char*) pj_stun_get_err_msg(pj_status_t status)
-{
-    switch (status) {
-    case 0:			    return "No error";
-    case -1:			    return "General error";
-    case PJ_STUN_ERR_MEMORY:	    return "Memory allocation failed";
-    case PJ_STUN_ERR_RESOLVE:	    return "Invalid IP or unable to resolve STUN server";
-    case PJ_STUN_ERR_TRANSPORT:	    return "Unable to contact STUN server";
-    case PJ_STUN_ERR_INVALID_MSG:   return "Invalid response from STUN server";
-    case PJ_STUN_ERR_NO_RESPONSE:   return "No response from STUN server";
-    case PJ_STUN_ERR_SYMETRIC:	    return "Different mappings are returned from servers";
-    }
-    return "Unknown error";
-}
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjlib-util/stun.h>

+#include <pj/pool.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/os.h>

+#include <pj/sock_select.h>

+

+enum { MAX_REQUEST = 3 };

+static int stun_timer[] = {1600, 1600, 1600 };

+

+#define THIS_FILE	"stunclient"

+#define LOG_ADDR(addr)	pj_inet_ntoa(addr.sin_addr), pj_ntohs(addr.sin_port)

+

+

+PJ_DECL(pj_status_t) pj_stun_get_mapped_addr( pj_pool_factory *pf,

+					      int sock_cnt, pj_sock_t sock[],

+					      const pj_str_t *srv1, int port1,

+					      const pj_str_t *srv2, int port2,

+					      pj_sockaddr_in mapped_addr[])

+{

+    pj_sockaddr_in srv_addr[2];

+    int i, j, rc, send_cnt = 0;

+    pj_pool_t *pool;

+    struct {

+	struct {

+	    pj_uint32_t	mapped_addr;

+	    pj_uint32_t	mapped_port;

+	} srv[2];

+    } *rec;

+    void       *out_msg;

+    pj_size_t	out_msg_len;

+    int wait_resp = 0;

+    int mapped_status = 0;

+

+    PJ_CHECK_STACK();

+

+    /* Create pool. */

+    pool = pj_pool_create(pf, "stun%p", 1024, 1024, NULL);

+    if (!pool) {

+	mapped_status = PJ_STUN_ERR_MEMORY; 

+	return -1;

+    }

+

+    /* Allocate client records */

+    rec = pj_pool_calloc(pool, sock_cnt, sizeof(*rec));

+    if (!rec) {

+	mapped_status = PJ_STUN_ERR_MEMORY; 

+	goto on_error;

+    }

+

+    /* Create the outgoing BIND REQUEST message template */

+    rc = pj_stun_create_bind_req( pool, &out_msg, &out_msg_len, 0, 0);

+    if (rc != 0) {

+	mapped_status = -1;

+	goto on_error;

+    }

+

+    /* Resolve servers. */

+    if (pj_sockaddr_in_init(&srv_addr[0], srv1, (pj_uint16_t)port1) != 0) {

+	mapped_status = PJ_STUN_ERR_RESOLVE; 

+	goto on_error;

+    }

+    if (pj_sockaddr_in_init(&srv_addr[1], srv2, (pj_uint16_t)port2) != 0) {

+	mapped_status = PJ_STUN_ERR_RESOLVE;

+	goto on_error;

+    }

+

+    /* Init mapped addresses to zero */

+    pj_memset(mapped_addr, 0, sock_cnt * sizeof(pj_sockaddr_in));

+

+    /* Main retransmission loop. */

+    for (send_cnt=0; send_cnt<MAX_REQUEST; ++send_cnt) {

+	pj_time_val next_tx, now;

+	pj_fd_set_t r;

+	int select_rc;

+

+	PJ_LOG(4,(THIS_FILE, "STUN retransmit %d, wait_resp=%d", 

+			     send_cnt, wait_resp));

+

+	PJ_FD_ZERO(&r);

+

+	/* Send messages to servers that has not given us response. */

+	for (i=0; i<sock_cnt && mapped_status==0; ++i) {

+	    for (j=0; j<2 && mapped_status==0; ++j) {

+		pj_stun_msg_hdr *msg_hdr = out_msg;

+                pj_ssize_t sent_len;

+

+		if (rec[i].srv[j].mapped_port != 0)

+		    continue;

+

+		/* Modify message so that we can distinguish response. */

+		msg_hdr->tsx[2] = pj_htonl(i);

+		msg_hdr->tsx[3] = pj_htonl(j);

+

+		/* Send! */

+                sent_len = out_msg_len;

+		rc = pj_sock_sendto(sock[i], out_msg, &sent_len, 0,

+				    (pj_sockaddr_t*)&srv_addr[j], 

+				    sizeof(pj_sockaddr_in));

+		if (sent_len != (int)out_msg_len) {

+		    PJ_LOG(4,(THIS_FILE, 

+			      "Error sending STUN request to %s:%d",

+			      LOG_ADDR(srv_addr[j])));

+		    mapped_status = PJ_STUN_ERR_TRANSPORT; 

+		} else {

+		    ++wait_resp;

+		}

+	    }

+	}

+

+	/* All requests sent.

+	 * The loop below will wait for responses until all responses have

+	 * been received (i.e. wait_resp==0) or timeout occurs, which then

+	 * we'll go to the next retransmission iteration.

+	 */

+

+	/* Calculate time of next retransmission. */

+	pj_gettimeofday(&next_tx);

+	next_tx.sec += (stun_timer[send_cnt]/1000);

+	next_tx.msec += (stun_timer[send_cnt]%1000);

+	pj_time_val_normalize(&next_tx);

+

+	for (pj_gettimeofday(&now), select_rc=1; 

+	     mapped_status==0 && select_rc==1 && wait_resp>0 && PJ_TIME_VAL_LT(now, next_tx); 

+	     pj_gettimeofday(&now)) 

+	{

+	    pj_time_val timeout;

+

+	    timeout = next_tx;

+	    PJ_TIME_VAL_SUB(timeout, now);

+

+	    for (i=0; i<sock_cnt; ++i) {

+		PJ_FD_SET(sock[i], &r);

+	    }

+

+	    select_rc = pj_sock_select(FD_SETSIZE, &r, NULL, NULL, &timeout);

+	    if (select_rc < 1)

+		continue;

+

+	    for (i=0; i<sock_cnt; ++i) {

+		int sock_idx, srv_idx;

+                pj_ssize_t len;

+		pj_stun_msg msg;

+		pj_sockaddr_in addr;

+		int addrlen = sizeof(addr);

+		pj_stun_mapped_addr_attr *attr;

+		char recv_buf[128];

+

+		if (!PJ_FD_ISSET(sock[i], &r))

+		    continue;

+

+                len = sizeof(recv_buf);

+		pj_sock_recvfrom( sock[i], recv_buf, 

+				  &len, 0,

+				  (pj_sockaddr_t*)&addr,

+				  &addrlen);

+

+		--wait_resp;

+

+		if (len < 1) {

+		    mapped_status = PJ_STUN_ERR_TRANSPORT; 

+		    continue;

+		}

+

+		if (pj_stun_parse_msg(recv_buf, len, &msg) != 0) {

+		    PJ_LOG(4,(THIS_FILE, 

+				"Error parsing STUN response from %s:%d",

+				LOG_ADDR(addr)));

+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

+		    continue;

+		}

+

+		sock_idx = pj_ntohl(msg.hdr->tsx[2]);

+		srv_idx = pj_ntohl(msg.hdr->tsx[3]);

+

+		if (sock_idx<0 || sock_idx>=sock_cnt || srv_idx<0 || srv_idx>=2) {

+		    PJ_LOG(4,(THIS_FILE, 

+				"Invalid transaction ID from %s:%d", 

+				LOG_ADDR(addr)));

+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

+		    continue;

+		}

+

+		if (pj_ntohs(msg.hdr->type) != PJ_STUN_BINDING_RESPONSE) {

+		    PJ_LOG(4,(THIS_FILE, 

+				"Non binding response %d from %s:%d", 

+				pj_ntohs(msg.hdr->type), LOG_ADDR(addr)));

+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

+		    continue;

+		}

+

+		if (pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_ERROR_CODE) != NULL) {

+		    PJ_LOG(4,(THIS_FILE, 

+				"Got STUN error attribute from %s:%d",

+				LOG_ADDR(addr)));

+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

+		    continue;

+		}

+

+		attr = (void*)pj_stun_msg_find_attr(&msg, PJ_STUN_ATTR_MAPPED_ADDR);

+		if (!attr) {

+		    PJ_LOG(4,(THIS_FILE,

+				"No mapped address in response from %s:%d",

+				LOG_ADDR(addr)));

+		    mapped_status = PJ_STUN_ERR_INVALID_MSG;

+		    continue;

+		}

+

+		rec[sock_idx].srv[srv_idx].mapped_addr = attr->addr;

+		rec[sock_idx].srv[srv_idx].mapped_port = attr->port;

+	    }

+	}

+

+	/* The best scenario is if all requests have been replied.

+	 * Then we don't need to go to the next retransmission iteration.

+	 */

+	if (wait_resp <= 0)

+	    break;

+    }

+

+    for (i=0; i<sock_cnt && mapped_status==0; ++i) {

+	if (rec[i].srv[0].mapped_addr == rec[i].srv[1].mapped_addr &&

+	    rec[i].srv[0].mapped_port == rec[i].srv[1].mapped_port)

+	{

+	    mapped_addr[i].sin_family = PJ_AF_INET;

+	    mapped_addr[i].sin_addr.s_addr = rec[i].srv[0].mapped_addr;

+	    mapped_addr[i].sin_port = (pj_uint16_t)rec[i].srv[0].mapped_port;

+

+	    if (rec[i].srv[0].mapped_addr == 0 || rec[i].srv[0].mapped_port == 0) {

+		mapped_status = PJ_STUN_ERR_NO_RESPONSE;

+	    }

+	} else {

+	    mapped_status = PJ_STUN_ERR_SYMETRIC;

+	}

+    }

+

+    pj_pool_release(pool);

+

+    return mapped_status;

+

+on_error:

+    if (pool) pj_pool_release(pool);

+    return -1;

+}

+

+PJ_DEF(const char*) pj_stun_get_err_msg(pj_status_t status)

+{

+    switch (status) {

+    case 0:			    return "No error";

+    case -1:			    return "General error";

+    case PJ_STUN_ERR_MEMORY:	    return "Memory allocation failed";

+    case PJ_STUN_ERR_RESOLVE:	    return "Invalid IP or unable to resolve STUN server";

+    case PJ_STUN_ERR_TRANSPORT:	    return "Unable to contact STUN server";

+    case PJ_STUN_ERR_INVALID_MSG:   return "Invalid response from STUN server";

+    case PJ_STUN_ERR_NO_RESPONSE:   return "No response from STUN server";

+    case PJ_STUN_ERR_SYMETRIC:	    return "Different mappings are returned from servers";

+    }

+    return "Unknown error";

+}

diff --git a/pjlib-util/src/pjlib-util/symbols.c b/pjlib-util/src/pjlib-util/symbols.c
index adf7219..b25fa0d 100644
--- a/pjlib-util/src/pjlib-util/symbols.c
+++ b/pjlib-util/src/pjlib-util/symbols.c
@@ -1,4 +1,25 @@
 /* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #include <pjlib.h>

 #include <pjlib-util.h>

 

diff --git a/pjlib-util/src/pjlib-util/xml.c b/pjlib-util/src/pjlib-util/xml.c
index 600666d..dd9fb4d 100644
--- a/pjlib-util/src/pjlib-util/xml.c
+++ b/pjlib-util/src/pjlib-util/xml.c
@@ -1,380 +1,401 @@
-/* $Id$
- */
-#include <pjlib-util/xml.h>
-#include <pjlib-util/scanner.h>
-#include <pj/except.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/log.h>
-#include <pj/os.h>
-
-#define EX_SYNTAX_ERROR	12
-#define THIS_FILE	"xml.c"
-
-static void on_syntax_error(struct pj_scanner *scanner)
-{
-    PJ_UNUSED_ARG(scanner);
-    PJ_THROW(EX_SYNTAX_ERROR);
-}
-
-static pj_xml_node *alloc_node( pj_pool_t *pool )
-{
-    pj_xml_node *node;
-
-    node = pj_pool_calloc(pool, 1, sizeof(pj_xml_node));
-    pj_list_init( &node->attr_head );
-    pj_list_init( &node->node_head );
-
-    return node;
-}
-
-static pj_xml_attr *alloc_attr( pj_pool_t *pool )
-{
-    return pj_pool_calloc(pool, 1, sizeof(pj_xml_attr));
-}
-
-/* This is a recursive function! */
-static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner)
-{
-    pj_xml_node *node;
-    pj_str_t end_name;
-
-    PJ_CHECK_STACK();
-
-    if (*scanner->curptr != '<')
-	on_syntax_error(scanner);
-
-    /* Handle Processing Instructino (PI) construct (i.e. "<?") */
-    if (*scanner->curptr == '<' && *(scanner->curptr+1) == '?') {
-	pj_scan_advance_n(scanner, 2, PJ_FALSE);
-	for (;;) {
-	    pj_str_t dummy;
-	    pj_scan_get_until_ch(scanner, '?', &dummy);
-	    if (*scanner->curptr=='?' && *(scanner->curptr+1)=='>') {
-		pj_scan_advance_n(scanner, 2, PJ_TRUE);
-		break;
-	    } else {
-		pj_scan_advance_n(scanner, 1, PJ_FALSE);
-	    }
-	}
-	return xml_parse_node(pool, scanner);
-    }
-
-    /* Handle comments construct (i.e. "<!--") */
-    if (pj_scan_strcmp(scanner, "<!--", 4) == 0) {
-	pj_scan_advance_n(scanner, 4, PJ_FALSE);
-	for (;;) {
-	    pj_str_t dummy;
-	    pj_scan_get_until_ch(scanner, '-', &dummy);
-	    if (pj_scan_strcmp(scanner, "-->", 3) == 0) {
-		pj_scan_advance_n(scanner, 3, PJ_TRUE);
-		break;
-	    } else {
-		pj_scan_advance_n(scanner, 1, PJ_FALSE);
-	    }
-	}
-	return xml_parse_node(pool, scanner);
-    }
-
-    /* Alloc node. */
-    node = alloc_node(pool);
-
-    /* Get '<' */
-    pj_scan_get_char(scanner);
-
-    /* Get node name. */
-    pj_scan_get_until_chr( scanner, " />\t", &node->name);
-
-    /* Get attributes. */
-    while (*scanner->curptr != '>' && *scanner->curptr != '/') {
-	pj_xml_attr *attr = alloc_attr(pool);
-	
-	pj_scan_get_until_chr( scanner, "=> \t", &attr->name);
-	if (*scanner->curptr == '=') {
-	    pj_scan_get_char( scanner );
-	    pj_scan_get_quote(scanner, '"', '"', &attr->value);
-	    /* remove quote characters */
-	    ++attr->value.ptr;
-	    attr->value.slen -= 2;
-	}
-	
-	pj_list_insert_before( &node->attr_head, attr );
-    }
-
-    if (*scanner->curptr == '/') {
-	pj_scan_get_char(scanner);
-	if (pj_scan_get_char(scanner) != '>')
-	    on_syntax_error(scanner);
-	return node;
-    }
-
-    /* Enclosing bracket. */
-    if (pj_scan_get_char(scanner) != '>')
-	on_syntax_error(scanner);
-
-    /* Sub nodes. */
-    while (*scanner->curptr == '<' && *(scanner->curptr+1) != '/') {
-	pj_xml_node *sub_node = xml_parse_node(pool, scanner);
-	pj_list_insert_before( &node->node_head, sub_node );
-    }
-
-    /* Content. */
-    if (!pj_scan_is_eof(scanner) && *scanner->curptr != '<') {
-	pj_scan_get_until_ch(scanner, '<', &node->content);
-    }
-
-    /* Enclosing node. */
-    if (pj_scan_get_char(scanner) != '<' || pj_scan_get_char(scanner) != '/')
-	on_syntax_error(scanner);
-
-    pj_scan_get_until_chr(scanner, " \t>", &end_name);
-
-    /* Compare name. */
-    if (pj_stricmp(&node->name, &end_name) != 0)
-	on_syntax_error(scanner);
-
-    /* Enclosing '>' */
-    if (pj_scan_get_char(scanner) != '>')
-	on_syntax_error(scanner);
-
-    return node;
-}
-
-PJ_DEF(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len)
-{
-    pj_xml_node *node = NULL;
-    pj_scanner scanner;
-    PJ_USE_EXCEPTION;
-
-    if (!msg || !len || !pool)
-	return NULL;
-
-    pj_scan_init( &scanner, msg, len, 
-		  PJ_SCAN_AUTOSKIP_WS|PJ_SCAN_AUTOSKIP_NEWLINE, 
-		  &on_syntax_error);
-    PJ_TRY {
-	node =  xml_parse_node(pool, &scanner);
-    }
-    PJ_DEFAULT {
-	PJ_LOG(4,(THIS_FILE, "Syntax error parsing XML in line %d column %d",
-		  scanner.line, scanner.col));
-    }
-    PJ_END;
-    pj_scan_fini( &scanner );
-    return node;
-}
-
-/* This is a recursive function. */
-static int xml_print_node( const pj_xml_node *node, int indent, 
-			   char *buf, pj_size_t len )
-{
-    int i;
-    char *p = buf;
-    pj_xml_attr *attr;
-    pj_xml_node *sub_node;
-
-#define SIZE_LEFT()	((int)(len - (p-buf)))
-
-    PJ_CHECK_STACK();
-
-    /* Print name. */
-    if (SIZE_LEFT() < node->name.slen + indent + 5)
-	return -1;
-    for (i=0; i<indent; ++i)
-	*p++ = ' ';
-    *p++ = '<';
-    pj_memcpy(p, node->name.ptr, node->name.slen);
-    p += node->name.slen;
-
-    /* Print attributes. */
-    attr = node->attr_head.next;
-    while (attr != &node->attr_head) {
-
-	if (SIZE_LEFT() < attr->name.slen + attr->value.slen + 4)
-	    return -1;
-
-	*p++ = ' ';
-
-	/* Attribute name. */
-	pj_memcpy(p, attr->name.ptr, attr->name.slen);
-	p += attr->name.slen;
-
-	/* Attribute value. */
-	if (attr->value.slen) {
-	    *p++ = '=';
-	    *p++ = '"';
-	    pj_memcpy(p, attr->value.ptr, attr->value.slen);
-	    p += attr->value.slen;
-	    *p++ = '"';
-	}
-
-	attr = attr->next;
-    }
-
-    /* Check for empty node. */
-    if (node->content.slen==0 &&
-	node->node_head.next==(pj_xml_node*)&node->node_head)
-    {
-	*p++ = ' ';
-	*p++ = '/';
-	*p++ = '>';
-	return p-buf;
-    }
-
-    /* Enclosing '>' */
-    if (SIZE_LEFT() < 1) return -1;
-    *p++ = '>';
-
-    /* Print sub nodes. */
-    sub_node = node->node_head.next;
-    while (sub_node != (pj_xml_node*)&node->node_head) {
-	int printed;
-
-	if (SIZE_LEFT() < indent + 3)
-	    return -1;
-	//*p++ = '\r';
-	*p++ = '\n';
-
-	printed = xml_print_node(sub_node, indent + 1, p, SIZE_LEFT());
-	if (printed < 0)
-	    return -1;
-
-	p += printed;
-	sub_node = sub_node->next;
-    }
-
-    /* Content. */
-    if (node->content.slen) {
-	if (SIZE_LEFT() < node->content.slen) return -1;
-	pj_memcpy(p, node->content.ptr, node->content.slen);
-	p += node->content.slen;
-    }
-
-    /* Enclosing node. */
-    if (node->node_head.next != (pj_xml_node*)&node->node_head) {
-	if (SIZE_LEFT() < node->name.slen + 5 + indent)
-	    return -1;
-	//*p++ = '\r';
-	*p++ = '\n';
-	for (i=0; i<indent; ++i)
-	    *p++ = ' ';
-    } else {
-	if (SIZE_LEFT() < node->name.slen + 3)
-	    return -1;
-    }
-    *p++ = '<';
-    *p++ = '/';
-    pj_memcpy(p, node->name.ptr, node->name.slen);
-    p += node->name.slen;
-    *p++ = '>';
-
-#undef SIZE_LEFT
-
-    return p - buf;
-}
-
-PJ_DEF(int) pj_xml_print(const pj_xml_node *node, char *buf, pj_size_t len,
-			 pj_bool_t include_prolog)
-{
-    int prolog_len = 0;
-    int printed;
-
-    if (!node || !buf || !len)
-	return 0;
-
-    if (include_prolog) {
-	pj_str_t prolog = {"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", 39};
-	if ((int)len < prolog.slen)
-	    return -1;
-	pj_memcpy(buf, prolog.ptr, prolog.slen);
-	prolog_len = prolog.slen;
-    }
-
-    printed = xml_print_node(node, 0, buf+prolog_len, len-prolog_len) + prolog_len;
-    if (printed > 0 && len-printed >= 1) {
-	buf[printed++] = '\n';
-    }
-    return printed;
-}
-
-
-PJ_DEF(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node )
-{
-    pj_list_insert_before(&parent->node_head, node);
-}
-
-PJ_DEF(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr )
-{
-    pj_list_insert_before(&node->attr_head, attr);
-}
-
-PJ_DEF(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name)
-{
-    pj_xml_node *node = parent->node_head.next;
-
-    PJ_CHECK_STACK();
-
-    while (node != (void*)&parent->node_head) {
-	if (pj_stricmp(&node->name, name) == 0)
-	    return node;
-	node = node->next;
-    }
-    return NULL;
-}
-
-
-PJ_DEF(pj_xml_node*) pj_xml_find_next_node( pj_xml_node *parent, pj_xml_node *node,
-					    const pj_str_t *name)
-{
-    PJ_CHECK_STACK();
-
-    node = node->next;
-    while (node != (void*)&parent->node_head) {
-	if (pj_stricmp(&node->name, name) == 0)
-	    return node;
-	node = node->next;
-    }
-    return NULL;
-}
-
-
-PJ_DEF(pj_xml_attr*) pj_xml_find_attr( pj_xml_node *node, const pj_str_t *name,
-				       const pj_str_t *value)
-{
-    pj_xml_attr *attr = node->attr_head.next;
-    while (attr != (void*)&node->attr_head) {
-	if (pj_stricmp(&attr->name, name)==0) {
-	    if (value) {
-		if (pj_stricmp(&attr->value, value)==0)
-		    return attr;
-	    } else {
-		return attr;
-	    }
-	}
-	attr = attr->next;
-    }
-    return NULL;
-}
-
-
-
-PJ_DEF(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name,
-				  const void *data, 
-				  pj_bool_t (*match)(pj_xml_node *, const void*))
-{
-    pj_xml_node *head = (void*)&parent->node_head, *node = head->next;
-
-    while (node != (void*)head) {
-	if (name && pj_stricmp(&node->name, name)==0) {
-	    if (match) {
-		if (match(node, data))
-		    return node;
-	    } else {
-		return node;
-	    }
-	}
-	node = node->next;
-    }
-    return NULL;
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjlib-util/xml.h>

+#include <pjlib-util/scanner.h>

+#include <pj/except.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/log.h>

+#include <pj/os.h>

+

+#define EX_SYNTAX_ERROR	12

+#define THIS_FILE	"xml.c"

+

+static void on_syntax_error(struct pj_scanner *scanner)

+{

+    PJ_UNUSED_ARG(scanner);

+    PJ_THROW(EX_SYNTAX_ERROR);

+}

+

+static pj_xml_node *alloc_node( pj_pool_t *pool )

+{

+    pj_xml_node *node;

+

+    node = pj_pool_calloc(pool, 1, sizeof(pj_xml_node));

+    pj_list_init( &node->attr_head );

+    pj_list_init( &node->node_head );

+

+    return node;

+}

+

+static pj_xml_attr *alloc_attr( pj_pool_t *pool )

+{

+    return pj_pool_calloc(pool, 1, sizeof(pj_xml_attr));

+}

+

+/* This is a recursive function! */

+static pj_xml_node *xml_parse_node( pj_pool_t *pool, pj_scanner *scanner)

+{

+    pj_xml_node *node;

+    pj_str_t end_name;

+

+    PJ_CHECK_STACK();

+

+    if (*scanner->curptr != '<')

+	on_syntax_error(scanner);

+

+    /* Handle Processing Instructino (PI) construct (i.e. "<?") */

+    if (*scanner->curptr == '<' && *(scanner->curptr+1) == '?') {

+	pj_scan_advance_n(scanner, 2, PJ_FALSE);

+	for (;;) {

+	    pj_str_t dummy;

+	    pj_scan_get_until_ch(scanner, '?', &dummy);

+	    if (*scanner->curptr=='?' && *(scanner->curptr+1)=='>') {

+		pj_scan_advance_n(scanner, 2, PJ_TRUE);

+		break;

+	    } else {

+		pj_scan_advance_n(scanner, 1, PJ_FALSE);

+	    }

+	}

+	return xml_parse_node(pool, scanner);

+    }

+

+    /* Handle comments construct (i.e. "<!--") */

+    if (pj_scan_strcmp(scanner, "<!--", 4) == 0) {

+	pj_scan_advance_n(scanner, 4, PJ_FALSE);

+	for (;;) {

+	    pj_str_t dummy;

+	    pj_scan_get_until_ch(scanner, '-', &dummy);

+	    if (pj_scan_strcmp(scanner, "-->", 3) == 0) {

+		pj_scan_advance_n(scanner, 3, PJ_TRUE);

+		break;

+	    } else {

+		pj_scan_advance_n(scanner, 1, PJ_FALSE);

+	    }

+	}

+	return xml_parse_node(pool, scanner);

+    }

+

+    /* Alloc node. */

+    node = alloc_node(pool);

+

+    /* Get '<' */

+    pj_scan_get_char(scanner);

+

+    /* Get node name. */

+    pj_scan_get_until_chr( scanner, " />\t", &node->name);

+

+    /* Get attributes. */

+    while (*scanner->curptr != '>' && *scanner->curptr != '/') {

+	pj_xml_attr *attr = alloc_attr(pool);

+	

+	pj_scan_get_until_chr( scanner, "=> \t", &attr->name);

+	if (*scanner->curptr == '=') {

+	    pj_scan_get_char( scanner );

+	    pj_scan_get_quote(scanner, '"', '"', &attr->value);

+	    /* remove quote characters */

+	    ++attr->value.ptr;

+	    attr->value.slen -= 2;

+	}

+	

+	pj_list_insert_before( &node->attr_head, attr );

+    }

+

+    if (*scanner->curptr == '/') {

+	pj_scan_get_char(scanner);

+	if (pj_scan_get_char(scanner) != '>')

+	    on_syntax_error(scanner);

+	return node;

+    }

+

+    /* Enclosing bracket. */

+    if (pj_scan_get_char(scanner) != '>')

+	on_syntax_error(scanner);

+

+    /* Sub nodes. */

+    while (*scanner->curptr == '<' && *(scanner->curptr+1) != '/') {

+	pj_xml_node *sub_node = xml_parse_node(pool, scanner);

+	pj_list_insert_before( &node->node_head, sub_node );

+    }

+

+    /* Content. */

+    if (!pj_scan_is_eof(scanner) && *scanner->curptr != '<') {

+	pj_scan_get_until_ch(scanner, '<', &node->content);

+    }

+

+    /* Enclosing node. */

+    if (pj_scan_get_char(scanner) != '<' || pj_scan_get_char(scanner) != '/')

+	on_syntax_error(scanner);

+

+    pj_scan_get_until_chr(scanner, " \t>", &end_name);

+

+    /* Compare name. */

+    if (pj_stricmp(&node->name, &end_name) != 0)

+	on_syntax_error(scanner);

+

+    /* Enclosing '>' */

+    if (pj_scan_get_char(scanner) != '>')

+	on_syntax_error(scanner);

+

+    return node;

+}

+

+PJ_DEF(pj_xml_node*) pj_xml_parse( pj_pool_t *pool, char *msg, pj_size_t len)

+{

+    pj_xml_node *node = NULL;

+    pj_scanner scanner;

+    PJ_USE_EXCEPTION;

+

+    if (!msg || !len || !pool)

+	return NULL;

+

+    pj_scan_init( &scanner, msg, len, 

+		  PJ_SCAN_AUTOSKIP_WS|PJ_SCAN_AUTOSKIP_NEWLINE, 

+		  &on_syntax_error);

+    PJ_TRY {

+	node =  xml_parse_node(pool, &scanner);

+    }

+    PJ_DEFAULT {

+	PJ_LOG(4,(THIS_FILE, "Syntax error parsing XML in line %d column %d",

+		  scanner.line, scanner.col));

+    }

+    PJ_END;

+    pj_scan_fini( &scanner );

+    return node;

+}

+

+/* This is a recursive function. */

+static int xml_print_node( const pj_xml_node *node, int indent, 

+			   char *buf, pj_size_t len )

+{

+    int i;

+    char *p = buf;

+    pj_xml_attr *attr;

+    pj_xml_node *sub_node;

+

+#define SIZE_LEFT()	((int)(len - (p-buf)))

+

+    PJ_CHECK_STACK();

+

+    /* Print name. */

+    if (SIZE_LEFT() < node->name.slen + indent + 5)

+	return -1;

+    for (i=0; i<indent; ++i)

+	*p++ = ' ';

+    *p++ = '<';

+    pj_memcpy(p, node->name.ptr, node->name.slen);

+    p += node->name.slen;

+

+    /* Print attributes. */

+    attr = node->attr_head.next;

+    while (attr != &node->attr_head) {

+

+	if (SIZE_LEFT() < attr->name.slen + attr->value.slen + 4)

+	    return -1;

+

+	*p++ = ' ';

+

+	/* Attribute name. */

+	pj_memcpy(p, attr->name.ptr, attr->name.slen);

+	p += attr->name.slen;

+

+	/* Attribute value. */

+	if (attr->value.slen) {

+	    *p++ = '=';

+	    *p++ = '"';

+	    pj_memcpy(p, attr->value.ptr, attr->value.slen);

+	    p += attr->value.slen;

+	    *p++ = '"';

+	}

+

+	attr = attr->next;

+    }

+

+    /* Check for empty node. */

+    if (node->content.slen==0 &&

+	node->node_head.next==(pj_xml_node*)&node->node_head)

+    {

+	*p++ = ' ';

+	*p++ = '/';

+	*p++ = '>';

+	return p-buf;

+    }

+

+    /* Enclosing '>' */

+    if (SIZE_LEFT() < 1) return -1;

+    *p++ = '>';

+

+    /* Print sub nodes. */

+    sub_node = node->node_head.next;

+    while (sub_node != (pj_xml_node*)&node->node_head) {

+	int printed;

+

+	if (SIZE_LEFT() < indent + 3)

+	    return -1;

+	//*p++ = '\r';

+	*p++ = '\n';

+

+	printed = xml_print_node(sub_node, indent + 1, p, SIZE_LEFT());

+	if (printed < 0)

+	    return -1;

+

+	p += printed;

+	sub_node = sub_node->next;

+    }

+

+    /* Content. */

+    if (node->content.slen) {

+	if (SIZE_LEFT() < node->content.slen) return -1;

+	pj_memcpy(p, node->content.ptr, node->content.slen);

+	p += node->content.slen;

+    }

+

+    /* Enclosing node. */

+    if (node->node_head.next != (pj_xml_node*)&node->node_head) {

+	if (SIZE_LEFT() < node->name.slen + 5 + indent)

+	    return -1;

+	//*p++ = '\r';

+	*p++ = '\n';

+	for (i=0; i<indent; ++i)

+	    *p++ = ' ';

+    } else {

+	if (SIZE_LEFT() < node->name.slen + 3)

+	    return -1;

+    }

+    *p++ = '<';

+    *p++ = '/';

+    pj_memcpy(p, node->name.ptr, node->name.slen);

+    p += node->name.slen;

+    *p++ = '>';

+

+#undef SIZE_LEFT

+

+    return p - buf;

+}

+

+PJ_DEF(int) pj_xml_print(const pj_xml_node *node, char *buf, pj_size_t len,

+			 pj_bool_t include_prolog)

+{

+    int prolog_len = 0;

+    int printed;

+

+    if (!node || !buf || !len)

+	return 0;

+

+    if (include_prolog) {

+	pj_str_t prolog = {"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", 39};

+	if ((int)len < prolog.slen)

+	    return -1;

+	pj_memcpy(buf, prolog.ptr, prolog.slen);

+	prolog_len = prolog.slen;

+    }

+

+    printed = xml_print_node(node, 0, buf+prolog_len, len-prolog_len) + prolog_len;

+    if (printed > 0 && len-printed >= 1) {

+	buf[printed++] = '\n';

+    }

+    return printed;

+}

+

+

+PJ_DEF(void) pj_xml_add_node( pj_xml_node *parent, pj_xml_node *node )

+{

+    pj_list_insert_before(&parent->node_head, node);

+}

+

+PJ_DEF(void) pj_xml_add_attr( pj_xml_node *node, pj_xml_attr *attr )

+{

+    pj_list_insert_before(&node->attr_head, attr);

+}

+

+PJ_DEF(pj_xml_node*) pj_xml_find_node(pj_xml_node *parent, const pj_str_t *name)

+{

+    pj_xml_node *node = parent->node_head.next;

+

+    PJ_CHECK_STACK();

+

+    while (node != (void*)&parent->node_head) {

+	if (pj_stricmp(&node->name, name) == 0)

+	    return node;

+	node = node->next;

+    }

+    return NULL;

+}

+

+

+PJ_DEF(pj_xml_node*) pj_xml_find_next_node( pj_xml_node *parent, pj_xml_node *node,

+					    const pj_str_t *name)

+{

+    PJ_CHECK_STACK();

+

+    node = node->next;

+    while (node != (void*)&parent->node_head) {

+	if (pj_stricmp(&node->name, name) == 0)

+	    return node;

+	node = node->next;

+    }

+    return NULL;

+}

+

+

+PJ_DEF(pj_xml_attr*) pj_xml_find_attr( pj_xml_node *node, const pj_str_t *name,

+				       const pj_str_t *value)

+{

+    pj_xml_attr *attr = node->attr_head.next;

+    while (attr != (void*)&node->attr_head) {

+	if (pj_stricmp(&attr->name, name)==0) {

+	    if (value) {

+		if (pj_stricmp(&attr->value, value)==0)

+		    return attr;

+	    } else {

+		return attr;

+	    }

+	}

+	attr = attr->next;

+    }

+    return NULL;

+}

+

+

+

+PJ_DEF(pj_xml_node*) pj_xml_find( pj_xml_node *parent, const pj_str_t *name,

+				  const void *data, 

+				  pj_bool_t (*match)(pj_xml_node *, const void*))

+{

+    pj_xml_node *head = (void*)&parent->node_head, *node = head->next;

+

+    while (node != (void*)head) {

+	if (name && pj_stricmp(&node->name, name)==0) {

+	    if (match) {

+		if (match(node, data))

+		    return node;

+	    } else {

+		return node;

+	    }

+	}

+	node = node->next;

+    }

+    return NULL;

+}

+

diff --git a/pjlib/include/pj++/file.hpp b/pjlib/include/pj++/file.hpp
index e45810c..1c35123 100644
--- a/pjlib/include/pj++/file.hpp
+++ b/pjlib/include/pj++/file.hpp
@@ -1,171 +1,192 @@
-/* $Id$ 
- */
-#ifndef __PJPP_FILE_HPP__
-#define __PJPP_FILE_HPP__
-
-#include <pj/file_io.h>
-#include <pj/file_access.h>
-#include <pj++/types.hpp>
-#include <pj++/pool.hpp>
-
-//
-// File API.
-//
-class Pj_File_API
-{
-public:
-    //
-    // Check file existance.
-    //
-    static bool file_exists(const char *filename)
-    {
-        return pj_file_exists(filename) != 0;
-    }
-
-    //
-    // Get file size.
-    //
-    static pj_off_t file_size(const char *filename)
-    {
-        return pj_file_size(filename);
-    }
-
-    //
-    // Delete file.
-    //
-    static pj_status_t file_delete(const char *filename)
-    {
-        return pj_file_delete(filename);
-    }
-
-    //
-    // Move/rename file.
-    //
-    static pj_status_t file_move(const char *oldname, const char *newname)
-    {
-        return pj_file_move(oldname, newname);
-    }
-
-    //
-    // Get stat.
-    //
-    static pj_status_t file_stat(const char *filename, pj_file_stat *buf)
-    {
-        return pj_file_getstat(filename, buf);
-    }
-};
-
-
-//
-// File.
-//
-class Pj_File : public Pj_Object
-{
-public:
-    //
-    // Offset type to be used in setpos.
-    //
-    enum Offset_Type
-    {
-        SEEK_SET = PJ_SEEK_SET,
-        SEEK_CUR = PJ_SEEK_CUR,
-        SEEK_END = PJ_SEEK_END,
-    };
-
-    //
-    // Default constructor.
-    //
-    Pj_File()
-        : hnd_(0)
-    {
-    }
-
-    //
-    // Construct and open a file.
-    //
-    Pj_File(Pj_Pool *pool, const char *filename,
-            unsigned access = PJ_O_RDONLY)
-    : hnd_(NULL)
-    {
-        open(pool, filename, access);
-    }
-
-    //
-    // Destructor closes the file.
-    //
-    ~Pj_File()
-    {
-        close();
-    }
-
-    //
-    // Open a file.
-    //
-    pj_status_t open(Pj_Pool *pool, const char *filename, 
-                     unsigned access = PJ_O_RDONLY )
-    {
-        close();
-        return pj_file_open(pool->pool_(), filename, access, &hnd_);
-    }
-
-    //
-    // Close a file.
-    //
-    void close()
-    {
-        if (hnd_ != 0) {
-            pj_file_close(hnd_);
-            hnd_ = 0;
-        }
-    }
-
-    //
-    // Write data.
-    //
-    pj_ssize_t write(const void *buff, pj_size_t size)
-    {
-        pj_ssize_t bytes = size;
-        if (pj_file_write(hnd_, buff, &bytes) != PJ_SUCCESS)
-            return -1;
-        return bytes;
-    }
-
-    //
-    // Read data.
-    //
-    pj_ssize_t read(void *buf, pj_size_t size)
-    {
-        pj_ssize_t bytes = size;
-        if (pj_file_read(hnd_, buf, &bytes) != PJ_SUCCESS)
-            return -1;
-        return bytes;
-    }
-
-    //
-    // Set file position.
-    //
-    pj_status_t setpos(pj_off_t offset, Offset_Type whence)
-    {
-        return pj_file_setpos(hnd_, offset, 
-                              (enum pj_file_seek_type)whence);
-    }
-
-    //
-    // Get file position.
-    //
-    pj_off_t getpos()
-    {
-        pj_off_t pos;
-        if (pj_file_getpos(hnd_, &pos) != PJ_SUCCESS)
-            return -1;
-        return pos;
-    }
-
-private:
-    pj_oshandle_t hnd_;
-};
-
-
-
-#endif  /* __PJPP_FILE_HPP__ */
-
+/* $Id$ 

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_FILE_HPP__

+#define __PJPP_FILE_HPP__

+

+#include <pj/file_io.h>

+#include <pj/file_access.h>

+#include <pj++/types.hpp>

+#include <pj++/pool.hpp>

+

+//

+// File API.

+//

+class Pj_File_API

+{

+public:

+    //

+    // Check file existance.

+    //

+    static bool file_exists(const char *filename)

+    {

+        return pj_file_exists(filename) != 0;

+    }

+

+    //

+    // Get file size.

+    //

+    static pj_off_t file_size(const char *filename)

+    {

+        return pj_file_size(filename);

+    }

+

+    //

+    // Delete file.

+    //

+    static pj_status_t file_delete(const char *filename)

+    {

+        return pj_file_delete(filename);

+    }

+

+    //

+    // Move/rename file.

+    //

+    static pj_status_t file_move(const char *oldname, const char *newname)

+    {

+        return pj_file_move(oldname, newname);

+    }

+

+    //

+    // Get stat.

+    //

+    static pj_status_t file_stat(const char *filename, pj_file_stat *buf)

+    {

+        return pj_file_getstat(filename, buf);

+    }

+};

+

+

+//

+// File.

+//

+class Pj_File : public Pj_Object

+{

+public:

+    //

+    // Offset type to be used in setpos.

+    //

+    enum Offset_Type

+    {

+        SEEK_SET = PJ_SEEK_SET,

+        SEEK_CUR = PJ_SEEK_CUR,

+        SEEK_END = PJ_SEEK_END,

+    };

+

+    //

+    // Default constructor.

+    //

+    Pj_File()

+        : hnd_(0)

+    {

+    }

+

+    //

+    // Construct and open a file.

+    //

+    Pj_File(Pj_Pool *pool, const char *filename,

+            unsigned access = PJ_O_RDONLY)

+    : hnd_(NULL)

+    {

+        open(pool, filename, access);

+    }

+

+    //

+    // Destructor closes the file.

+    //

+    ~Pj_File()

+    {

+        close();

+    }

+

+    //

+    // Open a file.

+    //

+    pj_status_t open(Pj_Pool *pool, const char *filename, 

+                     unsigned access = PJ_O_RDONLY )

+    {

+        close();

+        return pj_file_open(pool->pool_(), filename, access, &hnd_);

+    }

+

+    //

+    // Close a file.

+    //

+    void close()

+    {

+        if (hnd_ != 0) {

+            pj_file_close(hnd_);

+            hnd_ = 0;

+        }

+    }

+

+    //

+    // Write data.

+    //

+    pj_ssize_t write(const void *buff, pj_size_t size)

+    {

+        pj_ssize_t bytes = size;

+        if (pj_file_write(hnd_, buff, &bytes) != PJ_SUCCESS)

+            return -1;

+        return bytes;

+    }

+

+    //

+    // Read data.

+    //

+    pj_ssize_t read(void *buf, pj_size_t size)

+    {

+        pj_ssize_t bytes = size;

+        if (pj_file_read(hnd_, buf, &bytes) != PJ_SUCCESS)

+            return -1;

+        return bytes;

+    }

+

+    //

+    // Set file position.

+    //

+    pj_status_t setpos(pj_off_t offset, Offset_Type whence)

+    {

+        return pj_file_setpos(hnd_, offset, 

+                              (enum pj_file_seek_type)whence);

+    }

+

+    //

+    // Get file position.

+    //

+    pj_off_t getpos()

+    {

+        pj_off_t pos;

+        if (pj_file_getpos(hnd_, &pos) != PJ_SUCCESS)

+            return -1;

+        return pos;

+    }

+

+private:

+    pj_oshandle_t hnd_;

+};

+

+

+

+#endif  /* __PJPP_FILE_HPP__ */

+

diff --git a/pjlib/include/pj++/hash.hpp b/pjlib/include/pj++/hash.hpp
index 691ac3a..c362625 100644
--- a/pjlib/include/pj++/hash.hpp
+++ b/pjlib/include/pj++/hash.hpp
@@ -1,139 +1,160 @@
-/* $Id$
- */
-#ifndef __PJPP_HASH_HPP__
-#define __PJPP_HASH_HPP__
-
-#include <pj++/types.hpp>
-#include <pj++/pool.hpp>
-#include <pj/hash.h>
-
-//
-// Hash table.
-//
-class Pj_Hash_Table : public Pj_Object
-{
-public:
-    //
-    // Hash table iterator.
-    //
-    class iterator
-    {
-    public:
-	iterator() 
-        {
-        }
-	explicit iterator(pj_hash_table_t *h, pj_hash_iterator_t *i) 
-        : ht_(h), it_(i) 
-        {
-        }
-	iterator(const iterator &rhs) 
-        : ht_(rhs.ht_), it_(rhs.it_) 
-        {
-        }
-	void operator++() 
-        { 
-            it_ = pj_hash_next(ht_, it_); 
-        }
-	bool operator==(const iterator &rhs) 
-        { 
-            return ht_ == rhs.ht_ && it_ == rhs.it_; 
-        }
-	iterator & operator=(const iterator &rhs) 
-        { 
-            ht_=rhs.ht_; it_=rhs.it_; 
-            return *this; 
-        }
-    private:
-	pj_hash_table_t *ht_;
-	pj_hash_iterator_t it_val_;
-	pj_hash_iterator_t *it_;
-
-	friend class Pj_Hash_Table;
-    };
-
-    //
-    // Construct hash table.
-    //
-    Pj_Hash_Table(Pj_Pool *pool, unsigned size)
-    {
-	table_ = pj_hash_create(pool->pool_(), size);
-    }
-
-    //
-    // Destroy hash table.
-    //
-    ~Pj_Hash_Table()
-    {
-    }
-
-    //
-    // Calculate hash value.
-    //
-    static pj_uint32_t calc( pj_uint32_t initial_hval, 
-                             const void *key, 
-                             unsigned keylen = PJ_HASH_KEY_STRING)
-    {
-	return pj_hash_calc(initial_hval, key, keylen);
-    }
-
-    //
-    // Return pjlib compatible hash table object.
-    //
-    pj_hash_table_t *pj_hash_table_t_()
-    {
-	return table_;
-    }
-
-    //
-    // Get the value associated with the specified key.
-    //
-    void *get(const void *key, unsigned keylen = PJ_HASH_KEY_STRING)
-    {
-	return pj_hash_get(table_, key, keylen);
-    }
-
-    //
-    // Associate a value with a key.
-    // Set the value to NULL to delete the key from the hash table.
-    //
-    void set(Pj_Pool *pool, 
-             const void *key, 
-             void *value,
-             unsigned keylen = PJ_HASH_KEY_STRING)
-    {
-	pj_hash_set(pool->pool_(), table_, key, keylen, value);
-    }
-
-    //
-    // Get number of items in the hash table.
-    //
-    unsigned count()
-    {
-	return pj_hash_count(table_);
-    }
-
-    //
-    // Iterate hash table.
-    //
-    iterator begin()
-    {
-	iterator it(table_, NULL);
-	it.it_ = pj_hash_first(table_, &it.it_val_);
-	return it;
-    }
-
-    //
-    // End of items.
-    //
-    iterator end()
-    {
-	return iterator(table_, NULL);
-    }
-
-private:
-    pj_hash_table_t *table_;
-};
-
-
-#endif	/* __PJPP_HASH_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_HASH_HPP__

+#define __PJPP_HASH_HPP__

+

+#include <pj++/types.hpp>

+#include <pj++/pool.hpp>

+#include <pj/hash.h>

+

+//

+// Hash table.

+//

+class Pj_Hash_Table : public Pj_Object

+{

+public:

+    //

+    // Hash table iterator.

+    //

+    class iterator

+    {

+    public:

+	iterator() 

+        {

+        }

+	explicit iterator(pj_hash_table_t *h, pj_hash_iterator_t *i) 

+        : ht_(h), it_(i) 

+        {

+        }

+	iterator(const iterator &rhs) 

+        : ht_(rhs.ht_), it_(rhs.it_) 

+        {

+        }

+	void operator++() 

+        { 

+            it_ = pj_hash_next(ht_, it_); 

+        }

+	bool operator==(const iterator &rhs) 

+        { 

+            return ht_ == rhs.ht_ && it_ == rhs.it_; 

+        }

+	iterator & operator=(const iterator &rhs) 

+        { 

+            ht_=rhs.ht_; it_=rhs.it_; 

+            return *this; 

+        }

+    private:

+	pj_hash_table_t *ht_;

+	pj_hash_iterator_t it_val_;

+	pj_hash_iterator_t *it_;

+

+	friend class Pj_Hash_Table;

+    };

+

+    //

+    // Construct hash table.

+    //

+    Pj_Hash_Table(Pj_Pool *pool, unsigned size)

+    {

+	table_ = pj_hash_create(pool->pool_(), size);

+    }

+

+    //

+    // Destroy hash table.

+    //

+    ~Pj_Hash_Table()

+    {

+    }

+

+    //

+    // Calculate hash value.

+    //

+    static pj_uint32_t calc( pj_uint32_t initial_hval, 

+                             const void *key, 

+                             unsigned keylen = PJ_HASH_KEY_STRING)

+    {

+	return pj_hash_calc(initial_hval, key, keylen);

+    }

+

+    //

+    // Return pjlib compatible hash table object.

+    //

+    pj_hash_table_t *pj_hash_table_t_()

+    {

+	return table_;

+    }

+

+    //

+    // Get the value associated with the specified key.

+    //

+    void *get(const void *key, unsigned keylen = PJ_HASH_KEY_STRING)

+    {

+	return pj_hash_get(table_, key, keylen);

+    }

+

+    //

+    // Associate a value with a key.

+    // Set the value to NULL to delete the key from the hash table.

+    //

+    void set(Pj_Pool *pool, 

+             const void *key, 

+             void *value,

+             unsigned keylen = PJ_HASH_KEY_STRING)

+    {

+	pj_hash_set(pool->pool_(), table_, key, keylen, value);

+    }

+

+    //

+    // Get number of items in the hash table.

+    //

+    unsigned count()

+    {

+	return pj_hash_count(table_);

+    }

+

+    //

+    // Iterate hash table.

+    //

+    iterator begin()

+    {

+	iterator it(table_, NULL);

+	it.it_ = pj_hash_first(table_, &it.it_val_);

+	return it;

+    }

+

+    //

+    // End of items.

+    //

+    iterator end()

+    {

+	return iterator(table_, NULL);

+    }

+

+private:

+    pj_hash_table_t *table_;

+};

+

+

+#endif	/* __PJPP_HASH_HPP__ */

+

diff --git a/pjlib/include/pj++/list.hpp b/pjlib/include/pj++/list.hpp
index c3a8f38..363c1fa 100644
--- a/pjlib/include/pj++/list.hpp
+++ b/pjlib/include/pj++/list.hpp
@@ -1,311 +1,332 @@
-/* $Id$
- */
-#ifndef __PJPP_LIST_HPP__
-#define __PJPP_LIST_HPP__
-
-#include <pj/list.h>
-#include <pj++/pool.hpp>
-
-
-//
-// Linked-list.
-//
-// Note:
-//  List_Node must have public member next and prev. Normally
-//  it will be declared like:
-//
-//  struct my_node
-//  {
-//      PJ_DECL_LIST_MEMBER(struct my_node);
-//      ..
-//  };
-//
-//
-template <class List_Node>
-class Pj_List : public Pj_Object
-{
-public:
-    //
-    // List const_iterator.
-    //
-    class const_iterator
-    {
-    public:
-	const_iterator() 
-            : node_(NULL) 
-        {}
-	const_iterator(const List_Node *nd) 
-            : node_((List_Node*)nd) 
-        {}
-	const List_Node * operator *() 
-        { 
-            return node_; 
-        }
-	const List_Node * operator -> () 
-        { 
-            return node_; 
-        }
-	const_iterator operator++() 
-        { 
-            return const_iterator(node_->next); 
-        }
-	bool operator==(const const_iterator &rhs) 
-        { 
-            return node_ == rhs.node_; 
-        }
-	bool operator!=(const const_iterator &rhs) 
-        { 
-            return node_ != rhs.node_; 
-        }
-
-    protected:
-	List_Node *node_;
-    };
-
-    //
-    // List iterator.
-    //
-    class iterator : public const_iterator
-    {
-    public:
-	iterator() 
-        {}
-	iterator(List_Node *nd) 
-            : const_iterator(nd) 
-        {}
-	List_Node * operator *() 
-        { 
-            return node_; 
-        }
-	List_Node * operator -> () 
-        { 
-            return node_; 
-        }
-	iterator operator++() 
-        { 
-            return iterator(node_->next); 
-        }
-	bool operator==(const iterator &rhs) 
-        { 
-            return node_ == rhs.node_; 
-        }
-	bool operator!=(const iterator &rhs) 
-        { 
-            return node_ != rhs.node_; 
-        }
-    };
-
-    //
-    // Default constructor.
-    //
-    Pj_List() 
-    { 
-        pj_list_init(&root_); 
-        if (0) compiletest(); 
-    }
-
-    //
-    // Check if list is empty.
-    // 
-    bool empty() const
-    {
-	return pj_list_empty(&root_);
-    }
-
-    //
-    // Get first element.
-    //
-    iterator begin()
-    {
-	return iterator(root_.next);
-    }
-
-    //
-    // Get first element.
-    //
-    const_iterator begin() const
-    {
-	return const_iterator(root_.next);
-    }
-
-    //
-    // Get end-of-element
-    //
-    const_iterator end() const
-    {
-	return const_iterator((List_Node*)&root_);
-    }
-
-    //
-    // Get end-of-element
-    //
-    iterator end()
-    {
-	return iterator((List_Node*)&root_);
-    }
-
-    //
-    // Insert node.
-    //
-    void insert_before (iterator &pos, List_Node *node)
-    {
-	pj_list_insert_before( *pos, node );
-    }
-
-    //
-    // Insert node.
-    //
-    void insert_after(iterator &pos, List_Node *node)
-    {
-	pj_list_insert_after(*pos, node);
-    }
-
-    //
-    // Merge list.
-    //
-    void merge_first(List_Node *list2)
-    {
-	pj_list_merge_first(&root_, list2);
-    }
-
-    //
-    // Merge list.
-    //
-    void merge_last(Pj_List *list)
-    {
-	pj_list_merge_last(&root_, &list->root_);
-    }
-
-    //
-    // Insert list.
-    //
-    void insert_nodes_before(iterator &pos, Pj_List *list2)
-    {
-	pj_list_insert_nodes_before(*pos, &list2->root_);
-    }
-
-    //
-    // Insert list.
-    //
-    void insert_nodes_after(iterator &pos, Pj_List *list2)
-    {
-	pj_list_insert_nodes_after(*pos, &list2->root_);
-    }
-
-    //
-    // Erase an element.
-    //
-    void erase(iterator &it)
-    {
-	pj_list_erase(*it);
-    }
-
-    //
-    // Get first element.
-    //
-    List_Node *front()
-    {
-	return root_.next;
-    }
-
-    //
-    // Get first element.
-    //
-    const List_Node *front() const
-    {
-	return root_.next;
-    }
-
-    //
-    // Remove first element.
-    //
-    void pop_front()
-    {
-	pj_list_erase(root_.next);
-    }
-
-    //
-    // Get last element.
-    //
-    List_Node *back()
-    {
-	return root_.prev;
-    }
-
-    //
-    // Get last element.
-    //
-    const List_Node *back() const
-    {
-	return root_.prev;
-    }
-
-    //
-    // Remove last element.
-    //
-    void pop_back()
-    {
-	pj_list_erase(root_.prev);
-    }
-
-    //
-    // Find a node.
-    //
-    iterator find(List_Node *node)
-    {
-	List_Node *n = pj_list_find_node(&root_, node);
-	return n ? iterator(n) : end();
-    }
-
-    //
-    // Find a node.
-    //
-    const_iterator find(List_Node *node) const
-    {
-	List_Node *n = pj_list_find_node(&root_, node);
-	return n ? const_iterator(n) : end();
-    }
-
-    //
-    // Insert a node in the back.
-    //
-    void push_back(List_Node *node)
-    {
-	pj_list_insert_after(root_.prev, node);
-    }
-
-    //
-    // Insert a node in the front.
-    //
-    void push_front(List_Node *node)
-    {
-	pj_list_insert_before(root_.next, node);
-    }
-
-    //
-    // Remove all elements.
-    //
-    void clear()
-    {
-	root_.next = &root_;
-	root_.prev = &root_;
-    }
-
-private:
-    struct RootNode
-    {
-	PJ_DECL_LIST_MEMBER(List_Node);
-    } root_;
-
-    void compiletest()
-    {
-	// If you see error in this line, 
-	// it's because List_Node is not derived from Pj_List_Node.
-	List_Node *n = (List_Node*)0;
-	n = n->next; n = n->prev;
-    }
-};
-
-
-#endif	/* __PJPP_LIST_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_LIST_HPP__

+#define __PJPP_LIST_HPP__

+

+#include <pj/list.h>

+#include <pj++/pool.hpp>

+

+

+//

+// Linked-list.

+//

+// Note:

+//  List_Node must have public member next and prev. Normally

+//  it will be declared like:

+//

+//  struct my_node

+//  {

+//      PJ_DECL_LIST_MEMBER(struct my_node);

+//      ..

+//  };

+//

+//

+template <class List_Node>

+class Pj_List : public Pj_Object

+{

+public:

+    //

+    // List const_iterator.

+    //

+    class const_iterator

+    {

+    public:

+	const_iterator() 

+            : node_(NULL) 

+        {}

+	const_iterator(const List_Node *nd) 

+            : node_((List_Node*)nd) 

+        {}

+	const List_Node * operator *() 

+        { 

+            return node_; 

+        }

+	const List_Node * operator -> () 

+        { 

+            return node_; 

+        }

+	const_iterator operator++() 

+        { 

+            return const_iterator(node_->next); 

+        }

+	bool operator==(const const_iterator &rhs) 

+        { 

+            return node_ == rhs.node_; 

+        }

+	bool operator!=(const const_iterator &rhs) 

+        { 

+            return node_ != rhs.node_; 

+        }

+

+    protected:

+	List_Node *node_;

+    };

+

+    //

+    // List iterator.

+    //

+    class iterator : public const_iterator

+    {

+    public:

+	iterator() 

+        {}

+	iterator(List_Node *nd) 

+            : const_iterator(nd) 

+        {}

+	List_Node * operator *() 

+        { 

+            return node_; 

+        }

+	List_Node * operator -> () 

+        { 

+            return node_; 

+        }

+	iterator operator++() 

+        { 

+            return iterator(node_->next); 

+        }

+	bool operator==(const iterator &rhs) 

+        { 

+            return node_ == rhs.node_; 

+        }

+	bool operator!=(const iterator &rhs) 

+        { 

+            return node_ != rhs.node_; 

+        }

+    };

+

+    //

+    // Default constructor.

+    //

+    Pj_List() 

+    { 

+        pj_list_init(&root_); 

+        if (0) compiletest(); 

+    }

+

+    //

+    // Check if list is empty.

+    // 

+    bool empty() const

+    {

+	return pj_list_empty(&root_);

+    }

+

+    //

+    // Get first element.

+    //

+    iterator begin()

+    {

+	return iterator(root_.next);

+    }

+

+    //

+    // Get first element.

+    //

+    const_iterator begin() const

+    {

+	return const_iterator(root_.next);

+    }

+

+    //

+    // Get end-of-element

+    //

+    const_iterator end() const

+    {

+	return const_iterator((List_Node*)&root_);

+    }

+

+    //

+    // Get end-of-element

+    //

+    iterator end()

+    {

+	return iterator((List_Node*)&root_);

+    }

+

+    //

+    // Insert node.

+    //

+    void insert_before (iterator &pos, List_Node *node)

+    {

+	pj_list_insert_before( *pos, node );

+    }

+

+    //

+    // Insert node.

+    //

+    void insert_after(iterator &pos, List_Node *node)

+    {

+	pj_list_insert_after(*pos, node);

+    }

+

+    //

+    // Merge list.

+    //

+    void merge_first(List_Node *list2)

+    {

+	pj_list_merge_first(&root_, list2);

+    }

+

+    //

+    // Merge list.

+    //

+    void merge_last(Pj_List *list)

+    {

+	pj_list_merge_last(&root_, &list->root_);

+    }

+

+    //

+    // Insert list.

+    //

+    void insert_nodes_before(iterator &pos, Pj_List *list2)

+    {

+	pj_list_insert_nodes_before(*pos, &list2->root_);

+    }

+

+    //

+    // Insert list.

+    //

+    void insert_nodes_after(iterator &pos, Pj_List *list2)

+    {

+	pj_list_insert_nodes_after(*pos, &list2->root_);

+    }

+

+    //

+    // Erase an element.

+    //

+    void erase(iterator &it)

+    {

+	pj_list_erase(*it);

+    }

+

+    //

+    // Get first element.

+    //

+    List_Node *front()

+    {

+	return root_.next;

+    }

+

+    //

+    // Get first element.

+    //

+    const List_Node *front() const

+    {

+	return root_.next;

+    }

+

+    //

+    // Remove first element.

+    //

+    void pop_front()

+    {

+	pj_list_erase(root_.next);

+    }

+

+    //

+    // Get last element.

+    //

+    List_Node *back()

+    {

+	return root_.prev;

+    }

+

+    //

+    // Get last element.

+    //

+    const List_Node *back() const

+    {

+	return root_.prev;

+    }

+

+    //

+    // Remove last element.

+    //

+    void pop_back()

+    {

+	pj_list_erase(root_.prev);

+    }

+

+    //

+    // Find a node.

+    //

+    iterator find(List_Node *node)

+    {

+	List_Node *n = pj_list_find_node(&root_, node);

+	return n ? iterator(n) : end();

+    }

+

+    //

+    // Find a node.

+    //

+    const_iterator find(List_Node *node) const

+    {

+	List_Node *n = pj_list_find_node(&root_, node);

+	return n ? const_iterator(n) : end();

+    }

+

+    //

+    // Insert a node in the back.

+    //

+    void push_back(List_Node *node)

+    {

+	pj_list_insert_after(root_.prev, node);

+    }

+

+    //

+    // Insert a node in the front.

+    //

+    void push_front(List_Node *node)

+    {

+	pj_list_insert_before(root_.next, node);

+    }

+

+    //

+    // Remove all elements.

+    //

+    void clear()

+    {

+	root_.next = &root_;

+	root_.prev = &root_;

+    }

+

+private:

+    struct RootNode

+    {

+	PJ_DECL_LIST_MEMBER(List_Node);

+    } root_;

+

+    void compiletest()

+    {

+	// If you see error in this line, 

+	// it's because List_Node is not derived from Pj_List_Node.

+	List_Node *n = (List_Node*)0;

+	n = n->next; n = n->prev;

+    }

+};

+

+

+#endif	/* __PJPP_LIST_HPP__ */

+

diff --git a/pjlib/include/pj++/lock.hpp b/pjlib/include/pj++/lock.hpp
index 95ea63b..cf5a57d 100644
--- a/pjlib/include/pj++/lock.hpp
+++ b/pjlib/include/pj++/lock.hpp
@@ -1,132 +1,153 @@
-/* $Id$ 
- */
-#ifndef __PJPP_LOCK_HPP__
-#define __PJPP_LOCK_HPP__
-
-#include <pj++/types.hpp>
-#include <pj/lock.h>
-#include <pj++/pool.hpp>
-
-//////////////////////////////////////////////////////////////////////////////
-// Lock object.
-//
-class Pj_Lock : public Pj_Object
-{
-public:
-    //
-    // Constructor.
-    //
-    explicit Pj_Lock(pj_lock_t *lock)
-        : lock_(lock)
-    {
-    }
-
-    //
-    // Destructor.
-    //
-    ~Pj_Lock()
-    {
-        if (lock_)
-            pj_lock_destroy(lock_);
-    }
-
-    //
-    // Get pjlib compatible lock object.
-    //
-    pj_lock_t *pj_lock_t_()
-    {
-        return lock_;
-    }
-
-    //
-    // acquire lock.
-    //
-    pj_status_t acquire()
-    {
-        return pj_lock_acquire(lock_);
-    }
-
-    //
-    // release lock,.
-    //
-    pj_status_t release()
-    {
-        return pj_lock_release(lock_);
-    }
-
-protected:
-    pj_lock_t *lock_;
-};
-
-
-//////////////////////////////////////////////////////////////////////////////
-// Null lock object.
-//
-class Pj_Null_Lock : public Pj_Lock
-{
-public:
-    //
-    // Default constructor.
-    //
-    explicit Pj_Null_Lock(Pj_Pool *pool, const char *name = NULL)
-        : Pj_Lock(NULL)
-    {
-        pj_lock_create_null_mutex(pool->pool_(), name, &lock_);
-    }
-};
-
-//////////////////////////////////////////////////////////////////////////////
-// Simple mutex lock object.
-//
-class Pj_Simple_Mutex_Lock : public Pj_Lock
-{
-public:
-    //
-    // Default constructor.
-    //
-    explicit Pj_Simple_Mutex_Lock(Pj_Pool *pool, const char *name = NULL)
-        : Pj_Lock(NULL)
-    {
-        pj_lock_create_simple_mutex(pool->pool_(), name, &lock_);
-    }
-};
-
-//////////////////////////////////////////////////////////////////////////////
-// Recursive mutex lock object.
-//
-class Pj_Recursive_Mutex_Lock : public Pj_Lock
-{
-public:
-    //
-    // Default constructor.
-    //
-    explicit Pj_Recursive_Mutex_Lock(Pj_Pool *pool, const char *name = NULL)
-        : Pj_Lock(NULL)
-    {
-        pj_lock_create_recursive_mutex(pool->pool_(), name, &lock_);
-    }
-};
-
-//////////////////////////////////////////////////////////////////////////////
-// Semaphore lock object.
-//
-class Pj_Semaphore_Lock : public Pj_Lock
-{
-public:
-    //
-    // Default constructor.
-    //
-    explicit Pj_Semaphore_Lock(Pj_Pool *pool, 
-                               unsigned max=PJ_MAXINT32,
-                               unsigned initial=0,
-                               const char *name=NULL)
-        : Pj_Lock(NULL)
-    {
-        pj_lock_create_semaphore(pool->pool_(), name, initial, max, &lock_);
-    }
-};
-
-
-
-#endif	/* __PJPP_LOCK_HPP__ */
-
+/* $Id$ 

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_LOCK_HPP__

+#define __PJPP_LOCK_HPP__

+

+#include <pj++/types.hpp>

+#include <pj/lock.h>

+#include <pj++/pool.hpp>

+

+//////////////////////////////////////////////////////////////////////////////

+// Lock object.

+//

+class Pj_Lock : public Pj_Object

+{

+public:

+    //

+    // Constructor.

+    //

+    explicit Pj_Lock(pj_lock_t *lock)

+        : lock_(lock)

+    {

+    }

+

+    //

+    // Destructor.

+    //

+    ~Pj_Lock()

+    {

+        if (lock_)

+            pj_lock_destroy(lock_);

+    }

+

+    //

+    // Get pjlib compatible lock object.

+    //

+    pj_lock_t *pj_lock_t_()

+    {

+        return lock_;

+    }

+

+    //

+    // acquire lock.

+    //

+    pj_status_t acquire()

+    {

+        return pj_lock_acquire(lock_);

+    }

+

+    //

+    // release lock,.

+    //

+    pj_status_t release()

+    {

+        return pj_lock_release(lock_);

+    }

+

+protected:

+    pj_lock_t *lock_;

+};

+

+

+//////////////////////////////////////////////////////////////////////////////

+// Null lock object.

+//

+class Pj_Null_Lock : public Pj_Lock

+{

+public:

+    //

+    // Default constructor.

+    //

+    explicit Pj_Null_Lock(Pj_Pool *pool, const char *name = NULL)

+        : Pj_Lock(NULL)

+    {

+        pj_lock_create_null_mutex(pool->pool_(), name, &lock_);

+    }

+};

+

+//////////////////////////////////////////////////////////////////////////////

+// Simple mutex lock object.

+//

+class Pj_Simple_Mutex_Lock : public Pj_Lock

+{

+public:

+    //

+    // Default constructor.

+    //

+    explicit Pj_Simple_Mutex_Lock(Pj_Pool *pool, const char *name = NULL)

+        : Pj_Lock(NULL)

+    {

+        pj_lock_create_simple_mutex(pool->pool_(), name, &lock_);

+    }

+};

+

+//////////////////////////////////////////////////////////////////////////////

+// Recursive mutex lock object.

+//

+class Pj_Recursive_Mutex_Lock : public Pj_Lock

+{

+public:

+    //

+    // Default constructor.

+    //

+    explicit Pj_Recursive_Mutex_Lock(Pj_Pool *pool, const char *name = NULL)

+        : Pj_Lock(NULL)

+    {

+        pj_lock_create_recursive_mutex(pool->pool_(), name, &lock_);

+    }

+};

+

+//////////////////////////////////////////////////////////////////////////////

+// Semaphore lock object.

+//

+class Pj_Semaphore_Lock : public Pj_Lock

+{

+public:

+    //

+    // Default constructor.

+    //

+    explicit Pj_Semaphore_Lock(Pj_Pool *pool, 

+                               unsigned max=PJ_MAXINT32,

+                               unsigned initial=0,

+                               const char *name=NULL)

+        : Pj_Lock(NULL)

+    {

+        pj_lock_create_semaphore(pool->pool_(), name, initial, max, &lock_);

+    }

+};

+

+

+

+#endif	/* __PJPP_LOCK_HPP__ */

+

diff --git a/pjlib/include/pj++/os.hpp b/pjlib/include/pj++/os.hpp
index 461a36e..65553b0 100644
--- a/pjlib/include/pj++/os.hpp
+++ b/pjlib/include/pj++/os.hpp
@@ -1,788 +1,809 @@
-/* $Id$
- */
-#ifndef __PJPP_OS_HPP__
-#define __PJPP_OS_HPP__
-
-#include <pj/os.h>
-#include <pj++/types.hpp>
-#include <pj++/pool.hpp>
-
-class Pj_Thread;
-
-//
-// Thread API.
-//
-class Pj_Thread_API
-{
-public:
-    //
-    // Create a thread.
-    //
-    static pj_status_t create( Pj_Pool *pool, pj_thread_t **thread,
-                               pj_thread_proc *proc, void *arg,
-                               unsigned flags = 0,
-                               const char *name = NULL,
-                               pj_size_t stack_size = 0 )
-    {
-        return pj_thread_create(pool->pool_(), name, proc, arg, stack_size,
-                                flags, thread);
-    }
-
-    //
-    // Register a thread.
-    //
-    static pj_status_t register_this_thread( pj_thread_desc desc,
-                                             pj_thread_t **thread,
-                                             const char *name = NULL )
-    {
-        return pj_thread_register( name, desc, thread );
-    }
-
-    //
-    // Get current thread.
-    // Will return pj_thread_t (sorry folks, not Pj_Thread).
-    //
-    static pj_thread_t *this_thread()
-    {
-        return pj_thread_this();
-    }
-
-    //
-    // Get thread name.
-    //
-    static const char *get_name(pj_thread_t *thread)
-    {
-        return pj_thread_get_name(thread);
-    }
-
-    //
-    // Resume thread.
-    //
-    static pj_status_t resume(pj_thread_t *thread)
-    {
-        return pj_thread_resume(thread);
-    }
-
-    //
-    // Sleep.
-    //
-    static pj_status_t sleep(unsigned msec)
-    {
-	return pj_thread_sleep(msec);
-    }
-
-    //
-    // Join the specified thread.
-    //
-    static pj_status_t join(pj_thread_t *thread)
-    {
-        return pj_thread_join(thread);
-    }
-
-    //
-    // Destroy thread
-    //
-    static pj_status_t destroy(pj_thread_t *thread)
-    {
-        return pj_thread_destroy(thread);
-    }
-};
-
-
-
-//
-// Thread object.
-//
-// How to use:
-//  Derive a class from this class, then override main().
-//
-class Pj_Thread : public Pj_Object
-{
-public:
-    enum Flags
-    {
-	FLAG_SUSPENDED = PJ_THREAD_SUSPENDED
-    };
-
-    //
-    // Default constructor.
-    //
-    Pj_Thread()
-        : thread_(NULL)
-    {
-    }
-
-    //
-    // Destroy thread.
-    //
-    ~Pj_Thread()
-    {
-        destroy();
-    }
-
-    //
-    // This is the main thread function.
-    //
-    virtual int main() = 0;
-
-    //
-    // Start a thread.
-    //
-    pj_status_t create( Pj_Pool *pool, 
-                        unsigned flags = 0,
-                        const char *thread_name = NULL,
-			pj_size_t stack_size = PJ_THREAD_DEFAULT_STACK_SIZE)
-    {
-        destroy();
-        return Pj_Thread_API::create( pool, &thread_, &thread_proc, this,
-                                      flags, thread_name);
-    }
-
-    //
-    // Get pjlib compatible thread object.
-    //
-    pj_thread_t *pj_thread_t_()
-    {
-	return thread_;
-    }
-
-    //
-    // Get thread name.
-    //
-    const char *get_name()
-    {
-        return Pj_Thread_API::get_name(thread_);
-    }
-
-    //
-    // Resume a suspended thread.
-    //
-    pj_status_t resume()
-    {
-        return Pj_Thread_API::resume(thread_);
-    }
-
-    //
-    // Join this thread.
-    //
-    pj_status_t join()
-    {
-        return Pj_Thread_API::join(thread_);
-    }
-
-    //
-    // Destroy thread.
-    //
-    pj_status_t destroy()
-    {
-        if (thread_) {
-            Pj_Thread_API::destroy(thread_);
-            thread_ = NULL;
-        }
-    }
-
-protected:
-    pj_thread_t *thread_;
-
-    static int PJ_THREAD_FUNC thread_proc(void *obj)
-    {
-        Pj_Thread *thread_class = (Pj_Thread*)obj;
-        return thread_class->main();
-    }
-};
-
-
-//
-// External Thread
-//  (threads that were started by external means, i.e. not 
-//   with Pj_Thread::create).
-//
-// This class will normally be defined as local variable in
-// external thread's stack, normally inside thread's main proc.
-// But be aware that the handle will be destroyed on destructor!
-//
-class Pj_External_Thread : public Pj_Thread
-{
-public:
-    Pj_External_Thread()
-    {
-    }
-
-    //
-    // Register external thread so that pjlib functions can work
-    // in that thread.
-    //
-    pj_status_t register_this_thread( const char *name=NULL )
-    {
-        return Pj_Thread_API::register_this_thread(desc_, &thread_,name);
-    }
-
-private:
-    pj_thread_desc desc_;
-};
-
-
-//
-// Thread specific data/thread local storage/TLS.
-//
-class Pj_Thread_Local_API
-{
-public:
-    //
-    // Allocate thread local storage (TLS) index.
-    //
-    static pj_status_t alloc(long *index)
-    {
-        return pj_thread_local_alloc(index);
-    }
-
-    //
-    // Free TLS index.
-    //
-    static void free(long index)
-    {
-        pj_thread_local_free(index);
-    }
-
-    //
-    // Set thread specific data.
-    //
-    static pj_status_t set(long index, void *value)
-    {
-        return pj_thread_local_set(index, value);
-    }
-
-    //
-    // Get thread specific data.
-    //
-    static void *get(long index)
-    {
-        return pj_thread_local_get(index);
-    }
-
-};
-
-//
-// Atomic variable
-//
-// How to use:
-//   Pj_Atomic_Var var(pool, 0);
-//   var.set(..);
-//
-class Pj_Atomic_Var : public Pj_Object
-{
-public:
-    //
-    // Default constructor, initialize variable with NULL.
-    //
-    Pj_Atomic_Var()
-        : var_(NULL)
-    {
-    }
-
-    //
-    // Construct atomic variable.
-    //
-    Pj_Atomic_Var(Pj_Pool *pool, pj_atomic_value_t value)
-        : var_(NULL)
-    {
-        create(pool, value);
-    }
-
-    //
-    // Destructor.
-    //
-    ~Pj_Atomic_Var()
-    {
-        destroy();
-    }
-
-    //
-    // Create atomic variable.
-    //
-    pj_status_t create( Pj_Pool *pool, pj_atomic_value_t value)
-    {
-        destroy();
-	return pj_atomic_create(pool->pool_(), value, &var_);
-    }
-
-    //
-    // Destroy.
-    //
-    void destroy()
-    {
-        if (var_) {
-            pj_atomic_destroy(var_);
-            var_ = NULL;
-        }
-    }
-
-    //
-    // Get pjlib compatible atomic variable.
-    //
-    pj_atomic_t *pj_atomic_t_()
-    {
-	return var_;
-    }
-
-    //
-    // Set the value.
-    //
-    void set(pj_atomic_value_t val)
-    {
-	pj_atomic_set(var_, val);
-    }
-
-    //
-    // Get the value.
-    //
-    pj_atomic_value_t get()
-    {
-	return pj_atomic_get(var_);
-    }
-
-    //
-    // Increment.
-    //
-    void inc()
-    {
-	pj_atomic_inc(var_);
-    }
-
-    //
-    // Increment and get the result.
-    //
-    pj_atomic_value_t inc_and_get()
-    {
-        return pj_atomic_inc_and_get(var_);
-    }
-
-    //
-    // Decrement.
-    //
-    void dec()
-    {
-	pj_atomic_dec(var_);
-    }
-
-    //
-    // Decrement and get the result.
-    //
-    pj_atomic_value_t dec_and_get()
-    {
-        return pj_atomic_dec_and_get(var_);
-    }
-
-    //
-    // Add the variable.
-    //
-    void add(pj_atomic_value_t value)
-    {
-        pj_atomic_add(var_, value);
-    }
-
-    //
-    // Add the variable and get the value.
-    //
-    pj_atomic_value_t add_and_get(pj_atomic_value_t value)
-    {
-        return pj_atomic_add_and_get(var_, value );
-    }
-
-private:
-    pj_atomic_t *var_;
-};
-
-
-//
-// Mutex
-//
-class Pj_Mutex : public Pj_Object
-{
-public:
-    //
-    // Mutex type.
-    //
-    enum Type
-    {
-	DEFAULT = PJ_MUTEX_DEFAULT,
-	SIMPLE = PJ_MUTEX_SIMPLE,
-	RECURSE = PJ_MUTEX_RECURSE,
-    };
-
-    //
-    // Default constructor will create default mutex.
-    //
-    explicit Pj_Mutex(Pj_Pool *pool, Type type = DEFAULT,
-                      const char *name = NULL)
-        : mutex_(NULL)
-    {
-        create(pool, type, name);
-    }
-
-    //
-    // Destructor.
-    //
-    ~Pj_Mutex()
-    {
-        destroy();
-    }
-
-    //
-    // Create mutex.
-    //
-    pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL)
-    {
-        destroy();
-	return pj_mutex_create( pool->pool_(), name, type,
-                                &mutex_ );
-    }
-
-    //
-    // Create simple mutex.
-    //
-    pj_status_t create_simple( Pj_Pool *pool,const char *name = NULL)
-    {
-        return create(pool, SIMPLE, name);
-    }
-
-    //
-    // Create recursive mutex.
-    //
-    pj_status_t create_recursive( Pj_Pool *pool, const char *name = NULL )
-    {
-        return create(pool, RECURSE, name);
-    }
-
-    //
-    // Get pjlib compatible mutex object.
-    //
-    pj_mutex_t *pj_mutex_t_()
-    {
-	return mutex_;
-    }
-
-    //
-    // Destroy mutex.
-    //
-    void destroy()
-    {
-        if (mutex_) {
-	    pj_mutex_destroy(mutex_);
-            mutex_ = NULL;
-        }
-    }
-
-    //
-    // Lock mutex.
-    //
-    pj_status_t acquire()
-    {
-	return pj_mutex_lock(mutex_);
-    }
-
-    //
-    // Unlock mutex.
-    //
-    pj_status_t release()
-    {
-	return pj_mutex_unlock(mutex_);
-    }
-
-    //
-    // Try locking the mutex.
-    //
-    pj_status_t tryacquire()
-    {
-	return pj_mutex_trylock(mutex_);
-    }
-
-private:
-    pj_mutex_t *mutex_;
-};
-
-
-//
-// Semaphore
-//
-class Pj_Semaphore : public Pj_Object
-{
-public:
-    //
-    // Construct semaphore
-    //
-    Pj_Semaphore(Pj_Pool *pool, unsigned max,
-                 unsigned initial = 0, const char *name = NULL)
-    : sem_(NULL)
-    {
-    }
-
-    //
-    // Destructor.
-    //
-    ~Pj_Semaphore()
-    {
-        destroy();
-    }
-
-    //
-    // Create semaphore
-    //
-    pj_status_t create( Pj_Pool *pool, unsigned max,
-                        unsigned initial = 0, const char *name = NULL )
-    {
-        destroy();
-	return pj_sem_create( pool->pool_(), name, initial, max, &sem_);
-    }
-
-    //
-    // Destroy semaphore.
-    //
-    void destroy()
-    {
-        if (sem_) {
-            pj_sem_destroy(sem_);
-            sem_ = NULL;
-        }
-    }
-
-    //
-    // Get pjlib compatible semaphore object.
-    //
-    pj_sem_t *pj_sem_t_()
-    {
-	return (pj_sem_t*)this;
-    }
-
-    //
-    // Wait semaphore.
-    //
-    pj_status_t wait()
-    {
-	return pj_sem_wait(this->pj_sem_t_());
-    }
-
-    //
-    // Wait semaphore.
-    //
-    pj_status_t acquire()
-    {
-	return wait();
-    }
-
-    //
-    // Try wait semaphore.
-    //
-    pj_status_t trywait()
-    {
-	return pj_sem_trywait(this->pj_sem_t_());
-    }
-
-    //
-    // Try wait semaphore.
-    //
-    pj_status_t tryacquire()
-    {
-	return trywait();
-    }
-
-    //
-    // Post semaphore.
-    //
-    pj_status_t post()
-    {
-	return pj_sem_post(this->pj_sem_t_());
-    }
-
-    //
-    // Post semaphore.
-    //
-    pj_status_t release()
-    {
-	return post();
-    }
-
-private:
-    pj_sem_t *sem_;
-};
-
-
-//
-// Event object.
-//
-class Pj_Event
-{
-public:
-    //
-    // Construct event object.
-    //
-    Pj_Event( Pj_Pool *pool, bool manual_reset = false,
-              bool initial = false, const char *name = NULL )
-    : event_(NULL)
-    {
-        create(pool, manual_reset, initial, name);
-    }
-
-    //
-    // Destructor.
-    //
-    ~Pj_Event()
-    {
-        destroy();
-    }
-
-    //
-    // Create event object.
-    //
-    pj_status_t create( Pj_Pool *pool, bool manual_reset = false, 
-                        bool initial = false, const char *name = NULL)
-    {
-        destroy();
-	return pj_event_create(pool->pool_(), name, manual_reset, initial,
-                               &event_);
-    }
-
-    //
-    // Get pjlib compatible event object.
-    //
-    pj_event_t *pj_event_t_()
-    {
-	return event_;
-    }
-
-    //
-    // Destroy event object.
-    //
-    void destroy()
-    {
-        if (event_) {
-	    pj_event_destroy(event_);
-            event_ = NULL;
-        }
-    }
-
-    //
-    // Wait.
-    //
-    pj_status_t wait()
-    {
-	return pj_event_wait(event_);
-    }
-
-    //
-    // Try wait.
-    //
-    pj_status_t trywait()
-    {
-	return pj_event_trywait(event_);
-    }
-
-    //
-    // Set event state to signalled.
-    //
-    pj_status_t set()
-    {
-	return pj_event_set(this->pj_event_t_());
-    }
-
-    //
-    // Release one waiting thread.
-    //
-    pj_status_t pulse()
-    {
-	return pj_event_pulse(this->pj_event_t_());
-    }
-
-    //
-    // Set a non-signalled.
-    //
-    pj_status_t reset()
-    {
-	return pj_event_reset(this->pj_event_t_());
-    }
-
-private:
-    pj_event_t *event_;
-};
-
-//
-// OS abstraction.
-//
-class Pj_OS_API
-{
-public:
-    //
-    // Get current time.
-    //
-    static pj_status_t gettimeofday( Pj_Time_Val *tv )
-    {
-	return pj_gettimeofday(tv);
-    }
-
-    //
-    // Parse to time of day.
-    //
-    static pj_status_t time_decode( const Pj_Time_Val *tv, 
-                                    pj_parsed_time *pt )
-    {
-	return pj_time_decode(tv, pt);
-    }
-
-    //
-    // Parse from time of day.
-    //
-    static pj_status_t time_encode( const pj_parsed_time *pt, 
-                                    Pj_Time_Val *tv)
-    {
-	return pj_time_encode(pt, tv);
-    }
-
-    //
-    // Convert to GMT.
-    //
-    static pj_status_t time_local_to_gmt( Pj_Time_Val *tv )
-    {
-	return pj_time_local_to_gmt( tv );
-    }
-
-    //
-    // Convert time to local.
-    //
-    static pj_status_t time_gmt_to_local( Pj_Time_Val *tv) 
-    {
-	return pj_time_gmt_to_local( tv );
-    }
-};
-
-//
-// Timeval inlines.
-//
-inline pj_status_t Pj_Time_Val::gettimeofday()
-{
-    return Pj_OS_API::gettimeofday(this);
-}
-
-inline pj_parsed_time Pj_Time_Val::decode()
-{
-    pj_parsed_time pt;
-    Pj_OS_API::time_decode(this, &pt);
-    return pt;
-}
-
-inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt)
-{
-    return Pj_OS_API::time_encode(pt, this);
-}
-
-inline pj_status_t Pj_Time_Val::to_gmt()
-{
-    return Pj_OS_API::time_local_to_gmt(this);
-}
-
-inline pj_status_t Pj_Time_Val::to_local()
-{
-    return Pj_OS_API::time_gmt_to_local(this);
-}
-
-#endif	/* __PJPP_OS_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_OS_HPP__

+#define __PJPP_OS_HPP__

+

+#include <pj/os.h>

+#include <pj++/types.hpp>

+#include <pj++/pool.hpp>

+

+class Pj_Thread;

+

+//

+// Thread API.

+//

+class Pj_Thread_API

+{

+public:

+    //

+    // Create a thread.

+    //

+    static pj_status_t create( Pj_Pool *pool, pj_thread_t **thread,

+                               pj_thread_proc *proc, void *arg,

+                               unsigned flags = 0,

+                               const char *name = NULL,

+                               pj_size_t stack_size = 0 )

+    {

+        return pj_thread_create(pool->pool_(), name, proc, arg, stack_size,

+                                flags, thread);

+    }

+

+    //

+    // Register a thread.

+    //

+    static pj_status_t register_this_thread( pj_thread_desc desc,

+                                             pj_thread_t **thread,

+                                             const char *name = NULL )

+    {

+        return pj_thread_register( name, desc, thread );

+    }

+

+    //

+    // Get current thread.

+    // Will return pj_thread_t (sorry folks, not Pj_Thread).

+    //

+    static pj_thread_t *this_thread()

+    {

+        return pj_thread_this();

+    }

+

+    //

+    // Get thread name.

+    //

+    static const char *get_name(pj_thread_t *thread)

+    {

+        return pj_thread_get_name(thread);

+    }

+

+    //

+    // Resume thread.

+    //

+    static pj_status_t resume(pj_thread_t *thread)

+    {

+        return pj_thread_resume(thread);

+    }

+

+    //

+    // Sleep.

+    //

+    static pj_status_t sleep(unsigned msec)

+    {

+	return pj_thread_sleep(msec);

+    }

+

+    //

+    // Join the specified thread.

+    //

+    static pj_status_t join(pj_thread_t *thread)

+    {

+        return pj_thread_join(thread);

+    }

+

+    //

+    // Destroy thread

+    //

+    static pj_status_t destroy(pj_thread_t *thread)

+    {

+        return pj_thread_destroy(thread);

+    }

+};

+

+

+

+//

+// Thread object.

+//

+// How to use:

+//  Derive a class from this class, then override main().

+//

+class Pj_Thread : public Pj_Object

+{

+public:

+    enum Flags

+    {

+	FLAG_SUSPENDED = PJ_THREAD_SUSPENDED

+    };

+

+    //

+    // Default constructor.

+    //

+    Pj_Thread()

+        : thread_(NULL)

+    {

+    }

+

+    //

+    // Destroy thread.

+    //

+    ~Pj_Thread()

+    {

+        destroy();

+    }

+

+    //

+    // This is the main thread function.

+    //

+    virtual int main() = 0;

+

+    //

+    // Start a thread.

+    //

+    pj_status_t create( Pj_Pool *pool, 

+                        unsigned flags = 0,

+                        const char *thread_name = NULL,

+			pj_size_t stack_size = PJ_THREAD_DEFAULT_STACK_SIZE)

+    {

+        destroy();

+        return Pj_Thread_API::create( pool, &thread_, &thread_proc, this,

+                                      flags, thread_name);

+    }

+

+    //

+    // Get pjlib compatible thread object.

+    //

+    pj_thread_t *pj_thread_t_()

+    {

+	return thread_;

+    }

+

+    //

+    // Get thread name.

+    //

+    const char *get_name()

+    {

+        return Pj_Thread_API::get_name(thread_);

+    }

+

+    //

+    // Resume a suspended thread.

+    //

+    pj_status_t resume()

+    {

+        return Pj_Thread_API::resume(thread_);

+    }

+

+    //

+    // Join this thread.

+    //

+    pj_status_t join()

+    {

+        return Pj_Thread_API::join(thread_);

+    }

+

+    //

+    // Destroy thread.

+    //

+    pj_status_t destroy()

+    {

+        if (thread_) {

+            Pj_Thread_API::destroy(thread_);

+            thread_ = NULL;

+        }

+    }

+

+protected:

+    pj_thread_t *thread_;

+

+    static int PJ_THREAD_FUNC thread_proc(void *obj)

+    {

+        Pj_Thread *thread_class = (Pj_Thread*)obj;

+        return thread_class->main();

+    }

+};

+

+

+//

+// External Thread

+//  (threads that were started by external means, i.e. not 

+//   with Pj_Thread::create).

+//

+// This class will normally be defined as local variable in

+// external thread's stack, normally inside thread's main proc.

+// But be aware that the handle will be destroyed on destructor!

+//

+class Pj_External_Thread : public Pj_Thread

+{

+public:

+    Pj_External_Thread()

+    {

+    }

+

+    //

+    // Register external thread so that pjlib functions can work

+    // in that thread.

+    //

+    pj_status_t register_this_thread( const char *name=NULL )

+    {

+        return Pj_Thread_API::register_this_thread(desc_, &thread_,name);

+    }

+

+private:

+    pj_thread_desc desc_;

+};

+

+

+//

+// Thread specific data/thread local storage/TLS.

+//

+class Pj_Thread_Local_API

+{

+public:

+    //

+    // Allocate thread local storage (TLS) index.

+    //

+    static pj_status_t alloc(long *index)

+    {

+        return pj_thread_local_alloc(index);

+    }

+

+    //

+    // Free TLS index.

+    //

+    static void free(long index)

+    {

+        pj_thread_local_free(index);

+    }

+

+    //

+    // Set thread specific data.

+    //

+    static pj_status_t set(long index, void *value)

+    {

+        return pj_thread_local_set(index, value);

+    }

+

+    //

+    // Get thread specific data.

+    //

+    static void *get(long index)

+    {

+        return pj_thread_local_get(index);

+    }

+

+};

+

+//

+// Atomic variable

+//

+// How to use:

+//   Pj_Atomic_Var var(pool, 0);

+//   var.set(..);

+//

+class Pj_Atomic_Var : public Pj_Object

+{

+public:

+    //

+    // Default constructor, initialize variable with NULL.

+    //

+    Pj_Atomic_Var()

+        : var_(NULL)

+    {

+    }

+

+    //

+    // Construct atomic variable.

+    //

+    Pj_Atomic_Var(Pj_Pool *pool, pj_atomic_value_t value)

+        : var_(NULL)

+    {

+        create(pool, value);

+    }

+

+    //

+    // Destructor.

+    //

+    ~Pj_Atomic_Var()

+    {

+        destroy();

+    }

+

+    //

+    // Create atomic variable.

+    //

+    pj_status_t create( Pj_Pool *pool, pj_atomic_value_t value)

+    {

+        destroy();

+	return pj_atomic_create(pool->pool_(), value, &var_);

+    }

+

+    //

+    // Destroy.

+    //

+    void destroy()

+    {

+        if (var_) {

+            pj_atomic_destroy(var_);

+            var_ = NULL;

+        }

+    }

+

+    //

+    // Get pjlib compatible atomic variable.

+    //

+    pj_atomic_t *pj_atomic_t_()

+    {

+	return var_;

+    }

+

+    //

+    // Set the value.

+    //

+    void set(pj_atomic_value_t val)

+    {

+	pj_atomic_set(var_, val);

+    }

+

+    //

+    // Get the value.

+    //

+    pj_atomic_value_t get()

+    {

+	return pj_atomic_get(var_);

+    }

+

+    //

+    // Increment.

+    //

+    void inc()

+    {

+	pj_atomic_inc(var_);

+    }

+

+    //

+    // Increment and get the result.

+    //

+    pj_atomic_value_t inc_and_get()

+    {

+        return pj_atomic_inc_and_get(var_);

+    }

+

+    //

+    // Decrement.

+    //

+    void dec()

+    {

+	pj_atomic_dec(var_);

+    }

+

+    //

+    // Decrement and get the result.

+    //

+    pj_atomic_value_t dec_and_get()

+    {

+        return pj_atomic_dec_and_get(var_);

+    }

+

+    //

+    // Add the variable.

+    //

+    void add(pj_atomic_value_t value)

+    {

+        pj_atomic_add(var_, value);

+    }

+

+    //

+    // Add the variable and get the value.

+    //

+    pj_atomic_value_t add_and_get(pj_atomic_value_t value)

+    {

+        return pj_atomic_add_and_get(var_, value );

+    }

+

+private:

+    pj_atomic_t *var_;

+};

+

+

+//

+// Mutex

+//

+class Pj_Mutex : public Pj_Object

+{

+public:

+    //

+    // Mutex type.

+    //

+    enum Type

+    {

+	DEFAULT = PJ_MUTEX_DEFAULT,

+	SIMPLE = PJ_MUTEX_SIMPLE,

+	RECURSE = PJ_MUTEX_RECURSE,

+    };

+

+    //

+    // Default constructor will create default mutex.

+    //

+    explicit Pj_Mutex(Pj_Pool *pool, Type type = DEFAULT,

+                      const char *name = NULL)

+        : mutex_(NULL)

+    {

+        create(pool, type, name);

+    }

+

+    //

+    // Destructor.

+    //

+    ~Pj_Mutex()

+    {

+        destroy();

+    }

+

+    //

+    // Create mutex.

+    //

+    pj_status_t create( Pj_Pool *pool, Type type, const char *name = NULL)

+    {

+        destroy();

+	return pj_mutex_create( pool->pool_(), name, type,

+                                &mutex_ );

+    }

+

+    //

+    // Create simple mutex.

+    //

+    pj_status_t create_simple( Pj_Pool *pool,const char *name = NULL)

+    {

+        return create(pool, SIMPLE, name);

+    }

+

+    //

+    // Create recursive mutex.

+    //

+    pj_status_t create_recursive( Pj_Pool *pool, const char *name = NULL )

+    {

+        return create(pool, RECURSE, name);

+    }

+

+    //

+    // Get pjlib compatible mutex object.

+    //

+    pj_mutex_t *pj_mutex_t_()

+    {

+	return mutex_;

+    }

+

+    //

+    // Destroy mutex.

+    //

+    void destroy()

+    {

+        if (mutex_) {

+	    pj_mutex_destroy(mutex_);

+            mutex_ = NULL;

+        }

+    }

+

+    //

+    // Lock mutex.

+    //

+    pj_status_t acquire()

+    {

+	return pj_mutex_lock(mutex_);

+    }

+

+    //

+    // Unlock mutex.

+    //

+    pj_status_t release()

+    {

+	return pj_mutex_unlock(mutex_);

+    }

+

+    //

+    // Try locking the mutex.

+    //

+    pj_status_t tryacquire()

+    {

+	return pj_mutex_trylock(mutex_);

+    }

+

+private:

+    pj_mutex_t *mutex_;

+};

+

+

+//

+// Semaphore

+//

+class Pj_Semaphore : public Pj_Object

+{

+public:

+    //

+    // Construct semaphore

+    //

+    Pj_Semaphore(Pj_Pool *pool, unsigned max,

+                 unsigned initial = 0, const char *name = NULL)

+    : sem_(NULL)

+    {

+    }

+

+    //

+    // Destructor.

+    //

+    ~Pj_Semaphore()

+    {

+        destroy();

+    }

+

+    //

+    // Create semaphore

+    //

+    pj_status_t create( Pj_Pool *pool, unsigned max,

+                        unsigned initial = 0, const char *name = NULL )

+    {

+        destroy();

+	return pj_sem_create( pool->pool_(), name, initial, max, &sem_);

+    }

+

+    //

+    // Destroy semaphore.

+    //

+    void destroy()

+    {

+        if (sem_) {

+            pj_sem_destroy(sem_);

+            sem_ = NULL;

+        }

+    }

+

+    //

+    // Get pjlib compatible semaphore object.

+    //

+    pj_sem_t *pj_sem_t_()

+    {

+	return (pj_sem_t*)this;

+    }

+

+    //

+    // Wait semaphore.

+    //

+    pj_status_t wait()

+    {

+	return pj_sem_wait(this->pj_sem_t_());

+    }

+

+    //

+    // Wait semaphore.

+    //

+    pj_status_t acquire()

+    {

+	return wait();

+    }

+

+    //

+    // Try wait semaphore.

+    //

+    pj_status_t trywait()

+    {

+	return pj_sem_trywait(this->pj_sem_t_());

+    }

+

+    //

+    // Try wait semaphore.

+    //

+    pj_status_t tryacquire()

+    {

+	return trywait();

+    }

+

+    //

+    // Post semaphore.

+    //

+    pj_status_t post()

+    {

+	return pj_sem_post(this->pj_sem_t_());

+    }

+

+    //

+    // Post semaphore.

+    //

+    pj_status_t release()

+    {

+	return post();

+    }

+

+private:

+    pj_sem_t *sem_;

+};

+

+

+//

+// Event object.

+//

+class Pj_Event

+{

+public:

+    //

+    // Construct event object.

+    //

+    Pj_Event( Pj_Pool *pool, bool manual_reset = false,

+              bool initial = false, const char *name = NULL )

+    : event_(NULL)

+    {

+        create(pool, manual_reset, initial, name);

+    }

+

+    //

+    // Destructor.

+    //

+    ~Pj_Event()

+    {

+        destroy();

+    }

+

+    //

+    // Create event object.

+    //

+    pj_status_t create( Pj_Pool *pool, bool manual_reset = false, 

+                        bool initial = false, const char *name = NULL)

+    {

+        destroy();

+	return pj_event_create(pool->pool_(), name, manual_reset, initial,

+                               &event_);

+    }

+

+    //

+    // Get pjlib compatible event object.

+    //

+    pj_event_t *pj_event_t_()

+    {

+	return event_;

+    }

+

+    //

+    // Destroy event object.

+    //

+    void destroy()

+    {

+        if (event_) {

+	    pj_event_destroy(event_);

+            event_ = NULL;

+        }

+    }

+

+    //

+    // Wait.

+    //

+    pj_status_t wait()

+    {

+	return pj_event_wait(event_);

+    }

+

+    //

+    // Try wait.

+    //

+    pj_status_t trywait()

+    {

+	return pj_event_trywait(event_);

+    }

+

+    //

+    // Set event state to signalled.

+    //

+    pj_status_t set()

+    {

+	return pj_event_set(this->pj_event_t_());

+    }

+

+    //

+    // Release one waiting thread.

+    //

+    pj_status_t pulse()

+    {

+	return pj_event_pulse(this->pj_event_t_());

+    }

+

+    //

+    // Set a non-signalled.

+    //

+    pj_status_t reset()

+    {

+	return pj_event_reset(this->pj_event_t_());

+    }

+

+private:

+    pj_event_t *event_;

+};

+

+//

+// OS abstraction.

+//

+class Pj_OS_API

+{

+public:

+    //

+    // Get current time.

+    //

+    static pj_status_t gettimeofday( Pj_Time_Val *tv )

+    {

+	return pj_gettimeofday(tv);

+    }

+

+    //

+    // Parse to time of day.

+    //

+    static pj_status_t time_decode( const Pj_Time_Val *tv, 

+                                    pj_parsed_time *pt )

+    {

+	return pj_time_decode(tv, pt);

+    }

+

+    //

+    // Parse from time of day.

+    //

+    static pj_status_t time_encode( const pj_parsed_time *pt, 

+                                    Pj_Time_Val *tv)

+    {

+	return pj_time_encode(pt, tv);

+    }

+

+    //

+    // Convert to GMT.

+    //

+    static pj_status_t time_local_to_gmt( Pj_Time_Val *tv )

+    {

+	return pj_time_local_to_gmt( tv );

+    }

+

+    //

+    // Convert time to local.

+    //

+    static pj_status_t time_gmt_to_local( Pj_Time_Val *tv) 

+    {

+	return pj_time_gmt_to_local( tv );

+    }

+};

+

+//

+// Timeval inlines.

+//

+inline pj_status_t Pj_Time_Val::gettimeofday()

+{

+    return Pj_OS_API::gettimeofday(this);

+}

+

+inline pj_parsed_time Pj_Time_Val::decode()

+{

+    pj_parsed_time pt;

+    Pj_OS_API::time_decode(this, &pt);

+    return pt;

+}

+

+inline pj_status_t Pj_Time_Val::encode(const pj_parsed_time *pt)

+{

+    return Pj_OS_API::time_encode(pt, this);

+}

+

+inline pj_status_t Pj_Time_Val::to_gmt()

+{

+    return Pj_OS_API::time_local_to_gmt(this);

+}

+

+inline pj_status_t Pj_Time_Val::to_local()

+{

+    return Pj_OS_API::time_gmt_to_local(this);

+}

+

+#endif	/* __PJPP_OS_HPP__ */

+

diff --git a/pjlib/include/pj++/pool.hpp b/pjlib/include/pj++/pool.hpp
index 1fa7575..2236511 100644
--- a/pjlib/include/pj++/pool.hpp
+++ b/pjlib/include/pj++/pool.hpp
@@ -1,254 +1,275 @@
-/* $Id$
- */
-#ifndef __PJPP_POOL_HPP__
-#define __PJPP_POOL_HPP__
-
-#include <pj/pool.h>
-
-class Pj_Pool;
-class Pj_Caching_Pool;
-
-//
-// Base class for all Pjlib objects
-//
-class Pj_Object
-{
-public:
-    void *operator new(unsigned int class_size, Pj_Pool *pool);
-    void *operator new(unsigned int class_size, Pj_Pool &pool);
-
-    void operator delete(void*)
-    {
-    }
-
-    void operator delete(void*, Pj_Pool*)
-    {
-    }
-
-    void operator delete(void*, Pj_Pool&)
-    {
-    }
-
-    //
-    // Inline implementations at the end of this file.
-    //
-
-private:
-    // Can not use normal new operator; must use pool.
-    // e.g.:
-    //   obj = new(pool) Pj_The_Object(pool, ...);
-    //
-    void *operator new(unsigned int)
-    {}
-};
-
-
-//
-// Pool.
-//
-class Pj_Pool : public Pj_Object
-{
-public:
-    //
-    // Default constructor, initializes internal pool to NULL.
-    // Application must call attach() some time later.
-    //
-    Pj_Pool()
-        : p_(NULL)
-    {
-    }
-
-    //
-    // Create pool.
-    //
-    Pj_Pool(Pj_Caching_Pool &caching_pool,
-            pj_size_t initial_size, 
-            pj_size_t increment_size, 
-            const char *name = NULL, 
-            pj_pool_callback *callback = NULL);
-
-    //
-    // Construct from existing pool.
-    //
-    explicit Pj_Pool(pj_pool_t *pool)
-        : p_(pool)
-    {
-    }
-
-    //
-    // Attach existing pool.
-    //
-    void attach(pj_pool_t *pool)
-    {
-        p_ = pool;
-    }
-
-    //
-    // Destructor.
-    //
-    // Release pool back to factory. Remember: if you delete pool, then 
-    // make sure that all objects that have been allocated from this pool
-    // have been properly destroyed.
-    //
-    // This is where C++ is trickier than plain C!!
-    //
-    ~Pj_Pool()
-    {
-        if (p_)
-	    pj_pool_release(p_);
-    }
-
-    //
-    // Get name.
-    //
-    const char *getobjname() const
-    {
-	return pj_pool_getobjname(p_);
-    }
-
-    //
-    // Get pjlib compatible pool object.
-    //
-    pj_pool_t *pool_()
-    {
-	return p_;
-    }
-
-    //
-    // Get pjlib compatible pool object.
-    //
-    const pj_pool_t *pool_() const
-    {
-	return p_;
-    }
-
-    //
-    // Get pjlib compatible pool object.
-    //
-    pj_pool_t *pj_pool_t_()
-    {
-	return p_;
-    }
-
-    //
-    // Reset pool.
-    //
-    void reset()
-    {
-	pj_pool_reset(p_);
-    }
-
-    //
-    // Get current capacity.
-    //
-    pj_size_t get_capacity()
-    {
-	pj_pool_get_capacity(p_);
-    }
-
-    //
-    // Get current total bytes allocated from the pool.
-    //
-    pj_size_t get_used_size()
-    {
-	pj_pool_get_used_size(p_);
-    }
-
-    //
-    // Allocate.
-    //
-    void *alloc(pj_size_t size)
-    {
-	return pj_pool_alloc(p_, size);
-    }
-
-    //
-    // Allocate elements and zero fill the memory.
-    //
-    void *calloc(pj_size_t count, pj_size_t elem)
-    {
-	return pj_pool_calloc(p_, count, elem);
-    }
-
-    //
-    // Allocate and zero fill memory.
-    //
-    void *zalloc(pj_size_t size)
-    {
-        return pj_pool_zalloc(p_, size);
-    }
-
-private:
-    pj_pool_t *p_;
-};
-
-
-//
-// Caching pool.
-//
-class Pj_Caching_Pool
-{
-public:
-    //
-    // Construct caching pool.
-    //
-    Pj_Caching_Pool( pj_size_t cache_capacity = 0,
-	             const pj_pool_factory_policy *pol=&pj_pool_factory_default_policy)
-    {
-	pj_caching_pool_init(&cp_, pol, cache_capacity);
-    }
-
-    //
-    // Destroy caching pool.
-    //
-    ~Pj_Caching_Pool()
-    {
-	pj_caching_pool_destroy(&cp_);
-    }
-
-    //
-    // Create pool.
-    //
-    pj_pool_t *create_pool( pj_size_t initial_size, 
-                            pj_size_t increment_size, 
-                            const char *name = NULL, 
-                            pj_pool_callback *callback = NULL)
-    {
-	return (pj_pool_t*)(*cp_.factory.create_pool)(&cp_.factory, name, 
-                                                     initial_size, 
-                                                     increment_size, 
-                                                     callback);
-    }
-
-private:
-    pj_caching_pool cp_;
-};
-
-//
-// Inlines for Pj_Object
-//
-inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool *pool)
-{
-    return pool->alloc(class_size);
-}
-inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool &pool)
-{
-    return pool.alloc(class_size);
-}
-
-//
-// Inlines for Pj_Pool
-//
-inline Pj_Pool::Pj_Pool( Pj_Caching_Pool &caching_pool,
-                         pj_size_t initial_size, 
-                         pj_size_t increment_size, 
-                         const char *name, 
-                         pj_pool_callback *callback)
-{
-    p_ = caching_pool.create_pool(initial_size, increment_size, name,
-                                  callback);
-}
-
-
-#endif	/* __PJPP_POOL_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_POOL_HPP__

+#define __PJPP_POOL_HPP__

+

+#include <pj/pool.h>

+

+class Pj_Pool;

+class Pj_Caching_Pool;

+

+//

+// Base class for all Pjlib objects

+//

+class Pj_Object

+{

+public:

+    void *operator new(unsigned int class_size, Pj_Pool *pool);

+    void *operator new(unsigned int class_size, Pj_Pool &pool);

+

+    void operator delete(void*)

+    {

+    }

+

+    void operator delete(void*, Pj_Pool*)

+    {

+    }

+

+    void operator delete(void*, Pj_Pool&)

+    {

+    }

+

+    //

+    // Inline implementations at the end of this file.

+    //

+

+private:

+    // Can not use normal new operator; must use pool.

+    // e.g.:

+    //   obj = new(pool) Pj_The_Object(pool, ...);

+    //

+    void *operator new(unsigned int)

+    {}

+};

+

+

+//

+// Pool.

+//

+class Pj_Pool : public Pj_Object

+{

+public:

+    //

+    // Default constructor, initializes internal pool to NULL.

+    // Application must call attach() some time later.

+    //

+    Pj_Pool()

+        : p_(NULL)

+    {

+    }

+

+    //

+    // Create pool.

+    //

+    Pj_Pool(Pj_Caching_Pool &caching_pool,

+            pj_size_t initial_size, 

+            pj_size_t increment_size, 

+            const char *name = NULL, 

+            pj_pool_callback *callback = NULL);

+

+    //

+    // Construct from existing pool.

+    //

+    explicit Pj_Pool(pj_pool_t *pool)

+        : p_(pool)

+    {

+    }

+

+    //

+    // Attach existing pool.

+    //

+    void attach(pj_pool_t *pool)

+    {

+        p_ = pool;

+    }

+

+    //

+    // Destructor.

+    //

+    // Release pool back to factory. Remember: if you delete pool, then 

+    // make sure that all objects that have been allocated from this pool

+    // have been properly destroyed.

+    //

+    // This is where C++ is trickier than plain C!!

+    //

+    ~Pj_Pool()

+    {

+        if (p_)

+	    pj_pool_release(p_);

+    }

+

+    //

+    // Get name.

+    //

+    const char *getobjname() const

+    {

+	return pj_pool_getobjname(p_);

+    }

+

+    //

+    // Get pjlib compatible pool object.

+    //

+    pj_pool_t *pool_()

+    {

+	return p_;

+    }

+

+    //

+    // Get pjlib compatible pool object.

+    //

+    const pj_pool_t *pool_() const

+    {

+	return p_;

+    }

+

+    //

+    // Get pjlib compatible pool object.

+    //

+    pj_pool_t *pj_pool_t_()

+    {

+	return p_;

+    }

+

+    //

+    // Reset pool.

+    //

+    void reset()

+    {

+	pj_pool_reset(p_);

+    }

+

+    //

+    // Get current capacity.

+    //

+    pj_size_t get_capacity()

+    {

+	pj_pool_get_capacity(p_);

+    }

+

+    //

+    // Get current total bytes allocated from the pool.

+    //

+    pj_size_t get_used_size()

+    {

+	pj_pool_get_used_size(p_);

+    }

+

+    //

+    // Allocate.

+    //

+    void *alloc(pj_size_t size)

+    {

+	return pj_pool_alloc(p_, size);

+    }

+

+    //

+    // Allocate elements and zero fill the memory.

+    //

+    void *calloc(pj_size_t count, pj_size_t elem)

+    {

+	return pj_pool_calloc(p_, count, elem);

+    }

+

+    //

+    // Allocate and zero fill memory.

+    //

+    void *zalloc(pj_size_t size)

+    {

+        return pj_pool_zalloc(p_, size);

+    }

+

+private:

+    pj_pool_t *p_;

+};

+

+

+//

+// Caching pool.

+//

+class Pj_Caching_Pool

+{

+public:

+    //

+    // Construct caching pool.

+    //

+    Pj_Caching_Pool( pj_size_t cache_capacity = 0,

+	             const pj_pool_factory_policy *pol=&pj_pool_factory_default_policy)

+    {

+	pj_caching_pool_init(&cp_, pol, cache_capacity);

+    }

+

+    //

+    // Destroy caching pool.

+    //

+    ~Pj_Caching_Pool()

+    {

+	pj_caching_pool_destroy(&cp_);

+    }

+

+    //

+    // Create pool.

+    //

+    pj_pool_t *create_pool( pj_size_t initial_size, 

+                            pj_size_t increment_size, 

+                            const char *name = NULL, 

+                            pj_pool_callback *callback = NULL)

+    {

+	return (pj_pool_t*)(*cp_.factory.create_pool)(&cp_.factory, name, 

+                                                     initial_size, 

+                                                     increment_size, 

+                                                     callback);

+    }

+

+private:

+    pj_caching_pool cp_;

+};

+

+//

+// Inlines for Pj_Object

+//

+inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool *pool)

+{

+    return pool->alloc(class_size);

+}

+inline void *Pj_Object::operator new(unsigned int class_size, Pj_Pool &pool)

+{

+    return pool.alloc(class_size);

+}

+

+//

+// Inlines for Pj_Pool

+//

+inline Pj_Pool::Pj_Pool( Pj_Caching_Pool &caching_pool,

+                         pj_size_t initial_size, 

+                         pj_size_t increment_size, 

+                         const char *name, 

+                         pj_pool_callback *callback)

+{

+    p_ = caching_pool.create_pool(initial_size, increment_size, name,

+                                  callback);

+}

+

+

+#endif	/* __PJPP_POOL_HPP__ */

+

diff --git a/pjlib/include/pj++/proactor.hpp b/pjlib/include/pj++/proactor.hpp
index 73be85f..7c4f992 100644
--- a/pjlib/include/pj++/proactor.hpp
+++ b/pjlib/include/pj++/proactor.hpp
@@ -1,502 +1,523 @@
-/* $Id$
- */
-#ifndef __PJPP_PROACTOR_HPP__
-#define __PJPP_PROACTOR_HPP__
-
-#include <pj/ioqueue.h>
-#include <pj++/pool.hpp>
-#include <pj++/sock.hpp>
-#include <pj++/timer.hpp>
-#include <pj/errno.h>
-
-class Pj_Proactor;
-class Pj_Event_Handler;
-
-
-//////////////////////////////////////////////////////////////////////////////
-// Asynchronous operation key.
-//
-// Applications may inheric this class to put their application
-// specific data.
-//
-class Pj_Async_Op : public pj_ioqueue_op_key_t
-{
-public:
-    //
-    // Construct with null handler.
-    // App must call set_handler() before use.
-    //
-    Pj_Async_Op()
-        : handler_(NULL)
-    {
-	pj_ioqueue_op_key_init(this, sizeof(*this));
-    }
-
-    //
-    // Constructor.
-    //
-    explicit Pj_Async_Op(Pj_Event_Handler *handler)
-        : handler_(handler)
-    {
-	pj_ioqueue_op_key_init(this, sizeof(*this));
-    }
-
-    //
-    // Set handler.
-    //
-    void set_handler(Pj_Event_Handler *handler)
-    {
-        handler_ = handler;
-    }
-
-    //
-    // Check whether operation is still pending for this key.
-    //
-    bool is_pending();
-
-    //
-    // Cancel the operation.
-    //
-    bool cancel(pj_ssize_t bytes_status=-PJ_ECANCELLED);
-
-protected:
-    Pj_Event_Handler *handler_;
-};
-
-
-//////////////////////////////////////////////////////////////////////////////
-// Event handler.
-//
-// Applications should inherit this class to receive various event
-// notifications.
-//
-// Applications should implement get_socket_handle().
-//
-class Pj_Event_Handler : public Pj_Object
-{
-    friend class Pj_Proactor;
-public:
-    //
-    // Default constructor.
-    //
-    Pj_Event_Handler()
-        : key_(NULL)
-    {
-        pj_memset(&timer_, 0, sizeof(timer_));
-        timer_.user_data = this;
-        timer_.cb = &timer_callback;
-    }
-    
-    //
-    // Destroy.
-    //
-    virtual ~Pj_Event_Handler()
-    {
-        unregister();
-    }
-
-    //
-    // Unregister this handler from the ioqueue.
-    //
-    void unregister()
-    {
-        if (key_) {
-            pj_ioqueue_unregister(key_);
-            key_ = NULL;
-        }
-    }
-
-    //
-    // Get socket handle associated with this.
-    //
-    virtual pj_sock_t get_socket_handle()
-    {
-        return PJ_INVALID_SOCKET;
-    }
-
-    //
-    // Start async receive.
-    //
-    pj_status_t recv( Pj_Async_Op *op_key, 
-                      void *buf, pj_ssize_t *len, 
-                      unsigned flags)
-    {
-        return pj_ioqueue_recv( key_, op_key,
-                                buf, len, flags);
-    }
-
-    //
-    // Start async recvfrom()
-    //
-    pj_status_t recvfrom( Pj_Async_Op *op_key, 
-                          void *buf, pj_ssize_t *len, unsigned flags,
-                          Pj_Inet_Addr *addr)
-    {
-        addr->addrlen_ = sizeof(Pj_Inet_Addr);
-        return pj_ioqueue_recvfrom( key_, op_key, buf, len, flags,
-                                    addr, &addr->addrlen_ );
-    }
-
-    //
-    // Start async send()
-    //
-    pj_status_t send( Pj_Async_Op *op_key, 
-                      const void *data, pj_ssize_t *len, 
-                      unsigned flags)
-    {
-        return pj_ioqueue_send( key_, op_key, data, len, flags);
-    }
-
-    //
-    // Start async sendto()
-    //
-    pj_status_t sendto( Pj_Async_Op *op_key,
-                        const void *data, pj_ssize_t *len, unsigned flags,
-                        const Pj_Inet_Addr &addr)
-    {
-        return pj_ioqueue_sendto(key_, op_key, data, len, flags,
-                                 &addr, sizeof(addr));
-    }
-
-#if PJ_HAS_TCP
-    //
-    // Start async connect()
-    //
-    pj_status_t connect(const Pj_Inet_Addr &addr)
-    {
-        return pj_ioqueue_connect(key_, &addr, sizeof(addr));
-    }
-
-    //
-    // Start async accept().
-    //
-    pj_status_t accept( Pj_Async_Op *op_key,
-                        Pj_Socket *sock, 
-                        Pj_Inet_Addr *local = NULL, 
-                        Pj_Inet_Addr *remote = NULL)
-    {
-        int *addrlen = local ? &local->addrlen_ : NULL;
-        return pj_ioqueue_accept( key_, op_key, &sock->sock_,
-                                  local, remote, addrlen );
-    }
-
-#endif
-
-protected:
-    //////////////////
-    // Overridables
-    //////////////////
-
-    //
-    // Timeout callback.
-    //
-    virtual void on_timeout(int data) 
-    {
-    }
-
-    //
-    // On read complete callback.
-    //
-    virtual void on_read_complete( Pj_Async_Op *op_key,
-                                   pj_ssize_t bytes_read) 
-    {
-    }
-
-    //
-    // On write complete callback.
-    //
-    virtual void on_write_complete( Pj_Async_Op *op_key, 
-                                    pj_ssize_t bytes_sent) 
-    {
-    }
-
-#if PJ_HAS_TCP
-    //
-    // On connect complete callback.
-    //
-    virtual void on_connect_complete(pj_status_t status) 
-    {
-    }
-
-    //
-    // On new connection callback.
-    //
-    virtual void on_accept_complete( Pj_Async_Op *op_key,
-                                     pj_sock_t new_sock,
-                                     pj_status_t status) 
-    {
-    }
-
-#endif
-
-
-private:
-    pj_ioqueue_key_t *key_;
-    pj_timer_entry    timer_;
-
-    friend class Pj_Proactor;
-    friend class Pj_Async_Op;
-
-    //
-    // Static timer callback.
-    //
-    static void timer_callback( pj_timer_heap_t *timer_heap, 
-                                struct pj_timer_entry *entry)
-    {
-        Pj_Event_Handler *handler = 
-            (Pj_Event_Handler*) entry->user_data;
-
-        handler->on_timeout(entry->id);
-    }
-};
-
-inline bool Pj_Async_Op::is_pending()
-{
-    return pj_ioqueue_is_pending(handler_->key_, this) != 0;
-}
-
-inline bool Pj_Async_Op::cancel(pj_ssize_t bytes_status)
-{
-    return pj_ioqueue_post_completion(handler_->key_, this, 
-                                      bytes_status) == PJ_SUCCESS;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// Proactor
-//
-class Pj_Proactor : public Pj_Object
-{
-public:
-    //
-    // Default constructor, initializes to NULL.
-    //
-    Pj_Proactor()
-        : ioq_(NULL), th_(NULL)
-    {
-        cb_.on_read_complete    = &read_complete_cb;
-        cb_.on_write_complete   = &write_complete_cb;
-        cb_.on_accept_complete  = &accept_complete_cb;
-        cb_.on_connect_complete = &connect_complete_cb;
-    }
-
-    //
-    // Construct proactor.
-    //
-    Pj_Proactor( Pj_Pool *pool, pj_size_t max_fd,
-                 pj_size_t max_timer_entries )
-    : ioq_(NULL), th_(NULL)
-    {
-        cb_.on_read_complete    = &read_complete_cb;
-        cb_.on_write_complete   = &write_complete_cb;
-        cb_.on_accept_complete  = &accept_complete_cb;
-        cb_.on_connect_complete = &connect_complete_cb;
-
-        create(pool, max_fd, max_timer_entries);
-    }
-
-    //
-    // Destructor.
-    //
-    ~Pj_Proactor()
-    {
-        destroy();
-    }
-
-    //
-    // Create proactor.
-    //
-    pj_status_t create( Pj_Pool *pool, pj_size_t max_fd, 
-			pj_size_t timer_entry_count)
-    {
-        pj_status_t status;
-
-        destroy();
-
-        status = pj_ioqueue_create(pool->pool_(), max_fd, &ioq_);
-        if (status != PJ_SUCCESS) 
-            return status;
-        
-        status = pj_timer_heap_create(pool->pool_(), 
-                                      timer_entry_count, &th_);
-        if (status != PJ_SUCCESS) {
-            pj_ioqueue_destroy(ioq_);
-            ioq_ = NULL;
-            return NULL;
-        }
-        
-        return status;
-    }
-
-    //
-    // Destroy proactor.
-    //
-    void destroy()
-    {
-        if (ioq_) {
-            pj_ioqueue_destroy(ioq_);
-            ioq_ = NULL;
-        }
-        if (th_) {
-            pj_timer_heap_destroy(th_);
-            th_ = NULL;
-        }
-    }
-
-    //
-    // Register handler.
-    // This will call handler->get_socket_handle()
-    //
-    pj_status_t register_socket_handler(Pj_Pool *pool, 
-                                        Pj_Event_Handler *handler)
-    {
-        return   pj_ioqueue_register_sock( pool->pool_(), ioq_,
-                                           handler->get_socket_handle(),
-                                           handler, &cb_, &handler->key_ );
-    }
-
-    //
-    // Unregister handler.
-    //
-    static void unregister_handler(Pj_Event_Handler *handler)
-    {
-        if (handler->key_) {
-            pj_ioqueue_unregister( handler->key_ );
-            handler->key_ = NULL;
-        }
-    }
-
-    //
-    // Scheduler timer.
-    //
-    bool schedule_timer( Pj_Event_Handler *handler, 
-                         const Pj_Time_Val &delay, 
-                         int id=-1)
-    {
-        return schedule_timer(th_, handler, delay, id);
-    }
-
-    //
-    // Cancel timer.
-    //
-    bool cancel_timer(Pj_Event_Handler *handler)
-    {
-        return pj_timer_heap_cancel(th_, &handler->timer_) == 1;
-    }
-
-    //
-    // Handle events.
-    //
-    int handle_events(Pj_Time_Val *max_timeout)
-    {
-        Pj_Time_Val timeout(0, 0);
-        int timer_count;
-
-        timer_count = pj_timer_heap_poll( th_, &timeout );
-
-        if (timeout.get_sec() < 0) 
-            timeout.sec = PJ_MAXINT32;
-
-        /* If caller specifies maximum time to wait, then compare the value 
-         * with the timeout to wait from timer, and use the minimum value.
-         */
-        if (max_timeout && timeout >= *max_timeout) {
-	    timeout = *max_timeout;
-        }
-
-        /* Poll events in ioqueue. */
-        int ioqueue_count;
-
-        ioqueue_count = pj_ioqueue_poll(ioq_, &timeout);
-        if (ioqueue_count < 0)
-	    return ioqueue_count;
-
-        return ioqueue_count + timer_count;
-    }
-
-    //
-    // Get the internal ioqueue object.
-    //
-    pj_ioqueue_t *get_io_queue()
-    {
-        return ioq_;
-    }
-
-    //
-    // Get the internal timer heap object.
-    //
-    pj_timer_heap_t *get_timer_heap()
-    {
-        return th_;
-    }
-
-private:
-    pj_ioqueue_t *ioq_;
-    pj_timer_heap_t *th_;
-    pj_ioqueue_callback cb_;
-
-    static bool schedule_timer( pj_timer_heap_t *timer, 
-                                Pj_Event_Handler *handler,
-				const Pj_Time_Val &delay, 
-                                int id=-1)
-    {
-        handler->timer_.id = id;
-        return pj_timer_heap_schedule(timer, &handler->timer_, &delay) == 0;
-    }
-
-
-    //
-    // Static read completion callback.
-    //
-    static void read_complete_cb( pj_ioqueue_key_t *key, 
-                                  pj_ioqueue_op_key_t *op_key, 
-                                  pj_ssize_t bytes_read)
-    {
-        Pj_Event_Handler *handler = 
-	    (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
-
-        handler->on_read_complete((Pj_Async_Op*)op_key, bytes_read);
-    }
-
-    //
-    // Static write completion callback.
-    //
-    static void write_complete_cb(pj_ioqueue_key_t *key, 
-                                  pj_ioqueue_op_key_t *op_key,
-                                  pj_ssize_t bytes_sent)
-    {
-        Pj_Event_Handler *handler = 
-	    (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
-
-        handler->on_write_complete((Pj_Async_Op*)op_key, bytes_sent);
-    }
-
-    //
-    // Static accept completion callback.
-    //
-    static void accept_complete_cb(pj_ioqueue_key_t *key, 
-                                   pj_ioqueue_op_key_t *op_key,
-                                   pj_sock_t new_sock,
-                                   pj_status_t status)
-    {
-        Pj_Event_Handler *handler = 
-	    (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
-
-        handler->on_accept_complete((Pj_Async_Op*)op_key, new_sock, status);
-    }
-
-    //
-    // Static connect completion callback.
-    //
-    static void connect_complete_cb(pj_ioqueue_key_t *key, 
-                                    pj_status_t status)
-    {
-        Pj_Event_Handler *handler = 
-	    (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);
-
-        handler->on_connect_complete(status);
-    }
-
-};
-
-#endif	/* __PJPP_PROACTOR_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_PROACTOR_HPP__

+#define __PJPP_PROACTOR_HPP__

+

+#include <pj/ioqueue.h>

+#include <pj++/pool.hpp>

+#include <pj++/sock.hpp>

+#include <pj++/timer.hpp>

+#include <pj/errno.h>

+

+class Pj_Proactor;

+class Pj_Event_Handler;

+

+

+//////////////////////////////////////////////////////////////////////////////

+// Asynchronous operation key.

+//

+// Applications may inheric this class to put their application

+// specific data.

+//

+class Pj_Async_Op : public pj_ioqueue_op_key_t

+{

+public:

+    //

+    // Construct with null handler.

+    // App must call set_handler() before use.

+    //

+    Pj_Async_Op()

+        : handler_(NULL)

+    {

+	pj_ioqueue_op_key_init(this, sizeof(*this));

+    }

+

+    //

+    // Constructor.

+    //

+    explicit Pj_Async_Op(Pj_Event_Handler *handler)

+        : handler_(handler)

+    {

+	pj_ioqueue_op_key_init(this, sizeof(*this));

+    }

+

+    //

+    // Set handler.

+    //

+    void set_handler(Pj_Event_Handler *handler)

+    {

+        handler_ = handler;

+    }

+

+    //

+    // Check whether operation is still pending for this key.

+    //

+    bool is_pending();

+

+    //

+    // Cancel the operation.

+    //

+    bool cancel(pj_ssize_t bytes_status=-PJ_ECANCELLED);

+

+protected:

+    Pj_Event_Handler *handler_;

+};

+

+

+//////////////////////////////////////////////////////////////////////////////

+// Event handler.

+//

+// Applications should inherit this class to receive various event

+// notifications.

+//

+// Applications should implement get_socket_handle().

+//

+class Pj_Event_Handler : public Pj_Object

+{

+    friend class Pj_Proactor;

+public:

+    //

+    // Default constructor.

+    //

+    Pj_Event_Handler()

+        : key_(NULL)

+    {

+        pj_memset(&timer_, 0, sizeof(timer_));

+        timer_.user_data = this;

+        timer_.cb = &timer_callback;

+    }

+    

+    //

+    // Destroy.

+    //

+    virtual ~Pj_Event_Handler()

+    {

+        unregister();

+    }

+

+    //

+    // Unregister this handler from the ioqueue.

+    //

+    void unregister()

+    {

+        if (key_) {

+            pj_ioqueue_unregister(key_);

+            key_ = NULL;

+        }

+    }

+

+    //

+    // Get socket handle associated with this.

+    //

+    virtual pj_sock_t get_socket_handle()

+    {

+        return PJ_INVALID_SOCKET;

+    }

+

+    //

+    // Start async receive.

+    //

+    pj_status_t recv( Pj_Async_Op *op_key, 

+                      void *buf, pj_ssize_t *len, 

+                      unsigned flags)

+    {

+        return pj_ioqueue_recv( key_, op_key,

+                                buf, len, flags);

+    }

+

+    //

+    // Start async recvfrom()

+    //

+    pj_status_t recvfrom( Pj_Async_Op *op_key, 

+                          void *buf, pj_ssize_t *len, unsigned flags,

+                          Pj_Inet_Addr *addr)

+    {

+        addr->addrlen_ = sizeof(Pj_Inet_Addr);

+        return pj_ioqueue_recvfrom( key_, op_key, buf, len, flags,

+                                    addr, &addr->addrlen_ );

+    }

+

+    //

+    // Start async send()

+    //

+    pj_status_t send( Pj_Async_Op *op_key, 

+                      const void *data, pj_ssize_t *len, 

+                      unsigned flags)

+    {

+        return pj_ioqueue_send( key_, op_key, data, len, flags);

+    }

+

+    //

+    // Start async sendto()

+    //

+    pj_status_t sendto( Pj_Async_Op *op_key,

+                        const void *data, pj_ssize_t *len, unsigned flags,

+                        const Pj_Inet_Addr &addr)

+    {

+        return pj_ioqueue_sendto(key_, op_key, data, len, flags,

+                                 &addr, sizeof(addr));

+    }

+

+#if PJ_HAS_TCP

+    //

+    // Start async connect()

+    //

+    pj_status_t connect(const Pj_Inet_Addr &addr)

+    {

+        return pj_ioqueue_connect(key_, &addr, sizeof(addr));

+    }

+

+    //

+    // Start async accept().

+    //

+    pj_status_t accept( Pj_Async_Op *op_key,

+                        Pj_Socket *sock, 

+                        Pj_Inet_Addr *local = NULL, 

+                        Pj_Inet_Addr *remote = NULL)

+    {

+        int *addrlen = local ? &local->addrlen_ : NULL;

+        return pj_ioqueue_accept( key_, op_key, &sock->sock_,

+                                  local, remote, addrlen );

+    }

+

+#endif

+

+protected:

+    //////////////////

+    // Overridables

+    //////////////////

+

+    //

+    // Timeout callback.

+    //

+    virtual void on_timeout(int data) 

+    {

+    }

+

+    //

+    // On read complete callback.

+    //

+    virtual void on_read_complete( Pj_Async_Op *op_key,

+                                   pj_ssize_t bytes_read) 

+    {

+    }

+

+    //

+    // On write complete callback.

+    //

+    virtual void on_write_complete( Pj_Async_Op *op_key, 

+                                    pj_ssize_t bytes_sent) 

+    {

+    }

+

+#if PJ_HAS_TCP

+    //

+    // On connect complete callback.

+    //

+    virtual void on_connect_complete(pj_status_t status) 

+    {

+    }

+

+    //

+    // On new connection callback.

+    //

+    virtual void on_accept_complete( Pj_Async_Op *op_key,

+                                     pj_sock_t new_sock,

+                                     pj_status_t status) 

+    {

+    }

+

+#endif

+

+

+private:

+    pj_ioqueue_key_t *key_;

+    pj_timer_entry    timer_;

+

+    friend class Pj_Proactor;

+    friend class Pj_Async_Op;

+

+    //

+    // Static timer callback.

+    //

+    static void timer_callback( pj_timer_heap_t *timer_heap, 

+                                struct pj_timer_entry *entry)

+    {

+        Pj_Event_Handler *handler = 

+            (Pj_Event_Handler*) entry->user_data;

+

+        handler->on_timeout(entry->id);

+    }

+};

+

+inline bool Pj_Async_Op::is_pending()

+{

+    return pj_ioqueue_is_pending(handler_->key_, this) != 0;

+}

+

+inline bool Pj_Async_Op::cancel(pj_ssize_t bytes_status)

+{

+    return pj_ioqueue_post_completion(handler_->key_, this, 

+                                      bytes_status) == PJ_SUCCESS;

+}

+

+//////////////////////////////////////////////////////////////////////////////

+// Proactor

+//

+class Pj_Proactor : public Pj_Object

+{

+public:

+    //

+    // Default constructor, initializes to NULL.

+    //

+    Pj_Proactor()

+        : ioq_(NULL), th_(NULL)

+    {

+        cb_.on_read_complete    = &read_complete_cb;

+        cb_.on_write_complete   = &write_complete_cb;

+        cb_.on_accept_complete  = &accept_complete_cb;

+        cb_.on_connect_complete = &connect_complete_cb;

+    }

+

+    //

+    // Construct proactor.

+    //

+    Pj_Proactor( Pj_Pool *pool, pj_size_t max_fd,

+                 pj_size_t max_timer_entries )

+    : ioq_(NULL), th_(NULL)

+    {

+        cb_.on_read_complete    = &read_complete_cb;

+        cb_.on_write_complete   = &write_complete_cb;

+        cb_.on_accept_complete  = &accept_complete_cb;

+        cb_.on_connect_complete = &connect_complete_cb;

+

+        create(pool, max_fd, max_timer_entries);

+    }

+

+    //

+    // Destructor.

+    //

+    ~Pj_Proactor()

+    {

+        destroy();

+    }

+

+    //

+    // Create proactor.

+    //

+    pj_status_t create( Pj_Pool *pool, pj_size_t max_fd, 

+			pj_size_t timer_entry_count)

+    {

+        pj_status_t status;

+

+        destroy();

+

+        status = pj_ioqueue_create(pool->pool_(), max_fd, &ioq_);

+        if (status != PJ_SUCCESS) 

+            return status;

+        

+        status = pj_timer_heap_create(pool->pool_(), 

+                                      timer_entry_count, &th_);

+        if (status != PJ_SUCCESS) {

+            pj_ioqueue_destroy(ioq_);

+            ioq_ = NULL;

+            return NULL;

+        }

+        

+        return status;

+    }

+

+    //

+    // Destroy proactor.

+    //

+    void destroy()

+    {

+        if (ioq_) {

+            pj_ioqueue_destroy(ioq_);

+            ioq_ = NULL;

+        }

+        if (th_) {

+            pj_timer_heap_destroy(th_);

+            th_ = NULL;

+        }

+    }

+

+    //

+    // Register handler.

+    // This will call handler->get_socket_handle()

+    //

+    pj_status_t register_socket_handler(Pj_Pool *pool, 

+                                        Pj_Event_Handler *handler)

+    {

+        return   pj_ioqueue_register_sock( pool->pool_(), ioq_,

+                                           handler->get_socket_handle(),

+                                           handler, &cb_, &handler->key_ );

+    }

+

+    //

+    // Unregister handler.

+    //

+    static void unregister_handler(Pj_Event_Handler *handler)

+    {

+        if (handler->key_) {

+            pj_ioqueue_unregister( handler->key_ );

+            handler->key_ = NULL;

+        }

+    }

+

+    //

+    // Scheduler timer.

+    //

+    bool schedule_timer( Pj_Event_Handler *handler, 

+                         const Pj_Time_Val &delay, 

+                         int id=-1)

+    {

+        return schedule_timer(th_, handler, delay, id);

+    }

+

+    //

+    // Cancel timer.

+    //

+    bool cancel_timer(Pj_Event_Handler *handler)

+    {

+        return pj_timer_heap_cancel(th_, &handler->timer_) == 1;

+    }

+

+    //

+    // Handle events.

+    //

+    int handle_events(Pj_Time_Val *max_timeout)

+    {

+        Pj_Time_Val timeout(0, 0);

+        int timer_count;

+

+        timer_count = pj_timer_heap_poll( th_, &timeout );

+

+        if (timeout.get_sec() < 0) 

+            timeout.sec = PJ_MAXINT32;

+

+        /* If caller specifies maximum time to wait, then compare the value 

+         * with the timeout to wait from timer, and use the minimum value.

+         */

+        if (max_timeout && timeout >= *max_timeout) {

+	    timeout = *max_timeout;

+        }

+

+        /* Poll events in ioqueue. */

+        int ioqueue_count;

+

+        ioqueue_count = pj_ioqueue_poll(ioq_, &timeout);

+        if (ioqueue_count < 0)

+	    return ioqueue_count;

+

+        return ioqueue_count + timer_count;

+    }

+

+    //

+    // Get the internal ioqueue object.

+    //

+    pj_ioqueue_t *get_io_queue()

+    {

+        return ioq_;

+    }

+

+    //

+    // Get the internal timer heap object.

+    //

+    pj_timer_heap_t *get_timer_heap()

+    {

+        return th_;

+    }

+

+private:

+    pj_ioqueue_t *ioq_;

+    pj_timer_heap_t *th_;

+    pj_ioqueue_callback cb_;

+

+    static bool schedule_timer( pj_timer_heap_t *timer, 

+                                Pj_Event_Handler *handler,

+				const Pj_Time_Val &delay, 

+                                int id=-1)

+    {

+        handler->timer_.id = id;

+        return pj_timer_heap_schedule(timer, &handler->timer_, &delay) == 0;

+    }

+

+

+    //

+    // Static read completion callback.

+    //

+    static void read_complete_cb( pj_ioqueue_key_t *key, 

+                                  pj_ioqueue_op_key_t *op_key, 

+                                  pj_ssize_t bytes_read)

+    {

+        Pj_Event_Handler *handler = 

+	    (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);

+

+        handler->on_read_complete((Pj_Async_Op*)op_key, bytes_read);

+    }

+

+    //

+    // Static write completion callback.

+    //

+    static void write_complete_cb(pj_ioqueue_key_t *key, 

+                                  pj_ioqueue_op_key_t *op_key,

+                                  pj_ssize_t bytes_sent)

+    {

+        Pj_Event_Handler *handler = 

+	    (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);

+

+        handler->on_write_complete((Pj_Async_Op*)op_key, bytes_sent);

+    }

+

+    //

+    // Static accept completion callback.

+    //

+    static void accept_complete_cb(pj_ioqueue_key_t *key, 

+                                   pj_ioqueue_op_key_t *op_key,

+                                   pj_sock_t new_sock,

+                                   pj_status_t status)

+    {

+        Pj_Event_Handler *handler = 

+	    (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);

+

+        handler->on_accept_complete((Pj_Async_Op*)op_key, new_sock, status);

+    }

+

+    //

+    // Static connect completion callback.

+    //

+    static void connect_complete_cb(pj_ioqueue_key_t *key, 

+                                    pj_status_t status)

+    {

+        Pj_Event_Handler *handler = 

+	    (Pj_Event_Handler*) pj_ioqueue_get_user_data(key);

+

+        handler->on_connect_complete(status);

+    }

+

+};

+

+#endif	/* __PJPP_PROACTOR_HPP__ */

+

diff --git a/pjlib/include/pj++/scanner.hpp b/pjlib/include/pj++/scanner.hpp
index 8a3d989..2131d4d 100644
--- a/pjlib/include/pj++/scanner.hpp
+++ b/pjlib/include/pj++/scanner.hpp
@@ -1,173 +1,194 @@
-/* $Id$
- */
-#ifndef __PJPP_SCANNER_HPP__
-#define __PJPP_SCANNER_HPP__
-
-#include <pjlib-util/scanner.h>
-#include <pj++/string.hpp>
-
-class Pj_Char_Spec
-{
-public:
-    Pj_Char_Spec() { pj_cs_init(cs__); }
-
-    void set(int c) { pj_cs_set(cs__, c); }
-    void add_range(int begin, int end) { pj_cs_add_range(cs__, begin, end); }
-    void add_alpha() { pj_cs_add_alpha(cs__); }
-    void add_num() { pj_cs_add_num(cs__); }
-    void add_str(const char *str) { pj_cs_add_str(cs__, str); }
-    void del_range(int begin, int end) { pj_cs_del_range(cs__, begin, end); }
-    void del_str(const char *str) { pj_cs_del_str(cs__, str); }
-    void invert() { pj_cs_invert(cs__); }
-    int  match(int c) { return pj_cs_match(cs__, c); }
-
-    pj_char_spec_element_t *cs_()
-    {
-	return cs__;
-    }
-
-    const pj_char_spec_element_t *cs_() const
-    {
-	return cs__;
-    }
-
-private:
-    pj_char_spec cs__;
-};
-
-class Pj_Scanner
-{
-public:
-    Pj_Scanner() {}
-
-    enum
-    {
-	SYNTAX_ERROR = 101
-    };
-    static void syntax_error_handler_throw_pj(pj_scanner *);
-
-    typedef pj_scan_state State;
-
-    void init(char *buf, int len, unsigned options=PJ_SCAN_AUTOSKIP_WS, 
-	      pj_syn_err_func_ptr callback = &syntax_error_handler_throw_pj)
-    {
-	pj_scan_init(&scanner_, buf, len, options, callback);
-    }
-
-    void fini()
-    {
-	pj_scan_fini(&scanner_);
-    }
-
-    int eof() const
-    {
-	return pj_scan_is_eof(&scanner_);
-    }
-
-    int peek_char() const
-    {
-	return *scanner_.curptr;
-    }
-
-    int peek(const Pj_Char_Spec *cs, Pj_String *out)
-    {
-	return pj_scan_peek(&scanner_,  cs->cs_(), out);
-    }
-
-    int peek_n(pj_size_t len, Pj_String *out)
-    {
-	return pj_scan_peek_n(&scanner_, len, out);
-    }
-
-    int peek_until(const Pj_Char_Spec *cs, Pj_String *out)
-    {
-	return pj_scan_peek_until(&scanner_, cs->cs_(), out);
-    }
-
-    void get(const Pj_Char_Spec *cs, Pj_String *out)
-    {
-	pj_scan_get(&scanner_, cs->cs_(), out);
-    }
-
-    void get_n(unsigned N, Pj_String *out)
-    {
-	pj_scan_get_n(&scanner_, N, out);
-    }
-
-    int get_char()
-    {
-	return pj_scan_get_char(&scanner_);
-    }
-
-    void get_quote(int begin_quote, int end_quote, Pj_String *out)
-    {
-	pj_scan_get_quote(&scanner_, begin_quote, end_quote, out);
-    }
-
-    void get_newline()
-    {
-	pj_scan_get_newline(&scanner_);
-    }
-
-    void get_until(const Pj_Char_Spec *cs, Pj_String *out)
-    {
-	pj_scan_get_until(&scanner_, cs->cs_(), out);
-    }
-
-    void get_until_ch(int until_ch, Pj_String *out)
-    {
-	pj_scan_get_until_ch(&scanner_, until_ch, out);
-    }
-
-    void get_until_chr(const char *spec, Pj_String *out)
-    {
-	pj_scan_get_until_chr(&scanner_, spec, out);
-    }
-
-    void advance_n(unsigned N, bool skip_ws=true)
-    {
-	pj_scan_advance_n(&scanner_, N, skip_ws);
-    }
-
-    int strcmp(const char *s, int len)
-    {
-	return pj_scan_strcmp(&scanner_, s, len);
-    }
-
-    int stricmp(const char *s, int len)
-    {
-	return pj_scan_stricmp(&scanner_, s, len);
-    }
-
-    void skip_ws()
-    {
-	pj_scan_skip_whitespace(&scanner_);
-    }
-
-    void save_state(State *state)
-    {
-	pj_scan_save_state(&scanner_, state);
-    }
-
-    void restore_state(State *state)
-    {
-	pj_scan_restore_state(&scanner_, state);
-    }
-
-    int get_pos_line() const
-    {
-	return scanner_.line;
-    }
-
-    int get_pos_col() const
-    {
-	return scanner_.col;
-    }
-
-
-private:
-    pj_scanner scanner_;
-};
-
-#endif	/* __PJPP_SCANNER_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_SCANNER_HPP__

+#define __PJPP_SCANNER_HPP__

+

+#include <pjlib-util/scanner.h>

+#include <pj++/string.hpp>

+

+class Pj_Char_Spec

+{

+public:

+    Pj_Char_Spec() { pj_cs_init(cs__); }

+

+    void set(int c) { pj_cs_set(cs__, c); }

+    void add_range(int begin, int end) { pj_cs_add_range(cs__, begin, end); }

+    void add_alpha() { pj_cs_add_alpha(cs__); }

+    void add_num() { pj_cs_add_num(cs__); }

+    void add_str(const char *str) { pj_cs_add_str(cs__, str); }

+    void del_range(int begin, int end) { pj_cs_del_range(cs__, begin, end); }

+    void del_str(const char *str) { pj_cs_del_str(cs__, str); }

+    void invert() { pj_cs_invert(cs__); }

+    int  match(int c) { return pj_cs_match(cs__, c); }

+

+    pj_char_spec_element_t *cs_()

+    {

+	return cs__;

+    }

+

+    const pj_char_spec_element_t *cs_() const

+    {

+	return cs__;

+    }

+

+private:

+    pj_char_spec cs__;

+};

+

+class Pj_Scanner

+{

+public:

+    Pj_Scanner() {}

+

+    enum

+    {

+	SYNTAX_ERROR = 101

+    };

+    static void syntax_error_handler_throw_pj(pj_scanner *);

+

+    typedef pj_scan_state State;

+

+    void init(char *buf, int len, unsigned options=PJ_SCAN_AUTOSKIP_WS, 

+	      pj_syn_err_func_ptr callback = &syntax_error_handler_throw_pj)

+    {

+	pj_scan_init(&scanner_, buf, len, options, callback);

+    }

+

+    void fini()

+    {

+	pj_scan_fini(&scanner_);

+    }

+

+    int eof() const

+    {

+	return pj_scan_is_eof(&scanner_);

+    }

+

+    int peek_char() const

+    {

+	return *scanner_.curptr;

+    }

+

+    int peek(const Pj_Char_Spec *cs, Pj_String *out)

+    {

+	return pj_scan_peek(&scanner_,  cs->cs_(), out);

+    }

+

+    int peek_n(pj_size_t len, Pj_String *out)

+    {

+	return pj_scan_peek_n(&scanner_, len, out);

+    }

+

+    int peek_until(const Pj_Char_Spec *cs, Pj_String *out)

+    {

+	return pj_scan_peek_until(&scanner_, cs->cs_(), out);

+    }

+

+    void get(const Pj_Char_Spec *cs, Pj_String *out)

+    {

+	pj_scan_get(&scanner_, cs->cs_(), out);

+    }

+

+    void get_n(unsigned N, Pj_String *out)

+    {

+	pj_scan_get_n(&scanner_, N, out);

+    }

+

+    int get_char()

+    {

+	return pj_scan_get_char(&scanner_);

+    }

+

+    void get_quote(int begin_quote, int end_quote, Pj_String *out)

+    {

+	pj_scan_get_quote(&scanner_, begin_quote, end_quote, out);

+    }

+

+    void get_newline()

+    {

+	pj_scan_get_newline(&scanner_);

+    }

+

+    void get_until(const Pj_Char_Spec *cs, Pj_String *out)

+    {

+	pj_scan_get_until(&scanner_, cs->cs_(), out);

+    }

+

+    void get_until_ch(int until_ch, Pj_String *out)

+    {

+	pj_scan_get_until_ch(&scanner_, until_ch, out);

+    }

+

+    void get_until_chr(const char *spec, Pj_String *out)

+    {

+	pj_scan_get_until_chr(&scanner_, spec, out);

+    }

+

+    void advance_n(unsigned N, bool skip_ws=true)

+    {

+	pj_scan_advance_n(&scanner_, N, skip_ws);

+    }

+

+    int strcmp(const char *s, int len)

+    {

+	return pj_scan_strcmp(&scanner_, s, len);

+    }

+

+    int stricmp(const char *s, int len)

+    {

+	return pj_scan_stricmp(&scanner_, s, len);

+    }

+

+    void skip_ws()

+    {

+	pj_scan_skip_whitespace(&scanner_);

+    }

+

+    void save_state(State *state)

+    {

+	pj_scan_save_state(&scanner_, state);

+    }

+

+    void restore_state(State *state)

+    {

+	pj_scan_restore_state(&scanner_, state);

+    }

+

+    int get_pos_line() const

+    {

+	return scanner_.line;

+    }

+

+    int get_pos_col() const

+    {

+	return scanner_.col;

+    }

+

+

+private:

+    pj_scanner scanner_;

+};

+

+#endif	/* __PJPP_SCANNER_HPP__ */

+

diff --git a/pjlib/include/pj++/sock.hpp b/pjlib/include/pj++/sock.hpp
index f1a1e45..3a401b0 100644
--- a/pjlib/include/pj++/sock.hpp
+++ b/pjlib/include/pj++/sock.hpp
@@ -1,427 +1,448 @@
-/* $Id$
- */
-#ifndef __PJPP_SOCK_HPP__
-#define __PJPP_SOCK_HPP__
-
-#include <pj/sock.h>
-#include <pj/string.h>
-
-class Pj_Event_Handler;
-
-//
-// Base class for address.
-//
-class Pj_Addr
-{
-};
-
-//
-// Internet address.
-//
-class Pj_Inet_Addr : public pj_sockaddr_in, public Pj_Addr
-{
-public:
-    //
-    // Get port number.
-    //
-    pj_uint16_t get_port_number() const
-    {
-	return pj_sockaddr_in_get_port(this);
-    }
-
-    //
-    // Set port number.
-    //
-    void set_port_number(pj_uint16_t port)
-    {
-	sin_family = PJ_AF_INET;
-	pj_sockaddr_in_set_port(this, port);
-    }
-
-    //
-    // Get IP address.
-    //
-    pj_uint32_t get_ip_address() const
-    {
-	return pj_sockaddr_in_get_addr(this).s_addr;
-    }
-
-    //
-    // Get address string.
-    //
-    const char *get_address() const
-    {
-	return pj_inet_ntoa(sin_addr);
-    }
-
-    //
-    // Set IP address.
-    //
-    void set_ip_address(pj_uint32_t addr)
-    {
-	sin_family = PJ_AF_INET;
-	pj_sockaddr_in_set_addr(this, addr);
-    }
-
-    //
-    // Set address.
-    //
-    pj_status_t set_address(const pj_str_t *addr)
-    {
-	return pj_sockaddr_in_set_str_addr(this, addr);
-    }
-
-    //
-    // Set address.
-    //
-    pj_status_t set_address(const char *addr)
-    {
-        pj_str_t s;
-	return pj_sockaddr_in_set_str_addr(this, pj_cstr(&s, addr));
-    }
-
-    //
-    // Compare for equality.
-    //
-    bool operator==(const Pj_Inet_Addr &rhs) const
-    {
-	return sin_family == rhs.sin_family &&
-               sin_addr.s_addr == rhs.sin_addr.s_addr &&
-               sin_port == rhs.sin_port;
-    }
-
-private:
-    //
-    // Dummy length used in pj_ioqueue_recvfrom() etc
-    //
-    friend class Pj_Event_Handler;
-    friend class Pj_Socket;
-    friend class Pj_Sock_Stream;
-    friend class Pj_Sock_Dgram;
-
-    int addrlen_;
-};
-
-
-//
-// Socket base class.
-//
-// Note:
-//  socket will not automatically be closed on destructor.
-//
-class Pj_Socket
-{
-public:
-    //
-    // Default constructor.
-    //
-    Pj_Socket()
-        : sock_(PJ_INVALID_SOCKET) 
-    {
-    }
-
-    //
-    // Initialize from a socket handle.
-    //
-    explicit Pj_Socket(pj_sock_t sock)
-        : sock_(sock)
-    {
-    }
-
-    //
-    // Copy constructor.
-    //
-    Pj_Socket(const Pj_Socket &rhs) 
-        : sock_(rhs.sock_) 
-    {
-    }
-
-    //
-    // Destructor will not close the socket.
-    // You must call close() explicitly.
-    //
-    ~Pj_Socket()
-    {
-    }
-
-    //
-    // Set socket handle.
-    //
-    void set_handle(pj_sock_t sock)
-    {
-	sock_ = sock;
-    }
-
-    //
-    // Get socket handle.
-    //
-    pj_sock_t get_handle() const
-    {
-	return sock_;
-    }
-
-    //
-    // Get socket handle.
-    //
-    pj_sock_t& get_handle()
-    {
-	return sock_;
-    }
-
-    //
-    // See if the socket is valid.
-    //
-    bool is_valid() const
-    {
-        return sock_ != PJ_INVALID_SOCKET;
-    }
-
-    //
-    // Create the socket.
-    //
-    pj_status_t create(int af, int type, int proto)
-    {
-	return pj_sock_socket(af, type, proto, &sock_);
-    }
-
-    //
-    // Bind socket.
-    //
-    pj_status_t bind(const Pj_Inet_Addr &addr)
-    {
-	return pj_sock_bind(sock_, &addr, sizeof(Pj_Inet_Addr));
-    }
-
-    //
-    // Close socket.
-    //
-    pj_status_t close()
-    {
-	pj_sock_close(sock_);
-    }
-
-    //
-    // Get peer socket name.
-    //
-    pj_status_t getpeername(Pj_Inet_Addr *addr)
-    {
-	return pj_sock_getpeername(sock_, addr, &addr->addrlen_);
-    }
-
-    //
-    // getsockname
-    //
-    pj_status_t getsockname(Pj_Inet_Addr *addr)
-    {
-	return pj_sock_getsockname(sock_, addr, &addr->addrlen_);
-    }
-
-    //
-    // getsockopt.
-    //
-    pj_status_t getsockopt(int level, int optname, 
-                           void *optval, int *optlen)
-    {
-	return pj_sock_getsockopt(sock_, level, optname, optval, optlen);
-    }
-
-    //
-    // setsockopt
-    // 
-    pj_status_t setsockopt(int level, int optname, 
-                           const void *optval, int optlen)
-    {
-	return pj_sock_setsockopt(sock_, level, optname, optval, optlen);
-    }
-
-    //
-    // receive data.
-    //
-    pj_ssize_t recv(void *buf, pj_size_t len, int flag = 0)
-    {
-        pj_ssize_t bytes = len;
-	if (pj_sock_recv(sock_, buf, &bytes, flag) != PJ_SUCCESS)
-            return -1;
-        return bytes;
-    }
-
-    //
-    // send data.
-    //
-    pj_ssize_t send(const void *buf, pj_ssize_t len, int flag = 0)
-    {
-        pj_ssize_t bytes = len;
-	if (pj_sock_send(sock_, buf, &bytes, flag) != PJ_SUCCESS)
-            return -1;
-        return bytes;
-    }
-
-    //
-    // connect.
-    //
-    pj_status_t connect(const Pj_Inet_Addr &addr)
-    {
-	return pj_sock_connect(sock_, &addr, sizeof(Pj_Inet_Addr));
-    }
-
-    //
-    // assignment.
-    //
-    Pj_Socket &operator=(const Pj_Socket &rhs)
-    {
-        sock_ = rhs.sock_;
-        return *this;
-    }
-
-protected:
-    friend class Pj_Event_Handler;
-    pj_sock_t sock_;
-};
-
-
-#if PJ_HAS_TCP
-//
-// Stream socket.
-//
-class Pj_Sock_Stream : public Pj_Socket
-{
-public:
-    //
-    // Default constructor.
-    //
-    Pj_Sock_Stream() 
-    {
-    }
-
-    //
-    // Initialize from a socket handle.
-    //
-    explicit Pj_Sock_Stream(pj_sock_t sock)
-        : Pj_Socket(sock)
-    {
-    }
-
-    //
-    // Copy constructor.
-    //
-    Pj_Sock_Stream(const Pj_Sock_Stream &rhs) : Pj_Socket(rhs) 
-    {
-    }
-
-    //
-    // Assignment.
-    //
-    Pj_Sock_Stream &operator=(const Pj_Sock_Stream &rhs) 
-    { 
-        sock_ = rhs.sock_; 
-        return *this; 
-    }
-
-    //
-    // listen()
-    //
-    pj_status_t listen(int backlog = 5)
-    {
-	return pj_sock_listen(sock_, backlog);
-    }
-
-    //
-    // blocking accept()
-    //
-    Pj_Sock_Stream accept(Pj_Inet_Addr *remote_addr = NULL)
-    {
-        pj_sock_t newsock;
-        int *addrlen = remote_addr ? &remote_addr->addrlen_ : NULL;
-        pj_status_t status;
-        
-        status = pj_sock_accept(sock_, &newsock, remote_addr, addrlen);
-        if (status != PJ_SUCCESS)
-            return Pj_Sock_Stream(-1);
-
-        return Pj_Sock_Stream(newsock);
-    }
-
-    //
-    // shutdown()
-    //
-    pj_status_t shutdown(int how = PJ_SHUT_RDWR)
-    {
-	return pj_sock_shutdown(sock_, how);
-    }
-
-};
-#endif
-
-//
-// Datagram socket.
-//
-class Pj_Sock_Dgram : public Pj_Socket
-{
-public:
-    //
-    // Default constructor.
-    //
-    Pj_Sock_Dgram() 
-    {
-    }
-
-    //
-    // Initialize from a socket handle.
-    //
-    explicit Pj_Sock_Dgram(pj_sock_t sock)
-        : Pj_Socket(sock)
-    {
-    }
-
-    //
-    // Copy constructor.
-    //
-    Pj_Sock_Dgram(const Pj_Sock_Dgram &rhs) 
-        : Pj_Socket(rhs) 
-    {
-    }
-
-    //
-    // Assignment.
-    //
-    Pj_Sock_Dgram &operator=(const Pj_Sock_Dgram &rhs) 
-    { 
-        Pj_Socket::operator =(rhs);
-        return *this; 
-    }
-
-    //
-    // recvfrom()
-    //
-    pj_ssize_t recvfrom( void *buf, pj_size_t len, int flag = 0, 
-                         Pj_Inet_Addr *fromaddr = NULL)
-    {
-        pj_ssize_t bytes = len;
-        int *addrlen = fromaddr ? &fromaddr->addrlen_ : NULL;
-	if (pj_sock_recvfrom( sock_, buf, &bytes, flag, 
-                              fromaddr, addrlen) != PJ_SUCCESS)
-        {
-            return -1;
-        }
-        return bytes;
-    }
-
-    //
-    // sendto()
-    //
-    pj_ssize_t sendto( const void *buf, pj_size_t len, int flag, 
-                       const Pj_Inet_Addr &addr)
-    {
-        pj_ssize_t bytes = len;
-	if (pj_sock_sendto( sock_, buf, &bytes, flag, 
-                            &addr, sizeof(pj_sockaddr_in)) != PJ_SUCCESS)
-        {
-            return -1;
-        }
-        return bytes;
-    }
-};
-
-
-#endif	/* __PJPP_SOCK_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_SOCK_HPP__

+#define __PJPP_SOCK_HPP__

+

+#include <pj/sock.h>

+#include <pj/string.h>

+

+class Pj_Event_Handler;

+

+//

+// Base class for address.

+//

+class Pj_Addr

+{

+};

+

+//

+// Internet address.

+//

+class Pj_Inet_Addr : public pj_sockaddr_in, public Pj_Addr

+{

+public:

+    //

+    // Get port number.

+    //

+    pj_uint16_t get_port_number() const

+    {

+	return pj_sockaddr_in_get_port(this);

+    }

+

+    //

+    // Set port number.

+    //

+    void set_port_number(pj_uint16_t port)

+    {

+	sin_family = PJ_AF_INET;

+	pj_sockaddr_in_set_port(this, port);

+    }

+

+    //

+    // Get IP address.

+    //

+    pj_uint32_t get_ip_address() const

+    {

+	return pj_sockaddr_in_get_addr(this).s_addr;

+    }

+

+    //

+    // Get address string.

+    //

+    const char *get_address() const

+    {

+	return pj_inet_ntoa(sin_addr);

+    }

+

+    //

+    // Set IP address.

+    //

+    void set_ip_address(pj_uint32_t addr)

+    {

+	sin_family = PJ_AF_INET;

+	pj_sockaddr_in_set_addr(this, addr);

+    }

+

+    //

+    // Set address.

+    //

+    pj_status_t set_address(const pj_str_t *addr)

+    {

+	return pj_sockaddr_in_set_str_addr(this, addr);

+    }

+

+    //

+    // Set address.

+    //

+    pj_status_t set_address(const char *addr)

+    {

+        pj_str_t s;

+	return pj_sockaddr_in_set_str_addr(this, pj_cstr(&s, addr));

+    }

+

+    //

+    // Compare for equality.

+    //

+    bool operator==(const Pj_Inet_Addr &rhs) const

+    {

+	return sin_family == rhs.sin_family &&

+               sin_addr.s_addr == rhs.sin_addr.s_addr &&

+               sin_port == rhs.sin_port;

+    }

+

+private:

+    //

+    // Dummy length used in pj_ioqueue_recvfrom() etc

+    //

+    friend class Pj_Event_Handler;

+    friend class Pj_Socket;

+    friend class Pj_Sock_Stream;

+    friend class Pj_Sock_Dgram;

+

+    int addrlen_;

+};

+

+

+//

+// Socket base class.

+//

+// Note:

+//  socket will not automatically be closed on destructor.

+//

+class Pj_Socket

+{

+public:

+    //

+    // Default constructor.

+    //

+    Pj_Socket()

+        : sock_(PJ_INVALID_SOCKET) 

+    {

+    }

+

+    //

+    // Initialize from a socket handle.

+    //

+    explicit Pj_Socket(pj_sock_t sock)

+        : sock_(sock)

+    {

+    }

+

+    //

+    // Copy constructor.

+    //

+    Pj_Socket(const Pj_Socket &rhs) 

+        : sock_(rhs.sock_) 

+    {

+    }

+

+    //

+    // Destructor will not close the socket.

+    // You must call close() explicitly.

+    //

+    ~Pj_Socket()

+    {

+    }

+

+    //

+    // Set socket handle.

+    //

+    void set_handle(pj_sock_t sock)

+    {

+	sock_ = sock;

+    }

+

+    //

+    // Get socket handle.

+    //

+    pj_sock_t get_handle() const

+    {

+	return sock_;

+    }

+

+    //

+    // Get socket handle.

+    //

+    pj_sock_t& get_handle()

+    {

+	return sock_;

+    }

+

+    //

+    // See if the socket is valid.

+    //

+    bool is_valid() const

+    {

+        return sock_ != PJ_INVALID_SOCKET;

+    }

+

+    //

+    // Create the socket.

+    //

+    pj_status_t create(int af, int type, int proto)

+    {

+	return pj_sock_socket(af, type, proto, &sock_);

+    }

+

+    //

+    // Bind socket.

+    //

+    pj_status_t bind(const Pj_Inet_Addr &addr)

+    {

+	return pj_sock_bind(sock_, &addr, sizeof(Pj_Inet_Addr));

+    }

+

+    //

+    // Close socket.

+    //

+    pj_status_t close()

+    {

+	pj_sock_close(sock_);

+    }

+

+    //

+    // Get peer socket name.

+    //

+    pj_status_t getpeername(Pj_Inet_Addr *addr)

+    {

+	return pj_sock_getpeername(sock_, addr, &addr->addrlen_);

+    }

+

+    //

+    // getsockname

+    //

+    pj_status_t getsockname(Pj_Inet_Addr *addr)

+    {

+	return pj_sock_getsockname(sock_, addr, &addr->addrlen_);

+    }

+

+    //

+    // getsockopt.

+    //

+    pj_status_t getsockopt(int level, int optname, 

+                           void *optval, int *optlen)

+    {

+	return pj_sock_getsockopt(sock_, level, optname, optval, optlen);

+    }

+

+    //

+    // setsockopt

+    // 

+    pj_status_t setsockopt(int level, int optname, 

+                           const void *optval, int optlen)

+    {

+	return pj_sock_setsockopt(sock_, level, optname, optval, optlen);

+    }

+

+    //

+    // receive data.

+    //

+    pj_ssize_t recv(void *buf, pj_size_t len, int flag = 0)

+    {

+        pj_ssize_t bytes = len;

+	if (pj_sock_recv(sock_, buf, &bytes, flag) != PJ_SUCCESS)

+            return -1;

+        return bytes;

+    }

+

+    //

+    // send data.

+    //

+    pj_ssize_t send(const void *buf, pj_ssize_t len, int flag = 0)

+    {

+        pj_ssize_t bytes = len;

+	if (pj_sock_send(sock_, buf, &bytes, flag) != PJ_SUCCESS)

+            return -1;

+        return bytes;

+    }

+

+    //

+    // connect.

+    //

+    pj_status_t connect(const Pj_Inet_Addr &addr)

+    {

+	return pj_sock_connect(sock_, &addr, sizeof(Pj_Inet_Addr));

+    }

+

+    //

+    // assignment.

+    //

+    Pj_Socket &operator=(const Pj_Socket &rhs)

+    {

+        sock_ = rhs.sock_;

+        return *this;

+    }

+

+protected:

+    friend class Pj_Event_Handler;

+    pj_sock_t sock_;

+};

+

+

+#if PJ_HAS_TCP

+//

+// Stream socket.

+//

+class Pj_Sock_Stream : public Pj_Socket

+{

+public:

+    //

+    // Default constructor.

+    //

+    Pj_Sock_Stream() 

+    {

+    }

+

+    //

+    // Initialize from a socket handle.

+    //

+    explicit Pj_Sock_Stream(pj_sock_t sock)

+        : Pj_Socket(sock)

+    {

+    }

+

+    //

+    // Copy constructor.

+    //

+    Pj_Sock_Stream(const Pj_Sock_Stream &rhs) : Pj_Socket(rhs) 

+    {

+    }

+

+    //

+    // Assignment.

+    //

+    Pj_Sock_Stream &operator=(const Pj_Sock_Stream &rhs) 

+    { 

+        sock_ = rhs.sock_; 

+        return *this; 

+    }

+

+    //

+    // listen()

+    //

+    pj_status_t listen(int backlog = 5)

+    {

+	return pj_sock_listen(sock_, backlog);

+    }

+

+    //

+    // blocking accept()

+    //

+    Pj_Sock_Stream accept(Pj_Inet_Addr *remote_addr = NULL)

+    {

+        pj_sock_t newsock;

+        int *addrlen = remote_addr ? &remote_addr->addrlen_ : NULL;

+        pj_status_t status;

+        

+        status = pj_sock_accept(sock_, &newsock, remote_addr, addrlen);

+        if (status != PJ_SUCCESS)

+            return Pj_Sock_Stream(-1);

+

+        return Pj_Sock_Stream(newsock);

+    }

+

+    //

+    // shutdown()

+    //

+    pj_status_t shutdown(int how = PJ_SHUT_RDWR)

+    {

+	return pj_sock_shutdown(sock_, how);

+    }

+

+};

+#endif

+

+//

+// Datagram socket.

+//

+class Pj_Sock_Dgram : public Pj_Socket

+{

+public:

+    //

+    // Default constructor.

+    //

+    Pj_Sock_Dgram() 

+    {

+    }

+

+    //

+    // Initialize from a socket handle.

+    //

+    explicit Pj_Sock_Dgram(pj_sock_t sock)

+        : Pj_Socket(sock)

+    {

+    }

+

+    //

+    // Copy constructor.

+    //

+    Pj_Sock_Dgram(const Pj_Sock_Dgram &rhs) 

+        : Pj_Socket(rhs) 

+    {

+    }

+

+    //

+    // Assignment.

+    //

+    Pj_Sock_Dgram &operator=(const Pj_Sock_Dgram &rhs) 

+    { 

+        Pj_Socket::operator =(rhs);

+        return *this; 

+    }

+

+    //

+    // recvfrom()

+    //

+    pj_ssize_t recvfrom( void *buf, pj_size_t len, int flag = 0, 

+                         Pj_Inet_Addr *fromaddr = NULL)

+    {

+        pj_ssize_t bytes = len;

+        int *addrlen = fromaddr ? &fromaddr->addrlen_ : NULL;

+	if (pj_sock_recvfrom( sock_, buf, &bytes, flag, 

+                              fromaddr, addrlen) != PJ_SUCCESS)

+        {

+            return -1;

+        }

+        return bytes;

+    }

+

+    //

+    // sendto()

+    //

+    pj_ssize_t sendto( const void *buf, pj_size_t len, int flag, 

+                       const Pj_Inet_Addr &addr)

+    {

+        pj_ssize_t bytes = len;

+	if (pj_sock_sendto( sock_, buf, &bytes, flag, 

+                            &addr, sizeof(pj_sockaddr_in)) != PJ_SUCCESS)

+        {

+            return -1;

+        }

+        return bytes;

+    }

+};

+

+

+#endif	/* __PJPP_SOCK_HPP__ */

+

diff --git a/pjlib/include/pj++/string.hpp b/pjlib/include/pj++/string.hpp
index 6be1e50..dbb2d57 100644
--- a/pjlib/include/pj++/string.hpp
+++ b/pjlib/include/pj++/string.hpp
@@ -1,409 +1,430 @@
-/* $Id$
- */
-#ifndef __PJPP_STRING_HPP__
-#define __PJPP_STRING_HPP__
-
-#include <pj/string.h>
-#include <pj++/pool.hpp>
-#include <pj/assert.h>
-
-//
-// String wrapper class for pj_str_t.
-//
-class Pj_String : public pj_str_t
-{
-public:
-    //
-    // Default constructor.
-    //
-    Pj_String() 
-    { 
-	pj_assert(sizeof(Pj_String) == sizeof(pj_str_t));
-	ptr=NULL; 
-        slen=0; 
-    }
-
-    //
-    // Construct the buffer from a char*.
-    //
-    explicit Pj_String(char *str) 
-    { 
-	set(str);
-    }
-
-    //
-    // Construct from a const char*.
-    //
-    Pj_String(Pj_Pool *pool, const char *src)
-    {
-	set(pool, src);
-    }
-
-    //
-    // Construct from pj_str_t*.
-    //
-    explicit Pj_String(pj_str_t *s)
-    {
-	set(s);
-    }
-
-    //
-    // Construct by copying from const pj_str_t*.
-    //
-    Pj_String(Pj_Pool *pool, const pj_str_t *s)
-    {
-	set(pool, s);
-    }
-
-    //
-    // Construct from another Pj_String
-    //
-    explicit Pj_String(Pj_String &rhs)
-    {
-	set(rhs);
-    }
-
-    //
-    // Construct by copying from Pj_String
-    //
-    Pj_String(Pj_Pool *pool, const Pj_String &rhs)
-    {
-	set(pool, rhs);
-    }
-
-    //
-    // Construct from a char* and a length.
-    //
-    Pj_String(char *str, pj_size_t len)
-    {
-	set(str, len);
-    }
-
-    //
-    // Construct from pair of pointer.
-    //
-    Pj_String(char *begin, char *end)
-    {
-	pj_strset3(this, begin, end);
-    }
-
-    //
-    // Get the length of the string.
-    //
-    pj_size_t length() const
-    {
-	return pj_strlen(this);
-    }
-
-    //
-    // Get the length of the string.
-    //
-    pj_size_t size() const
-    {
-	return length();
-    }
-
-    //
-    // Get the string buffer.
-    //
-    const char *buf() const
-    {
-	return ptr;
-    }
-
-    //
-    // Initialize buffer from char*.
-    //
-    void set(char *str)
-    {
-	pj_strset2(this, str);
-    }
-
-    //
-    // Initialize by copying from a const char*.
-    //
-    void set(Pj_Pool *pool, const char *s)
-    {
-	pj_strdup2(pool->pool_(), this, s);
-    }
-
-    //
-    // Initialize from pj_str_t*.
-    //
-    void set(pj_str_t *s)
-    {
-	pj_strassign(this, s);
-    }
-
-    //
-    // Initialize by copying from const pj_str_t*.
-    //
-    void set(Pj_Pool *pool, const pj_str_t *s)
-    {
-	pj_strdup(pool->pool_(), this, s);
-    }
-
-    //
-    // Initialize from char* and length.
-    //
-    void set(char *str, pj_size_t len)
-    {
-	pj_strset(this, str, len);
-    }
-
-    //
-    // Initialize from pair of pointers.
-    //
-    void set(char *begin, char *end)
-    {
-	pj_strset3(this, begin, end);
-    }
-
-    //
-    // Initialize from other Pj_String.
-    //
-    void set(Pj_String &rhs)
-    {
-	pj_strassign(this, &rhs);
-    }
-
-    //
-    // Initialize by copying from a Pj_String*.
-    //
-    void set(Pj_Pool *pool, const Pj_String *s)
-    {
-	pj_strdup(pool->pool_(), this, s);
-    }
-
-    //
-    // Initialize by copying from other Pj_String.
-    //
-    void set(Pj_Pool *pool, const Pj_String &s)
-    {
-	pj_strdup(pool->pool_(), this, &s);
-    }
-
-    //
-    // Copy the contents of other string.
-    //
-    void strcpy(const pj_str_t *s)
-    {
-	pj_strcpy(this, s);
-    }
-
-    //
-    // Copy the contents of other string.
-    //
-    void strcpy(const Pj_String &rhs)
-    {
-	pj_strcpy(this, &rhs);
-    }
-
-    //
-    // Copy the contents of other string.
-    //
-    void strcpy(const char *s)
-    {
-	pj_strcpy2(this, s);
-    }
-
-    //
-    // Compare string.
-    //
-    int strcmp(const char *s) const
-    {
-	return pj_strcmp2(this, s);
-    }
-
-    //
-    // Compare string.
-    //
-    int strcmp(const pj_str_t *s) const
-    {
-	return pj_strcmp(this, s);
-    }
-
-    //
-    // Compare string.
-    //
-    int strcmp(const Pj_String &rhs) const
-    {
-	return pj_strcmp(this, &rhs);
-    }
-
-    //
-    // Compare string.
-    //
-    int strncmp(const char *s, pj_size_t len) const
-    {
-	return pj_strncmp2(this, s, len);
-    }
-
-    //
-    // Compare string.
-    //
-    int strncmp(const pj_str_t *s, pj_size_t len) const
-    {
-	return pj_strncmp(this, s, len);
-    }
-
-    //
-    // Compare string.
-    //
-    int strncmp(const Pj_String &rhs, pj_size_t len) const
-    {
-	return pj_strncmp(this, &rhs, len);
-    }
-
-    //
-    // Compare string.
-    //
-    int stricmp(const char *s) const
-    {
-	return pj_stricmp2(this, s);
-    }
-
-    //
-    // Compare string.
-    //
-    int stricmp(const pj_str_t *s) const
-    {
-	return pj_stricmp(this, s);
-    }
-
-    //
-    // Compare string.
-    //
-    int stricmp(const Pj_String &rhs) const
-    {
-	return stricmp(&rhs);
-    }
-
-    //
-    // Compare string.
-    //
-    int strnicmp(const char *s, pj_size_t len) const
-    {
-	return pj_strnicmp2(this, s, len);
-    }
-
-    //
-    // Compare string.
-    //
-    int strnicmp(const pj_str_t *s, pj_size_t len) const
-    {
-	return pj_strnicmp(this, s, len);
-    }
-
-    //
-    // Compare string.
-    //
-    int strnicmp(const Pj_String &rhs, pj_size_t len) const
-    {
-	return strnicmp(&rhs, len);
-    }
-
-    //
-    // Compare contents for equality.
-    //
-    bool operator==(const char *s) const
-    {
-	return strcmp(s) == 0;
-    }
-
-    //
-    // Compare contents for equality.
-    //
-    bool operator==(const pj_str_t *s) const
-    {
-	return strcmp(s) == 0;
-    }
-
-    //
-    // Compare contents for equality.
-    //
-    bool operator==(const Pj_String &rhs) const
-    {
-	return pj_strcmp(this, &rhs) == 0;
-    }
-
-    //
-    // Find a character in the string.
-    //
-    char *strchr(int chr)
-    {
-	return pj_strchr(this, chr);
-    }
-
-    //
-    // Find a character in the string.
-    //
-    char *find(int chr)
-    {
-	return strchr(chr);
-    }
-
-    //
-    // Concatenate string.
-    //
-    void strcat(const Pj_String &rhs)
-    {
-	pj_strcat(this, &rhs);
-    }
-
-    //
-    // Left trim.
-    //
-    void ltrim()
-    {
-	pj_strltrim(this);
-    }
-
-    //
-    // Right trim.
-    //
-    void rtrim()
-    {
-	pj_strrtrim(this);
-    }
-
-    //
-    // Left and right trim.
-    //
-    void trim()
-    {
-	pj_strtrim(this);
-    }
-
-    //
-    // Convert to unsigned long.
-    //
-    unsigned long to_ulong() const
-    {
-	return pj_strtoul(this);
-    }
-
-    //
-    // Convert from unsigned long.
-    //
-    void from_ulong(unsigned long value)
-    {
-        slen = pj_utoa(value, ptr);
-    }
-
-    //
-    // Convert from unsigned long with padding.
-    //
-    void from_ulong_with_pad(unsigned long value, int min_dig=0, int pad=' ')
-    {
-        slen = pj_utoa_pad(value, ptr, min_dig, pad);
-    }
-
-
-private:
-    //Pj_String(const Pj_String &rhs) {}
-    void operator=(const Pj_String &rhs) { pj_assert(false); }
-};
-
-#endif	/* __PJPP_STRING_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_STRING_HPP__

+#define __PJPP_STRING_HPP__

+

+#include <pj/string.h>

+#include <pj++/pool.hpp>

+#include <pj/assert.h>

+

+//

+// String wrapper class for pj_str_t.

+//

+class Pj_String : public pj_str_t

+{

+public:

+    //

+    // Default constructor.

+    //

+    Pj_String() 

+    { 

+	pj_assert(sizeof(Pj_String) == sizeof(pj_str_t));

+	ptr=NULL; 

+        slen=0; 

+    }

+

+    //

+    // Construct the buffer from a char*.

+    //

+    explicit Pj_String(char *str) 

+    { 

+	set(str);

+    }

+

+    //

+    // Construct from a const char*.

+    //

+    Pj_String(Pj_Pool *pool, const char *src)

+    {

+	set(pool, src);

+    }

+

+    //

+    // Construct from pj_str_t*.

+    //

+    explicit Pj_String(pj_str_t *s)

+    {

+	set(s);

+    }

+

+    //

+    // Construct by copying from const pj_str_t*.

+    //

+    Pj_String(Pj_Pool *pool, const pj_str_t *s)

+    {

+	set(pool, s);

+    }

+

+    //

+    // Construct from another Pj_String

+    //

+    explicit Pj_String(Pj_String &rhs)

+    {

+	set(rhs);

+    }

+

+    //

+    // Construct by copying from Pj_String

+    //

+    Pj_String(Pj_Pool *pool, const Pj_String &rhs)

+    {

+	set(pool, rhs);

+    }

+

+    //

+    // Construct from a char* and a length.

+    //

+    Pj_String(char *str, pj_size_t len)

+    {

+	set(str, len);

+    }

+

+    //

+    // Construct from pair of pointer.

+    //

+    Pj_String(char *begin, char *end)

+    {

+	pj_strset3(this, begin, end);

+    }

+

+    //

+    // Get the length of the string.

+    //

+    pj_size_t length() const

+    {

+	return pj_strlen(this);

+    }

+

+    //

+    // Get the length of the string.

+    //

+    pj_size_t size() const

+    {

+	return length();

+    }

+

+    //

+    // Get the string buffer.

+    //

+    const char *buf() const

+    {

+	return ptr;

+    }

+

+    //

+    // Initialize buffer from char*.

+    //

+    void set(char *str)

+    {

+	pj_strset2(this, str);

+    }

+

+    //

+    // Initialize by copying from a const char*.

+    //

+    void set(Pj_Pool *pool, const char *s)

+    {

+	pj_strdup2(pool->pool_(), this, s);

+    }

+

+    //

+    // Initialize from pj_str_t*.

+    //

+    void set(pj_str_t *s)

+    {

+	pj_strassign(this, s);

+    }

+

+    //

+    // Initialize by copying from const pj_str_t*.

+    //

+    void set(Pj_Pool *pool, const pj_str_t *s)

+    {

+	pj_strdup(pool->pool_(), this, s);

+    }

+

+    //

+    // Initialize from char* and length.

+    //

+    void set(char *str, pj_size_t len)

+    {

+	pj_strset(this, str, len);

+    }

+

+    //

+    // Initialize from pair of pointers.

+    //

+    void set(char *begin, char *end)

+    {

+	pj_strset3(this, begin, end);

+    }

+

+    //

+    // Initialize from other Pj_String.

+    //

+    void set(Pj_String &rhs)

+    {

+	pj_strassign(this, &rhs);

+    }

+

+    //

+    // Initialize by copying from a Pj_String*.

+    //

+    void set(Pj_Pool *pool, const Pj_String *s)

+    {

+	pj_strdup(pool->pool_(), this, s);

+    }

+

+    //

+    // Initialize by copying from other Pj_String.

+    //

+    void set(Pj_Pool *pool, const Pj_String &s)

+    {

+	pj_strdup(pool->pool_(), this, &s);

+    }

+

+    //

+    // Copy the contents of other string.

+    //

+    void strcpy(const pj_str_t *s)

+    {

+	pj_strcpy(this, s);

+    }

+

+    //

+    // Copy the contents of other string.

+    //

+    void strcpy(const Pj_String &rhs)

+    {

+	pj_strcpy(this, &rhs);

+    }

+

+    //

+    // Copy the contents of other string.

+    //

+    void strcpy(const char *s)

+    {

+	pj_strcpy2(this, s);

+    }

+

+    //

+    // Compare string.

+    //

+    int strcmp(const char *s) const

+    {

+	return pj_strcmp2(this, s);

+    }

+

+    //

+    // Compare string.

+    //

+    int strcmp(const pj_str_t *s) const

+    {

+	return pj_strcmp(this, s);

+    }

+

+    //

+    // Compare string.

+    //

+    int strcmp(const Pj_String &rhs) const

+    {

+	return pj_strcmp(this, &rhs);

+    }

+

+    //

+    // Compare string.

+    //

+    int strncmp(const char *s, pj_size_t len) const

+    {

+	return pj_strncmp2(this, s, len);

+    }

+

+    //

+    // Compare string.

+    //

+    int strncmp(const pj_str_t *s, pj_size_t len) const

+    {

+	return pj_strncmp(this, s, len);

+    }

+

+    //

+    // Compare string.

+    //

+    int strncmp(const Pj_String &rhs, pj_size_t len) const

+    {

+	return pj_strncmp(this, &rhs, len);

+    }

+

+    //

+    // Compare string.

+    //

+    int stricmp(const char *s) const

+    {

+	return pj_stricmp2(this, s);

+    }

+

+    //

+    // Compare string.

+    //

+    int stricmp(const pj_str_t *s) const

+    {

+	return pj_stricmp(this, s);

+    }

+

+    //

+    // Compare string.

+    //

+    int stricmp(const Pj_String &rhs) const

+    {

+	return stricmp(&rhs);

+    }

+

+    //

+    // Compare string.

+    //

+    int strnicmp(const char *s, pj_size_t len) const

+    {

+	return pj_strnicmp2(this, s, len);

+    }

+

+    //

+    // Compare string.

+    //

+    int strnicmp(const pj_str_t *s, pj_size_t len) const

+    {

+	return pj_strnicmp(this, s, len);

+    }

+

+    //

+    // Compare string.

+    //

+    int strnicmp(const Pj_String &rhs, pj_size_t len) const

+    {

+	return strnicmp(&rhs, len);

+    }

+

+    //

+    // Compare contents for equality.

+    //

+    bool operator==(const char *s) const

+    {

+	return strcmp(s) == 0;

+    }

+

+    //

+    // Compare contents for equality.

+    //

+    bool operator==(const pj_str_t *s) const

+    {

+	return strcmp(s) == 0;

+    }

+

+    //

+    // Compare contents for equality.

+    //

+    bool operator==(const Pj_String &rhs) const

+    {

+	return pj_strcmp(this, &rhs) == 0;

+    }

+

+    //

+    // Find a character in the string.

+    //

+    char *strchr(int chr)

+    {

+	return pj_strchr(this, chr);

+    }

+

+    //

+    // Find a character in the string.

+    //

+    char *find(int chr)

+    {

+	return strchr(chr);

+    }

+

+    //

+    // Concatenate string.

+    //

+    void strcat(const Pj_String &rhs)

+    {

+	pj_strcat(this, &rhs);

+    }

+

+    //

+    // Left trim.

+    //

+    void ltrim()

+    {

+	pj_strltrim(this);

+    }

+

+    //

+    // Right trim.

+    //

+    void rtrim()

+    {

+	pj_strrtrim(this);

+    }

+

+    //

+    // Left and right trim.

+    //

+    void trim()

+    {

+	pj_strtrim(this);

+    }

+

+    //

+    // Convert to unsigned long.

+    //

+    unsigned long to_ulong() const

+    {

+	return pj_strtoul(this);

+    }

+

+    //

+    // Convert from unsigned long.

+    //

+    void from_ulong(unsigned long value)

+    {

+        slen = pj_utoa(value, ptr);

+    }

+

+    //

+    // Convert from unsigned long with padding.

+    //

+    void from_ulong_with_pad(unsigned long value, int min_dig=0, int pad=' ')

+    {

+        slen = pj_utoa_pad(value, ptr, min_dig, pad);

+    }

+

+

+private:

+    //Pj_String(const Pj_String &rhs) {}

+    void operator=(const Pj_String &rhs) { pj_assert(false); }

+};

+

+#endif	/* __PJPP_STRING_HPP__ */

+

diff --git a/pjlib/include/pj++/timer.hpp b/pjlib/include/pj++/timer.hpp
index fbb15f7..7a5618d 100644
--- a/pjlib/include/pj++/timer.hpp
+++ b/pjlib/include/pj++/timer.hpp
@@ -1,181 +1,202 @@
-/* $Id$
- */
-#ifndef __PJPP_TIMER_HPP__
-#define __PJPP_TIMER_HPP__
-
-#include <pj/timer.h>
-#include <pj++/types.hpp>
-#include <pj/assert.h>
-#include <pj++/lock.hpp>
-
-class Pj_Timer_Heap;
-
-//////////////////////////////////////////////////////////////////////////////
-// Timer entry.
-//
-// How to use:
-//  Derive class from Pj_Timer_Entry and override on_timeout().
-//  Scheduler timer in Pj_Timer_Heap.
-//
-class Pj_Timer_Entry : public Pj_Object
-{
-    friend class Pj_Timer_Heap;
-
-public:
-    //
-    // Default constructor.
-    //
-    Pj_Timer_Entry() 
-    { 
-        entry_.user_data = this;
-        entry_.cb = &timer_heap_callback; 
-    }
-
-    //
-    // Destructor, do nothing.
-    //
-    ~Pj_Timer_Entry()
-    {
-    }
-
-    //
-    // Override this to get the timeout notification.
-    //
-    virtual void on_timeout(int id) = 0;
-
-private:
-    pj_timer_entry entry_;
-
-    static void timer_heap_callback(pj_timer_heap_t *th, pj_timer_entry *e)
-    {
-        Pj_Timer_Entry *entry = (Pj_Timer_Entry*) e->user_data;
-        entry->on_timeout(e->id);
-    }
-
-};
-
-//////////////////////////////////////////////////////////////////////////////
-// Timer heap.
-//
-class Pj_Timer_Heap : public Pj_Object
-{
-public:
-    //
-    // Default constructor.
-    //
-    Pj_Timer_Heap() 
-        : ht_(NULL) 
-    {
-    }
-
-    //
-    // Construct timer heap.
-    //
-    Pj_Timer_Heap(Pj_Pool *pool, pj_size_t initial_count)
-        : ht_(NULL)
-    {
-        create(pool, initial_count);
-    }
-
-    //
-    // Destructor.
-    //
-    ~Pj_Timer_Heap()
-    {
-        destroy();
-    }
-
-    //
-    // Create
-    // 
-    pj_status_t create(Pj_Pool *pool, pj_size_t initial_count)
-    {
-        destroy();
-	return pj_timer_heap_create(pool->pool_(), initial_count, &ht_);
-    }
-
-    //
-    // Destroy
-    //
-    void destroy()
-    {
-        if (ht_) {
-            pj_timer_heap_destroy(ht_);
-            ht_ = NULL;
-        }
-    }
-
-    //
-    // Get pjlib compatible timer heap object.
-    //
-    pj_timer_heap_t *get_timer_heap()
-    {
-	return ht_;
-    }
-
-    //
-    // Set the lock object.
-    //
-    void set_lock( Pj_Lock *lock, bool auto_delete )
-    {
-        pj_timer_heap_set_lock( ht_, lock->pj_lock_t_(), auto_delete);
-    }
-
-    //
-    // Set maximum number of timed out entries to be processed per poll.
-    //
-    unsigned set_max_timed_out_per_poll(unsigned count)
-    {
-        return pj_timer_heap_set_max_timed_out_per_poll(ht_, count);
-    }
-
-    //
-    // Schedule a timer.
-    //
-    bool schedule( Pj_Timer_Entry *ent, const Pj_Time_Val &delay,
-                   int id)
-    {
-        ent->entry_.id = id;
-	return pj_timer_heap_schedule(ht_, &ent->entry_, &delay) == 0;
-    }
-
-    //
-    // Cancel a timer.
-    //
-    bool cancel(Pj_Timer_Entry *ent)
-    {
-	return pj_timer_heap_cancel(ht_, &ent->entry_) == 1;
-    }
-
-    //
-    // Get current number of timers
-    //
-    pj_size_t count()
-    {
-	return pj_timer_heap_count(ht_);
-    }
-
-    //
-    // Get the earliest time.
-    // Return false if no timer is found.
-    //
-    bool earliest_time(Pj_Time_Val *t)
-    {
-	return pj_timer_heap_earliest_time(ht_, t) == PJ_SUCCESS;
-    }
-
-    //
-    // Poll the timer.
-    // Return number of timed out entries has been called.
-    //
-    unsigned poll(Pj_Time_Val *next_delay = NULL)
-    {
-	return pj_timer_heap_poll(ht_, next_delay);
-    }
-
-private:
-    pj_timer_heap_t *ht_;
-};
-
-#endif	/* __PJPP_TIMER_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_TIMER_HPP__

+#define __PJPP_TIMER_HPP__

+

+#include <pj/timer.h>

+#include <pj++/types.hpp>

+#include <pj/assert.h>

+#include <pj++/lock.hpp>

+

+class Pj_Timer_Heap;

+

+//////////////////////////////////////////////////////////////////////////////

+// Timer entry.

+//

+// How to use:

+//  Derive class from Pj_Timer_Entry and override on_timeout().

+//  Scheduler timer in Pj_Timer_Heap.

+//

+class Pj_Timer_Entry : public Pj_Object

+{

+    friend class Pj_Timer_Heap;

+

+public:

+    //

+    // Default constructor.

+    //

+    Pj_Timer_Entry() 

+    { 

+        entry_.user_data = this;

+        entry_.cb = &timer_heap_callback; 

+    }

+

+    //

+    // Destructor, do nothing.

+    //

+    ~Pj_Timer_Entry()

+    {

+    }

+

+    //

+    // Override this to get the timeout notification.

+    //

+    virtual void on_timeout(int id) = 0;

+

+private:

+    pj_timer_entry entry_;

+

+    static void timer_heap_callback(pj_timer_heap_t *th, pj_timer_entry *e)

+    {

+        Pj_Timer_Entry *entry = (Pj_Timer_Entry*) e->user_data;

+        entry->on_timeout(e->id);

+    }

+

+};

+

+//////////////////////////////////////////////////////////////////////////////

+// Timer heap.

+//

+class Pj_Timer_Heap : public Pj_Object

+{

+public:

+    //

+    // Default constructor.

+    //

+    Pj_Timer_Heap() 

+        : ht_(NULL) 

+    {

+    }

+

+    //

+    // Construct timer heap.

+    //

+    Pj_Timer_Heap(Pj_Pool *pool, pj_size_t initial_count)

+        : ht_(NULL)

+    {

+        create(pool, initial_count);

+    }

+

+    //

+    // Destructor.

+    //

+    ~Pj_Timer_Heap()

+    {

+        destroy();

+    }

+

+    //

+    // Create

+    // 

+    pj_status_t create(Pj_Pool *pool, pj_size_t initial_count)

+    {

+        destroy();

+	return pj_timer_heap_create(pool->pool_(), initial_count, &ht_);

+    }

+

+    //

+    // Destroy

+    //

+    void destroy()

+    {

+        if (ht_) {

+            pj_timer_heap_destroy(ht_);

+            ht_ = NULL;

+        }

+    }

+

+    //

+    // Get pjlib compatible timer heap object.

+    //

+    pj_timer_heap_t *get_timer_heap()

+    {

+	return ht_;

+    }

+

+    //

+    // Set the lock object.

+    //

+    void set_lock( Pj_Lock *lock, bool auto_delete )

+    {

+        pj_timer_heap_set_lock( ht_, lock->pj_lock_t_(), auto_delete);

+    }

+

+    //

+    // Set maximum number of timed out entries to be processed per poll.

+    //

+    unsigned set_max_timed_out_per_poll(unsigned count)

+    {

+        return pj_timer_heap_set_max_timed_out_per_poll(ht_, count);

+    }

+

+    //

+    // Schedule a timer.

+    //

+    bool schedule( Pj_Timer_Entry *ent, const Pj_Time_Val &delay,

+                   int id)

+    {

+        ent->entry_.id = id;

+	return pj_timer_heap_schedule(ht_, &ent->entry_, &delay) == 0;

+    }

+

+    //

+    // Cancel a timer.

+    //

+    bool cancel(Pj_Timer_Entry *ent)

+    {

+	return pj_timer_heap_cancel(ht_, &ent->entry_) == 1;

+    }

+

+    //

+    // Get current number of timers

+    //

+    pj_size_t count()

+    {

+	return pj_timer_heap_count(ht_);

+    }

+

+    //

+    // Get the earliest time.

+    // Return false if no timer is found.

+    //

+    bool earliest_time(Pj_Time_Val *t)

+    {

+	return pj_timer_heap_earliest_time(ht_, t) == PJ_SUCCESS;

+    }

+

+    //

+    // Poll the timer.

+    // Return number of timed out entries has been called.

+    //

+    unsigned poll(Pj_Time_Val *next_delay = NULL)

+    {

+	return pj_timer_heap_poll(ht_, next_delay);

+    }

+

+private:

+    pj_timer_heap_t *ht_;

+};

+

+#endif	/* __PJPP_TIMER_HPP__ */

+

diff --git a/pjlib/include/pj++/tree.hpp b/pjlib/include/pj++/tree.hpp
index f4fe8fc..d58d6a0 100644
--- a/pjlib/include/pj++/tree.hpp
+++ b/pjlib/include/pj++/tree.hpp
@@ -1,112 +1,133 @@
-/* $Id$
- */
-#ifndef __PJPP_TREE_HPP__
-#define __PJPP_TREE_HPP__
-
-#include <pj/rbtree.h>
-
-//
-// Tree.
-//
-class PJ_Tree
-{
-public:
-    typedef pj_rbtree_comp Comp;
-    class iterator;
-    class reverse_iterator;
-
-    class Node : private pj_rbtree_node
-    {
-	friend class PJ_Tree;
-	friend class iterator;
-	friend class reverse_iterator;
-
-    public:
-	Node() {}
-	explicit Node(void *data) { user_data = data; }
-	void  set_user_data(void *data) { user_data = data; }
-	void *get_user_data() const { return user_data; }
-    };
-
-    class iterator
-    {
-    public:
-	iterator() {}
-	iterator(const iterator &rhs) : tr_(rhs.tr_), nd_(rhs.nd_) {}
-	iterator(pj_rbtree *tr, pj_rbtree_node *nd) : tr_(tr), nd_(nd) {}
-	Node *operator*() { return (Node*)nd_; }
-	bool operator==(const iterator &rhs) const { return tr_==rhs.tr_ && nd_==rhs.nd_; }
-	iterator &operator=(const iterator &rhs) { tr_=rhs.tr_; nd_=rhs.nd_; return *this; }
-	void operator++() { nd_=pj_rbtree_next(tr_, nd_); }
-	void operator--() { nd_=pj_rbtree_prev(tr_, nd_); }
-    protected:
-	pj_rbtree *tr_;
-	pj_rbtree_node *nd_;
-    };
-
-    class reverse_iterator : public iterator
-    {
-    public:
-	reverse_iterator() {}
-	reverse_iterator(const reverse_iterator &it) : iterator(it) {}
-	reverse_iterator(pj_rbtree *t, pj_rbtree_node *n) : iterator(t, n) {}
-	reverse_iterator &operator=(const reverse_iterator &rhs) { iterator::operator=(rhs); return *this; }
-	Node *operator*() { return (Node*)nd_; }
-	bool operator==(const reverse_iterator &rhs) const { return iterator::operator==(rhs); }
-	void operator++() { nd_=pj_rbtree_prev(tr_, nd_); }
-	void operator--() { nd_=pj_rbtree_next(tr_, nd_); }
-    };
-
-    explicit PJ_Tree(Comp *comp) { pj_rbtree_init(&t_, comp); }
-
-    iterator begin()
-    {
-	return iterator(&t_, pj_rbtree_first(&t_));
-    }
-
-    iterator end()
-    {
-	return iterator(&t_, NULL);
-    }
-
-    reverse_iterator rbegin()
-    {
-	return reverse_iterator(&t_, pj_rbtree_last(&t_));
-    }
-
-    reverse_iterator rend()
-    {
-	return reverse_iterator(&t_, NULL);
-    }
-
-    bool insert(Node *node)
-    {
-	return pj_rbtree_insert(&t_, node)==0 ? true : false;
-    }
-
-    Node *find(const void *key)
-    {
-	return (Node*)pj_rbtree_find(&t_, key);
-    }
-
-    Node *erase(Node *node)
-    {
-	return (Node*)pj_rbtree_erase(&t_, node);
-    }
-
-    unsigned max_height(Node *node=NULL)
-    {
-	return pj_rbtree_max_height(&t_, node);
-    }
-
-    unsigned min_height(Node *node=NULL)
-    {
-	return pj_rbtree_min_height(&t_, node);
-    }
-
-private:
-    pj_rbtree t_;
-};
-
-#endif	/* __PJPP_TREE_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_TREE_HPP__

+#define __PJPP_TREE_HPP__

+

+#include <pj/rbtree.h>

+

+//

+// Tree.

+//

+class PJ_Tree

+{

+public:

+    typedef pj_rbtree_comp Comp;

+    class iterator;

+    class reverse_iterator;

+

+    class Node : private pj_rbtree_node

+    {

+	friend class PJ_Tree;

+	friend class iterator;

+	friend class reverse_iterator;

+

+    public:

+	Node() {}

+	explicit Node(void *data) { user_data = data; }

+	void  set_user_data(void *data) { user_data = data; }

+	void *get_user_data() const { return user_data; }

+    };

+

+    class iterator

+    {

+    public:

+	iterator() {}

+	iterator(const iterator &rhs) : tr_(rhs.tr_), nd_(rhs.nd_) {}

+	iterator(pj_rbtree *tr, pj_rbtree_node *nd) : tr_(tr), nd_(nd) {}

+	Node *operator*() { return (Node*)nd_; }

+	bool operator==(const iterator &rhs) const { return tr_==rhs.tr_ && nd_==rhs.nd_; }

+	iterator &operator=(const iterator &rhs) { tr_=rhs.tr_; nd_=rhs.nd_; return *this; }

+	void operator++() { nd_=pj_rbtree_next(tr_, nd_); }

+	void operator--() { nd_=pj_rbtree_prev(tr_, nd_); }

+    protected:

+	pj_rbtree *tr_;

+	pj_rbtree_node *nd_;

+    };

+

+    class reverse_iterator : public iterator

+    {

+    public:

+	reverse_iterator() {}

+	reverse_iterator(const reverse_iterator &it) : iterator(it) {}

+	reverse_iterator(pj_rbtree *t, pj_rbtree_node *n) : iterator(t, n) {}

+	reverse_iterator &operator=(const reverse_iterator &rhs) { iterator::operator=(rhs); return *this; }

+	Node *operator*() { return (Node*)nd_; }

+	bool operator==(const reverse_iterator &rhs) const { return iterator::operator==(rhs); }

+	void operator++() { nd_=pj_rbtree_prev(tr_, nd_); }

+	void operator--() { nd_=pj_rbtree_next(tr_, nd_); }

+    };

+

+    explicit PJ_Tree(Comp *comp) { pj_rbtree_init(&t_, comp); }

+

+    iterator begin()

+    {

+	return iterator(&t_, pj_rbtree_first(&t_));

+    }

+

+    iterator end()

+    {

+	return iterator(&t_, NULL);

+    }

+

+    reverse_iterator rbegin()

+    {

+	return reverse_iterator(&t_, pj_rbtree_last(&t_));

+    }

+

+    reverse_iterator rend()

+    {

+	return reverse_iterator(&t_, NULL);

+    }

+

+    bool insert(Node *node)

+    {

+	return pj_rbtree_insert(&t_, node)==0 ? true : false;

+    }

+

+    Node *find(const void *key)

+    {

+	return (Node*)pj_rbtree_find(&t_, key);

+    }

+

+    Node *erase(Node *node)

+    {

+	return (Node*)pj_rbtree_erase(&t_, node);

+    }

+

+    unsigned max_height(Node *node=NULL)

+    {

+	return pj_rbtree_max_height(&t_, node);

+    }

+

+    unsigned min_height(Node *node=NULL)

+    {

+	return pj_rbtree_min_height(&t_, node);

+    }

+

+private:

+    pj_rbtree t_;

+};

+

+#endif	/* __PJPP_TREE_HPP__ */

+

diff --git a/pjlib/include/pj++/types.hpp b/pjlib/include/pj++/types.hpp
index 3155eb0..18a2f52 100644
--- a/pjlib/include/pj++/types.hpp
+++ b/pjlib/include/pj++/types.hpp
@@ -1,144 +1,165 @@
-/* $Id$
- */
-#ifndef __PJPP_TYPES_HPP__
-#define __PJPP_TYPES_HPP__
-
-#include <pj/types.h>
-
-class Pj_Pool;
-class Pj_Socket ;
-class Pj_Lock;
-
-
-//
-// PJLIB initializer.
-//
-class Pjlib
-{
-public:
-    Pjlib()
-    {
-        pj_init();
-    }
-};
-
-//
-// Class Pj_Object is declared in pool.hpp
-//
-
-//
-// Time value wrapper.
-//
-class Pj_Time_Val : public pj_time_val
-{
-public:
-    Pj_Time_Val()
-    {
-    }
-
-    Pj_Time_Val(long init_sec, long init_msec)
-    {
-        sec = init_sec;
-        msec = init_msec;
-    }
-
-    Pj_Time_Val(const Pj_Time_Val &rhs) 
-    { 
-        sec=rhs.sec; 
-        msec=rhs.msec; 
-    }
-
-    explicit Pj_Time_Val(const pj_time_val &tv) 
-    { 
-        sec = tv.sec; 
-        msec = tv.msec; 
-    }
-
-    long get_sec()  const    
-    { 
-        return sec; 
-    }
-
-    long get_msec() const    
-    { 
-        return msec; 
-    }
-
-    void set_sec (long s)    
-    { 
-        sec = s; 
-    }
-
-    void set_msec(long ms)   
-    { 
-        msec = ms; 
-        normalize(); 
-    }
-
-    long to_msec() const 
-    { 
-        return PJ_TIME_VAL_MSEC((*this)); 
-    }
-
-    bool operator == (const Pj_Time_Val &rhs) const 
-    { 
-        return PJ_TIME_VAL_EQ((*this), rhs);  
-    }
-
-    bool operator >  (const Pj_Time_Val &rhs) const 
-    { 
-        return PJ_TIME_VAL_GT((*this), rhs);  
-    }
-
-    bool operator >= (const Pj_Time_Val &rhs) const 
-    { 
-        return PJ_TIME_VAL_GTE((*this), rhs); 
-    }
-
-    bool operator <  (const Pj_Time_Val &rhs) const 
-    { 
-        return PJ_TIME_VAL_LT((*this), rhs);  
-    }
-
-    bool operator <= (const Pj_Time_Val &rhs) const 
-    { 
-        return PJ_TIME_VAL_LTE((*this), rhs); 
-    }
-
-    Pj_Time_Val & operator = (const Pj_Time_Val &rhs) 
-    {
-	sec = rhs.sec;
-	msec = rhs.msec;
-	return *this;
-    }
- 
-    Pj_Time_Val & operator += (const Pj_Time_Val &rhs) 
-    {
-	PJ_TIME_VAL_ADD((*this), rhs);
-	return *this;
-    }
-
-    Pj_Time_Val & operator -= (const Pj_Time_Val &rhs) 
-    {
-	PJ_TIME_VAL_SUB((*this), rhs);
-	return *this;
-    }
-
-    /* Must include os.hpp to use these, otherwise unresolved in linking */
-    inline pj_status_t	   gettimeofday();
-    inline pj_parsed_time  decode();
-    inline pj_status_t     encode(const pj_parsed_time *pt);
-    inline pj_status_t     to_gmt();
-    inline pj_status_t     to_local();
-
-
-private:
-    void normalize() 
-    { 
-        pj_time_val_normalize(this); 
-    }
-
-};
-
-#endif	/* __PJPP_TYPES_HPP__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJPP_TYPES_HPP__

+#define __PJPP_TYPES_HPP__

+

+#include <pj/types.h>

+

+class Pj_Pool;

+class Pj_Socket ;

+class Pj_Lock;

+

+

+//

+// PJLIB initializer.

+//

+class Pjlib

+{

+public:

+    Pjlib()

+    {

+        pj_init();

+    }

+};

+

+//

+// Class Pj_Object is declared in pool.hpp

+//

+

+//

+// Time value wrapper.

+//

+class Pj_Time_Val : public pj_time_val

+{

+public:

+    Pj_Time_Val()

+    {

+    }

+

+    Pj_Time_Val(long init_sec, long init_msec)

+    {

+        sec = init_sec;

+        msec = init_msec;

+    }

+

+    Pj_Time_Val(const Pj_Time_Val &rhs) 

+    { 

+        sec=rhs.sec; 

+        msec=rhs.msec; 

+    }

+

+    explicit Pj_Time_Val(const pj_time_val &tv) 

+    { 

+        sec = tv.sec; 

+        msec = tv.msec; 

+    }

+

+    long get_sec()  const    

+    { 

+        return sec; 

+    }

+

+    long get_msec() const    

+    { 

+        return msec; 

+    }

+

+    void set_sec (long s)    

+    { 

+        sec = s; 

+    }

+

+    void set_msec(long ms)   

+    { 

+        msec = ms; 

+        normalize(); 

+    }

+

+    long to_msec() const 

+    { 

+        return PJ_TIME_VAL_MSEC((*this)); 

+    }

+

+    bool operator == (const Pj_Time_Val &rhs) const 

+    { 

+        return PJ_TIME_VAL_EQ((*this), rhs);  

+    }

+

+    bool operator >  (const Pj_Time_Val &rhs) const 

+    { 

+        return PJ_TIME_VAL_GT((*this), rhs);  

+    }

+

+    bool operator >= (const Pj_Time_Val &rhs) const 

+    { 

+        return PJ_TIME_VAL_GTE((*this), rhs); 

+    }

+

+    bool operator <  (const Pj_Time_Val &rhs) const 

+    { 

+        return PJ_TIME_VAL_LT((*this), rhs);  

+    }

+

+    bool operator <= (const Pj_Time_Val &rhs) const 

+    { 

+        return PJ_TIME_VAL_LTE((*this), rhs); 

+    }

+

+    Pj_Time_Val & operator = (const Pj_Time_Val &rhs) 

+    {

+	sec = rhs.sec;

+	msec = rhs.msec;

+	return *this;

+    }

+ 

+    Pj_Time_Val & operator += (const Pj_Time_Val &rhs) 

+    {

+	PJ_TIME_VAL_ADD((*this), rhs);

+	return *this;

+    }

+

+    Pj_Time_Val & operator -= (const Pj_Time_Val &rhs) 

+    {

+	PJ_TIME_VAL_SUB((*this), rhs);

+	return *this;

+    }

+

+    /* Must include os.hpp to use these, otherwise unresolved in linking */

+    inline pj_status_t	   gettimeofday();

+    inline pj_parsed_time  decode();

+    inline pj_status_t     encode(const pj_parsed_time *pt);

+    inline pj_status_t     to_gmt();

+    inline pj_status_t     to_local();

+

+

+private:

+    void normalize() 

+    { 

+        pj_time_val_normalize(this); 

+    }

+

+};

+

+#endif	/* __PJPP_TYPES_HPP__ */

+

diff --git a/pjlib/include/pj/addr_resolv.h b/pjlib/include/pj/addr_resolv.h
index 1da9208..3a5c1eb 100644
--- a/pjlib/include/pj/addr_resolv.h
+++ b/pjlib/include/pj/addr_resolv.h
@@ -1,77 +1,98 @@
-/* $Id$
- */
-
-#ifndef __PJ_ADDR_RESOLV_H__
-#define __PJ_ADDR_RESOLV_H__
-
-/**
- * @file addr_resolv.h
- * @brief Address resolve (pj_gethostbyname()).
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup pj_addr_resolve Network Address Resolution
- * @ingroup PJ_IO
- * @{
- *
- * This module provides function to resolve Internet address of the
- * specified host name. To resolve a particular host name, application
- * can just call #pj_gethostbyname().
- *
- * Example:
- * <pre>
- *   ...
- *   pj_hostent he;
- *   pj_status_t rc;
- *   pj_str_t host = pj_str("host.example.com");
- *   
- *   rc = pj_gethostbyname( &host, &he);
- *   if (rc != PJ_SUCCESS) {
- *      char errbuf[80];
- *      pj_strerror( rc, errbuf, sizeof(errbuf));
- *      PJ_LOG(2,("sample", "Unable to resolve host, error=%s", errbuf));
- *      return rc;
- *   }
- *
- *   // process address...
- *   addr.sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
- *   ...
- * </pre>
- *
- * It's pretty simple really...
- */
-
-/** This structure describes an Internet host address. */
-typedef struct pj_hostent
-{
-    char    *h_name;		/**< The official name of the host. */
-    char   **h_aliases;		/**< Aliases list. */
-    int	     h_addrtype;	/**< Host address type. */
-    int	     h_length;		/**< Length of address. */
-    char   **h_addr_list;	/**< List of addresses. */
-} pj_hostent;
-
-/** Shortcut to h_addr_list[0] */
-#define h_addr h_addr_list[0]
-
-/**
- * This function fills the structure of type pj_hostent for a given host name.
- *
- * @param name	    Host name, or IPv4 or IPv6 address in standard dot notation.
- * @param he	    The pj_hostent structure to be filled.
- *
- * @return	    PJ_SUCCESS, or the appropriate error codes.
- */ 
-PJ_DECL(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he);
-
-
-/** @} */
-
-PJ_END_DECL
-
-#endif	/* __PJ_ADDR_RESOLV_H__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_ADDR_RESOLV_H__

+#define __PJ_ADDR_RESOLV_H__

+

+/**

+ * @file addr_resolv.h

+ * @brief Address resolve (pj_gethostbyname()).

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup pj_addr_resolve Network Address Resolution

+ * @ingroup PJ_IO

+ * @{

+ *

+ * This module provides function to resolve Internet address of the

+ * specified host name. To resolve a particular host name, application

+ * can just call #pj_gethostbyname().

+ *

+ * Example:

+ * <pre>

+ *   ...

+ *   pj_hostent he;

+ *   pj_status_t rc;

+ *   pj_str_t host = pj_str("host.example.com");

+ *   

+ *   rc = pj_gethostbyname( &host, &he);

+ *   if (rc != PJ_SUCCESS) {

+ *      char errbuf[80];

+ *      pj_strerror( rc, errbuf, sizeof(errbuf));

+ *      PJ_LOG(2,("sample", "Unable to resolve host, error=%s", errbuf));

+ *      return rc;

+ *   }

+ *

+ *   // process address...

+ *   addr.sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;

+ *   ...

+ * </pre>

+ *

+ * It's pretty simple really...

+ */

+

+/** This structure describes an Internet host address. */

+typedef struct pj_hostent

+{

+    char    *h_name;		/**< The official name of the host. */

+    char   **h_aliases;		/**< Aliases list. */

+    int	     h_addrtype;	/**< Host address type. */

+    int	     h_length;		/**< Length of address. */

+    char   **h_addr_list;	/**< List of addresses. */

+} pj_hostent;

+

+/** Shortcut to h_addr_list[0] */

+#define h_addr h_addr_list[0]

+

+/**

+ * This function fills the structure of type pj_hostent for a given host name.

+ *

+ * @param name	    Host name, or IPv4 or IPv6 address in standard dot notation.

+ * @param he	    The pj_hostent structure to be filled.

+ *

+ * @return	    PJ_SUCCESS, or the appropriate error codes.

+ */ 

+PJ_DECL(pj_status_t) pj_gethostbyname(const pj_str_t *name, pj_hostent *he);

+

+

+/** @} */

+

+PJ_END_DECL

+

+#endif	/* __PJ_ADDR_RESOLV_H__ */

+

diff --git a/pjlib/include/pj/array.h b/pjlib/include/pj/array.h
index eaec726..dc896c2 100644
--- a/pjlib/include/pj/array.h
+++ b/pjlib/include/pj/array.h
@@ -1,80 +1,101 @@
-/* $Id$
- *
- */
-#ifndef __PJ_ARRAY_H__
-#define __PJ_ARRAY_H__
-
-/**
- * @file array.h
- * @brief PJLIB Array helper.
- */
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_ARRAY Array helper.
- * @ingroup PJ_DS
- * @{
- *
- * This module provides helper to manipulate array of elements of any size.
- * It provides most used array operations such as insert, erase, and search.
- */
-
-/**
- * Insert value to the array at the given position, and rearrange the
- * remaining nodes after the position.
- *
- * @param array	    the array.
- * @param elem_size the size of the individual element.
- * @param count	    the current number of elements in the array.
- * @param pos	    the position where the new element is put.
- * @param value	    the value to copy to the new element.
- */
-PJ_DECL(void) pj_array_insert( void *array,
-			       unsigned elem_size,
-			       unsigned count,
-			       unsigned pos,
-			       const void *value);
-
-/**
- * Erase a value from the array at given position, and rearrange the remaining
- * elements post the erased element.
- *
- * @param array	    the array.
- * @param elem_size the size of the individual element.
- * @param count	    the current number of elements in the array.
- * @param pos	    the index/position to delete.
- */
-PJ_DECL(void) pj_array_erase( void *array,
-			      unsigned elem_size,
-			      unsigned count,
-			      unsigned pos);
-
-/**
- * Search the first value in the array according to matching function.
- *
- * @param array	    the array.
- * @param elem_size the individual size of the element.
- * @param count	    the number of elements.
- * @param matching  the matching function, which MUST return PJ_SUCCESS if 
- *		    the specified element match.
- * @param result    the pointer to the value found.
- *
- * @return	    PJ_SUCCESS if value is found, otherwise the error code.
- */
-PJ_DECL(pj_status_t) pj_array_find(   const void *array, 
-				      unsigned elem_size, 
-				      unsigned count, 
-				      pj_status_t (*matching)(const void *value),
-				      void **result);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-
-#endif	/* __PJ_ARRAY_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_ARRAY_H__

+#define __PJ_ARRAY_H__

+

+/**

+ * @file array.h

+ * @brief PJLIB Array helper.

+ */

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_ARRAY Array helper.

+ * @ingroup PJ_DS

+ * @{

+ *

+ * This module provides helper to manipulate array of elements of any size.

+ * It provides most used array operations such as insert, erase, and search.

+ */

+

+/**

+ * Insert value to the array at the given position, and rearrange the

+ * remaining nodes after the position.

+ *

+ * @param array	    the array.

+ * @param elem_size the size of the individual element.

+ * @param count	    the current number of elements in the array.

+ * @param pos	    the position where the new element is put.

+ * @param value	    the value to copy to the new element.

+ */

+PJ_DECL(void) pj_array_insert( void *array,

+			       unsigned elem_size,

+			       unsigned count,

+			       unsigned pos,

+			       const void *value);

+

+/**

+ * Erase a value from the array at given position, and rearrange the remaining

+ * elements post the erased element.

+ *

+ * @param array	    the array.

+ * @param elem_size the size of the individual element.

+ * @param count	    the current number of elements in the array.

+ * @param pos	    the index/position to delete.

+ */

+PJ_DECL(void) pj_array_erase( void *array,

+			      unsigned elem_size,

+			      unsigned count,

+			      unsigned pos);

+

+/**

+ * Search the first value in the array according to matching function.

+ *

+ * @param array	    the array.

+ * @param elem_size the individual size of the element.

+ * @param count	    the number of elements.

+ * @param matching  the matching function, which MUST return PJ_SUCCESS if 

+ *		    the specified element match.

+ * @param result    the pointer to the value found.

+ *

+ * @return	    PJ_SUCCESS if value is found, otherwise the error code.

+ */

+PJ_DECL(pj_status_t) pj_array_find(   const void *array, 

+				      unsigned elem_size, 

+				      unsigned count, 

+				      pj_status_t (*matching)(const void *value),

+				      void **result);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+

+#endif	/* __PJ_ARRAY_H__ */

+

diff --git a/pjlib/include/pj/assert.h b/pjlib/include/pj/assert.h
index d10c864..c6d3770 100644
--- a/pjlib/include/pj/assert.h
+++ b/pjlib/include/pj/assert.h
@@ -1,58 +1,79 @@
-/* $Id$
- *
- */
-#ifndef __PJ_ASSERT_H__
-#define __PJ_ASSERT_H__
-
-/**
- * @file assert.h
- * @brief Assertion macro pj_assert().
- */
-
-#include <pj/config.h>
-#include <pj/compat/assert.h>
-
-/**
- * @defgroup pj_assert Assertion Macro
- * @ingroup PJ_MISC
- * @{
- *
- * Assertion and other helper macros for sanity checking.
- */
-
-/**
- * @hideinitializer
- * Check during debug build that an expression is true. If the expression
- * computes to false during run-time, then the program will stop at the
- * offending statements.
- * For release build, this macro will not do anything.
- *
- * @param expr	    The expression to be evaluated.
- */
-#define pj_assert(expr)   assert(expr)
-
-
-/**
- * @hideinitializer
- * If #PJ_ENABLE_EXTRA_CHECK is declared and non-zero, then 
- * #PJ_ASSERT_RETURN macro will evaluate the expression in @a expr during
- * run-time. If the expression yields false, assertion will be triggered
- * and the current function will return with the specified return value.
- *
- * If #PJ_ENABLE_EXTRA_CHECK is not declared or is zero, then no run-time
- * checking will be performed. The macro simply evaluates to pj_assert(expr).
- */
-#if defined(PJ_ENABLE_EXTRA_CHECK) && PJ_ENABLE_EXTRA_CHECK != 0
-#   define PJ_ASSERT_RETURN(expr,retval)    \
-	    do { \
-		pj_assert(expr); \
-		if (!(expr)) return retval; \
-	    } while (0)
-#else
-#   define PJ_ASSERT_RETURN(expr,retval)    pj_assert(expr)
-#endif
-
-/** @} */
-
-#endif	/* __PJ_ASSERT_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_ASSERT_H__

+#define __PJ_ASSERT_H__

+

+/**

+ * @file assert.h

+ * @brief Assertion macro pj_assert().

+ */

+

+#include <pj/config.h>

+#include <pj/compat/assert.h>

+

+/**

+ * @defgroup pj_assert Assertion Macro

+ * @ingroup PJ_MISC

+ * @{

+ *

+ * Assertion and other helper macros for sanity checking.

+ */

+

+/**

+ * @hideinitializer

+ * Check during debug build that an expression is true. If the expression

+ * computes to false during run-time, then the program will stop at the

+ * offending statements.

+ * For release build, this macro will not do anything.

+ *

+ * @param expr	    The expression to be evaluated.

+ */

+#define pj_assert(expr)   assert(expr)

+

+

+/**

+ * @hideinitializer

+ * If #PJ_ENABLE_EXTRA_CHECK is declared and non-zero, then 

+ * #PJ_ASSERT_RETURN macro will evaluate the expression in @a expr during

+ * run-time. If the expression yields false, assertion will be triggered

+ * and the current function will return with the specified return value.

+ *

+ * If #PJ_ENABLE_EXTRA_CHECK is not declared or is zero, then no run-time

+ * checking will be performed. The macro simply evaluates to pj_assert(expr).

+ */

+#if defined(PJ_ENABLE_EXTRA_CHECK) && PJ_ENABLE_EXTRA_CHECK != 0

+#   define PJ_ASSERT_RETURN(expr,retval)    \

+	    do { \

+		pj_assert(expr); \

+		if (!(expr)) return retval; \

+	    } while (0)

+#else

+#   define PJ_ASSERT_RETURN(expr,retval)    pj_assert(expr)

+#endif

+

+/** @} */

+

+#endif	/* __PJ_ASSERT_H__ */

+

diff --git a/pjlib/include/pj/compat/assert.h b/pjlib/include/pj/compat/assert.h
index 586cafb..2cc1794 100644
--- a/pjlib/include/pj/compat/assert.h
+++ b/pjlib/include/pj/compat/assert.h
@@ -1,40 +1,61 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/assert.h $
- * 
- * 3     9/22/05 10:31a Bennylp
- * Moving all *.h files to include/.
- * 
- * 2     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_ASSERT_H__
-#define __PJ_COMPAT_ASSERT_H__
-
-/**
- * @file assert.h
- * @brief Provides assert() macro.
- */
-
-#if defined(PJ_HAS_ASSERT_H) && PJ_HAS_ASSERT_H != 0
-#  include <assert.h>
-
-#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
-#  define assert(expr) do { \
-			if (!(expr)) \
-			  printk("!!ASSERTION FAILED: [%s:%d] \"" #expr "\"\n",\
-				 __FILE__, __LINE__); \
-		       } while (0)
-
-#else
-#  warning "assert() is not implemented"
-#  define assert(expr)
-#endif
-
-#endif	/* __PJ_COMPAT_ASSERT_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/assert.h $

+ * 

+ * 3     9/22/05 10:31a Bennylp

+ * Moving all *.h files to include/.

+ * 

+ * 2     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_ASSERT_H__

+#define __PJ_COMPAT_ASSERT_H__

+

+/**

+ * @file assert.h

+ * @brief Provides assert() macro.

+ */

+

+#if defined(PJ_HAS_ASSERT_H) && PJ_HAS_ASSERT_H != 0

+#  include <assert.h>

+

+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0

+#  define assert(expr) do { \

+			if (!(expr)) \

+			  printk("!!ASSERTION FAILED: [%s:%d] \"" #expr "\"\n",\

+				 __FILE__, __LINE__); \

+		       } while (0)

+

+#else

+#  warning "assert() is not implemented"

+#  define assert(expr)

+#endif

+

+#endif	/* __PJ_COMPAT_ASSERT_H__ */

+

diff --git a/pjlib/include/pj/compat/cc_gcc.h b/pjlib/include/pj/compat/cc_gcc.h
index 913f691..96e9157 100644
--- a/pjlib/include/pj/compat/cc_gcc.h
+++ b/pjlib/include/pj/compat/cc_gcc.h
@@ -1,34 +1,55 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/cc_gcc.h $
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- */
-#ifndef __PJ_COMPAT_CC_GCC_H__
-#define __PJ_COMPAT_CC_GCC_H__
-
-/**
- * @file cc_gcc.h
- * @brief Describes GCC compiler specifics.
- */
-
-#ifndef __GNUC__
-#  error "This file is only for gcc!"
-#endif
-
-#define PJ_INLINE_SPECIFIER	static inline
-#define PJ_THREAD_FUNC	
-#define PJ_NORETURN		
-#define PJ_ATTR_NORETURN	__attribute__ ((noreturn))
-
-#define PJ_HAS_INT64		1
-
-typedef long long pj_int64_t;
-typedef unsigned long long pj_uint64_t;
-
-
-#endif	/* __PJ_COMPAT_CC_GCC_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/cc_gcc.h $

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ */

+#ifndef __PJ_COMPAT_CC_GCC_H__

+#define __PJ_COMPAT_CC_GCC_H__

+

+/**

+ * @file cc_gcc.h

+ * @brief Describes GCC compiler specifics.

+ */

+

+#ifndef __GNUC__

+#  error "This file is only for gcc!"

+#endif

+

+#define PJ_INLINE_SPECIFIER	static inline

+#define PJ_THREAD_FUNC	

+#define PJ_NORETURN		

+#define PJ_ATTR_NORETURN	__attribute__ ((noreturn))

+

+#define PJ_HAS_INT64		1

+

+typedef long long pj_int64_t;

+typedef unsigned long long pj_uint64_t;

+

+

+#endif	/* __PJ_COMPAT_CC_GCC_H__ */

+

diff --git a/pjlib/include/pj/compat/cc_msvc.h b/pjlib/include/pj/compat/cc_msvc.h
index f8407e3..d67210b 100644
--- a/pjlib/include/pj/compat/cc_msvc.h
+++ b/pjlib/include/pj/compat/cc_msvc.h
@@ -1,42 +1,63 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/compat/cc_msvc.h $
- * 
- * 3     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- */
-#ifndef __PJ_COMPAT_CC_MSVC_H__
-#define __PJ_COMPAT_CC_MSVC_H__
-
-/**
- * @file cc_msvc.h
- * @brief Describes Microsoft Visual C compiler specifics.
- */
-
-#ifndef _MSC_VER
-#  error "This header file is only for Visual C compiler!"
-#endif
-
-#  pragma warning(disable: 4127)	// conditional expression is constant
-#  pragma warning(disable: 4611)	// not wise to mix setjmp with C++
-#  pragma warning(disable: 4514)	// unreferenced inline function has been removed
-#  ifdef __cplusplus
-#    define PJ_INLINE_SPECIFIER	inline
-#  else
-#    define PJ_INLINE_SPECIFIER	static __inline
-#  endif
-#  define PJ_THREAD_FUNC	
-#  define PJ_NORETURN		__declspec(noreturn)
-#  define PJ_ATTR_NORETURN	
-
-#  define PJ_HAS_INT64	1
-typedef __int64 pj_int64_t;
-typedef unsigned __int64 pj_uint64_t;
-
-#endif	/* __PJ_COMPAT_CC_MSVC_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/cc_msvc.h $

+ * 

+ * 3     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ */

+#ifndef __PJ_COMPAT_CC_MSVC_H__

+#define __PJ_COMPAT_CC_MSVC_H__

+

+/**

+ * @file cc_msvc.h

+ * @brief Describes Microsoft Visual C compiler specifics.

+ */

+

+#ifndef _MSC_VER

+#  error "This header file is only for Visual C compiler!"

+#endif

+

+#  pragma warning(disable: 4127)	// conditional expression is constant

+#  pragma warning(disable: 4611)	// not wise to mix setjmp with C++

+#  pragma warning(disable: 4514)	// unreferenced inline function has been removed

+#  ifdef __cplusplus

+#    define PJ_INLINE_SPECIFIER	inline

+#  else

+#    define PJ_INLINE_SPECIFIER	static __inline

+#  endif

+#  define PJ_THREAD_FUNC	

+#  define PJ_NORETURN		__declspec(noreturn)

+#  define PJ_ATTR_NORETURN	

+

+#  define PJ_HAS_INT64	1

+typedef __int64 pj_int64_t;

+typedef unsigned __int64 pj_uint64_t;

+

+#endif	/* __PJ_COMPAT_CC_MSVC_H__ */

diff --git a/pjlib/include/pj/compat/ctype.h b/pjlib/include/pj/compat/ctype.h
index d01cc19..d8ddac1 100644
--- a/pjlib/include/pj/compat/ctype.h
+++ b/pjlib/include/pj/compat/ctype.h
@@ -1,44 +1,65 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/compat/ctype.h $
- * 
- * 3     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 2     9/22/05 10:31a Bennylp
- * Moving all *.h files to include/.
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_CTYPE_H__
-#define __PJ_COMPAT_CTYPE_H__
-
-/**
- * @file ctype.h
- * @brief Provides ctype function family.
- */
-
-#if defined(PJ_HAS_CTYPE_H) && PJ_HAS_CTYPE_H != 0
-#  include <ctype.h>
-#else
-#  define isalnum(c)	    (isalpha(c) || isdigit(c))
-#  define isalpha(c)	    (islower(c) || isupper(c))
-#  define isascii(c)	    (((unsigned char)(c))<=0x7f)
-#  define isdigit(c)	    ((c)>='0' && (c)<='9')
-#  define isspace(c)	    ((c)==' '  || (c)=='\t' ||\
-			     (c)=='\n' || (c)=='\r' || (c)=='\v')
-#  define islower(c)	    ((c)>='a' && (c)<='z')
-#  define isupper(c)	    ((c)>='A' && (c)<='Z')
-#  define isxdigit(c)	    (isdigit(c) || (tolower(c)>='a'&&tolower(c)<='f'))
-#  define tolower(c)	    (((c) >= 'A' && (c) <= 'Z') ? (c)+('a'-'A') : (c))
-#  define toupper(c)	    (((c) >= 'a' && (c) <= 'z') ? (c)-('a'-'A') : (c))
-#endif
-
-#define isblank(c)	    (c==' ' || c=='\t')
-
-
-#endif	/* __PJ_COMPAT_CTYPE_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/ctype.h $

+ * 

+ * 3     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 2     9/22/05 10:31a Bennylp

+ * Moving all *.h files to include/.

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_CTYPE_H__

+#define __PJ_COMPAT_CTYPE_H__

+

+/**

+ * @file ctype.h

+ * @brief Provides ctype function family.

+ */

+

+#if defined(PJ_HAS_CTYPE_H) && PJ_HAS_CTYPE_H != 0

+#  include <ctype.h>

+#else

+#  define isalnum(c)	    (isalpha(c) || isdigit(c))

+#  define isalpha(c)	    (islower(c) || isupper(c))

+#  define isascii(c)	    (((unsigned char)(c))<=0x7f)

+#  define isdigit(c)	    ((c)>='0' && (c)<='9')

+#  define isspace(c)	    ((c)==' '  || (c)=='\t' ||\

+			     (c)=='\n' || (c)=='\r' || (c)=='\v')

+#  define islower(c)	    ((c)>='a' && (c)<='z')

+#  define isupper(c)	    ((c)>='A' && (c)<='Z')

+#  define isxdigit(c)	    (isdigit(c) || (tolower(c)>='a'&&tolower(c)<='f'))

+#  define tolower(c)	    (((c) >= 'A' && (c) <= 'Z') ? (c)+('a'-'A') : (c))

+#  define toupper(c)	    (((c) >= 'a' && (c) <= 'z') ? (c)-('a'-'A') : (c))

+#endif

+

+#define isblank(c)	    (c==' ' || c=='\t')

+

+

+#endif	/* __PJ_COMPAT_CTYPE_H__ */

diff --git a/pjlib/include/pj/compat/errno.h b/pjlib/include/pj/compat/errno.h
index 7ee8324..be7a753 100644
--- a/pjlib/include/pj/compat/errno.h
+++ b/pjlib/include/pj/compat/errno.h
@@ -1,29 +1,50 @@
-/* $Id$
- *
- */
-#ifndef __PJ_COMPAT_ERRNO_H__
-#define __PJ_COMPAT_ERRNO_H__
-
-#if defined(PJ_WIN32) && PJ_WIN32 != 0
-
-    typedef unsigned long pj_os_err_type;
-#   define pj_get_native_os_error()	    GetLastError()
-#   define pj_get_native_netos_error()	    WSAGetLastError()
-
-#elif (defined(PJ_LINUX) && PJ_LINUX != 0) || \
-      (defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0) || \
-      (defined(PJ_SUNOS) && PJ_SUNOS != 0)
-
-    typedef int pj_os_err_type;
-#   define pj_get_native_os_error()	    (errno)
-#   define pj_get_native_netos_error()	    (errno)
-
-#else
-
-#   error "Please define pj_os_err_type for this platform here!"
-
-#endif
-
-
-#endif	/* __PJ_COMPAT_ERRNO_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_COMPAT_ERRNO_H__

+#define __PJ_COMPAT_ERRNO_H__

+

+#if defined(PJ_WIN32) && PJ_WIN32 != 0

+

+    typedef unsigned long pj_os_err_type;

+#   define pj_get_native_os_error()	    GetLastError()

+#   define pj_get_native_netos_error()	    WSAGetLastError()

+

+#elif (defined(PJ_LINUX) && PJ_LINUX != 0) || \

+      (defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0) || \

+      (defined(PJ_SUNOS) && PJ_SUNOS != 0)

+

+    typedef int pj_os_err_type;

+#   define pj_get_native_os_error()	    (errno)

+#   define pj_get_native_netos_error()	    (errno)

+

+#else

+

+#   error "Please define pj_os_err_type for this platform here!"

+

+#endif

+

+

+#endif	/* __PJ_COMPAT_ERRNO_H__ */

+

diff --git a/pjlib/include/pj/compat/high_precision.h b/pjlib/include/pj/compat/high_precision.h
index 431283d..ba48e43 100644
--- a/pjlib/include/pj/compat/high_precision.h
+++ b/pjlib/include/pj/compat/high_precision.h
@@ -1,87 +1,106 @@
-/* $Id$
- *
- */
-#ifndef __PJ_COMPAT_HIGH_PRECISION_H__
-#define __PJ_COMPAT_HIGH_PRECISION_H__
-
-
-#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT != 0
-    /*
-     * The first choice for high precision math is to use double.
-     */
-#   include <math.h>
-    typedef double pj_highprec_t;
-
-#   define PJ_HIGHPREC_VALUE_IS_ZERO(a)     (a==0)
-#   define pj_highprec_mod(a,b)             (a=fmod(a,b))
-
-#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
-
-#   include <asm/div64.h>
-    
-    typedef pj_int64_t pj_highprec_t;
-
-#   define pj_highprec_div(a1,a2)   do_div(a1,a2)
-#   define pj_highprec_mod(a1,a2)   (a1=do_mod(a1, a2))
-
-    PJ_INLINE(pj_int64_t) do_mod( pj_int64_t a1, pj_int64_t a2)
-    {
-	return do_div(a1,a2);
-    }
-    
-    
-#elif defined(PJ_HAS_INT64) && PJ_HAS_INT64 != 0
-    /*
-     * Next choice is to use 64-bit arithmatics.
-     */
-    typedef pj_int64_t pj_highprec_t;
-
-#else
-#   warning "High precision math is not available"
-
-    /*
-     * Last, fallback to 32-bit arithmetics.
-     */
-    typedef pj_int32_t pj_highprec_t;
-
-#endif
-
-/**
- * @def pj_highprec_mul
- * pj_highprec_mul(a1, a2) - High Precision Multiplication
- * Multiply a1 and a2, and store the result in a1.
- */
-#ifndef pj_highprec_mul
-#   define pj_highprec_mul(a1,a2)   (a1 = a1 * a2)
-#endif
-
-/**
- * @def pj_highprec_div
- * pj_highprec_div(a1, a2) - High Precision Division
- * Divide a2 from a1, and store the result in a1.
- */
-#ifndef pj_highprec_div
-#   define pj_highprec_div(a1,a2)   (a1 = a1 / a2)
-#endif
-
-/**
- * @def pj_highprec_mod
- * pj_highprec_mod(a1, a2) - High Precision Modulus
- * Get the modulus a2 from a1, and store the result in a1.
- */
-#ifndef pj_highprec_mod
-#   define pj_highprec_mod(a1,a2)   (a1 = a1 % a2)
-#endif
-
-
-/**
- * @def PJ_HIGHPREC_VALUE_IS_ZERO(a)
- * Test if the specified high precision value is zero.
- */
-#ifndef PJ_HIGHPREC_VALUE_IS_ZERO
-#   define PJ_HIGHPREC_VALUE_IS_ZERO(a)     (a==0)
-#endif
-
-
-#endif	/* __PJ_COMPAT_HIGH_PRECISION_H__ */
-
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_COMPAT_HIGH_PRECISION_H__

+#define __PJ_COMPAT_HIGH_PRECISION_H__

+

+

+#if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT != 0

+    /*

+     * The first choice for high precision math is to use double.

+     */

+#   include <math.h>

+    typedef double pj_highprec_t;

+

+#   define PJ_HIGHPREC_VALUE_IS_ZERO(a)     (a==0)

+#   define pj_highprec_mod(a,b)             (a=fmod(a,b))

+

+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0

+

+#   include <asm/div64.h>

+    

+    typedef pj_int64_t pj_highprec_t;

+

+#   define pj_highprec_div(a1,a2)   do_div(a1,a2)

+#   define pj_highprec_mod(a1,a2)   (a1=do_mod(a1, a2))

+

+    PJ_INLINE(pj_int64_t) do_mod( pj_int64_t a1, pj_int64_t a2)

+    {

+	return do_div(a1,a2);

+    }

+    

+    

+#elif defined(PJ_HAS_INT64) && PJ_HAS_INT64 != 0

+    /*

+     * Next choice is to use 64-bit arithmatics.

+     */

+    typedef pj_int64_t pj_highprec_t;

+

+#else

+#   warning "High precision math is not available"

+

+    /*

+     * Last, fallback to 32-bit arithmetics.

+     */

+    typedef pj_int32_t pj_highprec_t;

+

+#endif

+

+/**

+ * @def pj_highprec_mul

+ * pj_highprec_mul(a1, a2) - High Precision Multiplication

+ * Multiply a1 and a2, and store the result in a1.

+ */

+#ifndef pj_highprec_mul

+#   define pj_highprec_mul(a1,a2)   (a1 = a1 * a2)

+#endif

+

+/**

+ * @def pj_highprec_div

+ * pj_highprec_div(a1, a2) - High Precision Division

+ * Divide a2 from a1, and store the result in a1.

+ */

+#ifndef pj_highprec_div

+#   define pj_highprec_div(a1,a2)   (a1 = a1 / a2)

+#endif

+

+/**

+ * @def pj_highprec_mod

+ * pj_highprec_mod(a1, a2) - High Precision Modulus

+ * Get the modulus a2 from a1, and store the result in a1.

+ */

+#ifndef pj_highprec_mod

+#   define pj_highprec_mod(a1,a2)   (a1 = a1 % a2)

+#endif

+

+

+/**

+ * @def PJ_HIGHPREC_VALUE_IS_ZERO(a)

+ * Test if the specified high precision value is zero.

+ */

+#ifndef PJ_HIGHPREC_VALUE_IS_ZERO

+#   define PJ_HIGHPREC_VALUE_IS_ZERO(a)     (a==0)

+#endif

+

+

+#endif	/* __PJ_COMPAT_HIGH_PRECISION_H__ */

+

diff --git a/pjlib/include/pj/compat/m_alpha.h b/pjlib/include/pj/compat/m_alpha.h
index 38569dc..3a1376e 100644
--- a/pjlib/include/pj/compat/m_alpha.h
+++ b/pjlib/include/pj/compat/m_alpha.h
@@ -1,25 +1,46 @@
-/* $Id$
- *
- */
-/* 
- * $Log: /pjproject-0.3/pjlib/include/pj/compat/m_alpha.h $
- * 
- * 1     10/29/05 5:23p Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_M_ALPHA_H__
-#define __PJ_COMPAT_M_ALPHA_H__
-
-/**
- * @file m_alpha.h
- * @brief Describes Alpha processor family specifics.
- */
-
-#define PJ_HAS_PENTIUM		0
-#define PJ_IS_LITTLE_ENDIAN	1
-#define PJ_IS_BIG_ENDIAN	0
-
-
-#endif	/* __PJ_COMPAT_M_ALPHA_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* 

+ * $Log: /pjproject-0.3/pjlib/include/pj/compat/m_alpha.h $

+ * 

+ * 1     10/29/05 5:23p Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_M_ALPHA_H__

+#define __PJ_COMPAT_M_ALPHA_H__

+

+/**

+ * @file m_alpha.h

+ * @brief Describes Alpha processor family specifics.

+ */

+

+#define PJ_HAS_PENTIUM		0

+#define PJ_IS_LITTLE_ENDIAN	1

+#define PJ_IS_BIG_ENDIAN	0

+

+

+#endif	/* __PJ_COMPAT_M_ALPHA_H__ */

+

diff --git a/pjlib/include/pj/compat/m_i386.h b/pjlib/include/pj/compat/m_i386.h
index 8eaf19e..0239c34 100644
--- a/pjlib/include/pj/compat/m_i386.h
+++ b/pjlib/include/pj/compat/m_i386.h
@@ -1,28 +1,49 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_i386.h $
- * 
- * 3     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- */
-#ifndef __PJ_COMPAT_M_i386_H__
-#define __PJ_COMPAT_M_i386_H__
-
-/**
- * @file m_i386.h
- * @brief Describes Intel i386 family processor specifics.
- */
-
-#define PJ_M_I386		1
-
-#define PJ_HAS_PENTIUM		1
-#define PJ_IS_LITTLE_ENDIAN	1
-#define PJ_IS_BIG_ENDIAN	0
-
-
-#endif	/* __PJ_COMPAT_M_i386_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_i386.h $

+ * 

+ * 3     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ */

+#ifndef __PJ_COMPAT_M_i386_H__

+#define __PJ_COMPAT_M_i386_H__

+

+/**

+ * @file m_i386.h

+ * @brief Describes Intel i386 family processor specifics.

+ */

+

+#define PJ_M_I386		1

+

+#define PJ_HAS_PENTIUM		1

+#define PJ_IS_LITTLE_ENDIAN	1

+#define PJ_IS_BIG_ENDIAN	0

+

+

+#endif	/* __PJ_COMPAT_M_i386_H__ */

diff --git a/pjlib/include/pj/compat/m_m68k.h b/pjlib/include/pj/compat/m_m68k.h
index eb8db6e..caed75e 100644
--- a/pjlib/include/pj/compat/m_m68k.h
+++ b/pjlib/include/pj/compat/m_m68k.h
@@ -1,23 +1,44 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_m68k.h $
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- */
-#ifndef __PJ_COMPAT_M_M68K_H__
-#define __PJ_COMPAT_M_M68K_H__
-
-/**
- * @file m_m68k.h
- * @brief Describes Motorola m68k family processor specifics.
- */
-
-#define PJ_HAS_PENTIUM		0
-#define PJ_IS_LITTLE_ENDIAN	1
-#define PJ_IS_BIG_ENDIAN	0
-
-
-#endif	/* __PJ_COMPAT_M_M68K_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/m_m68k.h $

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ */

+#ifndef __PJ_COMPAT_M_M68K_H__

+#define __PJ_COMPAT_M_M68K_H__

+

+/**

+ * @file m_m68k.h

+ * @brief Describes Motorola m68k family processor specifics.

+ */

+

+#define PJ_HAS_PENTIUM		0

+#define PJ_IS_LITTLE_ENDIAN	1

+#define PJ_IS_BIG_ENDIAN	0

+

+

+#endif	/* __PJ_COMPAT_M_M68K_H__ */

diff --git a/pjlib/include/pj/compat/m_sparc.h b/pjlib/include/pj/compat/m_sparc.h
index 5fd6240..3cb5d0c 100644
--- a/pjlib/include/pj/compat/m_sparc.h
+++ b/pjlib/include/pj/compat/m_sparc.h
@@ -1,23 +1,44 @@
-/* $Id$
- *
- */
-/* 
- *$Log:  $
- * 
- */
-#ifndef __PJ_COMPAT_M_SPARC_H__
-#define __PJ_COMPAT_M_SPARC_H__
-
-/**
- * @file m_sparc.h
- * @brief Describes SPARC family processor specifics.
- */
-
-#define PJ_SPARC		1
-
-#define PJ_HAS_PENTIUM		0
-#define PJ_IS_LITTLE_ENDIAN	0
-#define PJ_IS_BIG_ENDIAN	1
-
-
-#endif	/* __PJ_COMPAT_M_SPARC_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* 

+ *$Log:  $

+ * 

+ */

+#ifndef __PJ_COMPAT_M_SPARC_H__

+#define __PJ_COMPAT_M_SPARC_H__

+

+/**

+ * @file m_sparc.h

+ * @brief Describes SPARC family processor specifics.

+ */

+

+#define PJ_SPARC		1

+

+#define PJ_HAS_PENTIUM		0

+#define PJ_IS_LITTLE_ENDIAN	0

+#define PJ_IS_BIG_ENDIAN	1

+

+

+#endif	/* __PJ_COMPAT_M_SPARC_H__ */

diff --git a/pjlib/include/pj/compat/malloc.h b/pjlib/include/pj/compat/malloc.h
index 78ed9c9..4b5da78 100644
--- a/pjlib/include/pj/compat/malloc.h
+++ b/pjlib/include/pj/compat/malloc.h
@@ -1,27 +1,48 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/malloc.h $
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- * 1     9/16/05 10:02p Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_MALLOC_H__
-#define __PJ_COMPAT_MALLOC_H__
-
-/**
- * @file malloc.h
- * @brief Provides malloc() and free() functions.
- */
-
-#if defined(PJ_HAS_MALLOC_H) && PJ_HAS_MALLOC_H != 0
-#  include <malloc.h>
-#elif defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0
-#  include <stdlib.h>
-#endif
-
-#endif	/* __PJ_COMPAT_MALLOC_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/malloc.h $

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ * 1     9/16/05 10:02p Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_MALLOC_H__

+#define __PJ_COMPAT_MALLOC_H__

+

+/**

+ * @file malloc.h

+ * @brief Provides malloc() and free() functions.

+ */

+

+#if defined(PJ_HAS_MALLOC_H) && PJ_HAS_MALLOC_H != 0

+#  include <malloc.h>

+#elif defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0

+#  include <stdlib.h>

+#endif

+

+#endif	/* __PJ_COMPAT_MALLOC_H__ */

diff --git a/pjlib/include/pj/compat/os_linux.h b/pjlib/include/pj/compat/os_linux.h
index efb661a..8c4d74b 100644
--- a/pjlib/include/pj/compat/os_linux.h
+++ b/pjlib/include/pj/compat/os_linux.h
@@ -1,86 +1,107 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux.h $
- * 
- * 6     10/29/05 11:51a Bennylp
- * Version 0.3-pre2.
- * 
- * 5     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 4     9/22/05 10:31a Bennylp
- * Moving all *.h files to include/.
- * 
- * 3     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- */
-#ifndef __PJ_COMPAT_OS_LINUX_H__
-#define __PJ_COMPAT_OS_LINUX_H__
-
-/**
- * @file os_linux.h
- * @brief Describes Linux operating system specifics.
- */
-
-#define PJ_HAS_ARPA_INET_H	    1
-#define PJ_HAS_ASSERT_H		    1
-#define PJ_HAS_CTYPE_H		    1
-#define PJ_HAS_ERRNO_H		    1
-#define PJ_HAS_LINUX_SOCKET_H	    0
-#define PJ_HAS_MALLOC_H		    1
-#define PJ_HAS_NETDB_H		    1
-#define PJ_HAS_NETINET_IN_H	    1
-#define PJ_HAS_SETJMP_H		    1
-#define PJ_HAS_STDARG_H		    1
-#define PJ_HAS_STDDEF_H		    1
-#define PJ_HAS_STDIO_H		    1
-#define PJ_HAS_STDLIB_H		    1
-#define PJ_HAS_STRING_H		    1
-#define PJ_HAS_SYS_IOCTL_H	    1
-#define PJ_HAS_SYS_SELECT_H	    1
-#define PJ_HAS_SYS_SOCKET_H	    1
-#define PJ_HAS_SYS_TIMEB_H	    1
-#define PJ_HAS_SYS_TYPES_H	    1
-#define PJ_HAS_TIME_H		    1
-#define PJ_HAS_UNISTD_H		    1
-
-#define PJ_HAS_MSWSOCK_H	    0
-#define PJ_HAS_WINSOCK_H	    0
-#define PJ_HAS_WINSOCK2_H	    0
-
-#define PJ_SOCK_HAS_INET_ATON	    1
-
-/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
- * the status of non-blocking connect() operation.
- */
-#define PJ_HAS_SO_ERROR             1
-
-/* This value specifies the value set in errno by the OS when a non-blocking
- * socket recv() can not return immediate daata.
- */
-#define PJ_BLOCKING_ERROR_VAL       EAGAIN
-
-/* This value specifies the value set in errno by the OS when a non-blocking
- * socket connect() can not get connected immediately.
- */
-#define PJ_BLOCKING_CONNECT_ERROR_VAL   EINPROGRESS
-
-/* Default threading is enabled, unless it's overridden. */
-#ifndef PJ_HAS_THREADS
-#  define PJ_HAS_THREADS	    (1)
-#endif
-
-#define PJ_HAS_HIGH_RES_TIMER	    1
-#define PJ_HAS_MALLOC               1
-#define PJ_OS_HAS_CHECK_STACK	    0
-
-#define PJ_ATOMIC_VALUE_TYPE	    long
-
-#endif	/* __PJ_COMPAT_OS_LINUX_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux.h $

+ * 

+ * 6     10/29/05 11:51a Bennylp

+ * Version 0.3-pre2.

+ * 

+ * 5     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 4     9/22/05 10:31a Bennylp

+ * Moving all *.h files to include/.

+ * 

+ * 3     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ */

+#ifndef __PJ_COMPAT_OS_LINUX_H__

+#define __PJ_COMPAT_OS_LINUX_H__

+

+/**

+ * @file os_linux.h

+ * @brief Describes Linux operating system specifics.

+ */

+

+#define PJ_HAS_ARPA_INET_H	    1

+#define PJ_HAS_ASSERT_H		    1

+#define PJ_HAS_CTYPE_H		    1

+#define PJ_HAS_ERRNO_H		    1

+#define PJ_HAS_LINUX_SOCKET_H	    0

+#define PJ_HAS_MALLOC_H		    1

+#define PJ_HAS_NETDB_H		    1

+#define PJ_HAS_NETINET_IN_H	    1

+#define PJ_HAS_SETJMP_H		    1

+#define PJ_HAS_STDARG_H		    1

+#define PJ_HAS_STDDEF_H		    1

+#define PJ_HAS_STDIO_H		    1

+#define PJ_HAS_STDLIB_H		    1

+#define PJ_HAS_STRING_H		    1

+#define PJ_HAS_SYS_IOCTL_H	    1

+#define PJ_HAS_SYS_SELECT_H	    1

+#define PJ_HAS_SYS_SOCKET_H	    1

+#define PJ_HAS_SYS_TIMEB_H	    1

+#define PJ_HAS_SYS_TYPES_H	    1

+#define PJ_HAS_TIME_H		    1

+#define PJ_HAS_UNISTD_H		    1

+

+#define PJ_HAS_MSWSOCK_H	    0

+#define PJ_HAS_WINSOCK_H	    0

+#define PJ_HAS_WINSOCK2_H	    0

+

+#define PJ_SOCK_HAS_INET_ATON	    1

+

+/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return

+ * the status of non-blocking connect() operation.

+ */

+#define PJ_HAS_SO_ERROR             1

+

+/* This value specifies the value set in errno by the OS when a non-blocking

+ * socket recv() can not return immediate daata.

+ */

+#define PJ_BLOCKING_ERROR_VAL       EAGAIN

+

+/* This value specifies the value set in errno by the OS when a non-blocking

+ * socket connect() can not get connected immediately.

+ */

+#define PJ_BLOCKING_CONNECT_ERROR_VAL   EINPROGRESS

+

+/* Default threading is enabled, unless it's overridden. */

+#ifndef PJ_HAS_THREADS

+#  define PJ_HAS_THREADS	    (1)

+#endif

+

+#define PJ_HAS_HIGH_RES_TIMER	    1

+#define PJ_HAS_MALLOC               1

+#define PJ_OS_HAS_CHECK_STACK	    0

+

+#define PJ_ATOMIC_VALUE_TYPE	    long

+

+#endif	/* __PJ_COMPAT_OS_LINUX_H__ */

+

diff --git a/pjlib/include/pj/compat/os_linux_kernel.h b/pjlib/include/pj/compat/os_linux_kernel.h
index ccae341..5f78456 100644
--- a/pjlib/include/pj/compat/os_linux_kernel.h
+++ b/pjlib/include/pj/compat/os_linux_kernel.h
@@ -1,103 +1,124 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux_kernel.h $
- * 
- * 4     10/29/05 11:51a Bennylp
- * Version 0.3-pre2.
- * 
- * 3     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 2     9/22/05 10:31a Bennylp
- * Moving all *.h files to include/.
- * 
- * 1     9/21/05 1:38p Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_OS_LINUX_KERNEL_H__
-#define __PJ_COMPAT_OS_LINUX_KERNEL_H__
-
-/**
- * @file os_linux.h
- * @brief Describes Linux operating system specifics.
- */
-
-#define PJ_HAS_ARPA_INET_H	    0
-#define PJ_HAS_ASSERT_H		    0
-#define PJ_HAS_CTYPE_H		    0
-#define PJ_HAS_ERRNO_H		    0
-#define PJ_HAS_LINUX_SOCKET_H	    1
-#define PJ_HAS_MALLOC_H		    0
-#define PJ_HAS_NETDB_H		    0
-#define PJ_HAS_NETINET_IN_H	    0
-#define PJ_HAS_SETJMP_H		    0
-#define PJ_HAS_STDARG_H		    1
-#define PJ_HAS_STDDEF_H		    0
-#define PJ_HAS_STDIO_H		    0
-#define PJ_HAS_STDLIB_H		    0
-#define PJ_HAS_STRING_H		    0
-#define PJ_HAS_SYS_IOCTL_H	    0
-#define PJ_HAS_SYS_SELECT_H	    0
-#define PJ_HAS_SYS_SOCKET_H	    0
-#define PJ_HAS_SYS_TIMEB_H	    0
-#define PJ_HAS_SYS_TYPES_H	    0
-#define PJ_HAS_TIME_H		    0
-#define PJ_HAS_UNISTD_H		    0
-
-#define PJ_HAS_MSWSOCK_H	    0
-#define PJ_HAS_WINSOCK_H	    0
-#define PJ_HAS_WINSOCK2_H	    0
-
-#define PJ_SOCK_HAS_INET_ATON	    0
-
-/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
- * the status of non-blocking connect() operation.
- */
-#define PJ_HAS_SO_ERROR             1
-
-/* This value specifies the value set in errno by the OS when a non-blocking
- * socket recv() can not return immediate daata.
- */
-#define PJ_BLOCKING_ERROR_VAL       EAGAIN
-
-/* This value specifies the value set in errno by the OS when a non-blocking
- * socket connect() can not get connected immediately.
- */
-#define PJ_BLOCKING_CONNECT_ERROR_VAL   EINPROGRESS
-
-#ifndef PJ_HAS_THREADS
-#  define PJ_HAS_THREADS	    (1)
-#endif
-
-
-/*
- * Declare __FD_SETSIZE now before including <linux*>.
- */
-#define __FD_SETSIZE		    PJ_IOQUEUE_MAX_HANDLES
-
-#define NULL			    ((void*)0)
-
-#include <linux/module.h>	/* Needed by all modules */
-#include <linux/kernel.h>	/* Needed for KERN_INFO */
-
-#define __PJ_EXPORT_SYMBOL(a)	    EXPORT_SYMBOL(a);
-
-/*
- * Override features.
- */
-#define PJ_HAS_FLOATING_POINT	    0
-#define PJ_HAS_MALLOC               0
-#define PJ_HAS_SEMAPHORE	    0
-#define PJ_HAS_EVENT_OBJ	    0
-#define PJ_HAS_HIGH_RES_TIMER	    1
-#define PJ_OS_HAS_CHECK_STACK	    0
-#define PJ_TERM_HAS_COLOR	    0
-
-#define PJ_ATOMIC_VALUE_TYPE	    int
-#define PJ_THREAD_DESC_SIZE	    128
-
-#endif	/* __PJ_COMPAT_OS_LINUX_KERNEL_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_linux_kernel.h $

+ * 

+ * 4     10/29/05 11:51a Bennylp

+ * Version 0.3-pre2.

+ * 

+ * 3     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 2     9/22/05 10:31a Bennylp

+ * Moving all *.h files to include/.

+ * 

+ * 1     9/21/05 1:38p Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_OS_LINUX_KERNEL_H__

+#define __PJ_COMPAT_OS_LINUX_KERNEL_H__

+

+/**

+ * @file os_linux.h

+ * @brief Describes Linux operating system specifics.

+ */

+

+#define PJ_HAS_ARPA_INET_H	    0

+#define PJ_HAS_ASSERT_H		    0

+#define PJ_HAS_CTYPE_H		    0

+#define PJ_HAS_ERRNO_H		    0

+#define PJ_HAS_LINUX_SOCKET_H	    1

+#define PJ_HAS_MALLOC_H		    0

+#define PJ_HAS_NETDB_H		    0

+#define PJ_HAS_NETINET_IN_H	    0

+#define PJ_HAS_SETJMP_H		    0

+#define PJ_HAS_STDARG_H		    1

+#define PJ_HAS_STDDEF_H		    0

+#define PJ_HAS_STDIO_H		    0

+#define PJ_HAS_STDLIB_H		    0

+#define PJ_HAS_STRING_H		    0

+#define PJ_HAS_SYS_IOCTL_H	    0

+#define PJ_HAS_SYS_SELECT_H	    0

+#define PJ_HAS_SYS_SOCKET_H	    0

+#define PJ_HAS_SYS_TIMEB_H	    0

+#define PJ_HAS_SYS_TYPES_H	    0

+#define PJ_HAS_TIME_H		    0

+#define PJ_HAS_UNISTD_H		    0

+

+#define PJ_HAS_MSWSOCK_H	    0

+#define PJ_HAS_WINSOCK_H	    0

+#define PJ_HAS_WINSOCK2_H	    0

+

+#define PJ_SOCK_HAS_INET_ATON	    0

+

+/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return

+ * the status of non-blocking connect() operation.

+ */

+#define PJ_HAS_SO_ERROR             1

+

+/* This value specifies the value set in errno by the OS when a non-blocking

+ * socket recv() can not return immediate daata.

+ */

+#define PJ_BLOCKING_ERROR_VAL       EAGAIN

+

+/* This value specifies the value set in errno by the OS when a non-blocking

+ * socket connect() can not get connected immediately.

+ */

+#define PJ_BLOCKING_CONNECT_ERROR_VAL   EINPROGRESS

+

+#ifndef PJ_HAS_THREADS

+#  define PJ_HAS_THREADS	    (1)

+#endif

+

+

+/*

+ * Declare __FD_SETSIZE now before including <linux*>.

+ */

+#define __FD_SETSIZE		    PJ_IOQUEUE_MAX_HANDLES

+

+#define NULL			    ((void*)0)

+

+#include <linux/module.h>	/* Needed by all modules */

+#include <linux/kernel.h>	/* Needed for KERN_INFO */

+

+#define __PJ_EXPORT_SYMBOL(a)	    EXPORT_SYMBOL(a);

+

+/*

+ * Override features.

+ */

+#define PJ_HAS_FLOATING_POINT	    0

+#define PJ_HAS_MALLOC               0

+#define PJ_HAS_SEMAPHORE	    0

+#define PJ_HAS_EVENT_OBJ	    0

+#define PJ_HAS_HIGH_RES_TIMER	    1

+#define PJ_OS_HAS_CHECK_STACK	    0

+#define PJ_TERM_HAS_COLOR	    0

+

+#define PJ_ATOMIC_VALUE_TYPE	    int

+#define PJ_THREAD_DESC_SIZE	    128

+

+#endif	/* __PJ_COMPAT_OS_LINUX_KERNEL_H__ */

+

diff --git a/pjlib/include/pj/compat/os_palmos.h b/pjlib/include/pj/compat/os_palmos.h
index e2ac4b5..7fb5647 100644
--- a/pjlib/include/pj/compat/os_palmos.h
+++ b/pjlib/include/pj/compat/os_palmos.h
@@ -1,49 +1,70 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/os_palmos.h $
- * 
- * 3     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- */
-#ifndef __PJ_COMPAT_OS_PALMOS_H__
-#define __PJ_COMPAT_OS_PALMOS_H__
-
-/**
- * @file os_palmos.h
- * @brief Describes PalmOS operating system specifics.
- */
-
-#define PJ_HAS_ARPA_INET_H	    0
-#define PJ_HAS_ASSERT_H		    1
-#define PJ_HAS_CTYPE_H		    1
-#define PJ_HAS_ERRNO_H		    0
-#define PJ_HAS_MALLOC_H		    1
-#define PJ_HAS_NETDB_H		    0
-#define PJ_HAS_NETINET_IN_H	    0
-#define PJ_HAS_SETJMP_H		    1
-#define PJ_HAS_STDARG_H		    1
-#define PJ_HAS_STDDEF_H		    1
-#define PJ_HAS_STDIO_H		    1
-#define PJ_HAS_STDLIB_H		    1
-#define PJ_HAS_STRING_H		    1
-#define PJ_HAS_SYS_IOCTL_H	    0
-#define PJ_HAS_SYS_SELECT_H	    0
-#define PJ_HAS_SYS_SOCKET_H	    0
-#define PJ_HAS_SYS_TIMEB_H	    0
-#define PJ_HAS_SYS_TYPES_H	    1
-#define PJ_HAS_TIME_H		    1
-#define PJ_HAS_UNISTD_H		    0
-
-#define PJ_HAS_MSWSOCK_H	    0
-#define PJ_HAS_WINSOCK_H	    0
-#define PJ_HAS_WINSOCK2_H	    0
-
-#define PJ_SOCK_HAS_INET_ATON	    0
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/os_palmos.h $

+ * 

+ * 3     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ */

+#ifndef __PJ_COMPAT_OS_PALMOS_H__

+#define __PJ_COMPAT_OS_PALMOS_H__

+

+/**

+ * @file os_palmos.h

+ * @brief Describes PalmOS operating system specifics.

+ */

+

+#define PJ_HAS_ARPA_INET_H	    0

+#define PJ_HAS_ASSERT_H		    1

+#define PJ_HAS_CTYPE_H		    1

+#define PJ_HAS_ERRNO_H		    0

+#define PJ_HAS_MALLOC_H		    1

+#define PJ_HAS_NETDB_H		    0

+#define PJ_HAS_NETINET_IN_H	    0

+#define PJ_HAS_SETJMP_H		    1

+#define PJ_HAS_STDARG_H		    1

+#define PJ_HAS_STDDEF_H		    1

+#define PJ_HAS_STDIO_H		    1

+#define PJ_HAS_STDLIB_H		    1

+#define PJ_HAS_STRING_H		    1

+#define PJ_HAS_SYS_IOCTL_H	    0

+#define PJ_HAS_SYS_SELECT_H	    0

+#define PJ_HAS_SYS_SOCKET_H	    0

+#define PJ_HAS_SYS_TIMEB_H	    0

+#define PJ_HAS_SYS_TYPES_H	    1

+#define PJ_HAS_TIME_H		    1

+#define PJ_HAS_UNISTD_H		    0

+

+#define PJ_HAS_MSWSOCK_H	    0

+#define PJ_HAS_WINSOCK_H	    0

+#define PJ_HAS_WINSOCK2_H	    0

+

+#define PJ_SOCK_HAS_INET_ATON	    0

 

 /* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return

  * the status of non-blocking connect() operation.

@@ -59,13 +80,13 @@
  * socket connect() can not get connected immediately.

  */

 #define PJ_BLOCKING_CONNECT_ERROR_VAL   xxx

-
-/* Default threading is enabled, unless it's overridden. */
-#ifndef PJ_HAS_THREADS
-#  define PJ_HAS_THREADS	    (1)
-#endif
-
-#define PJ_HAS_HIGH_RES_TIMER	    1
-#define PJ_OS_HAS_CHECK_STACK	    0
-
-#endif	/* __PJ_COMPAT_OS_PALMOS_H__ */
+

+/* Default threading is enabled, unless it's overridden. */

+#ifndef PJ_HAS_THREADS

+#  define PJ_HAS_THREADS	    (1)

+#endif

+

+#define PJ_HAS_HIGH_RES_TIMER	    1

+#define PJ_OS_HAS_CHECK_STACK	    0

+

+#endif	/* __PJ_COMPAT_OS_PALMOS_H__ */

diff --git a/pjlib/include/pj/compat/os_sunos.h b/pjlib/include/pj/compat/os_sunos.h
index 87c408a..d2406e5 100644
--- a/pjlib/include/pj/compat/os_sunos.h
+++ b/pjlib/include/pj/compat/os_sunos.h
@@ -1,73 +1,94 @@
-/* $Id$
- *
- */
-/* $Log:  $
- * 
- */
-#ifndef __PJ_COMPAT_OS_SUNOS_H__
-#define __PJ_COMPAT_OS_SUNOS_H__
-
-/**
- * @file os_sunos.h
- * @brief Describes SunOS/Solaris operating system specifics.
- */
-
-#define PJ_HAS_ARPA_INET_H	    1
-#define PJ_HAS_ASSERT_H		    1
-#define PJ_HAS_CTYPE_H		    1
-#define PJ_HAS_ERRNO_H		    1
-#define PJ_HAS_LINUX_SOCKET_H	    0
-#define PJ_HAS_MALLOC_H		    1
-#define PJ_HAS_NETDB_H		    1
-#define PJ_HAS_NETINET_IN_H	    1
-#define PJ_HAS_SETJMP_H		    1
-#define PJ_HAS_STDARG_H		    1
-#define PJ_HAS_STDDEF_H		    1
-#define PJ_HAS_STDIO_H		    1
-#define PJ_HAS_STDLIB_H		    1
-#define PJ_HAS_STRING_H		    1
-#define PJ_HAS_SYS_IOCTL_H	    1
-#define PJ_HAS_SYS_SELECT_H	    1
-#define PJ_HAS_SYS_SOCKET_H	    1
-#define PJ_HAS_SYS_TIMEB_H	    1
-#define PJ_HAS_SYS_TYPES_H	    1
-#define PJ_HAS_TIME_H		    1
-#define PJ_HAS_UNISTD_H		    1
-
-#define PJ_HAS_MSWSOCK_H	    0
-#define PJ_HAS_WINSOCK_H	    0
-#define PJ_HAS_WINSOCK2_H	    0
-
-#define PJ_SOCK_HAS_INET_ATON	    0
-
-/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
- * the status of non-blocking connect() operation.
- */
-#define PJ_HAS_SO_ERROR             0
-
-/* This value specifies the value set in errno by the OS when a non-blocking
- * socket recv() can not return immediate daata.
- */
-#define PJ_BLOCKING_ERROR_VAL       EWOULDBLOCK
-
-/* This value specifies the value set in errno by the OS when a non-blocking
- * socket connect() can not get connected immediately.
- */
-#define PJ_BLOCKING_CONNECT_ERROR_VAL   EINPROGRESS
-
-/* Default threading is enabled, unless it's overridden. */
-#ifndef PJ_HAS_THREADS
-#  define PJ_HAS_THREADS	    (1)
-#endif
-
-#define PJ_HAS_HIGH_RES_TIMER	    1
-#define PJ_HAS_MALLOC               1
-#define PJ_OS_HAS_CHECK_STACK	    0
-
-#define PJ_ATOMIC_VALUE_TYPE	    long
-
-/* Get BSD related identifers in Sun's include files */
-#define BSD_COMP
-
-#endif	/* __PJ_COMPAT_OS_SUNOS_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log:  $

+ * 

+ */

+#ifndef __PJ_COMPAT_OS_SUNOS_H__

+#define __PJ_COMPAT_OS_SUNOS_H__

+

+/**

+ * @file os_sunos.h

+ * @brief Describes SunOS/Solaris operating system specifics.

+ */

+

+#define PJ_HAS_ARPA_INET_H	    1

+#define PJ_HAS_ASSERT_H		    1

+#define PJ_HAS_CTYPE_H		    1

+#define PJ_HAS_ERRNO_H		    1

+#define PJ_HAS_LINUX_SOCKET_H	    0

+#define PJ_HAS_MALLOC_H		    1

+#define PJ_HAS_NETDB_H		    1

+#define PJ_HAS_NETINET_IN_H	    1

+#define PJ_HAS_SETJMP_H		    1

+#define PJ_HAS_STDARG_H		    1

+#define PJ_HAS_STDDEF_H		    1

+#define PJ_HAS_STDIO_H		    1

+#define PJ_HAS_STDLIB_H		    1

+#define PJ_HAS_STRING_H		    1

+#define PJ_HAS_SYS_IOCTL_H	    1

+#define PJ_HAS_SYS_SELECT_H	    1

+#define PJ_HAS_SYS_SOCKET_H	    1

+#define PJ_HAS_SYS_TIMEB_H	    1

+#define PJ_HAS_SYS_TYPES_H	    1

+#define PJ_HAS_TIME_H		    1

+#define PJ_HAS_UNISTD_H		    1

+

+#define PJ_HAS_MSWSOCK_H	    0

+#define PJ_HAS_WINSOCK_H	    0

+#define PJ_HAS_WINSOCK2_H	    0

+

+#define PJ_SOCK_HAS_INET_ATON	    0

+

+/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return

+ * the status of non-blocking connect() operation.

+ */

+#define PJ_HAS_SO_ERROR             0

+

+/* This value specifies the value set in errno by the OS when a non-blocking

+ * socket recv() can not return immediate daata.

+ */

+#define PJ_BLOCKING_ERROR_VAL       EWOULDBLOCK

+

+/* This value specifies the value set in errno by the OS when a non-blocking

+ * socket connect() can not get connected immediately.

+ */

+#define PJ_BLOCKING_CONNECT_ERROR_VAL   EINPROGRESS

+

+/* Default threading is enabled, unless it's overridden. */

+#ifndef PJ_HAS_THREADS

+#  define PJ_HAS_THREADS	    (1)

+#endif

+

+#define PJ_HAS_HIGH_RES_TIMER	    1

+#define PJ_HAS_MALLOC               1

+#define PJ_OS_HAS_CHECK_STACK	    0

+

+#define PJ_ATOMIC_VALUE_TYPE	    long

+

+/* Get BSD related identifers in Sun's include files */

+#define BSD_COMP

+

+#endif	/* __PJ_COMPAT_OS_SUNOS_H__ */

+

diff --git a/pjlib/include/pj/compat/os_win32.h b/pjlib/include/pj/compat/os_win32.h
index e8391b9..b128060 100644
--- a/pjlib/include/pj/compat/os_win32.h
+++ b/pjlib/include/pj/compat/os_win32.h
@@ -1,89 +1,110 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_win32.h $
- * 
- * 6     10/29/05 11:51a Bennylp
- * Version 0.3-pre2.
- * 
- * 5     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 4     9/22/05 10:31a Bennylp
- * Moving all *.h files to include/.
- * 
- * 3     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- */
-#ifndef __PJ_COMPAT_OS_WIN32_H__
-#define __PJ_COMPAT_OS_WIN32_H__
-
-/**
- * @file os_win32.h
- * @brief Describes Win32 operating system family specifics.
- */
-
-#define WIN32_LEAN_AND_MEAN
-#define PJ_WIN32_WINNT		    0x0400
-#define _WIN32_WINNT		    PJ_WIN32_WINNT
-
-#define PJ_HAS_ARPA_INET_H	    0
-#define PJ_HAS_ASSERT_H		    1
-#define PJ_HAS_CTYPE_H		    1
-#define PJ_HAS_ERRNO_H		    0   /* Must be zero, otherwise errno_test() fails. */
-#define PJ_HAS_LINUX_SOCKET_H	    0
-#define PJ_HAS_MALLOC_H		    1
-#define PJ_HAS_NETDB_H		    0
-#define PJ_HAS_NETINET_IN_H	    0
-#define PJ_HAS_SETJMP_H		    1
-#define PJ_HAS_STDARG_H		    1
-#define PJ_HAS_STDDEF_H		    1
-#define PJ_HAS_STDIO_H		    1
-#define PJ_HAS_STDLIB_H		    1
-#define PJ_HAS_STRING_H		    1
-#define PJ_HAS_SYS_IOCTL_H	    0
-#define PJ_HAS_SYS_SELECT_H	    0
-#define PJ_HAS_SYS_SOCKET_H	    0
-#define PJ_HAS_SYS_TIMEB_H	    1
-#define PJ_HAS_SYS_TYPES_H	    1
-#define PJ_HAS_TIME_H		    1
-#define PJ_HAS_UNISTD_H		    0
-
-#define PJ_HAS_MSWSOCK_H	    1
-#define PJ_HAS_WINSOCK_H	    0
-#define PJ_HAS_WINSOCK2_H	    1
-
-#define PJ_SOCK_HAS_INET_ATON	    0
-
-/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return
- * the status of non-blocking connect() operation.
- */
-#define PJ_HAS_SO_ERROR             0
-
-/* This value specifies the value set in errno by the OS when a non-blocking
- * socket recv() or send() can not return immediately.
- */
-#define PJ_BLOCKING_ERROR_VAL       WSAEWOULDBLOCK
-
-/* This value specifies the value set in errno by the OS when a non-blocking
- * socket connect() can not get connected immediately.
- */
-#define PJ_BLOCKING_CONNECT_ERROR_VAL   WSAEWOULDBLOCK
-
-/* Default threading is enabled, unless it's overridden. */
-#ifndef PJ_HAS_THREADS
-#  define PJ_HAS_THREADS	    (1)
-#endif
-
-#define PJ_HAS_HIGH_RES_TIMER	    1
-#define PJ_HAS_MALLOC               1
-#define PJ_OS_HAS_CHECK_STACK	    1
-
-#define PJ_ATOMIC_VALUE_TYPE	    long
-
-#endif	/* __PJ_COMPAT_OS_WIN32_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/os_win32.h $

+ * 

+ * 6     10/29/05 11:51a Bennylp

+ * Version 0.3-pre2.

+ * 

+ * 5     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 4     9/22/05 10:31a Bennylp

+ * Moving all *.h files to include/.

+ * 

+ * 3     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ */

+#ifndef __PJ_COMPAT_OS_WIN32_H__

+#define __PJ_COMPAT_OS_WIN32_H__

+

+/**

+ * @file os_win32.h

+ * @brief Describes Win32 operating system family specifics.

+ */

+

+#define WIN32_LEAN_AND_MEAN

+#define PJ_WIN32_WINNT		    0x0400

+#define _WIN32_WINNT		    PJ_WIN32_WINNT

+

+#define PJ_HAS_ARPA_INET_H	    0

+#define PJ_HAS_ASSERT_H		    1

+#define PJ_HAS_CTYPE_H		    1

+#define PJ_HAS_ERRNO_H		    0   /* Must be zero, otherwise errno_test() fails. */

+#define PJ_HAS_LINUX_SOCKET_H	    0

+#define PJ_HAS_MALLOC_H		    1

+#define PJ_HAS_NETDB_H		    0

+#define PJ_HAS_NETINET_IN_H	    0

+#define PJ_HAS_SETJMP_H		    1

+#define PJ_HAS_STDARG_H		    1

+#define PJ_HAS_STDDEF_H		    1

+#define PJ_HAS_STDIO_H		    1

+#define PJ_HAS_STDLIB_H		    1

+#define PJ_HAS_STRING_H		    1

+#define PJ_HAS_SYS_IOCTL_H	    0

+#define PJ_HAS_SYS_SELECT_H	    0

+#define PJ_HAS_SYS_SOCKET_H	    0

+#define PJ_HAS_SYS_TIMEB_H	    1

+#define PJ_HAS_SYS_TYPES_H	    1

+#define PJ_HAS_TIME_H		    1

+#define PJ_HAS_UNISTD_H		    0

+

+#define PJ_HAS_MSWSOCK_H	    1

+#define PJ_HAS_WINSOCK_H	    0

+#define PJ_HAS_WINSOCK2_H	    1

+

+#define PJ_SOCK_HAS_INET_ATON	    0

+

+/* When this macro is set, getsockopt(SOL_SOCKET, SO_ERROR) will return

+ * the status of non-blocking connect() operation.

+ */

+#define PJ_HAS_SO_ERROR             0

+

+/* This value specifies the value set in errno by the OS when a non-blocking

+ * socket recv() or send() can not return immediately.

+ */

+#define PJ_BLOCKING_ERROR_VAL       WSAEWOULDBLOCK

+

+/* This value specifies the value set in errno by the OS when a non-blocking

+ * socket connect() can not get connected immediately.

+ */

+#define PJ_BLOCKING_CONNECT_ERROR_VAL   WSAEWOULDBLOCK

+

+/* Default threading is enabled, unless it's overridden. */

+#ifndef PJ_HAS_THREADS

+#  define PJ_HAS_THREADS	    (1)

+#endif

+

+#define PJ_HAS_HIGH_RES_TIMER	    1

+#define PJ_HAS_MALLOC               1

+#define PJ_OS_HAS_CHECK_STACK	    1

+

+#define PJ_ATOMIC_VALUE_TYPE	    long

+

+#endif	/* __PJ_COMPAT_OS_WIN32_H__ */

diff --git a/pjlib/include/pj/compat/rand.h b/pjlib/include/pj/compat/rand.h
index b65bf10..af4d915 100644
--- a/pjlib/include/pj/compat/rand.h
+++ b/pjlib/include/pj/compat/rand.h
@@ -1,67 +1,88 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/compat/rand.h $
- * 
- * 3     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 2     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_RAND_H__
-#define __PJ_COMPAT_RAND_H__
-
-/**
- * @file rand.h
- * @brief Provides platform_rand() and platform_srand() functions.
- */
-
-#if defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0
-   /*
-    * Use stdlib based rand() and srand().
-    */
-#  include <stdlib.h>
-#  define platform_srand    srand
-#  if defined(RAND_MAX) && RAND_MAX <= 0xFFFF
-       /*
-        * When rand() is only 16 bit strong, double the strength
-	* by calling it twice!
-	*/
-       PJ_INLINE(int) platform_rand(void)
-       {
-	   return ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF);
-       }
-#  else
-#      define platform_rand rand
-#  endif
-
-#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
-   /*
-    * Linux kernel mode random number generator.
-    */
-#  include <linux/random.h>
-#  define platform_srand(seed)
-
-   PJ_INLINE(int) platform_rand(void)
-   {
-     int value;
-     get_random_bytes((void*)&value, sizeof(value));
-     return value;
-   }
-
-#else
-#  warning "platform_rand() is not implemented"
-#  define platform_rand()	1
-#  define platform_srand(seed)
-
-#endif
-
-
-#endif	/* __PJ_COMPAT_RAND_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/rand.h $

+ * 

+ * 3     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 2     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_RAND_H__

+#define __PJ_COMPAT_RAND_H__

+

+/**

+ * @file rand.h

+ * @brief Provides platform_rand() and platform_srand() functions.

+ */

+

+#if defined(PJ_HAS_STDLIB_H) && PJ_HAS_STDLIB_H != 0

+   /*

+    * Use stdlib based rand() and srand().

+    */

+#  include <stdlib.h>

+#  define platform_srand    srand

+#  if defined(RAND_MAX) && RAND_MAX <= 0xFFFF

+       /*

+        * When rand() is only 16 bit strong, double the strength

+	* by calling it twice!

+	*/

+       PJ_INLINE(int) platform_rand(void)

+       {

+	   return ((rand() & 0xFFFF) << 16) | (rand() & 0xFFFF);

+       }

+#  else

+#      define platform_rand rand

+#  endif

+

+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0

+   /*

+    * Linux kernel mode random number generator.

+    */

+#  include <linux/random.h>

+#  define platform_srand(seed)

+

+   PJ_INLINE(int) platform_rand(void)

+   {

+     int value;

+     get_random_bytes((void*)&value, sizeof(value));

+     return value;

+   }

+

+#else

+#  warning "platform_rand() is not implemented"

+#  define platform_rand()	1

+#  define platform_srand(seed)

+

+#endif

+

+

+#endif	/* __PJ_COMPAT_RAND_H__ */

+

diff --git a/pjlib/include/pj/compat/setjmp.h b/pjlib/include/pj/compat/setjmp.h
index fb0c7d6..f018cd9 100644
--- a/pjlib/include/pj/compat/setjmp.h
+++ b/pjlib/include/pj/compat/setjmp.h
@@ -1,91 +1,112 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/compat/setjmp.h $
- * 
- * 4     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 3     9/22/05 10:31a Bennylp
- * Moving all *.h files to include/.
- * 
- * 2     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_SETJMP_H__
-#define __PJ_COMPAT_SETJMP_H__
-
-/**
- * @file setjmp.h
- * @brief Provides setjmp.h functionality.
- */
-
-#if defined(PJ_HAS_SETJMP_H) && PJ_HAS_SETJMP_H != 0
-#  include <setjmp.h>
-   typedef jmp_buf pj_jmp_buf;
-#  define pj_setjmp(buf)	setjmp(buf)
-#  define pj_longjmp(buf,d)	longjmp(buf,d)
-
-#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 && \
-      defined(PJ_M_I386) && PJ_M_I386 != 0
-
-    /*
-     * These are taken from uClibc.
-     * Copyright (C) 2000-2003 Erik Andersen <andersen@uclibc.org>
-     */
-#   if defined __USE_MISC || defined _ASM
-#	define JB_BX	0
-#	define JB_SI	1
-#	define JB_DI	2
-#	define JB_BP	3
-#	define JB_SP	4
-#	define JB_PC	5
-#	define JB_SIZE 24
-#   endif
-
-# ifndef _ASM
-	typedef int __jmp_buf[6];
-
-    /* A `sigset_t' has a bit for each signal.  */
-#   define _SIGSET_NWORDS	(1024 / (8 * sizeof (unsigned long int)))
-    typedef struct __sigset_t_tag
-    {
-	unsigned long int __val[_SIGSET_NWORDS];
-    } __sigset_t;
-
-    /* Calling environment, plus possibly a saved signal mask.  */
-    typedef struct __jmp_buf_tag    /* C++ doesn't like tagless structs.  */
-    {
-	/* NOTE: The machine-dependent definitions of `__sigsetjmp'
-	   assume that a `jmp_buf' begins with a `__jmp_buf' and that
-	   `__mask_was_saved' follows it.  Do not move these members
-	   or add others before it.  */
-	__jmp_buf __jmpbuf;		/* Calling environment.  */
-	int __mask_was_saved;		/* Saved the signal mask?  */
-	// we never saved the mask.
-	__sigset_t __saved_mask;	/* Saved signal mask.  */
-    } jmp_buf[1];
-
-    typedef jmp_buf sigjmp_buf;
-    typedef jmp_buf pj_jmp_buf;
-
-    PJ_DECL(int) pj_setjmp(pj_jmp_buf env);
-    PJ_DECL(void) pj_longjmp(pj_jmp_buf env, int val) __attribute__((noreturn));
-
-# endif   /* _ASM */
-
-#else
-#  warning "setjmp()/longjmp() is not implemented"
-   typedef int pj_jmp_buf[1];
-#  define pj_setjmp(buf)	0
-#  define pj_longjmp(buf,d)	0
-#endif
-
-
-#endif	/* __PJ_COMPAT_SETJMP_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/setjmp.h $

+ * 

+ * 4     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 3     9/22/05 10:31a Bennylp

+ * Moving all *.h files to include/.

+ * 

+ * 2     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_SETJMP_H__

+#define __PJ_COMPAT_SETJMP_H__

+

+/**

+ * @file setjmp.h

+ * @brief Provides setjmp.h functionality.

+ */

+

+#if defined(PJ_HAS_SETJMP_H) && PJ_HAS_SETJMP_H != 0

+#  include <setjmp.h>

+   typedef jmp_buf pj_jmp_buf;

+#  define pj_setjmp(buf)	setjmp(buf)

+#  define pj_longjmp(buf,d)	longjmp(buf,d)

+

+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0 && \

+      defined(PJ_M_I386) && PJ_M_I386 != 0

+

+    /*

+     * These are taken from uClibc.

+     * Copyright (C) 2000-2003 Erik Andersen <andersen@uclibc.org>

+     */

+#   if defined __USE_MISC || defined _ASM

+#	define JB_BX	0

+#	define JB_SI	1

+#	define JB_DI	2

+#	define JB_BP	3

+#	define JB_SP	4

+#	define JB_PC	5

+#	define JB_SIZE 24

+#   endif

+

+# ifndef _ASM

+	typedef int __jmp_buf[6];

+

+    /* A `sigset_t' has a bit for each signal.  */

+#   define _SIGSET_NWORDS	(1024 / (8 * sizeof (unsigned long int)))

+    typedef struct __sigset_t_tag

+    {

+	unsigned long int __val[_SIGSET_NWORDS];

+    } __sigset_t;

+

+    /* Calling environment, plus possibly a saved signal mask.  */

+    typedef struct __jmp_buf_tag    /* C++ doesn't like tagless structs.  */

+    {

+	/* NOTE: The machine-dependent definitions of `__sigsetjmp'

+	   assume that a `jmp_buf' begins with a `__jmp_buf' and that

+	   `__mask_was_saved' follows it.  Do not move these members

+	   or add others before it.  */

+	__jmp_buf __jmpbuf;		/* Calling environment.  */

+	int __mask_was_saved;		/* Saved the signal mask?  */

+	// we never saved the mask.

+	__sigset_t __saved_mask;	/* Saved signal mask.  */

+    } jmp_buf[1];

+

+    typedef jmp_buf sigjmp_buf;

+    typedef jmp_buf pj_jmp_buf;

+

+    PJ_DECL(int) pj_setjmp(pj_jmp_buf env);

+    PJ_DECL(void) pj_longjmp(pj_jmp_buf env, int val) __attribute__((noreturn));

+

+# endif   /* _ASM */

+

+#else

+#  warning "setjmp()/longjmp() is not implemented"

+   typedef int pj_jmp_buf[1];

+#  define pj_setjmp(buf)	0

+#  define pj_longjmp(buf,d)	0

+#endif

+

+

+#endif	/* __PJ_COMPAT_SETJMP_H__ */

+

diff --git a/pjlib/include/pj/compat/size_t.h b/pjlib/include/pj/compat/size_t.h
index bdb7e02..70ae068 100644
--- a/pjlib/include/pj/compat/size_t.h
+++ b/pjlib/include/pj/compat/size_t.h
@@ -1,25 +1,46 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/size_t.h $
- * 
- * 2     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_SIZE_T_H__
-#define __PJ_COMPAT_SIZE_T_H__
-
-/**
- * @file size_t.h
- * @brief Provides size_t type.
- */
-#if PJ_HAS_STDDEF_H
-# include <stddef.h>
-#endif
-
-#endif	/* __PJ_COMPAT_SIZE_T_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/size_t.h $

+ * 

+ * 2     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_SIZE_T_H__

+#define __PJ_COMPAT_SIZE_T_H__

+

+/**

+ * @file size_t.h

+ * @brief Provides size_t type.

+ */

+#if PJ_HAS_STDDEF_H

+# include <stddef.h>

+#endif

+

+#endif	/* __PJ_COMPAT_SIZE_T_H__ */

+

diff --git a/pjlib/include/pj/compat/socket.h b/pjlib/include/pj/compat/socket.h
index f2de0cb..2a989d1 100644
--- a/pjlib/include/pj/compat/socket.h
+++ b/pjlib/include/pj/compat/socket.h
@@ -1,131 +1,152 @@
-/* $Id$
- *
-*/
-/* $Log: /pjproject-0.3/pjlib/include/pj/compat/socket.h $
- * 
- * 5     10/29/05 11:51a Bennylp
- * Version 0.3-pre2.
- * 
- * 4     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 3     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- */
-#ifndef __PJ_COMPAT_SOCKET_H__
-#define __PJ_COMPAT_SOCKET_H__
-
-/**
- * @file socket.h
- * @brief Provides all socket related functions,data types, error codes, etc.
- */
-
-#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
-#  include <winsock.h>
-#endif
-
-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
-#  include <winsock2.h>
-#endif
-
-#if defined(PJ_HAS_SYS_TYPES_H) && PJ_HAS_SYS_TYPES_H != 0
-#  include <sys/types.h>
-#endif
-
-#if defined(PJ_HAS_SYS_SOCKET_H) && PJ_HAS_SYS_SOCKET_H != 0
-#  include <sys/socket.h>
-#endif
-
-#if defined(PJ_HAS_LINUX_SOCKET_H) && PJ_HAS_LINUX_SOCKET_H != 0
-#  include <linux/socket.h>
-#endif
-
-#if defined(PJ_HAS_SYS_SELECT_H) && PJ_HAS_SYS_SELECT_H != 0
-#  include <sys/select.h>
-#endif
-
-#if defined(PJ_HAS_NETINET_IN_H) && PJ_HAS_NETINET_IN_H != 0
-#  include <netinet/in.h>
-#endif
-
-#if defined(PJ_HAS_ARPA_INET_H) && PJ_HAS_ARPA_INET_H != 0
-#  include <arpa/inet.h>
-#endif
-
-#if defined(PJ_HAS_SYS_IOCTL_H) && PJ_HAS_SYS_IOCTL_H != 0
-#  include <sys/ioctl.h>	/* FBIONBIO */
-#endif
-
-#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0
-#  include <errno.h>
-#endif
-
-#if defined(PJ_HAS_NETDB_H) && PJ_HAS_NETDB_H != 0
-#  include <netdb.h>
-#endif
-
-#if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0
-#  include <unistd.h>
-#endif
-
-
-/*
- * Define common errors.
- */
-#ifdef PJ_WIN32
-#  define OSERR_EWOULDBLOCK    WSAEWOULDBLOCK
-#  define OSERR_EINPROGRESS    WSAEINPROGRESS
-#else
-#  define OSERR_EWOULDBLOCK    EWOULDBLOCK
-#  define OSERR_EINPROGRESS    EINPROGRESS
-#endif
-
-
-/*
- * And undefine this..
- */
-#undef s_addr
-
-/*
- * Linux kernel specifics
- */
-#ifdef PJ_LINUX_KERNEL
-#   include <linux/net.h>
-#   include <asm/ioctls.h>		/* FIONBIO	*/
-#   include <linux/syscalls.h>	/* sys_select() */
-#   include <asm/uaccess.h>	/* set/get_fs()	*/
-
-    typedef int socklen_t;
-#   define getsockopt  sys_getsockopt
-
-    /*
-     * Wrapper for select() in Linux kernel.
-     */
-    PJ_INLINE(int) select(int n, fd_set *inp, fd_set *outp, fd_set *exp,
-		          struct timeval *tvp)
-    {
-        int count;
-        mm_segment_t oldfs = get_fs();
-        set_fs(KERNEL_DS);
-        count = sys_select(n, inp, outp, exp, tvp);
-        set_fs(oldfs);
-        return count;
-    }
-#endif	/* PJ_LINUX_KERNEL */
-
-
-/*
- * Windows specific
- */
-#ifdef PJ_WIN32
-    typedef int socklen_t;;
-#endif
-
-
-#endif	/* __PJ_COMPAT_SOCKET_H__ */
-
+/* $Id$

+ *

+*/

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/socket.h $

+ * 

+ * 5     10/29/05 11:51a Bennylp

+ * Version 0.3-pre2.

+ * 

+ * 4     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 3     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ */

+#ifndef __PJ_COMPAT_SOCKET_H__

+#define __PJ_COMPAT_SOCKET_H__

+

+/**

+ * @file socket.h

+ * @brief Provides all socket related functions,data types, error codes, etc.

+ */

+

+#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0

+#  include <winsock.h>

+#endif

+

+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0

+#  include <winsock2.h>

+#endif

+

+#if defined(PJ_HAS_SYS_TYPES_H) && PJ_HAS_SYS_TYPES_H != 0

+#  include <sys/types.h>

+#endif

+

+#if defined(PJ_HAS_SYS_SOCKET_H) && PJ_HAS_SYS_SOCKET_H != 0

+#  include <sys/socket.h>

+#endif

+

+#if defined(PJ_HAS_LINUX_SOCKET_H) && PJ_HAS_LINUX_SOCKET_H != 0

+#  include <linux/socket.h>

+#endif

+

+#if defined(PJ_HAS_SYS_SELECT_H) && PJ_HAS_SYS_SELECT_H != 0

+#  include <sys/select.h>

+#endif

+

+#if defined(PJ_HAS_NETINET_IN_H) && PJ_HAS_NETINET_IN_H != 0

+#  include <netinet/in.h>

+#endif

+

+#if defined(PJ_HAS_ARPA_INET_H) && PJ_HAS_ARPA_INET_H != 0

+#  include <arpa/inet.h>

+#endif

+

+#if defined(PJ_HAS_SYS_IOCTL_H) && PJ_HAS_SYS_IOCTL_H != 0

+#  include <sys/ioctl.h>	/* FBIONBIO */

+#endif

+

+#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0

+#  include <errno.h>

+#endif

+

+#if defined(PJ_HAS_NETDB_H) && PJ_HAS_NETDB_H != 0

+#  include <netdb.h>

+#endif

+

+#if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0

+#  include <unistd.h>

+#endif

+

+

+/*

+ * Define common errors.

+ */

+#ifdef PJ_WIN32

+#  define OSERR_EWOULDBLOCK    WSAEWOULDBLOCK

+#  define OSERR_EINPROGRESS    WSAEINPROGRESS

+#else

+#  define OSERR_EWOULDBLOCK    EWOULDBLOCK

+#  define OSERR_EINPROGRESS    EINPROGRESS

+#endif

+

+

+/*

+ * And undefine this..

+ */

+#undef s_addr

+

+/*

+ * Linux kernel specifics

+ */

+#ifdef PJ_LINUX_KERNEL

+#   include <linux/net.h>

+#   include <asm/ioctls.h>		/* FIONBIO	*/

+#   include <linux/syscalls.h>	/* sys_select() */

+#   include <asm/uaccess.h>	/* set/get_fs()	*/

+

+    typedef int socklen_t;

+#   define getsockopt  sys_getsockopt

+

+    /*

+     * Wrapper for select() in Linux kernel.

+     */

+    PJ_INLINE(int) select(int n, fd_set *inp, fd_set *outp, fd_set *exp,

+		          struct timeval *tvp)

+    {

+        int count;

+        mm_segment_t oldfs = get_fs();

+        set_fs(KERNEL_DS);

+        count = sys_select(n, inp, outp, exp, tvp);

+        set_fs(oldfs);

+        return count;

+    }

+#endif	/* PJ_LINUX_KERNEL */

+

+

+/*

+ * Windows specific

+ */

+#ifdef PJ_WIN32

+    typedef int socklen_t;;

+#endif

+

+

+#endif	/* __PJ_COMPAT_SOCKET_H__ */

+

diff --git a/pjlib/include/pj/compat/sprintf.h b/pjlib/include/pj/compat/sprintf.h
index a398770..9028d85 100644
--- a/pjlib/include/pj/compat/sprintf.h
+++ b/pjlib/include/pj/compat/sprintf.h
@@ -1,33 +1,54 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/compat/sprintf.h $
- * 
- * 2     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_SPRINTF_H__
-#define __PJ_COMPAT_SPRINTF_H__
-
-/**
- * @file sprintf.h
- * @brief Provides sprintf() and snprintf() functions.
- */
-
-#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0
-#  include <stdio.h>
-#endif
-
-#if defined(_MSC_VER)
-#  define snprintf	_snprintf
-#endif
-
-#define pj_sprintf      sprintf
-#define pj_snprintf	snprintf
-
-#endif	/* __PJ_COMPAT_SPRINTF_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/compat/sprintf.h $

+ * 

+ * 2     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_SPRINTF_H__

+#define __PJ_COMPAT_SPRINTF_H__

+

+/**

+ * @file sprintf.h

+ * @brief Provides sprintf() and snprintf() functions.

+ */

+

+#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0

+#  include <stdio.h>

+#endif

+

+#if defined(_MSC_VER)

+#  define snprintf	_snprintf

+#endif

+

+#define pj_sprintf      sprintf

+#define pj_snprintf	snprintf

+

+#endif	/* __PJ_COMPAT_SPRINTF_H__ */

diff --git a/pjlib/include/pj/compat/stdarg.h b/pjlib/include/pj/compat/stdarg.h
index 87b3f2c..a4a3add 100644
--- a/pjlib/include/pj/compat/stdarg.h
+++ b/pjlib/include/pj/compat/stdarg.h
@@ -1,22 +1,43 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdarg.h $
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_STDARG_H__
-#define __PJ_COMPAT_STDARG_H__
-
-/**
- * @file stdarg.h
- * @brief Provides stdarg functionality.
- */
-
-#if defined(PJ_HAS_STDARG_H) && PJ_HAS_STDARG_H != 0
-#  include <stdarg.h>
-#endif
-
-#endif	/* __PJ_COMPAT_STDARG_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdarg.h $

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_STDARG_H__

+#define __PJ_COMPAT_STDARG_H__

+

+/**

+ * @file stdarg.h

+ * @brief Provides stdarg functionality.

+ */

+

+#if defined(PJ_HAS_STDARG_H) && PJ_HAS_STDARG_H != 0

+#  include <stdarg.h>

+#endif

+

+#endif	/* __PJ_COMPAT_STDARG_H__ */

diff --git a/pjlib/include/pj/compat/stdfileio.h b/pjlib/include/pj/compat/stdfileio.h
index 620b170..e9915f7 100644
--- a/pjlib/include/pj/compat/stdfileio.h
+++ b/pjlib/include/pj/compat/stdfileio.h
@@ -1,22 +1,43 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdfileio.h $
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_STDFILEIO_H__
-#define __PJ_COMPAT_STDFILEIO_H__
-
-/**
- * @file stdfileio.h
- * @brief Compatibility for ANSI file I/O like fputs, fflush, etc.
- */
-
-#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0
-#  include <stdio.h>
-#endif
-
-#endif	/* __PJ_COMPAT_STDFILEIO_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/stdfileio.h $

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_STDFILEIO_H__

+#define __PJ_COMPAT_STDFILEIO_H__

+

+/**

+ * @file stdfileio.h

+ * @brief Compatibility for ANSI file I/O like fputs, fflush, etc.

+ */

+

+#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0

+#  include <stdio.h>

+#endif

+

+#endif	/* __PJ_COMPAT_STDFILEIO_H__ */

diff --git a/pjlib/include/pj/compat/string.h b/pjlib/include/pj/compat/string.h
index b891738..59d82c7 100644
--- a/pjlib/include/pj/compat/string.h
+++ b/pjlib/include/pj/compat/string.h
@@ -1,44 +1,65 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/string.h $
- * 
- * 3     9/22/05 10:31a Bennylp
- * Moving all *.h files to include/.
- * 
- * 2     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_STRING_H__
-#define __PJ_COMPAT_STRING_H__
-
-/**
- * @file string.h
- * @brief Provides string manipulation functions found in ANSI string.h.
- */
-
-#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H != 0
-#  include <string.h>
-#else
-
-    PJ_DECL(int) strcasecmp(const char *s1, const char *s2);
-    PJ_DECL(int) strncasecmp(const char *s1, const char *s2, int len);
-
-#endif
-
-#if defined(_MSC_VER)
-#  define strcasecmp	stricmp
-#  define strncasecmp	strnicmp
-#  define snprintf	_snprintf
-#else
-#  define stricmp	strcasecmp
-#  define strnicmp	strncasecmp
-#endif
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/string.h $

+ * 

+ * 3     9/22/05 10:31a Bennylp

+ * Moving all *.h files to include/.

+ * 

+ * 2     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_STRING_H__

+#define __PJ_COMPAT_STRING_H__

+

+/**

+ * @file string.h

+ * @brief Provides string manipulation functions found in ANSI string.h.

+ */

+

+#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H != 0

+#  include <string.h>

+#else

+

+    PJ_DECL(int) strcasecmp(const char *s1, const char *s2);

+    PJ_DECL(int) strncasecmp(const char *s1, const char *s2, int len);

+

+#endif

+

+#if defined(_MSC_VER)

+#  define strcasecmp	stricmp

+#  define strncasecmp	strnicmp

+#  define snprintf	_snprintf

+#else

+#  define stricmp	strcasecmp

+#  define strnicmp	strncasecmp

+#endif

+

 

 #define pj_native_strcmp        strcmp

 #define pj_native_strlen        strlen

@@ -48,5 +69,5 @@
 #define pj_native_strcasecmp    strcasecmp

 #define pj_native_strncasecmp   strncasecmp

 

-
-#endif	/* __PJ_COMPAT_STRING_H__ */
+

+#endif	/* __PJ_COMPAT_STRING_H__ */

diff --git a/pjlib/include/pj/compat/time.h b/pjlib/include/pj/compat/time.h
index 79d0f27..9303604 100644
--- a/pjlib/include/pj/compat/time.h
+++ b/pjlib/include/pj/compat/time.h
@@ -1,27 +1,48 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/time.h $
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_TIME_H__
-#define __PJ_COMPAT_TIME_H__
-
-/**
- * @file time.h
- * @brief Provides ftime() and localtime() etc functions.
- */
-
-#if defined(PJ_HAS_TIME_H) && PJ_HAS_TIME_H != 0
-#  include <time.h>
-#endif
-
-#if defined(PJ_HAS_SYS_TIMEB_H) && PJ_HAS_SYS_TIMEB_H != 0
-#  include <sys/timeb.h>
-#endif
-
-
-#endif	/* __PJ_COMPAT_TIME_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/time.h $

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_TIME_H__

+#define __PJ_COMPAT_TIME_H__

+

+/**

+ * @file time.h

+ * @brief Provides ftime() and localtime() etc functions.

+ */

+

+#if defined(PJ_HAS_TIME_H) && PJ_HAS_TIME_H != 0

+#  include <time.h>

+#endif

+

+#if defined(PJ_HAS_SYS_TIMEB_H) && PJ_HAS_SYS_TIMEB_H != 0

+#  include <sys/timeb.h>

+#endif

+

+

+#endif	/* __PJ_COMPAT_TIME_H__ */

diff --git a/pjlib/include/pj/compat/vsprintf.h b/pjlib/include/pj/compat/vsprintf.h
index 79be197..644f365 100644
--- a/pjlib/include/pj/compat/vsprintf.h
+++ b/pjlib/include/pj/compat/vsprintf.h
@@ -1,28 +1,49 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/compat/vsprintf.h $
- * 
- * 1     9/17/05 10:36a Bennylp
- * Created.
- * 
- */
-#ifndef __PJ_COMPAT_VSPRINTF_H__
-#define __PJ_COMPAT_VSPRINTF_H__
-
-/**
- * @file vsprintf.h
- * @brief Provides vsprintf and vsnprintf function.
- */
-
-#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0
-#  include <stdio.h>
-#endif
-
-#if defined(_MSC_VER)
-#  define vsnprintf	_vsnprintf	
-#endif
-
-#define pj_vsnprintf	vsnprintf
-
-#endif	/* __PJ_COMPAT_VSPRINTF_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/compat/vsprintf.h $

+ * 

+ * 1     9/17/05 10:36a Bennylp

+ * Created.

+ * 

+ */

+#ifndef __PJ_COMPAT_VSPRINTF_H__

+#define __PJ_COMPAT_VSPRINTF_H__

+

+/**

+ * @file vsprintf.h

+ * @brief Provides vsprintf and vsnprintf function.

+ */

+

+#if defined(PJ_HAS_STDIO_H) && PJ_HAS_STDIO_H != 0

+#  include <stdio.h>

+#endif

+

+#if defined(_MSC_VER)

+#  define vsnprintf	_vsnprintf	

+#endif

+

+#define pj_vsnprintf	vsnprintf

+

+#endif	/* __PJ_COMPAT_VSPRINTF_H__ */

diff --git a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
index 0465ac9..cb7cd59 100644
--- a/pjlib/include/pj/config.h
+++ b/pjlib/include/pj/config.h
@@ -1,408 +1,429 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_CONFIG_H__
-#define __PJ_CONFIG_H__
-
-/**
- * @file config.h
- * @brief PJLIB Main configuration settings.
- */
-
-/********************************************************************
- * Include compiler specific configuration.
- */
-#if defined(_MSC_VER)
-#  include <pj/compat/cc_msvc.h>
-#elif defined(__GNUC__)
-#  include <pj/compat/cc_gcc.h>
-#else
-#  error "Unknown compiler."
-#endif
-
-
-/********************************************************************
- * Include target OS specific configuration.
- */
-#if defined(PJ_WIN32) && PJ_WIN32!=0
-#  include <pj/compat/os_win32.h>
-#elif defined(PJ_LINUX) && PJ_LINUX!=0
-#  include <pj/compat/os_linux.h>
-#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
-#  include <pj/compat/os_linux_kernel.h>
-#elif defined(PJ_PALMOS) && PJ_PALMOS!=0
-#  include <pj/compat/os_palmos.h>
-#elif defined(PJ_SUNOS) && PJ_SUNOS!=0
-#  include <pj/compat/os_sunos.h>
-#else
-#  error "Please specify target os."
-#endif
-
-
-/********************************************************************
- * Target machine specific configuration.
- */
-#if defined (PJ_M_I386) && PJ_M_I386 != 0
-#   include <pj/compat/m_i386.h>
-#elif defined (PJ_M_M68K) && PJ_M_M68K != 0
-#   include <pj/compat/m_m68k.h>
-#elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0
-#   include <pj/compat/m_alpha.h>
-#elif defined (PJ_M_SPARC) && PJ_M_SPARC != 0
-#   include <pj/compat/m_sparc.h>
-#else
-#  error "Please specify target machine."
-#endif
-
-/* Include size_t definition. */
-#include <pj/compat/size_t.h>
-
-/* Include site/user specific configuration to control PJLIB features.
- * YOU MUST CREATE THIS FILE YOURSELF!!
- */
-#include <pj/config_site.h>
-
-/********************************************************************
- * PJLIB Features.
- */
-
-/* Overrides for DOXYGEN */
-#ifdef DOXYGEN
-#   undef PJ_FUNCTIONS_ARE_INLINED
-#   undef PJ_HAS_FLOATING_POINT
-#   undef PJ_LOG_MAX_LEVEL
-#   undef PJ_LOG_MAX_SIZE
-#   undef PJ_LOG_USE_STACK_BUFFER
-#   undef PJ_TERM_HAS_COLOR
-#   undef PJ_POOL_DEBUG
-#   undef PJ_HAS_TCP
-#   undef PJ_MAX_HOSTNAME
-#   undef PJ_IOQUEUE_MAX_HANDLES
-#   undef FD_SETSIZE
-#   undef PJ_HAS_SEMAPHORE
-#   undef PJ_HAS_EVENT_OBJ
-#   undef PJ_ENABLE_EXTRA_CHECK
-#endif
-
-/**
- * @defgroup pj_config Build Configuration
- * @ingroup PJ
- * @{
- *
- * This section contains macros that can set during PJLIB build process
- * to controll various aspects of the library.
- *
- * <b>Note</b>: the values in this page does NOT necessarily reflect to the
- * macro values during the build process.
- */
-
-/**
- * If this macro is set to 1, it will enable some debugging checking
- * in the library.
- *
- * Default: equal to (NOT NDEBUG).
- */
-#ifndef PJ_DEBUG
-#  ifndef NDEBUG
-#    define PJ_DEBUG		    1
-#  else
-#    define PJ_DEBUG		    0
-#  endif
-#endif
-
-/**
- * Expand functions in *_i.h header files as inline.
- *
- * Default: 0.
- */
-#ifndef PJ_FUNCTIONS_ARE_INLINED
-#  define PJ_FUNCTIONS_ARE_INLINED  0
-#endif
-
-/**
- * Use floating point computations in the library.
- *
- * Default: 1.
- */
-#ifndef PJ_HAS_FLOATING_POINT
-#  define PJ_HAS_FLOATING_POINT	    1
-#endif
-
-/**
- * Declare maximum logging level/verbosity. Lower number indicates higher
- * importance, with the highest importance has level zero. The least
- * important level is five in this implementation, but this can be extended
- * by supplying the appropriate implementation.
- *
- * The level conventions:
- *  - 0: fatal error
- *  - 1: error
- *  - 2: warning
- *  - 3: info
- *  - 4: debug
- *  - 5: trace
- *  - 6: more detailed trace
- *
- * Default: 4
- */
-#ifndef PJ_LOG_MAX_LEVEL
-#  define PJ_LOG_MAX_LEVEL   5
-#endif
-
-/**
- * Maximum message size that can be sent to output device for each call
- * to PJ_LOG(). If the message size is longer than this value, it will be cut.
- * This may affect the stack usage, depending whether PJ_LOG_USE_STACK_BUFFER
- * flag is set.
- *
- * Default: 800
- */
-#ifndef PJ_LOG_MAX_SIZE
-#  define PJ_LOG_MAX_SIZE	    800
-#endif
-
-/**
- * Log buffer.
- * Does the log get the buffer from the stack? (default is yes).
- * If the value is set to NO, then the buffer will be taken from static
- * buffer, which in this case will make the log function non-reentrant.
- *
- * Default: 1
- */
-#ifndef PJ_LOG_USE_STACK_BUFFER
-#  define PJ_LOG_USE_STACK_BUFFER   1
-#endif
-
-
-/**
- * Colorfull terminal (for logging etc).
- *
- * Default: 1
- */
-#ifndef PJ_TERM_HAS_COLOR
-#  define PJ_TERM_HAS_COLOR	    1
-#endif
-
-/**
- * Pool debugging.
- *
- * Default: 0
- */
-#ifndef PJ_POOL_DEBUG
-#  define PJ_POOL_DEBUG		    0
-#endif
-
-/**
- * \def PJ_HAS_TCP
- * Support TCP in the library.
- * Disabling TCP will reduce the footprint slightly (about 6KB).
- *
- * Default: 1
- */
-#ifndef PJ_HAS_TCP
-#  define PJ_HAS_TCP		    1
-#endif
-
-/**
- * Maximum hostname length.
- * Libraries sometimes needs to make copy of an address to stack buffer;
- * the value here affects the stack usage.
- *
- * Default: 128
- */
-#ifndef PJ_MAX_HOSTNAME
-#  define PJ_MAX_HOSTNAME	    (128)
-#endif
-
-/**
- * Constants for declaring the maximum handles that can be supported by
- * a single IOQ framework. This constant might not be relevant to the 
- * underlying I/O queue impelementation, but still, developers should be 
- * aware of this constant, to make sure that the program will not break when
- * the underlying implementation changes.
- *
- * For implementation based on select(), the value here will be used as the
- * maximum number of socket handles passed to select() (i.e. FD_SETSIZE will 
- * be set to this value).
- *
- * Default: 256
- */
-#ifndef PJ_IOQUEUE_MAX_HANDLES
-#  define PJ_IOQUEUE_MAX_HANDLES    (256)
-#endif
-
-/**
- * Overrides FD_SETSIZE so it is consistent throughout the library.
- * OS specific configuration header (compat/os_*) might have declared
- * FD_SETSIZE, thus we only set if it hasn't been declared.
- *
- * Default: #PJ_IOQUEUE_MAX_HANDLES
- */
-#ifndef FD_SETSIZE
-#  define FD_SETSIZE		    PJ_IOQUEUE_MAX_HANDLES
-#endif
-
-/**
- * Has semaphore functionality?
- *
- * Default: 1
- */
-#ifndef PJ_HAS_SEMAPHORE
-#  define PJ_HAS_SEMAPHORE	    1
-#endif
-
-
-/**
- * Event object (for synchronization, e.g. in Win32)
- *
- * Default: 1
- */
-#ifndef PJ_HAS_EVENT_OBJ
-#  define PJ_HAS_EVENT_OBJ	    1
-#endif
-
-
-/**
- * Enable library's extra check.
- * If this macro is enabled, #PJ_ASSERT_RETURN macro will expand to
- * run-time checking. If this macro is disabled, #PJ_ASSERT_RETURN
- * will simply evaluate to #pj_assert().
- *
- * You can disable this macro to reduce size, at the risk of crashes
- * if invalid value (e.g. NULL) is passed to the library.
- *
- * Default: 1
- */
-#ifndef PJ_ENABLE_EXTRA_CHECK
-#   define PJ_ENABLE_EXTRA_CHECK    1
-#endif
-
-
-/**
- * Enable name registration for exceptions with #pj_exception_id_alloc().
- * If this feature is enabled, then the library will keep track of
- * names associated with each exception ID requested by application via
- * #pj_exception_id_alloc().
- *
- * Disabling this macro will reduce the code and .bss size by a tad bit.
- * See also #PJ_MAX_EXCEPTION_ID.
- *
- * Default: 1
- */
-#ifndef PJ_HAS_EXCEPTION_NAMES
-#   define PJ_HAS_EXCEPTION_NAMES   1
-#endif
-
-/**
- * Maximum number of unique exception IDs that can be requested
- * with #pj_exception_id_alloc(). For each entry, a small record will
- * be allocated in the .bss segment.
- *
- * Default: 16
- */
-#ifndef PJ_MAX_EXCEPTION_ID
-#   define PJ_MAX_EXCEPTION_ID      16
-#endif
-
-/** @} */
-
-/********************************************************************
- * General macros.
- */
-
-/**
- * @def PJ_INLINE(type)
- * @param type The return type of the function.
- * Expand the function as inline.
- */
-#define PJ_INLINE(type)	  PJ_INLINE_SPECIFIER type
-
-/**
- * @def PJ_DECL(type)
- * @param type The return type of the function.
- * Declare a function.
- */
-/**
- * @def PJ_DECL_NO_RETURN(type)
- * @param type The return type of the function.
- * Declare a function that will not return.
- */
-/**
- * @def PJ_BEGIN_DECL
- * Mark beginning of declaration section in a header file.
- */
-/**
- * @def PJ_END_DECL
- * Mark end of declaration section in a header file.
- */
-#ifdef __cplusplus
-#  define PJ_DECL(type)		    type
-#  define PJ_DECL_NO_RETURN(type)   type PJ_NORETURN
-#  define PJ_BEGIN_DECL		    extern "C" {
-#  define PJ_END_DECL		    }
-#else
-#  define PJ_DECL(type)		    extern type
-#  define PJ_DECL_NO_RETURN(type)   PJ_NORETURN type
-#  define PJ_BEGIN_DECL
-#  define PJ_END_DECL
-#endif
-
-/**
- * @def PJ_DEF(type)
- * @param type The return type of the function.
- * Define a function.
- */
-#define PJ_DEF(type)	  type
-
-/**
- * @def PJ_EXPORT_SYMBOL(sym)
- * @param sym The symbol to export.
- * Export the specified symbol in compilation type that requires export
- * (e.g. Linux kernel).
- */
-#ifdef __PJ_EXPORT_SYMBOL
-#  define PJ_EXPORT_SYMBOL(sym)	    __PJ_EXPORT_SYMBOL(sym)
-#else
-#  define PJ_EXPORT_SYMBOL(sym)
-#endif
-
-/**
- * @def PJ_IDECL(type)
- * @param type  The function's return type.
- * Declare a function that may be expanded as inline.
- */
-/**
- * @def PJ_IDEF(type)
- * @param type  The function's return type.
- * Define a function that may be expanded as inline.
- */
-
-#if PJ_FUNCTIONS_ARE_INLINED
-#  define PJ_IDECL(type)  PJ_INLINE(type)
-#  define PJ_IDEF(type)   PJ_INLINE(type)
-#else
-#  define PJ_IDECL(type)  PJ_DECL(type)
-#  define PJ_IDEF(type)   PJ_DEF(type)
-#endif
-
-/**
- * @def PJ_UNUSED_ARG(arg)
- * @param arg   The argument name.
- * PJ_UNUSED_ARG prevents warning about unused argument in a function.
- */
-#define PJ_UNUSED_ARG(arg)  (void)arg
-
-/**
- * @def PJ_TODO(id)
- * @param id    Any identifier that will be printed as TODO message.
- * PJ_TODO macro will display TODO message as warning during compilation.
- * Example: PJ_TODO(CLEAN_UP_ERROR);
- */
-#ifndef PJ_TODO
-#  define PJ_TODO(id)	    TODO___##id:
-#endif
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_CONFIG_H__

+#define __PJ_CONFIG_H__

+

+/**

+ * @file config.h

+ * @brief PJLIB Main configuration settings.

+ */

+

+/********************************************************************

+ * Include compiler specific configuration.

+ */

+#if defined(_MSC_VER)

+#  include <pj/compat/cc_msvc.h>

+#elif defined(__GNUC__)

+#  include <pj/compat/cc_gcc.h>

+#else

+#  error "Unknown compiler."

+#endif

+

+

+/********************************************************************

+ * Include target OS specific configuration.

+ */

+#if defined(PJ_WIN32) && PJ_WIN32!=0

+#  include <pj/compat/os_win32.h>

+#elif defined(PJ_LINUX) && PJ_LINUX!=0

+#  include <pj/compat/os_linux.h>

+#elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0

+#  include <pj/compat/os_linux_kernel.h>

+#elif defined(PJ_PALMOS) && PJ_PALMOS!=0

+#  include <pj/compat/os_palmos.h>

+#elif defined(PJ_SUNOS) && PJ_SUNOS!=0

+#  include <pj/compat/os_sunos.h>

+#else

+#  error "Please specify target os."

+#endif

+

+

+/********************************************************************

+ * Target machine specific configuration.

+ */

+#if defined (PJ_M_I386) && PJ_M_I386 != 0

+#   include <pj/compat/m_i386.h>

+#elif defined (PJ_M_M68K) && PJ_M_M68K != 0

+#   include <pj/compat/m_m68k.h>

+#elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0

+#   include <pj/compat/m_alpha.h>

+#elif defined (PJ_M_SPARC) && PJ_M_SPARC != 0

+#   include <pj/compat/m_sparc.h>

+#else

+#  error "Please specify target machine."

+#endif

+

+/* Include size_t definition. */

+#include <pj/compat/size_t.h>

+

+/* Include site/user specific configuration to control PJLIB features.

+ * YOU MUST CREATE THIS FILE YOURSELF!!

+ */

+#include <pj/config_site.h>

+

+/********************************************************************

+ * PJLIB Features.

+ */

+

+/* Overrides for DOXYGEN */

+#ifdef DOXYGEN

+#   undef PJ_FUNCTIONS_ARE_INLINED

+#   undef PJ_HAS_FLOATING_POINT

+#   undef PJ_LOG_MAX_LEVEL

+#   undef PJ_LOG_MAX_SIZE

+#   undef PJ_LOG_USE_STACK_BUFFER

+#   undef PJ_TERM_HAS_COLOR

+#   undef PJ_POOL_DEBUG

+#   undef PJ_HAS_TCP

+#   undef PJ_MAX_HOSTNAME

+#   undef PJ_IOQUEUE_MAX_HANDLES

+#   undef FD_SETSIZE

+#   undef PJ_HAS_SEMAPHORE

+#   undef PJ_HAS_EVENT_OBJ

+#   undef PJ_ENABLE_EXTRA_CHECK

+#endif

+

+/**

+ * @defgroup pj_config Build Configuration

+ * @ingroup PJ

+ * @{

+ *

+ * This section contains macros that can set during PJLIB build process

+ * to controll various aspects of the library.

+ *

+ * <b>Note</b>: the values in this page does NOT necessarily reflect to the

+ * macro values during the build process.

+ */

+

+/**

+ * If this macro is set to 1, it will enable some debugging checking

+ * in the library.

+ *

+ * Default: equal to (NOT NDEBUG).

+ */

+#ifndef PJ_DEBUG

+#  ifndef NDEBUG

+#    define PJ_DEBUG		    1

+#  else

+#    define PJ_DEBUG		    0

+#  endif

+#endif

+

+/**

+ * Expand functions in *_i.h header files as inline.

+ *

+ * Default: 0.

+ */

+#ifndef PJ_FUNCTIONS_ARE_INLINED

+#  define PJ_FUNCTIONS_ARE_INLINED  0

+#endif

+

+/**

+ * Use floating point computations in the library.

+ *

+ * Default: 1.

+ */

+#ifndef PJ_HAS_FLOATING_POINT

+#  define PJ_HAS_FLOATING_POINT	    1

+#endif

+

+/**

+ * Declare maximum logging level/verbosity. Lower number indicates higher

+ * importance, with the highest importance has level zero. The least

+ * important level is five in this implementation, but this can be extended

+ * by supplying the appropriate implementation.

+ *

+ * The level conventions:

+ *  - 0: fatal error

+ *  - 1: error

+ *  - 2: warning

+ *  - 3: info

+ *  - 4: debug

+ *  - 5: trace

+ *  - 6: more detailed trace

+ *

+ * Default: 4

+ */

+#ifndef PJ_LOG_MAX_LEVEL

+#  define PJ_LOG_MAX_LEVEL   5

+#endif

+

+/**

+ * Maximum message size that can be sent to output device for each call

+ * to PJ_LOG(). If the message size is longer than this value, it will be cut.

+ * This may affect the stack usage, depending whether PJ_LOG_USE_STACK_BUFFER

+ * flag is set.

+ *

+ * Default: 800

+ */

+#ifndef PJ_LOG_MAX_SIZE

+#  define PJ_LOG_MAX_SIZE	    800

+#endif

+

+/**

+ * Log buffer.

+ * Does the log get the buffer from the stack? (default is yes).

+ * If the value is set to NO, then the buffer will be taken from static

+ * buffer, which in this case will make the log function non-reentrant.

+ *

+ * Default: 1

+ */

+#ifndef PJ_LOG_USE_STACK_BUFFER

+#  define PJ_LOG_USE_STACK_BUFFER   1

+#endif

+

+

+/**

+ * Colorfull terminal (for logging etc).

+ *

+ * Default: 1

+ */

+#ifndef PJ_TERM_HAS_COLOR

+#  define PJ_TERM_HAS_COLOR	    1

+#endif

+

+/**

+ * Pool debugging.

+ *

+ * Default: 0

+ */

+#ifndef PJ_POOL_DEBUG

+#  define PJ_POOL_DEBUG		    0

+#endif

+

+/**

+ * \def PJ_HAS_TCP

+ * Support TCP in the library.

+ * Disabling TCP will reduce the footprint slightly (about 6KB).

+ *

+ * Default: 1

+ */

+#ifndef PJ_HAS_TCP

+#  define PJ_HAS_TCP		    1

+#endif

+

+/**

+ * Maximum hostname length.

+ * Libraries sometimes needs to make copy of an address to stack buffer;

+ * the value here affects the stack usage.

+ *

+ * Default: 128

+ */

+#ifndef PJ_MAX_HOSTNAME

+#  define PJ_MAX_HOSTNAME	    (128)

+#endif

+

+/**

+ * Constants for declaring the maximum handles that can be supported by

+ * a single IOQ framework. This constant might not be relevant to the 

+ * underlying I/O queue impelementation, but still, developers should be 

+ * aware of this constant, to make sure that the program will not break when

+ * the underlying implementation changes.

+ *

+ * For implementation based on select(), the value here will be used as the

+ * maximum number of socket handles passed to select() (i.e. FD_SETSIZE will 

+ * be set to this value).

+ *

+ * Default: 256

+ */

+#ifndef PJ_IOQUEUE_MAX_HANDLES

+#  define PJ_IOQUEUE_MAX_HANDLES    (256)

+#endif

+

+/**

+ * Overrides FD_SETSIZE so it is consistent throughout the library.

+ * OS specific configuration header (compat/os_*) might have declared

+ * FD_SETSIZE, thus we only set if it hasn't been declared.

+ *

+ * Default: #PJ_IOQUEUE_MAX_HANDLES

+ */

+#ifndef FD_SETSIZE

+#  define FD_SETSIZE		    PJ_IOQUEUE_MAX_HANDLES

+#endif

+

+/**

+ * Has semaphore functionality?

+ *

+ * Default: 1

+ */

+#ifndef PJ_HAS_SEMAPHORE

+#  define PJ_HAS_SEMAPHORE	    1

+#endif

+

+

+/**

+ * Event object (for synchronization, e.g. in Win32)

+ *

+ * Default: 1

+ */

+#ifndef PJ_HAS_EVENT_OBJ

+#  define PJ_HAS_EVENT_OBJ	    1

+#endif

+

+

+/**

+ * Enable library's extra check.

+ * If this macro is enabled, #PJ_ASSERT_RETURN macro will expand to

+ * run-time checking. If this macro is disabled, #PJ_ASSERT_RETURN

+ * will simply evaluate to #pj_assert().

+ *

+ * You can disable this macro to reduce size, at the risk of crashes

+ * if invalid value (e.g. NULL) is passed to the library.

+ *

+ * Default: 1

+ */

+#ifndef PJ_ENABLE_EXTRA_CHECK

+#   define PJ_ENABLE_EXTRA_CHECK    1

+#endif

+

+

+/**

+ * Enable name registration for exceptions with #pj_exception_id_alloc().

+ * If this feature is enabled, then the library will keep track of

+ * names associated with each exception ID requested by application via

+ * #pj_exception_id_alloc().

+ *

+ * Disabling this macro will reduce the code and .bss size by a tad bit.

+ * See also #PJ_MAX_EXCEPTION_ID.

+ *

+ * Default: 1

+ */

+#ifndef PJ_HAS_EXCEPTION_NAMES

+#   define PJ_HAS_EXCEPTION_NAMES   1

+#endif

+

+/**

+ * Maximum number of unique exception IDs that can be requested

+ * with #pj_exception_id_alloc(). For each entry, a small record will

+ * be allocated in the .bss segment.

+ *

+ * Default: 16

+ */

+#ifndef PJ_MAX_EXCEPTION_ID

+#   define PJ_MAX_EXCEPTION_ID      16

+#endif

+

+/** @} */

+

+/********************************************************************

+ * General macros.

+ */

+

+/**

+ * @def PJ_INLINE(type)

+ * @param type The return type of the function.

+ * Expand the function as inline.

+ */

+#define PJ_INLINE(type)	  PJ_INLINE_SPECIFIER type

+

+/**

+ * @def PJ_DECL(type)

+ * @param type The return type of the function.

+ * Declare a function.

+ */

+/**

+ * @def PJ_DECL_NO_RETURN(type)

+ * @param type The return type of the function.

+ * Declare a function that will not return.

+ */

+/**

+ * @def PJ_BEGIN_DECL

+ * Mark beginning of declaration section in a header file.

+ */

+/**

+ * @def PJ_END_DECL

+ * Mark end of declaration section in a header file.

+ */

+#ifdef __cplusplus

+#  define PJ_DECL(type)		    type

+#  define PJ_DECL_NO_RETURN(type)   type PJ_NORETURN

+#  define PJ_BEGIN_DECL		    extern "C" {

+#  define PJ_END_DECL		    }

+#else

+#  define PJ_DECL(type)		    extern type

+#  define PJ_DECL_NO_RETURN(type)   PJ_NORETURN type

+#  define PJ_BEGIN_DECL

+#  define PJ_END_DECL

+#endif

+

+/**

+ * @def PJ_DEF(type)

+ * @param type The return type of the function.

+ * Define a function.

+ */

+#define PJ_DEF(type)	  type

+

+/**

+ * @def PJ_EXPORT_SYMBOL(sym)

+ * @param sym The symbol to export.

+ * Export the specified symbol in compilation type that requires export

+ * (e.g. Linux kernel).

+ */

+#ifdef __PJ_EXPORT_SYMBOL

+#  define PJ_EXPORT_SYMBOL(sym)	    __PJ_EXPORT_SYMBOL(sym)

+#else

+#  define PJ_EXPORT_SYMBOL(sym)

+#endif

+

+/**

+ * @def PJ_IDECL(type)

+ * @param type  The function's return type.

+ * Declare a function that may be expanded as inline.

+ */

+/**

+ * @def PJ_IDEF(type)

+ * @param type  The function's return type.

+ * Define a function that may be expanded as inline.

+ */

+

+#if PJ_FUNCTIONS_ARE_INLINED

+#  define PJ_IDECL(type)  PJ_INLINE(type)

+#  define PJ_IDEF(type)   PJ_INLINE(type)

+#else

+#  define PJ_IDECL(type)  PJ_DECL(type)

+#  define PJ_IDEF(type)   PJ_DEF(type)

+#endif

+

+/**

+ * @def PJ_UNUSED_ARG(arg)

+ * @param arg   The argument name.

+ * PJ_UNUSED_ARG prevents warning about unused argument in a function.

+ */

+#define PJ_UNUSED_ARG(arg)  (void)arg

+

+/**

+ * @def PJ_TODO(id)

+ * @param id    Any identifier that will be printed as TODO message.

+ * PJ_TODO macro will display TODO message as warning during compilation.

+ * Example: PJ_TODO(CLEAN_UP_ERROR);

+ */

+#ifndef PJ_TODO

+#  define PJ_TODO(id)	    TODO___##id:

+#endif

+

 /**

  * Function attributes to inform that the function may throw exception.

  *

@@ -410,42 +431,42 @@
  */

 #define __pj_throw__(x)

 

-
-/********************************************************************
- * Sanity Checks
- */
-#ifndef PJ_HAS_HIGH_RES_TIMER
-#  error "PJ_HAS_HIGH_RES_TIMER is not defined!"
-#endif
-
-#if !defined(PJ_HAS_PENTIUM)
-#  error "PJ_HAS_PENTIUM is not defined!"
-#endif
-
-#if !defined(PJ_IS_LITTLE_ENDIAN)
-#  error "PJ_IS_LITTLE_ENDIAN is not defined!"
-#endif
-
-#if !defined(PJ_IS_BIG_ENDIAN)
-#  error "PJ_IS_BIG_ENDIAN is not defined!"
-#endif
-
-
-
-PJ_BEGIN_DECL
-
-/**
- * PJLIB version string.
- */
-extern const char *PJ_VERSION;
-
-/**
- * Dump configuration to log with verbosity equal to info(3).
- */
-PJ_DECL(void) pj_dump_config(void);
-
-PJ_END_DECL
-
-
-#endif	/* __PJ_CONFIG_H__ */
-
+

+/********************************************************************

+ * Sanity Checks

+ */

+#ifndef PJ_HAS_HIGH_RES_TIMER

+#  error "PJ_HAS_HIGH_RES_TIMER is not defined!"

+#endif

+

+#if !defined(PJ_HAS_PENTIUM)

+#  error "PJ_HAS_PENTIUM is not defined!"

+#endif

+

+#if !defined(PJ_IS_LITTLE_ENDIAN)

+#  error "PJ_IS_LITTLE_ENDIAN is not defined!"

+#endif

+

+#if !defined(PJ_IS_BIG_ENDIAN)

+#  error "PJ_IS_BIG_ENDIAN is not defined!"

+#endif

+

+

+

+PJ_BEGIN_DECL

+

+/**

+ * PJLIB version string.

+ */

+extern const char *PJ_VERSION;

+

+/**

+ * Dump configuration to log with verbosity equal to info(3).

+ */

+PJ_DECL(void) pj_dump_config(void);

+

+PJ_END_DECL

+

+

+#endif	/* __PJ_CONFIG_H__ */

+

diff --git a/pjlib/include/pj/ctype.h b/pjlib/include/pj/ctype.h
index 4307fbb..39b45f8 100644
--- a/pjlib/include/pj/ctype.h
+++ b/pjlib/include/pj/ctype.h
@@ -1,121 +1,142 @@
-/* $Id$
- *
- */
-#ifndef __PJ_CTYPE_H__
-#define __PJ_CTYPE_H__
-
-/**
- * @file ctype.h
- * @brief C type helper macros.
- */
-
-#include <pj/compat/ctype.h>
-
-/**
- * @defgroup pj_ctype ctype - Character Type
- * @ingroup PJ_MISC
- * @{
- *
- * This module contains several inline functions/macros for testing or
- * manipulating character types. It is provided in PJLIB because PJLIB
- * must not depend to LIBC.
- */
-
-/** 
- * Returns a non-zero value if either isalpha or isdigit is true for c.
- * @param c     The integer character to test.
- * @return      Non-zero value if either isalpha or isdigit is true for c.
- */
-PJ_INLINE(int) pj_isalnum(int c) { return isalnum(c); }
-
-/** 
- * Returns a non-zero value if c is a particular representation of an 
- * alphabetic character.
- * @param c     The integer character to test.
- * @return      Non-zero value if c is a particular representation of an 
- *              alphabetic character.
- */
-PJ_INLINE(int) pj_isalpha(int c) { return isalpha(c); }
-
-/** 
- * Returns a non-zero value if c is a particular representation of an 
- * ASCII character.
- * @param c     The integer character to test.
- * @return      Non-zero value if c is a particular representation of 
- *              an ASCII character.
- */
-PJ_INLINE(int) pj_isascii(int c) { return isascii(c); }
-
-/** 
- * Returns a non-zero value if c is a particular representation of 
- * a decimal-digit character.
- * @param c     The integer character to test.
- * @return      Non-zero value if c is a particular representation of 
- *              a decimal-digit character.
- */
-PJ_INLINE(int) pj_isdigit(int c) { return isdigit(c); }
-
-/** 
- * Returns a non-zero value if c is a particular representation of 
- * a space character (0x09 - 0x0D or 0x20).
- * @param c     The integer character to test.
- * @return      Non-zero value if c is a particular representation of 
- *              a space character (0x09 - 0x0D or 0x20).
- */
-PJ_INLINE(int) pj_isspace(int c) { return isspace(c); }
-
-/** 
- * Returns a non-zero value if c is a particular representation of 
- * a lowercase character.
- * @param c     The integer character to test.
- * @return      Non-zero value if c is a particular representation of 
- *              a lowercase character.
- */
-PJ_INLINE(int) pj_islower(int c) { return islower(c); }
-
-
-/** 
- * Returns a non-zero value if c is a particular representation of 
- * a uppercase character.
- * @param c     The integer character to test.
- * @return      Non-zero value if c is a particular representation of 
- *              a uppercase character.
- */
-PJ_INLINE(int) pj_isupper(int c) { return isupper(c); }
-
-/**
- * Returns a non-zero value if c is a particular representation of 
- * an hexadecimal digit character.
- * @param c     The integer character to test.
- * @return      Non-zero value if c is a particular representation of 
- *              an hexadecimal digit character.
- */
-PJ_INLINE(int) pj_isxdigit(int c){ return isxdigit(c); }
-
-/**
- * Returns a non-zero value if c is a either a space (' ') or horizontal
- * tab ('\\t') character.
- * @param c     The integer character to test.
- * @return      Non-zero value if c is a either a space (' ') or horizontal
- *              tab ('\\t') character.
- */
-PJ_INLINE(int) pj_isblank(int c) { return isblank(c); }
-
-/**
- * Converts character to lowercase.
- * @param c     The integer character to convert.
- * @return      Lowercase character of c.
- */
-PJ_INLINE(int) pj_tolower(int c) { return tolower(c); }
-
-/**
- * Converts character to uppercase.
- * @param c     The integer character to convert.
- * @return      Uppercase character of c.
- */
-PJ_INLINE(int) pj_toupper(int c) { return toupper(c); }
-
-/** @} */
-
-#endif	/* __PJ_CTYPE_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_CTYPE_H__

+#define __PJ_CTYPE_H__

+

+/**

+ * @file ctype.h

+ * @brief C type helper macros.

+ */

+

+#include <pj/compat/ctype.h>

+

+/**

+ * @defgroup pj_ctype ctype - Character Type

+ * @ingroup PJ_MISC

+ * @{

+ *

+ * This module contains several inline functions/macros for testing or

+ * manipulating character types. It is provided in PJLIB because PJLIB

+ * must not depend to LIBC.

+ */

+

+/** 

+ * Returns a non-zero value if either isalpha or isdigit is true for c.

+ * @param c     The integer character to test.

+ * @return      Non-zero value if either isalpha or isdigit is true for c.

+ */

+PJ_INLINE(int) pj_isalnum(int c) { return isalnum(c); }

+

+/** 

+ * Returns a non-zero value if c is a particular representation of an 

+ * alphabetic character.

+ * @param c     The integer character to test.

+ * @return      Non-zero value if c is a particular representation of an 

+ *              alphabetic character.

+ */

+PJ_INLINE(int) pj_isalpha(int c) { return isalpha(c); }

+

+/** 

+ * Returns a non-zero value if c is a particular representation of an 

+ * ASCII character.

+ * @param c     The integer character to test.

+ * @return      Non-zero value if c is a particular representation of 

+ *              an ASCII character.

+ */

+PJ_INLINE(int) pj_isascii(int c) { return isascii(c); }

+

+/** 

+ * Returns a non-zero value if c is a particular representation of 

+ * a decimal-digit character.

+ * @param c     The integer character to test.

+ * @return      Non-zero value if c is a particular representation of 

+ *              a decimal-digit character.

+ */

+PJ_INLINE(int) pj_isdigit(int c) { return isdigit(c); }

+

+/** 

+ * Returns a non-zero value if c is a particular representation of 

+ * a space character (0x09 - 0x0D or 0x20).

+ * @param c     The integer character to test.

+ * @return      Non-zero value if c is a particular representation of 

+ *              a space character (0x09 - 0x0D or 0x20).

+ */

+PJ_INLINE(int) pj_isspace(int c) { return isspace(c); }

+

+/** 

+ * Returns a non-zero value if c is a particular representation of 

+ * a lowercase character.

+ * @param c     The integer character to test.

+ * @return      Non-zero value if c is a particular representation of 

+ *              a lowercase character.

+ */

+PJ_INLINE(int) pj_islower(int c) { return islower(c); }

+

+

+/** 

+ * Returns a non-zero value if c is a particular representation of 

+ * a uppercase character.

+ * @param c     The integer character to test.

+ * @return      Non-zero value if c is a particular representation of 

+ *              a uppercase character.

+ */

+PJ_INLINE(int) pj_isupper(int c) { return isupper(c); }

+

+/**

+ * Returns a non-zero value if c is a particular representation of 

+ * an hexadecimal digit character.

+ * @param c     The integer character to test.

+ * @return      Non-zero value if c is a particular representation of 

+ *              an hexadecimal digit character.

+ */

+PJ_INLINE(int) pj_isxdigit(int c){ return isxdigit(c); }

+

+/**

+ * Returns a non-zero value if c is a either a space (' ') or horizontal

+ * tab ('\\t') character.

+ * @param c     The integer character to test.

+ * @return      Non-zero value if c is a either a space (' ') or horizontal

+ *              tab ('\\t') character.

+ */

+PJ_INLINE(int) pj_isblank(int c) { return isblank(c); }

+

+/**

+ * Converts character to lowercase.

+ * @param c     The integer character to convert.

+ * @return      Lowercase character of c.

+ */

+PJ_INLINE(int) pj_tolower(int c) { return tolower(c); }

+

+/**

+ * Converts character to uppercase.

+ * @param c     The integer character to convert.

+ * @return      Uppercase character of c.

+ */

+PJ_INLINE(int) pj_toupper(int c) { return toupper(c); }

+

+/** @} */

+

+#endif	/* __PJ_CTYPE_H__ */

+

diff --git a/pjlib/include/pj/doxygen.h b/pjlib/include/pj/doxygen.h
index f7b2d14..891a192 100644
--- a/pjlib/include/pj/doxygen.h
+++ b/pjlib/include/pj/doxygen.h
@@ -1,398 +1,419 @@
-/* $Id$
- *
- */
-#ifndef __PJ_DOXYGEN_H__
-#define __PJ_DOXYGEN_H__
-
-/**
- * @file doxygen.h
- * @brief Doxygen's mainpage.
- */
-
-/*////////////////////////////////////////////////////////////////////////// */
-/*
-	INTRODUCTION PAGE
- */
-
-/**
- * @mainpage Welcome to PJLIB!
- *
- * @section intro_sec What is PJLIB
- *
- * PJLIB is a small foundation library written in C for making scalable 
- * applications. Because of its small footprint, it can be used in embedded 
- * applications (we hope so!), but yet the library is also aimed for 
- * facilitating high performance protocol stacks.
- *
- * PJLIB is released under LGPL terms.
- *
- * @section download_sec Download
- *
- * PJLIB and all documentation can be downloaded from 
- * http://www.pjproject.net.
- *
- *
- * @section how_to_use_sec About This Documentation
- *
- * This document is generated directly from PJLIB source file using
- * \a doxygen (http://www.doxygen.org). Doxygen is a great (and free!) 
- * tools for generating such documentation.
- *
- * @subsection doc_ver_subsec Version
- *
- * This document corresponds to PJLIB version 0.3-pre2.
- *
- *
- * @subsection find_samples_subsec How to Read This Document
- *
- * This documentation is laid out more to be a reference guide instead
- * of tutorial, therefore first time users may find it difficult to
- * grasp PJLIB by reading this document alone.
- *
- * However, we've tried our best to make this document easy to follow.
- * For first time users, we would suggest that you follow these steps
- * when reading this documentation:
- *
- *  - continue reading this introduction chapter. At the end of this
- *    chapter, you'll find section called \ref pjlib_fundamentals_sec
- *    which should guide you to understand basic things about PJLIB.
- *
- *  - find information about specific features that you want to use
- *    in PJLIB. Use the <b>Module Index</b> to find out about all 
- *    features in PJLIB (if you're browsing the HTML documentation,
- *    click on the \a Module link on top of the page, or if you're
- *    reading the PDF documentation, click on \a Module \a Documentation
- *    on the navigation pane on the left).
- *
- * @subsection doc_organize_sec How To's
- *
- * Please find below links to specific tasks that you probably
- * want to do:
- *
- *  - <b>How to Build PJLIB</b>
- *\n
- * Please refer to \ref pjlib_build_sys_pg page for more information.
- *
- *  - <b>How to Use PJLIB in My Application</b>
- *\n
- * Please refer to \ref configure_app_sec for more information.
- *
- *  - <b>How to Port PJLIB</b>
- *\n
- * Please refer to \ref porting_pjlib_pg page.
- *
- *  - <b>Where to Read Samples Documentation</b>
- *\n
- * Most of the modules provide link to the corresponding sample file.
- * Alternatively, to get the list of all examples, you can click on 
- * <b>Related Pages</b> on the top of HTML document or on 
- * <b>PJLIB Page Documentation</b> on navigation pane of your PDF reader.
+/* $Id$

  *

- *  - <b>How to Submit Code to PJLIB Project</b>
- *\n
+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_DOXYGEN_H__

+#define __PJ_DOXYGEN_H__

+

+/**

+ * @file doxygen.h

+ * @brief Doxygen's mainpage.

+ */

+

+/*////////////////////////////////////////////////////////////////////////// */

+/*

+	INTRODUCTION PAGE

+ */

+

+/**

+ * @mainpage Welcome to PJLIB!

+ *

+ * @section intro_sec What is PJLIB

+ *

+ * PJLIB is a small foundation library written in C for making scalable 

+ * applications. Because of its small footprint, it can be used in embedded 

+ * applications (we hope so!), but yet the library is also aimed for 

+ * facilitating high performance protocol stacks.

+ *

+ * PJLIB is released under LGPL terms.

+ *

+ * @section download_sec Download

+ *

+ * PJLIB and all documentation can be downloaded from 

+ * http://www.pjproject.net.

+ *

+ *

+ * @section how_to_use_sec About This Documentation

+ *

+ * This document is generated directly from PJLIB source file using

+ * \a doxygen (http://www.doxygen.org). Doxygen is a great (and free!) 

+ * tools for generating such documentation.

+ *

+ * @subsection doc_ver_subsec Version

+ *

+ * This document corresponds to PJLIB version 0.3-pre2.

+ *

+ *

+ * @subsection find_samples_subsec How to Read This Document

+ *

+ * This documentation is laid out more to be a reference guide instead

+ * of tutorial, therefore first time users may find it difficult to

+ * grasp PJLIB by reading this document alone.

+ *

+ * However, we've tried our best to make this document easy to follow.

+ * For first time users, we would suggest that you follow these steps

+ * when reading this documentation:

+ *

+ *  - continue reading this introduction chapter. At the end of this

+ *    chapter, you'll find section called \ref pjlib_fundamentals_sec

+ *    which should guide you to understand basic things about PJLIB.

+ *

+ *  - find information about specific features that you want to use

+ *    in PJLIB. Use the <b>Module Index</b> to find out about all 

+ *    features in PJLIB (if you're browsing the HTML documentation,

+ *    click on the \a Module link on top of the page, or if you're

+ *    reading the PDF documentation, click on \a Module \a Documentation

+ *    on the navigation pane on the left).

+ *

+ * @subsection doc_organize_sec How To's

+ *

+ * Please find below links to specific tasks that you probably

+ * want to do:

+ *

+ *  - <b>How to Build PJLIB</b>

+ *\n

+ * Please refer to \ref pjlib_build_sys_pg page for more information.

+ *

+ *  - <b>How to Use PJLIB in My Application</b>

+ *\n

+ * Please refer to \ref configure_app_sec for more information.

+ *

+ *  - <b>How to Port PJLIB</b>

+ *\n

+ * Please refer to \ref porting_pjlib_pg page.

+ *

+ *  - <b>Where to Read Samples Documentation</b>

+ *\n

+ * Most of the modules provide link to the corresponding sample file.

+ * Alternatively, to get the list of all examples, you can click on 

+ * <b>Related Pages</b> on the top of HTML document or on 

+ * <b>PJLIB Page Documentation</b> on navigation pane of your PDF reader.

+ *

+ *  - <b>How to Submit Code to PJLIB Project</b>

+ *\n

  * Please read \ref pjlib_coding_convention_page before submitting

- * your code. Send your code as patch against current Subversion tree
+ * your code. Send your code as patch against current Subversion tree

  * to the appropriate mailing list.

- *
- *
- * @section features_sec Features
- *
- * @subsection open_source_feat It's Open Source!
- *
- * PJLIB is currently released on LGPL license. We may release PJLIB under
- * additional schemes in the future (such as GPL or MPL) to incorporate
- * linking with specific application, however, one thing for sure is
- * we will NEVER be able to make PJLIB a proprietary software.
- *
- * @subsection extreme_portable_feat Extreme Portability
- *
- * PJLIB is designed to be extremely portable. It can run on any kind
- * of processors (16-bit, 32-bit, or 64-bit, big or little endian, single
- * or multi-processors) and operating systems. Floating point or no
- * floating point. Multi-threading or not.
- * It can even run in environment where no ANSI LIBC is available. 
- *
- * Currently PJLIB is being ported to:
- *  - x86, Win32 (Win95/98/ME, NT/2000/XP/2003, mingw).
- *  - x86, Linux (user mode and as <b>kernel module</b>(!)).
- *  - alpha, Linux
- * And coming up:
- *  - x86, eCos
- *  - ultra-II, Solaris.
- *  - powerpc, MacOS
- *  - m68k, PalmOS.
- *  - arm, PocketPC
- *
- * No other library is known to have this extreme portability!
- *
- * @subsection small_size_feat Small in Size
- *
- * One of the primary objectives is to have library that is small in size for
- * typical embedded applications. As a rough guidance, we aim to keep the 
- * library size below 100KB for it to be considered as small.
- * As the result, most of the functionalities in the library can be tailored
- * to meet the requirements; user can enable/disable specific functionalities
- * to get the desired size/performance/functionality balance.
- *
- * For more info, please see @ref pj_config.
- *
- * @subsection no_dyn_mem No Dynamic Memory Allocations
- *
- * The central idea of PJLIB is that for applications to run as fast as it can,
- * it should not use \a malloc() at all, but instead should get the memory 
- * from a preallocated storage pool. There are few things that can be 
- * optimized with this approach:
- *
- *  - \a alloc() is a O(1) operation.
- *  - no mutex is used inside alloc(). It is assumed that synchronization 
- *    will be used in higher abstraction by application anyway.
- *  - no \a free() is required. All chunks will be deleted when the pool is 
- *    destroyed.
- *
- * The performance gained on some systems can be as high as 10x speed up
- * against \a malloc() and \a free().
- *
- * For more information, see \ref PJ_POOL_GROUP
- *
- * 
- * @subsection os_abstract_feat Operating System Abstraction
- *
- * PJLIB has abstractions for features that are normally not portable 
- * across operating systems: 
- *  - @ref PJ_THREAD
- *\n
- *    Portable thread manipulation.
- *  - @ref PJ_TLS
- *\n
- *    Storing data in thread's private data.
- *  - @ref PJ_MUTEX
- *\n
- *    Mutual exclusion protection.
- *  - @ref PJ_SEM
- *\n
- *    Semaphores.
- *  - @ref PJ_ATOMIC
- *\n
- *    Atomic variables and their operations.
- *  - @ref PJ_CRIT_SEC
- *\n
- *    Fast locking of critical sections.
- *  - @ref PJ_LOCK
- *\n
- *    High level abstraction for lock objects.
- *  - @ref PJ_EVENT
- *\n
- *    Event object.
- *  - @ref PJ_TIME
- *\n
- *    Portable time manipulation.
- *  - @ref PJ_TIMESTAMP
- *\n
- *    High resolution time value.
- *  - etc.
- *
- *
- * @subsection ll_network_io_sec Low-Level Network I/O
- *
- * PJLIB has very portable abstraction and fairly complete set of API for
- * doing network I/O communications. At the lowest level, PJLIB provides:
- *
- *  - @ref PJ_SOCK
- *\n
- *    A highly portable socket abstraction, runs on all kind of
- *    network APIs such as standard BSD socket, Windows socket, Linux
- *    \b kernel socket, PalmOS networking API, etc.
- *
- *  - @ref pj_addr_resolve
- *\n
- *    Portable address resolution, which implements #pj_gethostbyname().
- *
- *  - @ref PJ_SOCK_SELECT
- *\n
- *    A portable \a select() like API (#pj_sock_select()) which can be
- *    implemented with various back-end.
- *
- *
- * @subsection hl_network_io_sec High-Level Network I/O
- *
- * At higher abstraction, PJLIB provides @ref PJ_IOQUEUE, 
- * which promotes creating high performance network
- * applications by managing asynchronous I/O. This is a passive framework
- * that utilizes the most effective way to manage asynchronous I/O
- * on a given platform, such as:
- *  - IoCompletionPort on WinNT,
- *  - on Linux it can use either /dev/epoll or aio.
- *  - or to fall back to use @a select()
- *
- * At even a higher abstraction, PJLIB provides @ref PJ_EQUEUE, which
- * combines asynchronous I/O with timer management and thread management 
- * to fasilitate creating trully high performance, event driven
- * application.
- * 
- *
- * @subsection timer_mgmt_sec Timer Management
- *
- * A passive framework for managing timer, see @ref PJ_TIMER for more info.
- * There is also function to retrieve high resolution timestamp
- * from the system (see @ref PJ_TIMESTAMP).
- *
- *
- * @subsection data_struct_sec Various Data Structures
- *
- * Various data structures are provided in the library:
- *
- *  - @ref PJ_PSTR
- *  - @ref PJ_ARRAY
- *  - @ref PJ_HASH
- *  - @ref PJ_LIST
- *  - @ref PJ_RBTREE
- *
- *
- * @subsection exception_sec Exception Construct
- *
- * A convenient TRY/CATCH like construct to propagate errors, which by
- * default are used by the @ref PJ_POOL_GROUP "memory pool" and 
- * the lexical scanner in pjlib-util. The exception
- * construct can be used to write programs like below:
- *
- * <pre>
- *    #define SYNTAX_ERROR  1
- *
- *    PJ_TRY {
- *       msg = NULL;
- *       msg = parse_msg(buf, len);
- *    }
- *    PJ_CATCH ( SYNTAX_ERROR ) {
- *       .. handle error ..
- *    }
- *    PJ_END;
- * </pre>
- *
- * Please see @ref PJ_EXCEPT for more information.
- *
- *
- * @subsection logging_sec Logging Facility
- *
- * PJLIB @ref PJ_LOG consists of macros to write logging information to
- * some output device. Some of the features of the logging facility:
- *
- *  - the verbosity can be fine-tuned both at compile time (to control
- *    the library size) or run-time (to control the verbosity of the
- *    information).
- *  - output device is configurable (e.g. stdout, printk, file, etc.)
- *  - log decoration is configurable.
- *
- * See @ref PJ_LOG for more information.
- *
- *
- * @subsection guid_gen_sec Random and GUID Generation
- *
- * PJLIB provides facility to create random string 
- * (#pj_create_random_string()) or globally unique identifier
- * (see @ref PJ_GUID).
- *
- *
- *
- * @section configure_app_sec Configuring Application to use PJLIB
- *
- * @subsection pjlib_compil_sec Building PJLIB
- *
- * Follow the instructions in \ref pjlib_build_sys_pg to build
- * PJLIB.
- *
- * @subsection pjlib_compil_app_sec Building Applications with PJLIB
- *
- * Use the following settings when building applications with PJLIB.
- *
- * @subsubsection compil_inc_dir_sec Include Search Path
- *
- * Add this to your include search path ($PJLIB is PJLIB root directory):
- * <pre>
- *   $PJLIB/include
- * </pre>
- *
- * @subsubsection compil_inc_file_sec Include PJLIB Header
- *
- * To include all PJLIB headers:
- * \verbatim
-    #include <pjlib.h>
-   \endverbatim
- *
- * Alternatively, you can include individual PJLIB headers like this:
- * \verbatim
-     #include <pj/log.h>
-     #include <pj/os.h>
-  \endverbatim
- *
- *
- * @subsubsection compil_lib_dir_sec Library Path
- *
- * Add this to your library search path:
- * <pre>
- *   $PJLIB/lib
- * </pre>
- *
- * Then add the appropriate PJLIB library to your link specification. For
- * example, you would add \c libpj-i386-linux-gcc.a when you're building
- * applications in Linux.
- *
- *
- * @subsection pjlib_fundamentals_sec Principles in Using PJLIB
- *
- * Few things that you \b MUST do when using PJLIB, to make sure that
- * you create trully portable applications.
- *
- * @subsubsection call_pjlib_init_sec Call pj_init()
- *
- * Before you do anything else, call \c pj_init(). This would make sure that
- * PJLIB system is properly set up.
- *
- * @subsubsection no_ansi_subsec Do NOT Use ANSI C
- *
- * Contrary to popular teaching, ANSI C (and LIBC) is not the most portable
- * library in the world, nor it's the most ubiquitous. For example, LIBC
- * is not available in Linux kernel. Also normally LIBC will be excluded
- * from compilation of RTOSes to reduce size.
- *
- * So for maximum portability, do NOT use ANSI C. Do not even try to include
- * any other header files outside <include/pj>. Stick with the functionalities
- * provided by PJLIB. 
- *
- *
- * @subsubsection string_rep_subsubsec Use pj_str_t instead of C Strings
- *
- * PJLIB uses pj_str_t instead of normal C strings. You SHOULD follow this
- * convention too. Remember, ANSI string-h is not always available. And
- * PJLIB string is faster!
- *
- * @subsubsection mem_alloc_subsubsec Use Pool for Memory Allocations
- *
- * You MUST NOT use \a malloc() or any other memory allocation functions.
- * Use PJLIB pool instead! It's faster and most portable.
- *
- * @subsection logging_subsubsec Use Logging for Text Display
- *
- * DO NOT use <stdio.h> for text output. Use PJLIB logging instead.
- *
- *
- * @section porting_pjlib_sec0 Porting PJLIB
- *
- * Please see \ref porting_pjlib_pg page on more information to port
- * PJLIB to new target.
- *
- * @section enjoy_sec Enjoy Using PJLIB!
- *
- * We hope that you find PJLIB usefull for your application. If you
- * have any questions, suggestions, critics, bug fixes, or anything
- * else, we would be happy to hear it.
- *
- * Enjoy using PJLIB!
- *
- * Benny Prijono < bennylp at pjproject dot net >
- */
-
-
-
+ *

+ *

+ * @section features_sec Features

+ *

+ * @subsection open_source_feat It's Open Source!

+ *

+ * PJLIB is currently released on LGPL license. We may release PJLIB under

+ * additional schemes in the future (such as GPL or MPL) to incorporate

+ * linking with specific application, however, one thing for sure is

+ * we will NEVER be able to make PJLIB a proprietary software.

+ *

+ * @subsection extreme_portable_feat Extreme Portability

+ *

+ * PJLIB is designed to be extremely portable. It can run on any kind

+ * of processors (16-bit, 32-bit, or 64-bit, big or little endian, single

+ * or multi-processors) and operating systems. Floating point or no

+ * floating point. Multi-threading or not.

+ * It can even run in environment where no ANSI LIBC is available. 

+ *

+ * Currently PJLIB is being ported to:

+ *  - x86, Win32 (Win95/98/ME, NT/2000/XP/2003, mingw).

+ *  - x86, Linux (user mode and as <b>kernel module</b>(!)).

+ *  - alpha, Linux

+ * And coming up:

+ *  - x86, eCos

+ *  - ultra-II, Solaris.

+ *  - powerpc, MacOS

+ *  - m68k, PalmOS.

+ *  - arm, PocketPC

+ *

+ * No other library is known to have this extreme portability!

+ *

+ * @subsection small_size_feat Small in Size

+ *

+ * One of the primary objectives is to have library that is small in size for

+ * typical embedded applications. As a rough guidance, we aim to keep the 

+ * library size below 100KB for it to be considered as small.

+ * As the result, most of the functionalities in the library can be tailored

+ * to meet the requirements; user can enable/disable specific functionalities

+ * to get the desired size/performance/functionality balance.

+ *

+ * For more info, please see @ref pj_config.

+ *

+ * @subsection no_dyn_mem No Dynamic Memory Allocations

+ *

+ * The central idea of PJLIB is that for applications to run as fast as it can,

+ * it should not use \a malloc() at all, but instead should get the memory 

+ * from a preallocated storage pool. There are few things that can be 

+ * optimized with this approach:

+ *

+ *  - \a alloc() is a O(1) operation.

+ *  - no mutex is used inside alloc(). It is assumed that synchronization 

+ *    will be used in higher abstraction by application anyway.

+ *  - no \a free() is required. All chunks will be deleted when the pool is 

+ *    destroyed.

+ *

+ * The performance gained on some systems can be as high as 10x speed up

+ * against \a malloc() and \a free().

+ *

+ * For more information, see \ref PJ_POOL_GROUP

+ *

+ * 

+ * @subsection os_abstract_feat Operating System Abstraction

+ *

+ * PJLIB has abstractions for features that are normally not portable 

+ * across operating systems: 

+ *  - @ref PJ_THREAD

+ *\n

+ *    Portable thread manipulation.

+ *  - @ref PJ_TLS

+ *\n

+ *    Storing data in thread's private data.

+ *  - @ref PJ_MUTEX

+ *\n

+ *    Mutual exclusion protection.

+ *  - @ref PJ_SEM

+ *\n

+ *    Semaphores.

+ *  - @ref PJ_ATOMIC

+ *\n

+ *    Atomic variables and their operations.

+ *  - @ref PJ_CRIT_SEC

+ *\n

+ *    Fast locking of critical sections.

+ *  - @ref PJ_LOCK

+ *\n

+ *    High level abstraction for lock objects.

+ *  - @ref PJ_EVENT

+ *\n

+ *    Event object.

+ *  - @ref PJ_TIME

+ *\n

+ *    Portable time manipulation.

+ *  - @ref PJ_TIMESTAMP

+ *\n

+ *    High resolution time value.

+ *  - etc.

+ *

+ *

+ * @subsection ll_network_io_sec Low-Level Network I/O

+ *

+ * PJLIB has very portable abstraction and fairly complete set of API for

+ * doing network I/O communications. At the lowest level, PJLIB provides:

+ *

+ *  - @ref PJ_SOCK

+ *\n

+ *    A highly portable socket abstraction, runs on all kind of

+ *    network APIs such as standard BSD socket, Windows socket, Linux

+ *    \b kernel socket, PalmOS networking API, etc.

+ *

+ *  - @ref pj_addr_resolve

+ *\n

+ *    Portable address resolution, which implements #pj_gethostbyname().

+ *

+ *  - @ref PJ_SOCK_SELECT

+ *\n

+ *    A portable \a select() like API (#pj_sock_select()) which can be

+ *    implemented with various back-end.

+ *

+ *

+ * @subsection hl_network_io_sec High-Level Network I/O

+ *

+ * At higher abstraction, PJLIB provides @ref PJ_IOQUEUE, 

+ * which promotes creating high performance network

+ * applications by managing asynchronous I/O. This is a passive framework

+ * that utilizes the most effective way to manage asynchronous I/O

+ * on a given platform, such as:

+ *  - IoCompletionPort on WinNT,

+ *  - on Linux it can use either /dev/epoll or aio.

+ *  - or to fall back to use @a select()

+ *

+ * At even a higher abstraction, PJLIB provides @ref PJ_EQUEUE, which

+ * combines asynchronous I/O with timer management and thread management 

+ * to fasilitate creating trully high performance, event driven

+ * application.

+ * 

+ *

+ * @subsection timer_mgmt_sec Timer Management

+ *

+ * A passive framework for managing timer, see @ref PJ_TIMER for more info.

+ * There is also function to retrieve high resolution timestamp

+ * from the system (see @ref PJ_TIMESTAMP).

+ *

+ *

+ * @subsection data_struct_sec Various Data Structures

+ *

+ * Various data structures are provided in the library:

+ *

+ *  - @ref PJ_PSTR

+ *  - @ref PJ_ARRAY

+ *  - @ref PJ_HASH

+ *  - @ref PJ_LIST

+ *  - @ref PJ_RBTREE

+ *

+ *

+ * @subsection exception_sec Exception Construct

+ *

+ * A convenient TRY/CATCH like construct to propagate errors, which by

+ * default are used by the @ref PJ_POOL_GROUP "memory pool" and 

+ * the lexical scanner in pjlib-util. The exception

+ * construct can be used to write programs like below:

+ *

+ * <pre>

+ *    #define SYNTAX_ERROR  1

+ *

+ *    PJ_TRY {

+ *       msg = NULL;

+ *       msg = parse_msg(buf, len);

+ *    }

+ *    PJ_CATCH ( SYNTAX_ERROR ) {

+ *       .. handle error ..

+ *    }

+ *    PJ_END;

+ * </pre>

+ *

+ * Please see @ref PJ_EXCEPT for more information.

+ *

+ *

+ * @subsection logging_sec Logging Facility

+ *

+ * PJLIB @ref PJ_LOG consists of macros to write logging information to

+ * some output device. Some of the features of the logging facility:

+ *

+ *  - the verbosity can be fine-tuned both at compile time (to control

+ *    the library size) or run-time (to control the verbosity of the

+ *    information).

+ *  - output device is configurable (e.g. stdout, printk, file, etc.)

+ *  - log decoration is configurable.

+ *

+ * See @ref PJ_LOG for more information.

+ *

+ *

+ * @subsection guid_gen_sec Random and GUID Generation

+ *

+ * PJLIB provides facility to create random string 

+ * (#pj_create_random_string()) or globally unique identifier

+ * (see @ref PJ_GUID).

+ *

+ *

+ *

+ * @section configure_app_sec Configuring Application to use PJLIB

+ *

+ * @subsection pjlib_compil_sec Building PJLIB

+ *

+ * Follow the instructions in \ref pjlib_build_sys_pg to build

+ * PJLIB.

+ *

+ * @subsection pjlib_compil_app_sec Building Applications with PJLIB

+ *

+ * Use the following settings when building applications with PJLIB.

+ *

+ * @subsubsection compil_inc_dir_sec Include Search Path

+ *

+ * Add this to your include search path ($PJLIB is PJLIB root directory):

+ * <pre>

+ *   $PJLIB/include

+ * </pre>

+ *

+ * @subsubsection compil_inc_file_sec Include PJLIB Header

+ *

+ * To include all PJLIB headers:

+ * \verbatim

+    #include <pjlib.h>

+   \endverbatim

+ *

+ * Alternatively, you can include individual PJLIB headers like this:

+ * \verbatim

+     #include <pj/log.h>

+     #include <pj/os.h>

+  \endverbatim

+ *

+ *

+ * @subsubsection compil_lib_dir_sec Library Path

+ *

+ * Add this to your library search path:

+ * <pre>

+ *   $PJLIB/lib

+ * </pre>

+ *

+ * Then add the appropriate PJLIB library to your link specification. For

+ * example, you would add \c libpj-i386-linux-gcc.a when you're building

+ * applications in Linux.

+ *

+ *

+ * @subsection pjlib_fundamentals_sec Principles in Using PJLIB

+ *

+ * Few things that you \b MUST do when using PJLIB, to make sure that

+ * you create trully portable applications.

+ *

+ * @subsubsection call_pjlib_init_sec Call pj_init()

+ *

+ * Before you do anything else, call \c pj_init(). This would make sure that

+ * PJLIB system is properly set up.

+ *

+ * @subsubsection no_ansi_subsec Do NOT Use ANSI C

+ *

+ * Contrary to popular teaching, ANSI C (and LIBC) is not the most portable

+ * library in the world, nor it's the most ubiquitous. For example, LIBC

+ * is not available in Linux kernel. Also normally LIBC will be excluded

+ * from compilation of RTOSes to reduce size.

+ *

+ * So for maximum portability, do NOT use ANSI C. Do not even try to include

+ * any other header files outside <include/pj>. Stick with the functionalities

+ * provided by PJLIB. 

+ *

+ *

+ * @subsubsection string_rep_subsubsec Use pj_str_t instead of C Strings

+ *

+ * PJLIB uses pj_str_t instead of normal C strings. You SHOULD follow this

+ * convention too. Remember, ANSI string-h is not always available. And

+ * PJLIB string is faster!

+ *

+ * @subsubsection mem_alloc_subsubsec Use Pool for Memory Allocations

+ *

+ * You MUST NOT use \a malloc() or any other memory allocation functions.

+ * Use PJLIB pool instead! It's faster and most portable.

+ *

+ * @subsection logging_subsubsec Use Logging for Text Display

+ *

+ * DO NOT use <stdio.h> for text output. Use PJLIB logging instead.

+ *

+ *

+ * @section porting_pjlib_sec0 Porting PJLIB

+ *

+ * Please see \ref porting_pjlib_pg page on more information to port

+ * PJLIB to new target.

+ *

+ * @section enjoy_sec Enjoy Using PJLIB!

+ *

+ * We hope that you find PJLIB usefull for your application. If you

+ * have any questions, suggestions, critics, bug fixes, or anything

+ * else, we would be happy to hear it.

+ *

+ * Enjoy using PJLIB!

+ *

+ * Benny Prijono < bennylp at pjproject dot net >

+ */

+

+

+

 /*////////////////////////////////////////////////////////////////////////// */

 /*

          CODING CONVENTION

@@ -439,566 +460,566 @@
  *

  */

 

-
-/*////////////////////////////////////////////////////////////////////////// */
-/*
-	BUILDING AND INSTALLING PJLIB
- */
-
-
-
-/**
- * @page pjlib_build_sys_pg Building, and Installing PJLIB
- *
- * @section build_sys_install_sec Build and Installation
- *
- * @subsection build_sys_install_win32_sec Visual Studio
- *
- * The PJLIB Visual Studio workspace supports the building of PJLIB
- * for Win32 target. Although currently only the Visual Studio 6 Workspace is
- * actively maintained, developers with later version of Visual Studio
- * can easily imports VS6 workspace into their IDE.
- *
- * To start building PJLIB projects with Visual Studio 6 or later, open
- * the \a workspace file in the corresponding \b \c build directory. You have
- * several choices on which \a dsw file to open:
- \verbatim
- $PJPROJECT/build/pjproject.dsw
- $PJPROJECT/pjlib/build/pjlib.dsw
- $PJPROJECT/pjsip/build/pjsip.dsw
- ..etc
- \endverbatim
- *
- * The easiest way is to open <tt>pjproject.dsw</tt> file in \b \c $PJPROJECT/build
- * directory. However this will only build the required projects, not
- * the complete projects. For example, the PJLIB test and samples projects 
- * are not included in this workspace. To build the complete projects, you must
- * open and build each \a dsw file in \c build directory in each
- * subprojects. For example, to open the complete PJLIB workspace, open
- * <tt>pjlib.dsw</tt> in <tt>$PJPROJECT/pjlib/build</tt> directory.
- *
- *
- * @subsubsection config_site_create_vc_sec Create config_site.h
- *
- * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>
- * is supposed to contain configuration that is specific to your site/target.
- * This file is not part of PJLIB, so you must create it yourself. Normally
- * you just need to create a blank file.
- *
- * The reason why it's not included in PJLIB is so that you would not accidently
- * overwrite your site configuration.
- *
- * If you fail to do this, Visual C will complain with error like: 
- *
- * <b>"fatal error C1083: Cannot open include file: 'pj/config_site.h': No such file 
- * or directory"</b>.
- *
- * @subsubsection build_vc_subsubsec Build the Projects
- *
- * Just hit the build button!
- *
- *
- * @subsection build_sys_install_unix_sec Make System
- *
- * For other targets, PJLIB provides a rather comprehensive build system
- * that uses GNU \a make (and only GNU \a make will work). 
- * Currently, the build system supports building * PJLIB for these targets:
- *  - i386/Win32/mingw
- *  - i386/Linux
- *  - i386/Linux (kernel)
- *  - alpha/linux
- *  - sparc/SunOS
- *  - etc..
- *
- *
- * @subsubsection build_req_sec Requirements
- *
- * In order to use the \c make based build system, you MUST have:
- *
- *  - <b>GNU make</b>
- *\n
- *    The Makefiles heavily utilize GNU make commands which most likely
- *    are not available in other \c make system.
- *  - <b>bash</b> shell is recommended.
- *\n
- *    Specificly, there is a command <tt>"echo -n"</tt> which may not work
- *    in other shells. This command is used when generating dependencies
- *    (<tt>make dep</tt>) and it's located in 
- *    <tt>$PJPROJECT/build/rules.mak</tt>.
- *  - <b>ar</b>, <b>ranlib</b> from GNU binutils
- *\n
- *    In your system has different <tt>ar</tt> or <tt>ranlib</tt> (e.g. they
- *    may have been installed as <tt>gar</tt> and <tt>granlib</tt>), then
- *    either you create the relevant symbolic links, <b>or</b> modify
- *    <tt>$PJPROJECT/build/cc-gcc.mak</tt> and rename <tt>ar</tt> and
- *    <tt>ranlib</tt> to the appropriate names.
- *  - <b>gcc</b> to generate dependency.
- *\n
- *    Currently the build system uses <tt>"gcc -MM"</tt> to generate build
- *    dependencies. If <tt>gcc</tt> is not desired to generate dependency,
- *    then either you don't run <tt>make dep</tt>, <b>or</b> edit
- *    <tt>$PJPROJECT/build/rules.mak</tt> to calculate dependency using
- *    your prefered method. (And let me know when you do so so that I can
- *    update the file. :) )
- *
- * @subsubsection build_overview_sec Building the Project
- *
- * Generally, steps required to build the PJLIB are:
- *
- \verbatim
-   $ cd /home/user/pjproject         # <-- go to $PJPROJECT
-   $ vi build.mak                    # <-- set build target etc
-   $ touch pjlib/include/pj/config_site.h
-   $ cd pjlib/build                  # <-- go to projet's build dir
-   $ make                            # <-- build the project
- \endverbatim
- *
- * For other project, \a cd to <tt>build</tt> directory in the project
- * and execute \a make from there.
- *
- * \note For Linux kernel target, there are additional steps required, which
- * will be explained in section \ref linux_kern_target_subsec.
- *
- * @subsubsection build_mak_sec Editing build.mak
- * 
- * The \c build.mak file in \c $PJPROJECT root directory is used to
- * specify the build configuration. This file is expected to export
- * the following \a make variables:
- *
- *  - <tt><b>MACHINE_NAME</b></tt>
- *\n
- *    Target machine/processor, one of: <b>{ i386 | alpha | sparc }</b>.
- *
- *  - <tt><b>OS_NAME</b></tt>
- *\n
- *    Target operating system, one of: <b>{ win32 | linux | 
- *      linux-kernel | sunos }</b>.
- *
- *  - <tt><b>CC_NAME</b></tt>
- *\n
- *    Compiler name: <b>{ gcc | vc }</b>\n
- *    (Note that support for Visual C (vc) compiler with the \c make system is
- *    experimental, and it will only work when run inside a DOS shell
- *    (i.e. <tt>"HOST_NAME=win32"</tt>)).
- *
- *  - <tt><b>HOST_NAME</b></tt>
- *\n
- *    Build host: <b>{ unix | mingw | win32 }</b>\n
- *    (Note: win32 host means a DOS command prompt. Support for this type
- *    of development host is experimental).
- *
- * These variables will cause the correct configuration file in 
- * \c $PJPROJECT/build directory to be executed by \a make. For 
- * example, specifying \c OS_NAME=linux will cause file \c os-linux.mak
- * in \c build directory to be executed. These files contain specific
- * configuration for the option that is selected.
- *
- * For Linux kernel target, you are also required to declare the following
- * variables in this file:
- *	- \c KERNEL_DIR: full path of kernel source tree.
- *	- \c KERNEL_ARCH: kernel ARCH options (e.g. "ARCH=um"), or leave blank
- * 	     for default.
- *	- \c PJPROJECT_DIR: full path of PJPROJECT source tree.
- *
- * Apart from these, there are also additional steps required to build
- * Linux kernel target, which will be explained in \ref linux_kern_target_subsec.
- *
- * @subsubsection build_dir_sec Files in "build" Directory
- *
- * The <tt>*.mak</tt> files in \c $PJPROJECT/build directory are used to specify
- * the configuration for the specified compiler, target machine target 
- * operating system, and host options. These files will be executed
- * (included) by \a make during building process, depending on the values
- * specified in <b>$PJPROJECT/build.mak</b> file.
- *
- * Normally you don't need to edit these files, except when you're porting
- * PJLIB to new target.
- *
- * Below are the description of some files in this directory:
- *
- *  - <tt>rules.mak</tt>: contains generic rules always included during make.
- *  - <tt>cc-gcc.mak</tt>: rules when gcc is used for compiler.
- *  - <tt>cc-vc.mak</tt>: rules when MSVC compiler is used.
- *  - <tt>host-mingw.mak</tt>: rules for building in mingw host.
- *  - <tt>host-unix.mak</tt>: rules for building in Unix/Posix host.
- *  - <tt>host-win32.mak</tt>: rules for building in Win32 command console
- *    (only valid when VC is used).
- *  - <tt>m-i386.mak</tt>: rules when target machine is an i386 processor.
- *  - <tt>m-m68k.mak</tt>: rules when target machine is an m68k processor.
- *  - <tt>os-linux.mak</tt>: rules when target OS is Linux.
- *  - <tt>os-linux-kernel.mak</tt>: rules when PJLIB is to be build as
- *    part of Linux kernel.
- *  - <tt>os-win32.mak</tt>: rules when target OS is Win32.
- *
- *
- * @subsubsection config_site_create_sec Create config_site.h
- *
- * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>
- * is supposed to contain configuration that is specific to your site/target.
- * This file is not part of PJLIB, so you must create it yourself.
- *
- * The reason why it's not included in PJLIB is so that you would not accidently
- * overwrite your site configuration.
- *
- *
- * @subsubsection invoking_make_sec Invoking make
- *
- * Normally, \a make is invoked in \c build directory under each project.
- * For example, to build PJLIB, you would invoke \a make in
- * \c $PJPROJECT/pjlib/build directory like below:
- *
- \verbatim
-   $ cd pjlib/build
-   $ make
- \endverbatim
- *
- * Alternatively you may invoke <tt>make</tt> in <tt>$PJPROJECT</tt> 
- * directory, to build all projects under that directory (e.g. 
- * PJLIB, PJSIP, etc.).
- *
- *
- * @subsubsection linux_kern_target_subsec Linux Kernel Target
- *
- * \note
- * <b>BUILDING APPLICATIONS IN LINUX KERNEL MODE IS A VERY DANGEROUS BUSINESS.
- * YOU MAY CRASH THE WHOLE OF YOUR SYSTEM, CORRUPT YOUR HARDISK, ETC. PJLIB
- * KERNEL MODULES ARE STILL IN EXPERIMENTAL PHASE. DO NOT RUN IT IN PRODUCTION
- * SYSTEMS OR OTHER SYSTEMS WHERE RISK OF LOSS OF DATA IS NOT ACCEPTABLE.
- * YOU HAVE BEEN WARNED.</b>
- *
- * \note
- * <b>User Mode Linux (UML)</b> provides excellent way to experiment with Linux
- * kernel without risking the stability of the host system. See
- * http://user-mode-linux.sourceforge.net for details.
- *
- * \note
- * I only use <b>UML</b> to experiment with PJLIB kernel modules.
- * <b>I wouldn't be so foolish to use my host Linux machine to experiment
- * with this.</b> 
- *
- * \note
- * You have been warned.
- *
- * For building PJLIB for Linux kernel target, there are additional steps required.
- * In general, the additional tasks are:
- *	- Declare some more variables in <b><tt>build.mak</tt></b> file (this
- *        has been explained in \ref build_mak_sec above).
- *      - Perform these two small modifications in kernel source tree.
- *
- * There are two small modification need to be applied to the kernel tree.
- *
- * <b>1. Edit <tt>Makefile</tt> in kernel root source tree.</b>
- *
- * Add the following lines at the end of the <tt>Makefile</tt> in your 
- * <tt>$KERNEL_SRC</tt> dir:
- \verbatim
-script:
-       $(SCRIPT)
- \endverbatim
- *
- * \note Remember to replace spaces with <b>tab</b> in the Makefile.
- *
- * The modification above is needed to capture kernel's \c $CFLAGS and 
- * \c $CFLAGS_MODULE which will be used for PJLIB's compilation.
- *
- * <b>2. Add Additional Exports.</b>
- *
- * We need the kernel to export some more symbols for our use. So we declare
- * the additional symbols to be exported in <tt>extra-exports.c</tt> file, and add
- * a this file to be compiled into the kernel:
- *
- *	- Copy the file <tt>extra-exports.c</tt> from <tt>pjlib/src/pj</tt> 
- *	  directory to <tt>$KERNEL_SRC/kernel/</tt> directory.
- *	- Edit <tt>Makefile</tt> in that directory, and add this line
- *        somewhere after the declaration of that variable:
- \verbatim
-obj-y   += extra-exports.o
- \endverbatim
- *
- * To illustrate what have been done in your kernel source tree, below
- * is screenshot of my kernel source tree _after_ the modification.
- *
- \verbatim
-[root@vpc-linux linux-2.6.7]# pwd
-/usr/src/linux-2.6.7
-[root@vpc-linux linux-2.6.7]# 
-[root@vpc-linux linux-2.6.7]# 
-[root@vpc-linux linux-2.6.7]# tail Makefile 
-
-endif   # skip-makefile
-
-FORCE:
-
-.PHONY: script
-
-script:
-        $(SCRIPT)
-
-[root@vpc-linux linux-2.6.7]# 
-[root@vpc-linux linux-2.6.7]# 
-[root@vpc-linux linux-2.6.7]# head kernel/extra-exports.c 
-#include <linux/module.h>
-#include <linux/syscalls.h>
-
-EXPORT_SYMBOL(sys_select);
-
-EXPORT_SYMBOL(sys_epoll_create);
-EXPORT_SYMBOL(sys_epoll_ctl);
-EXPORT_SYMBOL(sys_epoll_wait);
-
-EXPORT_SYMBOL(sys_socket);
-[root@vpc-linux linux-2.6.7]# 
-[root@vpc-linux linux-2.6.7]# 
-[root@vpc-linux linux-2.6.7]# head -15 kernel/Makefile 
-#
-# Makefile for the linux kernel.
-#
-
-obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
-            exit.o itimer.o time.o softirq.o resource.o \
-            sysctl.o capability.o ptrace.o timer.o user.o \
-            signal.o sys.o kmod.o workqueue.o pid.o \
-            rcupdate.o intermodule.o extable.o params.o posix-timers.o \
-            kthread.o
-
-obj-y   +=  extra-exports.o
-
-obj-$(CONFIG_FUTEX) += futex.o
-obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
-[root@vpc-linux linux-2.6.7]# 
-
- \endverbatim
- *
- * Then you must rebuild the kernel.
- * If you fail to do this, you won't be able to <b>insmod</b> pjlib.
- *
- * \note You will see a lots of warning messages during pjlib-test compilation.
- * The warning messages complain about unresolved symbols which are defined
- * in pjlib module. You can safely ignore these warnings. However, you can not
- * ignore warnings about non-pjlib unresolved symbols.
- *
- * 
- * @subsection makefile_explained_sec Makefile Explained
- *
- * The \a Makefile for each project (e.g. PJLIB, PJSIP, etc) should be
- * very similar in the contents. The Makefile is located under \c build
- * directory in each project subdir.
- *
- * @subsubsection pjlib_makefile_subsec PJLIB Makefile.
- *
- * Below is PJLIB's Makefile:
- *
- * \include build/Makefile
- *
- * @subsubsection pjlib_os_makefile_subsec PJLIB os-linux.mak.
- *
- * Below is file <tt><b>os-linux.mak</b></tt> file in 
- * <tt>$PJPROJECT/pjlib/build</tt> directory,
- * which is OS specific configuration file for Linux target that is specific 
- * for PJLIB project. For \b global OS specific configuration, please see
- * <tt>$PJPROJECT/build/os-*.mak</tt>.
- *
- * \include build/os-linux.mak
- *
- */
-
-
-/*////////////////////////////////////////////////////////////////////////// */
-/*
-         PORTING PJLIB
- */
-
-
-
-/**
- * @page porting_pjlib_pg Porting PJLIB
- *
- *
- * @section new_arch_sec Porting to New CPU Architecture
- *
- * Below is step-by-step guide to add support for new CPU architecture.
- * This sample is based on porting to Alpha architecture; however steps for 
- * porting to other CPU architectures should be pretty similar. 
- *
- * Also note that in this example, the operating system used is <b>Linux</b>.
- * Should you wish to add support for new operating system, then follow
- * the next section \ref porting_os_sec.
- *
- * Step-by-step guide to port to new CPU architecture:
- *  - decide the name for the new architecture. In this case, we choose
- *    <tt><b>alpha</b></tt>.
- *  - edit file <tt>$PJPROJECT/build.mak</tt>, and add new section for
- *    the new target:
- *    <pre>
- *      #
- *      # Linux alpha, gcc
- *      #
- *      export MACHINE_NAME := <b>alpha</b>
- *      export OS_NAME := linux
- *      export CC_NAME := gcc
- *      export HOST_NAME := unix
- *    </pre>
- *
- *  - create a new file <tt>$PJPROJECT/build/<b>m-alpha</b>.mak</tt>.
- *    Alternatively create a copy from other file in this directory.
- *    The contents of this file will look something like:
- *    <pre>
- *      export M_CFLAGS := $(CC_DEF)<b>PJ_M_ALPHA=1</b>
- *      export M_CXXFLAGS :=
- *      export M_LDFLAGS :=
- *      export M_SOURCES :=
- *    </pre>
- *  - create a new file <tt>$PJPROJECT/pjlib/include/pj/compat/<b>m_alpha.h</b></tt>.
- *    Alternatively create a copy from other header file in this directory.
- *    The contents of this file will look something like:
- *    <pre>
- *      #define PJ_HAS_PENTIUM          0
- *      #define PJ_IS_LITTLE_ENDIAN     1
- *      #define PJ_IS_BIG_ENDIAN        0
- *    </pre>
- *  - edit <tt>pjlib/include/pj/<b>config.h</b></tt>. Add new processor
- *    configuration in this header file, like follows:
- *    <pre>
- *      ...
- *      #elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0
- *      #   include <pj/compat/m_alpha.h>
- *      ...
- *    </pre>
- *  - done. Build PJLIB with:
- *    <pre>
- *      $ cd $PJPROJECT/pjlib/build
- *      $ make dep
- *      $ make clean
- *      $ make
- *    </pre>
- *
- * @section porting_os_sec Porting to New Operating System Target
- *
- * This section will try to give you rough guideline on how to
- * port PJLIB to a new target. As a sample, we give the target a name tag, 
- * for example <tt><b>xos</b></tt> (for X OS). 
- *
- * @subsection new_compat_os_h_file_sec Create New Compat Header File
- *
- * You'll need to create a new header file 
- * <b><tt>include/pj/compat/os_xos.h</tt></b>. You can copy as a 
- * template other header file and edit it accordingly.
- *
- * @subsection modify_config_h_file_sec Modify config.h
- *
- * Then modify file <b><tt>include/pj/config.h</tt></b> to include
- * this file accordingly (e.g. when macro <tt><b>PJ_XOS</b></tt> is
- * defined):
- *
- \verbatim
- ...
- #elif defined(PJ_XOS)
- #  include <pj/compat/os_xos.h>
- #else
- #...
- \endverbatim
- * 
- * @subsection new_target_mak_file_sec Create New Global Make Config File
- *
- * Then you'll need to create global configuration file that
- * is specific for this OS, i.e. <tt><b>os-xos.mak</b></tt> in 
- * <tt><b>$PJPROJECT/build</b></tt> directory.
- *
- * At very minimum, the file will normally need to define
- * <tt><b>PJ_XOS=1</b></tt> in the \c CFLAGS section:
- *
- \verbatim
-#
-# $PJPROJECT/build/os-xos.mak:
-#
-export OS_CFLAGS   := $(CC_DEF)PJ_XOS=1
-export OS_CXXFLAGS := 
-export OS_LDFLAGS  :=
-export OS_SOURCES  := 
- \endverbatim
- *
- *
- * @subsection new_target_prj_mak_file_sec Create New Project's Make Config File
- *
- * Then you'll need to create xos-specific configuration file
- * for PJLIB. This file is also named <tt><b>os-xos.mak</b></tt>,
- * but its located in <tt><b>pjlib/build</b></tt> directory.
- * This file will specify source files that are specific to
- * this OS to be included in the build process.
- *
- * Below is a sample:
- \verbatim
-#
-# pjlib/build/os-xos.mak:
-#  XOS specific configuration for PJLIB.
-#
-export PJLIB_OBJS += 	os_core_xos.o \
-                        os_error_unix.o \
-                        os_time_ansi.o
-export TEST_OBJS +=	main.o
-export TARGETS	    =	pjlib pjlib-test
- \endverbatim
- *
- * @subsection new_target_src_sec Create and Edit Source Files
- *
- * You'll normally need to create at least these files:
- *  - <tt><b>os_core_xos.c</b></tt>: core OS specific
- *    functionality.
- *  - <tt><b>os_timestamp_xos.c</b></tt>: how to get timestamp
- *    in this OS.
- *
- * Depending on how things are done in your OS, you may need
- * to create these files:
- *  - <tt><b>os_error_*.c</b></tt>: how to manipulate
- *    OS error codes. Alternatively you may use existing
- *    <tt>os_error_unix.c</tt> if the OS has \c errno and
- *    \c strerror() function.
- *  - <tt><b>ioqueue_*.c</b></tt>: if the OS has specific method
- *    to perform asynchronous I/O. Alternatively you may
- *    use existing <tt>ioqueue_select.c</tt> if the OS supports
- *    \c select() function call.
- *  - <tt><b>sock_*.c</b></tt>: if the OS has specific method
- *    to perform socket communication. Alternatively you may
- *    use existing <tt>sock_bsd.c</tt> if the OS supports
- *    BSD socket API, and edit <tt>include/pj/compat/socket.h</tt>
- *    file accordingly.
- *
- * You will also need to check various files in 
- * <tt><b>include/pj/compat/*.h</b></tt>, to see if they're 
- * compatible with your OS.
- *
- * @subsection new_target_build_file_sec Build The Project
- *
- * After basic building blocks have been created for the OS, then
- * the easiest way to see which parts need to be fixed is by building
- * the project and see the error messages.
- *
- * @subsection new_target_edit_vs_new_file_sec Editing Existing Files vs Creating New File
- *
- * When you encounter compatibility errors in PJLIB during porting,
- * you have three options on how to fix the error:
- *  - edit the existing <tt>*.c</tt> file, and give it <tt>#ifdef</tt>
- *    switch for the new OS, or
- *  - edit <tt>include/pj/compat/*.h</tt> instead, or
- *  - create a totally new file.
- *
- * Basicly there is no strict rule on which approach is the best
- * to use, however the following guidelines may be used:
- *  - if the file is expected to be completely different than
- *    any existing file, then perhaps you should create a completely
- *    new file. For example, file <tt>os_core_xxx.c</tt> will 
- *    normally be different for each OS flavour.
- *  - if the difference can be localized in <tt>include/compat</tt>
- *    header file, and existing <tt>#ifdef</tt> switch is there,
- *    then preferably you should edit this <tt>include/compat</tt>
- *    header file.
- *  - if the existing <tt>*.c</tt> file has <tt>#ifdef</tt> switch,
- *    then you may add another <tt>#elif</tt> switch there. This
- *    normally is used for behaviors that are not totally
- *    different on each platform.
- *  - other than that above, use your own judgement on whether
- *    to edit the file or create new file etc.
- */
-
-#endif	/* __PJ_DOXYGEN_H__ */
-
+

+/*////////////////////////////////////////////////////////////////////////// */

+/*

+	BUILDING AND INSTALLING PJLIB

+ */

+

+

+

+/**

+ * @page pjlib_build_sys_pg Building, and Installing PJLIB

+ *

+ * @section build_sys_install_sec Build and Installation

+ *

+ * @subsection build_sys_install_win32_sec Visual Studio

+ *

+ * The PJLIB Visual Studio workspace supports the building of PJLIB

+ * for Win32 target. Although currently only the Visual Studio 6 Workspace is

+ * actively maintained, developers with later version of Visual Studio

+ * can easily imports VS6 workspace into their IDE.

+ *

+ * To start building PJLIB projects with Visual Studio 6 or later, open

+ * the \a workspace file in the corresponding \b \c build directory. You have

+ * several choices on which \a dsw file to open:

+ \verbatim

+ $PJPROJECT/build/pjproject.dsw

+ $PJPROJECT/pjlib/build/pjlib.dsw

+ $PJPROJECT/pjsip/build/pjsip.dsw

+ ..etc

+ \endverbatim

+ *

+ * The easiest way is to open <tt>pjproject.dsw</tt> file in \b \c $PJPROJECT/build

+ * directory. However this will only build the required projects, not

+ * the complete projects. For example, the PJLIB test and samples projects 

+ * are not included in this workspace. To build the complete projects, you must

+ * open and build each \a dsw file in \c build directory in each

+ * subprojects. For example, to open the complete PJLIB workspace, open

+ * <tt>pjlib.dsw</tt> in <tt>$PJPROJECT/pjlib/build</tt> directory.

+ *

+ *

+ * @subsubsection config_site_create_vc_sec Create config_site.h

+ *

+ * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>

+ * is supposed to contain configuration that is specific to your site/target.

+ * This file is not part of PJLIB, so you must create it yourself. Normally

+ * you just need to create a blank file.

+ *

+ * The reason why it's not included in PJLIB is so that you would not accidently

+ * overwrite your site configuration.

+ *

+ * If you fail to do this, Visual C will complain with error like: 

+ *

+ * <b>"fatal error C1083: Cannot open include file: 'pj/config_site.h': No such file 

+ * or directory"</b>.

+ *

+ * @subsubsection build_vc_subsubsec Build the Projects

+ *

+ * Just hit the build button!

+ *

+ *

+ * @subsection build_sys_install_unix_sec Make System

+ *

+ * For other targets, PJLIB provides a rather comprehensive build system

+ * that uses GNU \a make (and only GNU \a make will work). 

+ * Currently, the build system supports building * PJLIB for these targets:

+ *  - i386/Win32/mingw

+ *  - i386/Linux

+ *  - i386/Linux (kernel)

+ *  - alpha/linux

+ *  - sparc/SunOS

+ *  - etc..

+ *

+ *

+ * @subsubsection build_req_sec Requirements

+ *

+ * In order to use the \c make based build system, you MUST have:

+ *

+ *  - <b>GNU make</b>

+ *\n

+ *    The Makefiles heavily utilize GNU make commands which most likely

+ *    are not available in other \c make system.

+ *  - <b>bash</b> shell is recommended.

+ *\n

+ *    Specificly, there is a command <tt>"echo -n"</tt> which may not work

+ *    in other shells. This command is used when generating dependencies

+ *    (<tt>make dep</tt>) and it's located in 

+ *    <tt>$PJPROJECT/build/rules.mak</tt>.

+ *  - <b>ar</b>, <b>ranlib</b> from GNU binutils

+ *\n

+ *    In your system has different <tt>ar</tt> or <tt>ranlib</tt> (e.g. they

+ *    may have been installed as <tt>gar</tt> and <tt>granlib</tt>), then

+ *    either you create the relevant symbolic links, <b>or</b> modify

+ *    <tt>$PJPROJECT/build/cc-gcc.mak</tt> and rename <tt>ar</tt> and

+ *    <tt>ranlib</tt> to the appropriate names.

+ *  - <b>gcc</b> to generate dependency.

+ *\n

+ *    Currently the build system uses <tt>"gcc -MM"</tt> to generate build

+ *    dependencies. If <tt>gcc</tt> is not desired to generate dependency,

+ *    then either you don't run <tt>make dep</tt>, <b>or</b> edit

+ *    <tt>$PJPROJECT/build/rules.mak</tt> to calculate dependency using

+ *    your prefered method. (And let me know when you do so so that I can

+ *    update the file. :) )

+ *

+ * @subsubsection build_overview_sec Building the Project

+ *

+ * Generally, steps required to build the PJLIB are:

+ *

+ \verbatim

+   $ cd /home/user/pjproject         # <-- go to $PJPROJECT

+   $ vi build.mak                    # <-- set build target etc

+   $ touch pjlib/include/pj/config_site.h

+   $ cd pjlib/build                  # <-- go to projet's build dir

+   $ make                            # <-- build the project

+ \endverbatim

+ *

+ * For other project, \a cd to <tt>build</tt> directory in the project

+ * and execute \a make from there.

+ *

+ * \note For Linux kernel target, there are additional steps required, which

+ * will be explained in section \ref linux_kern_target_subsec.

+ *

+ * @subsubsection build_mak_sec Editing build.mak

+ * 

+ * The \c build.mak file in \c $PJPROJECT root directory is used to

+ * specify the build configuration. This file is expected to export

+ * the following \a make variables:

+ *

+ *  - <tt><b>MACHINE_NAME</b></tt>

+ *\n

+ *    Target machine/processor, one of: <b>{ i386 | alpha | sparc }</b>.

+ *

+ *  - <tt><b>OS_NAME</b></tt>

+ *\n

+ *    Target operating system, one of: <b>{ win32 | linux | 

+ *      linux-kernel | sunos }</b>.

+ *

+ *  - <tt><b>CC_NAME</b></tt>

+ *\n

+ *    Compiler name: <b>{ gcc | vc }</b>\n

+ *    (Note that support for Visual C (vc) compiler with the \c make system is

+ *    experimental, and it will only work when run inside a DOS shell

+ *    (i.e. <tt>"HOST_NAME=win32"</tt>)).

+ *

+ *  - <tt><b>HOST_NAME</b></tt>

+ *\n

+ *    Build host: <b>{ unix | mingw | win32 }</b>\n

+ *    (Note: win32 host means a DOS command prompt. Support for this type

+ *    of development host is experimental).

+ *

+ * These variables will cause the correct configuration file in 

+ * \c $PJPROJECT/build directory to be executed by \a make. For 

+ * example, specifying \c OS_NAME=linux will cause file \c os-linux.mak

+ * in \c build directory to be executed. These files contain specific

+ * configuration for the option that is selected.

+ *

+ * For Linux kernel target, you are also required to declare the following

+ * variables in this file:

+ *	- \c KERNEL_DIR: full path of kernel source tree.

+ *	- \c KERNEL_ARCH: kernel ARCH options (e.g. "ARCH=um"), or leave blank

+ * 	     for default.

+ *	- \c PJPROJECT_DIR: full path of PJPROJECT source tree.

+ *

+ * Apart from these, there are also additional steps required to build

+ * Linux kernel target, which will be explained in \ref linux_kern_target_subsec.

+ *

+ * @subsubsection build_dir_sec Files in "build" Directory

+ *

+ * The <tt>*.mak</tt> files in \c $PJPROJECT/build directory are used to specify

+ * the configuration for the specified compiler, target machine target 

+ * operating system, and host options. These files will be executed

+ * (included) by \a make during building process, depending on the values

+ * specified in <b>$PJPROJECT/build.mak</b> file.

+ *

+ * Normally you don't need to edit these files, except when you're porting

+ * PJLIB to new target.

+ *

+ * Below are the description of some files in this directory:

+ *

+ *  - <tt>rules.mak</tt>: contains generic rules always included during make.

+ *  - <tt>cc-gcc.mak</tt>: rules when gcc is used for compiler.

+ *  - <tt>cc-vc.mak</tt>: rules when MSVC compiler is used.

+ *  - <tt>host-mingw.mak</tt>: rules for building in mingw host.

+ *  - <tt>host-unix.mak</tt>: rules for building in Unix/Posix host.

+ *  - <tt>host-win32.mak</tt>: rules for building in Win32 command console

+ *    (only valid when VC is used).

+ *  - <tt>m-i386.mak</tt>: rules when target machine is an i386 processor.

+ *  - <tt>m-m68k.mak</tt>: rules when target machine is an m68k processor.

+ *  - <tt>os-linux.mak</tt>: rules when target OS is Linux.

+ *  - <tt>os-linux-kernel.mak</tt>: rules when PJLIB is to be build as

+ *    part of Linux kernel.

+ *  - <tt>os-win32.mak</tt>: rules when target OS is Win32.

+ *

+ *

+ * @subsubsection config_site_create_sec Create config_site.h

+ *

+ * The file <tt><b>$PJPROJECT/pjlib/include/pj/config_site.h</b></tt>

+ * is supposed to contain configuration that is specific to your site/target.

+ * This file is not part of PJLIB, so you must create it yourself.

+ *

+ * The reason why it's not included in PJLIB is so that you would not accidently

+ * overwrite your site configuration.

+ *

+ *

+ * @subsubsection invoking_make_sec Invoking make

+ *

+ * Normally, \a make is invoked in \c build directory under each project.

+ * For example, to build PJLIB, you would invoke \a make in

+ * \c $PJPROJECT/pjlib/build directory like below:

+ *

+ \verbatim

+   $ cd pjlib/build

+   $ make

+ \endverbatim

+ *

+ * Alternatively you may invoke <tt>make</tt> in <tt>$PJPROJECT</tt> 

+ * directory, to build all projects under that directory (e.g. 

+ * PJLIB, PJSIP, etc.).

+ *

+ *

+ * @subsubsection linux_kern_target_subsec Linux Kernel Target

+ *

+ * \note

+ * <b>BUILDING APPLICATIONS IN LINUX KERNEL MODE IS A VERY DANGEROUS BUSINESS.

+ * YOU MAY CRASH THE WHOLE OF YOUR SYSTEM, CORRUPT YOUR HARDISK, ETC. PJLIB

+ * KERNEL MODULES ARE STILL IN EXPERIMENTAL PHASE. DO NOT RUN IT IN PRODUCTION

+ * SYSTEMS OR OTHER SYSTEMS WHERE RISK OF LOSS OF DATA IS NOT ACCEPTABLE.

+ * YOU HAVE BEEN WARNED.</b>

+ *

+ * \note

+ * <b>User Mode Linux (UML)</b> provides excellent way to experiment with Linux

+ * kernel without risking the stability of the host system. See

+ * http://user-mode-linux.sourceforge.net for details.

+ *

+ * \note

+ * I only use <b>UML</b> to experiment with PJLIB kernel modules.

+ * <b>I wouldn't be so foolish to use my host Linux machine to experiment

+ * with this.</b> 

+ *

+ * \note

+ * You have been warned.

+ *

+ * For building PJLIB for Linux kernel target, there are additional steps required.

+ * In general, the additional tasks are:

+ *	- Declare some more variables in <b><tt>build.mak</tt></b> file (this

+ *        has been explained in \ref build_mak_sec above).

+ *      - Perform these two small modifications in kernel source tree.

+ *

+ * There are two small modification need to be applied to the kernel tree.

+ *

+ * <b>1. Edit <tt>Makefile</tt> in kernel root source tree.</b>

+ *

+ * Add the following lines at the end of the <tt>Makefile</tt> in your 

+ * <tt>$KERNEL_SRC</tt> dir:

+ \verbatim

+script:

+       $(SCRIPT)

+ \endverbatim

+ *

+ * \note Remember to replace spaces with <b>tab</b> in the Makefile.

+ *

+ * The modification above is needed to capture kernel's \c $CFLAGS and 

+ * \c $CFLAGS_MODULE which will be used for PJLIB's compilation.

+ *

+ * <b>2. Add Additional Exports.</b>

+ *

+ * We need the kernel to export some more symbols for our use. So we declare

+ * the additional symbols to be exported in <tt>extra-exports.c</tt> file, and add

+ * a this file to be compiled into the kernel:

+ *

+ *	- Copy the file <tt>extra-exports.c</tt> from <tt>pjlib/src/pj</tt> 

+ *	  directory to <tt>$KERNEL_SRC/kernel/</tt> directory.

+ *	- Edit <tt>Makefile</tt> in that directory, and add this line

+ *        somewhere after the declaration of that variable:

+ \verbatim

+obj-y   += extra-exports.o

+ \endverbatim

+ *

+ * To illustrate what have been done in your kernel source tree, below

+ * is screenshot of my kernel source tree _after_ the modification.

+ *

+ \verbatim

+[root@vpc-linux linux-2.6.7]# pwd

+/usr/src/linux-2.6.7

+[root@vpc-linux linux-2.6.7]# 

+[root@vpc-linux linux-2.6.7]# 

+[root@vpc-linux linux-2.6.7]# tail Makefile 

+

+endif   # skip-makefile

+

+FORCE:

+

+.PHONY: script

+

+script:

+        $(SCRIPT)

+

+[root@vpc-linux linux-2.6.7]# 

+[root@vpc-linux linux-2.6.7]# 

+[root@vpc-linux linux-2.6.7]# head kernel/extra-exports.c 

+#include <linux/module.h>

+#include <linux/syscalls.h>

+

+EXPORT_SYMBOL(sys_select);

+

+EXPORT_SYMBOL(sys_epoll_create);

+EXPORT_SYMBOL(sys_epoll_ctl);

+EXPORT_SYMBOL(sys_epoll_wait);

+

+EXPORT_SYMBOL(sys_socket);

+[root@vpc-linux linux-2.6.7]# 

+[root@vpc-linux linux-2.6.7]# 

+[root@vpc-linux linux-2.6.7]# head -15 kernel/Makefile 

+#

+# Makefile for the linux kernel.

+#

+

+obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \

+            exit.o itimer.o time.o softirq.o resource.o \

+            sysctl.o capability.o ptrace.o timer.o user.o \

+            signal.o sys.o kmod.o workqueue.o pid.o \

+            rcupdate.o intermodule.o extable.o params.o posix-timers.o \

+            kthread.o

+

+obj-y   +=  extra-exports.o

+

+obj-$(CONFIG_FUTEX) += futex.o

+obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o

+[root@vpc-linux linux-2.6.7]# 

+

+ \endverbatim

+ *

+ * Then you must rebuild the kernel.

+ * If you fail to do this, you won't be able to <b>insmod</b> pjlib.

+ *

+ * \note You will see a lots of warning messages during pjlib-test compilation.

+ * The warning messages complain about unresolved symbols which are defined

+ * in pjlib module. You can safely ignore these warnings. However, you can not

+ * ignore warnings about non-pjlib unresolved symbols.

+ *

+ * 

+ * @subsection makefile_explained_sec Makefile Explained

+ *

+ * The \a Makefile for each project (e.g. PJLIB, PJSIP, etc) should be

+ * very similar in the contents. The Makefile is located under \c build

+ * directory in each project subdir.

+ *

+ * @subsubsection pjlib_makefile_subsec PJLIB Makefile.

+ *

+ * Below is PJLIB's Makefile:

+ *

+ * \include build/Makefile

+ *

+ * @subsubsection pjlib_os_makefile_subsec PJLIB os-linux.mak.

+ *

+ * Below is file <tt><b>os-linux.mak</b></tt> file in 

+ * <tt>$PJPROJECT/pjlib/build</tt> directory,

+ * which is OS specific configuration file for Linux target that is specific 

+ * for PJLIB project. For \b global OS specific configuration, please see

+ * <tt>$PJPROJECT/build/os-*.mak</tt>.

+ *

+ * \include build/os-linux.mak

+ *

+ */

+

+

+/*////////////////////////////////////////////////////////////////////////// */

+/*

+         PORTING PJLIB

+ */

+

+

+

+/**

+ * @page porting_pjlib_pg Porting PJLIB

+ *

+ *

+ * @section new_arch_sec Porting to New CPU Architecture

+ *

+ * Below is step-by-step guide to add support for new CPU architecture.

+ * This sample is based on porting to Alpha architecture; however steps for 

+ * porting to other CPU architectures should be pretty similar. 

+ *

+ * Also note that in this example, the operating system used is <b>Linux</b>.

+ * Should you wish to add support for new operating system, then follow

+ * the next section \ref porting_os_sec.

+ *

+ * Step-by-step guide to port to new CPU architecture:

+ *  - decide the name for the new architecture. In this case, we choose

+ *    <tt><b>alpha</b></tt>.

+ *  - edit file <tt>$PJPROJECT/build.mak</tt>, and add new section for

+ *    the new target:

+ *    <pre>

+ *      #

+ *      # Linux alpha, gcc

+ *      #

+ *      export MACHINE_NAME := <b>alpha</b>

+ *      export OS_NAME := linux

+ *      export CC_NAME := gcc

+ *      export HOST_NAME := unix

+ *    </pre>

+ *

+ *  - create a new file <tt>$PJPROJECT/build/<b>m-alpha</b>.mak</tt>.

+ *    Alternatively create a copy from other file in this directory.

+ *    The contents of this file will look something like:

+ *    <pre>

+ *      export M_CFLAGS := $(CC_DEF)<b>PJ_M_ALPHA=1</b>

+ *      export M_CXXFLAGS :=

+ *      export M_LDFLAGS :=

+ *      export M_SOURCES :=

+ *    </pre>

+ *  - create a new file <tt>$PJPROJECT/pjlib/include/pj/compat/<b>m_alpha.h</b></tt>.

+ *    Alternatively create a copy from other header file in this directory.

+ *    The contents of this file will look something like:

+ *    <pre>

+ *      #define PJ_HAS_PENTIUM          0

+ *      #define PJ_IS_LITTLE_ENDIAN     1

+ *      #define PJ_IS_BIG_ENDIAN        0

+ *    </pre>

+ *  - edit <tt>pjlib/include/pj/<b>config.h</b></tt>. Add new processor

+ *    configuration in this header file, like follows:

+ *    <pre>

+ *      ...

+ *      #elif defined (PJ_M_ALPHA) && PJ_M_ALPHA != 0

+ *      #   include <pj/compat/m_alpha.h>

+ *      ...

+ *    </pre>

+ *  - done. Build PJLIB with:

+ *    <pre>

+ *      $ cd $PJPROJECT/pjlib/build

+ *      $ make dep

+ *      $ make clean

+ *      $ make

+ *    </pre>

+ *

+ * @section porting_os_sec Porting to New Operating System Target

+ *

+ * This section will try to give you rough guideline on how to

+ * port PJLIB to a new target. As a sample, we give the target a name tag, 

+ * for example <tt><b>xos</b></tt> (for X OS). 

+ *

+ * @subsection new_compat_os_h_file_sec Create New Compat Header File

+ *

+ * You'll need to create a new header file 

+ * <b><tt>include/pj/compat/os_xos.h</tt></b>. You can copy as a 

+ * template other header file and edit it accordingly.

+ *

+ * @subsection modify_config_h_file_sec Modify config.h

+ *

+ * Then modify file <b><tt>include/pj/config.h</tt></b> to include

+ * this file accordingly (e.g. when macro <tt><b>PJ_XOS</b></tt> is

+ * defined):

+ *

+ \verbatim

+ ...

+ #elif defined(PJ_XOS)

+ #  include <pj/compat/os_xos.h>

+ #else

+ #...

+ \endverbatim

+ * 

+ * @subsection new_target_mak_file_sec Create New Global Make Config File

+ *

+ * Then you'll need to create global configuration file that

+ * is specific for this OS, i.e. <tt><b>os-xos.mak</b></tt> in 

+ * <tt><b>$PJPROJECT/build</b></tt> directory.

+ *

+ * At very minimum, the file will normally need to define

+ * <tt><b>PJ_XOS=1</b></tt> in the \c CFLAGS section:

+ *

+ \verbatim

+#

+# $PJPROJECT/build/os-xos.mak:

+#

+export OS_CFLAGS   := $(CC_DEF)PJ_XOS=1

+export OS_CXXFLAGS := 

+export OS_LDFLAGS  :=

+export OS_SOURCES  := 

+ \endverbatim

+ *

+ *

+ * @subsection new_target_prj_mak_file_sec Create New Project's Make Config File

+ *

+ * Then you'll need to create xos-specific configuration file

+ * for PJLIB. This file is also named <tt><b>os-xos.mak</b></tt>,

+ * but its located in <tt><b>pjlib/build</b></tt> directory.

+ * This file will specify source files that are specific to

+ * this OS to be included in the build process.

+ *

+ * Below is a sample:

+ \verbatim

+#

+# pjlib/build/os-xos.mak:

+#  XOS specific configuration for PJLIB.

+#

+export PJLIB_OBJS += 	os_core_xos.o \

+                        os_error_unix.o \

+                        os_time_ansi.o

+export TEST_OBJS +=	main.o

+export TARGETS	    =	pjlib pjlib-test

+ \endverbatim

+ *

+ * @subsection new_target_src_sec Create and Edit Source Files

+ *

+ * You'll normally need to create at least these files:

+ *  - <tt><b>os_core_xos.c</b></tt>: core OS specific

+ *    functionality.

+ *  - <tt><b>os_timestamp_xos.c</b></tt>: how to get timestamp

+ *    in this OS.

+ *

+ * Depending on how things are done in your OS, you may need

+ * to create these files:

+ *  - <tt><b>os_error_*.c</b></tt>: how to manipulate

+ *    OS error codes. Alternatively you may use existing

+ *    <tt>os_error_unix.c</tt> if the OS has \c errno and

+ *    \c strerror() function.

+ *  - <tt><b>ioqueue_*.c</b></tt>: if the OS has specific method

+ *    to perform asynchronous I/O. Alternatively you may

+ *    use existing <tt>ioqueue_select.c</tt> if the OS supports

+ *    \c select() function call.

+ *  - <tt><b>sock_*.c</b></tt>: if the OS has specific method

+ *    to perform socket communication. Alternatively you may

+ *    use existing <tt>sock_bsd.c</tt> if the OS supports

+ *    BSD socket API, and edit <tt>include/pj/compat/socket.h</tt>

+ *    file accordingly.

+ *

+ * You will also need to check various files in 

+ * <tt><b>include/pj/compat/*.h</b></tt>, to see if they're 

+ * compatible with your OS.

+ *

+ * @subsection new_target_build_file_sec Build The Project

+ *

+ * After basic building blocks have been created for the OS, then

+ * the easiest way to see which parts need to be fixed is by building

+ * the project and see the error messages.

+ *

+ * @subsection new_target_edit_vs_new_file_sec Editing Existing Files vs Creating New File

+ *

+ * When you encounter compatibility errors in PJLIB during porting,

+ * you have three options on how to fix the error:

+ *  - edit the existing <tt>*.c</tt> file, and give it <tt>#ifdef</tt>

+ *    switch for the new OS, or

+ *  - edit <tt>include/pj/compat/*.h</tt> instead, or

+ *  - create a totally new file.

+ *

+ * Basicly there is no strict rule on which approach is the best

+ * to use, however the following guidelines may be used:

+ *  - if the file is expected to be completely different than

+ *    any existing file, then perhaps you should create a completely

+ *    new file. For example, file <tt>os_core_xxx.c</tt> will 

+ *    normally be different for each OS flavour.

+ *  - if the difference can be localized in <tt>include/compat</tt>

+ *    header file, and existing <tt>#ifdef</tt> switch is there,

+ *    then preferably you should edit this <tt>include/compat</tt>

+ *    header file.

+ *  - if the existing <tt>*.c</tt> file has <tt>#ifdef</tt> switch,

+ *    then you may add another <tt>#elif</tt> switch there. This

+ *    normally is used for behaviors that are not totally

+ *    different on each platform.

+ *  - other than that above, use your own judgement on whether

+ *    to edit the file or create new file etc.

+ */

+

+#endif	/* __PJ_DOXYGEN_H__ */

+

diff --git a/pjlib/include/pj/equeue.h b/pjlib/include/pj/equeue.h
index cc751e2..44979b0 100644
--- a/pjlib/include/pj/equeue.h
+++ b/pjlib/include/pj/equeue.h
@@ -1,321 +1,342 @@
-/* $Id$
- *
- */
-#ifndef __PJ_EQUEUE_H__
-#define __PJ_EQUEUE_H__
-
-/**
- * @file equeue.h
- * @brief Event Queue
- */
-#include <pj/types.h>
-
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_EQUEUE Event Queue
- * @brief Event Queue
- * @ingroup PJ_OS
- * @{
- */
-
-
-/**
- * Opaque data type for Event Queue.
- */
-typedef struct pj_equeue_t pj_equeue_t;
-
-/**
- * Opaque data type for Event Queue key.
- */
-typedef struct pj_equeue_key_t pj_equeue_key_t;
-
-
-/**
- * This structure describes the callbacks to be called when I/O operation
- * completes.
- */
-typedef struct pj_io_callback
-{
-    /**
-     * This callback is called when #pj_equeue_read, #pj_equeue_recv or 
-     * #pj_equeue_recvfrom completes.
-     *
-     * @param key	    The key.
-     * @param bytes_read    The size of data that has just been read.
-     */
-    void (*on_read_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_read);
-
-    /**
-     * This callback is called when #pj_equeue_write, #pj_equeue_send, or
-     * #pj_equeue_sendto completes.
-     *
-     * @param key	    The key.
-     * @param bytes_read    The size of data that has just been written.
-     */
-    void (*on_write_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_sent);
-
-    /**
-     * This callback is called when #pj_equeue_accept completes.
-     *
-     * @param key	    The key.
-     * @param status	    Zero if the operation completes successfully.
-     */
-    void (*on_accept_complete)(pj_equeue_key_t *key, int status);
-
-    /**
-     * This callback is called when #pj_equeue_connect completes.
-     *
-     * @param key	    The key.
-     * @param status	    Zero if the operation completes successfully.
-     */
-    void (*on_connect_complete)(pj_equeue_key_t *key, int status);
-
-} pj_io_callback;
-
-/**
- * Event Queue options.
- */
-typedef struct pj_equeue_options
-{
-    /** Maximum number of threads that are allowed to access Event Queue
-     *  simulteneously.
-     */
-    unsigned	nb_threads;
-
-    /** If non-zero, then no mutex protection will be used. */
-    pj_bool_t	no_lock;
-
-    /** Interval of the busy loop inside the event queue.
-     *  The time resolution here determines the accuracy of the
-     *  timer in the Event Queue.
-     */
-    pj_time_val	poll_interval;
-
-} pj_equeue_options;
-
-
-/**
- * Error value returned by I/O operations to indicate that the operation
- * can't complete immediately and will complete later.
- */
-#define PJ_EQUEUE_PENDING   (-2)
-
-/**
- * Types of Event Queue operation.
- */
-typedef enum pj_equeue_op
-{
-    PJ_EQUEUE_OP_NONE		= 0,	/**< No operation.	    */
-    PJ_EQUEUE_OP_READ		= 1,	/**< read() operation.	    */
-    PJ_EQUEUE_OP_RECV_FROM	= 2,	/**< recvfrom() operation.  */
-    PJ_EQUEUE_OP_WRITE		= 4,	/**< write() operation.	    */
-    PJ_EQUEUE_OP_SEND_TO	= 8,	/**< sendto() operation.    */
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-    PJ_EQUEUE_OP_ACCEPT		= 16,	/**< accept() operation.    */
-    PJ_EQUEUE_OP_CONNECT	= 32,	/**< connect() operation.   */
-#endif	/* PJ_HAS_TCP */
-} pj_equeue_op;
-
-
-
-/**
- * Initialize Event Queue options with default values.
- *
- * @param options   Event Queue options.
- */
-PJ_DECL(void) pj_equeue_options_init(pj_equeue_options *options);
-
-/**
- * Create a new Event Queue framework.
- *
- * @param pool	    The pool to allocate the event queue structure.
- * @param options   Event queue options, or if NULL is given, then
- *		    default options will be used.
- * @param equeue    Pointer to receive event queue structure.
- *
- * @return	    zero on success.
- */
-PJ_DECL(pj_status_t) pj_equeue_create( pj_pool_t *pool, 
-				       const pj_equeue_options *options,
-				       pj_equeue_t **equeue);
-
-/**
- * Get the first instance of Event Queue, or NULL if no Event Queue
- * instance has been created in the application.
- *
- * @return	    The first instance of Event Queue created, or NULL.
- */
-PJ_DECL(pj_equeue_t*) pj_equeue_instance(void);
-
-/**
- * Destroy the Event Queue.
- *
- * @param equeue    The Event Queue instance to be destroyed.
- */
-PJ_DECL(pj_status_t) pj_equeue_destroy( pj_equeue_t *equeue );
-
-/**
- * Customize the lock object that is used by the Event Queue.
- *
- * @param equeue    The Event Queue instance.
- * @param lock	    The lock object.
- * @param auto_del  If non-zero, the lock will be destroyed by
- *		    Event Queue.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_equeue_set_lock( pj_equeue_t *equeue,
-					 pj_lock_t *lock, 
-					 pj_bool_t auto_del);
-
-/**
- * Associate an Event Queue key to particular handle. The key is also
- * associated with the callback and user data, which will be used by
- * the Event Queue framework when signalling event back to application.
- *
- * @param pool	    To allocate the resource for the specified handle, which
- *		    must be valid until the handle/key is unregistered
- *		    from Event Queue.
- * @param equeue    The Event Queue.
- * @param hnd	    The OS handle to be registered, which can be a socket
- *		    descriptor (pj_sock_t), file descriptor, etc.
- * @param cb	    Callback to be called when I/O operation completes. 
- * @param user_data User data to be associated with the key.
- * @param key	    Pointer to receive the key.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_equeue_register( pj_pool_t *pool,
-					 pj_equeue_t *equeue,
-					 pj_oshandle_t hnd,
-					 pj_io_callback *cb,
-					 void *user_data,
-					 pj_equeue_key_t **key);
-
-/**
- * Retrieve user data associated with a key.
- *
- * @param key	    The Event Queue key.
- *
- * @return	    User data associated with the key.
- */
-PJ_DECL(void*) pj_equeue_get_user_data( pj_equeue_key_t *key );
-
-
-/**
- * Unregister Event Queue key from the Event Queue.
- *
- * @param equeue    The Event Queue.
- * @param key	    The key.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_equeue_unregister( pj_equeue_t *equeue,
-					   pj_equeue_key_t *key);
-
-/**
- * Instruct the Event Queue to read from the specified handle. This function
- * returns immediately (i.e. non-blocking) regardless whether some data has 
- * been transfered. If the operation can't complete immediately, caller will 
- * be notified about the completion when it calls pj_equeue_poll().
- *
- * @param key	    The key that uniquely identifies the handle.
- * @param buffer    The buffer to hold the read data. The caller MUST make sure
- *		    that this buffer remain valid until the framework completes
- *		    reading the handle.
- * @param size	    The maximum size to be read.
- *
- * @return
- *  - zero or positive number to indicate the number of bytes has been
- *		    read, and in this case the operation was not queued.
- *  - (-1) on error, which in this case operation was not queued.
- *  - PJ_EQUEUE_PENDING if the operation has been queued.
- */
-PJ_DECL(pj_ssize_t) pj_equeue_read( pj_equeue_key_t *key,
-				    void *buffer,
-				    pj_size_t size);
-
-/**
- * Start recv() operation on the specified handle.
- *
- * @see ::pj_ioqueue_read
- */
-PJ_DECL(pj_ssize_t) pj_equeue_recv( pj_equeue_key_t *key,
-				    void *buf,
-				    pj_size_t size,
-				    unsigned flags);
-
-/**
- * Start recvfrom() operation on the specified handle.
- *
- * @see ::pj_equeue_read
- */
-PJ_DECL(pj_ssize_t) pj_equeue_recvfrom( pj_equeue_key_t *key,
-					void *buf,
-					pj_size_t size,
-					unsigned flags,
-					pj_sockaddr_t *addr,
-					int *addrlen );
-
-/**
- * Write.
- */
-PJ_DECL(pj_ssize_t) pj_equeue_write( pj_equeue_key_t *key,
-				     const void *buf,
-				     pj_size_t size);
-
-/**
- * Send.
- */
-PJ_DECL(pj_ssize_t) pj_equeue_send( pj_equeue_key_t *key,
-				    const void *buf,
-				    pj_size_t size,
-				    unsigned flags);
-
-/**
- * Sendto.
- */
-PJ_DECL(pj_ssize_t) pj_equeue_sendto( pj_equeue_key_t *key,
-				      const void *buf,
-				      pj_size_t size,
-				      unsigned flags,
-				      const pj_sockaddr_t *addr,
-				      int addrlen);
-
-/**
- * Schedule timer.
- */
-PJ_DECL(pj_status_t) pj_equeue_schedule_timer( pj_equeue_t *equeue,
-					       const pj_time_val *timeout,
-					       pj_timer_entry *entry);
-
-/**
- * Cancel timer.
- */
-PJ_DECL(pj_status_t) pj_equeue_cancel_timer( pj_equeue_t *equeue,
-					     pj_timer_entry *entry);
-
-/**
- * Poll for events.
- */
-PJ_DECL(pj_status_t) pj_equeue_poll( pj_equeue_t *equeue,
-				     const pj_time_val *timeout );
-
-/**
- * Run.
- */
-PJ_DECL(pj_status_t) pj_equeue_run( pj_equeue_t *equeue );
-
-/**
- * Stop all running threads.
- */
-PJ_DECL(pj_status_t) pj_equeue_stop( pj_equeue_t *equeue );
-
-
-/** @} */
-
-PJ_END_DECL
-
-#endif	/* __PJ_EQUEUE_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_EQUEUE_H__

+#define __PJ_EQUEUE_H__

+

+/**

+ * @file equeue.h

+ * @brief Event Queue

+ */

+#include <pj/types.h>

+

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_EQUEUE Event Queue

+ * @brief Event Queue

+ * @ingroup PJ_OS

+ * @{

+ */

+

+

+/**

+ * Opaque data type for Event Queue.

+ */

+typedef struct pj_equeue_t pj_equeue_t;

+

+/**

+ * Opaque data type for Event Queue key.

+ */

+typedef struct pj_equeue_key_t pj_equeue_key_t;

+

+

+/**

+ * This structure describes the callbacks to be called when I/O operation

+ * completes.

+ */

+typedef struct pj_io_callback

+{

+    /**

+     * This callback is called when #pj_equeue_read, #pj_equeue_recv or 

+     * #pj_equeue_recvfrom completes.

+     *

+     * @param key	    The key.

+     * @param bytes_read    The size of data that has just been read.

+     */

+    void (*on_read_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_read);

+

+    /**

+     * This callback is called when #pj_equeue_write, #pj_equeue_send, or

+     * #pj_equeue_sendto completes.

+     *

+     * @param key	    The key.

+     * @param bytes_read    The size of data that has just been written.

+     */

+    void (*on_write_complete)(pj_equeue_key_t *key, pj_ssize_t bytes_sent);

+

+    /**

+     * This callback is called when #pj_equeue_accept completes.

+     *

+     * @param key	    The key.

+     * @param status	    Zero if the operation completes successfully.

+     */

+    void (*on_accept_complete)(pj_equeue_key_t *key, int status);

+

+    /**

+     * This callback is called when #pj_equeue_connect completes.

+     *

+     * @param key	    The key.

+     * @param status	    Zero if the operation completes successfully.

+     */

+    void (*on_connect_complete)(pj_equeue_key_t *key, int status);

+

+} pj_io_callback;

+

+/**

+ * Event Queue options.

+ */

+typedef struct pj_equeue_options

+{

+    /** Maximum number of threads that are allowed to access Event Queue

+     *  simulteneously.

+     */

+    unsigned	nb_threads;

+

+    /** If non-zero, then no mutex protection will be used. */

+    pj_bool_t	no_lock;

+

+    /** Interval of the busy loop inside the event queue.

+     *  The time resolution here determines the accuracy of the

+     *  timer in the Event Queue.

+     */

+    pj_time_val	poll_interval;

+

+} pj_equeue_options;

+

+

+/**

+ * Error value returned by I/O operations to indicate that the operation

+ * can't complete immediately and will complete later.

+ */

+#define PJ_EQUEUE_PENDING   (-2)

+

+/**

+ * Types of Event Queue operation.

+ */

+typedef enum pj_equeue_op

+{

+    PJ_EQUEUE_OP_NONE		= 0,	/**< No operation.	    */

+    PJ_EQUEUE_OP_READ		= 1,	/**< read() operation.	    */

+    PJ_EQUEUE_OP_RECV_FROM	= 2,	/**< recvfrom() operation.  */

+    PJ_EQUEUE_OP_WRITE		= 4,	/**< write() operation.	    */

+    PJ_EQUEUE_OP_SEND_TO	= 8,	/**< sendto() operation.    */

+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

+    PJ_EQUEUE_OP_ACCEPT		= 16,	/**< accept() operation.    */

+    PJ_EQUEUE_OP_CONNECT	= 32,	/**< connect() operation.   */

+#endif	/* PJ_HAS_TCP */

+} pj_equeue_op;

+

+

+

+/**

+ * Initialize Event Queue options with default values.

+ *

+ * @param options   Event Queue options.

+ */

+PJ_DECL(void) pj_equeue_options_init(pj_equeue_options *options);

+

+/**

+ * Create a new Event Queue framework.

+ *

+ * @param pool	    The pool to allocate the event queue structure.

+ * @param options   Event queue options, or if NULL is given, then

+ *		    default options will be used.

+ * @param equeue    Pointer to receive event queue structure.

+ *

+ * @return	    zero on success.

+ */

+PJ_DECL(pj_status_t) pj_equeue_create( pj_pool_t *pool, 

+				       const pj_equeue_options *options,

+				       pj_equeue_t **equeue);

+

+/**

+ * Get the first instance of Event Queue, or NULL if no Event Queue

+ * instance has been created in the application.

+ *

+ * @return	    The first instance of Event Queue created, or NULL.

+ */

+PJ_DECL(pj_equeue_t*) pj_equeue_instance(void);

+

+/**

+ * Destroy the Event Queue.

+ *

+ * @param equeue    The Event Queue instance to be destroyed.

+ */

+PJ_DECL(pj_status_t) pj_equeue_destroy( pj_equeue_t *equeue );

+

+/**

+ * Customize the lock object that is used by the Event Queue.

+ *

+ * @param equeue    The Event Queue instance.

+ * @param lock	    The lock object.

+ * @param auto_del  If non-zero, the lock will be destroyed by

+ *		    Event Queue.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_equeue_set_lock( pj_equeue_t *equeue,

+					 pj_lock_t *lock, 

+					 pj_bool_t auto_del);

+

+/**

+ * Associate an Event Queue key to particular handle. The key is also

+ * associated with the callback and user data, which will be used by

+ * the Event Queue framework when signalling event back to application.

+ *

+ * @param pool	    To allocate the resource for the specified handle, which

+ *		    must be valid until the handle/key is unregistered

+ *		    from Event Queue.

+ * @param equeue    The Event Queue.

+ * @param hnd	    The OS handle to be registered, which can be a socket

+ *		    descriptor (pj_sock_t), file descriptor, etc.

+ * @param cb	    Callback to be called when I/O operation completes. 

+ * @param user_data User data to be associated with the key.

+ * @param key	    Pointer to receive the key.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_equeue_register( pj_pool_t *pool,

+					 pj_equeue_t *equeue,

+					 pj_oshandle_t hnd,

+					 pj_io_callback *cb,

+					 void *user_data,

+					 pj_equeue_key_t **key);

+

+/**

+ * Retrieve user data associated with a key.

+ *

+ * @param key	    The Event Queue key.

+ *

+ * @return	    User data associated with the key.

+ */

+PJ_DECL(void*) pj_equeue_get_user_data( pj_equeue_key_t *key );

+

+

+/**

+ * Unregister Event Queue key from the Event Queue.

+ *

+ * @param equeue    The Event Queue.

+ * @param key	    The key.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_equeue_unregister( pj_equeue_t *equeue,

+					   pj_equeue_key_t *key);

+

+/**

+ * Instruct the Event Queue to read from the specified handle. This function

+ * returns immediately (i.e. non-blocking) regardless whether some data has 

+ * been transfered. If the operation can't complete immediately, caller will 

+ * be notified about the completion when it calls pj_equeue_poll().

+ *

+ * @param key	    The key that uniquely identifies the handle.

+ * @param buffer    The buffer to hold the read data. The caller MUST make sure

+ *		    that this buffer remain valid until the framework completes

+ *		    reading the handle.

+ * @param size	    The maximum size to be read.

+ *

+ * @return

+ *  - zero or positive number to indicate the number of bytes has been

+ *		    read, and in this case the operation was not queued.

+ *  - (-1) on error, which in this case operation was not queued.

+ *  - PJ_EQUEUE_PENDING if the operation has been queued.

+ */

+PJ_DECL(pj_ssize_t) pj_equeue_read( pj_equeue_key_t *key,

+				    void *buffer,

+				    pj_size_t size);

+

+/**

+ * Start recv() operation on the specified handle.

+ *

+ * @see ::pj_ioqueue_read

+ */

+PJ_DECL(pj_ssize_t) pj_equeue_recv( pj_equeue_key_t *key,

+				    void *buf,

+				    pj_size_t size,

+				    unsigned flags);

+

+/**

+ * Start recvfrom() operation on the specified handle.

+ *

+ * @see ::pj_equeue_read

+ */

+PJ_DECL(pj_ssize_t) pj_equeue_recvfrom( pj_equeue_key_t *key,

+					void *buf,

+					pj_size_t size,

+					unsigned flags,

+					pj_sockaddr_t *addr,

+					int *addrlen );

+

+/**

+ * Write.

+ */

+PJ_DECL(pj_ssize_t) pj_equeue_write( pj_equeue_key_t *key,

+				     const void *buf,

+				     pj_size_t size);

+

+/**

+ * Send.

+ */

+PJ_DECL(pj_ssize_t) pj_equeue_send( pj_equeue_key_t *key,

+				    const void *buf,

+				    pj_size_t size,

+				    unsigned flags);

+

+/**

+ * Sendto.

+ */

+PJ_DECL(pj_ssize_t) pj_equeue_sendto( pj_equeue_key_t *key,

+				      const void *buf,

+				      pj_size_t size,

+				      unsigned flags,

+				      const pj_sockaddr_t *addr,

+				      int addrlen);

+

+/**

+ * Schedule timer.

+ */

+PJ_DECL(pj_status_t) pj_equeue_schedule_timer( pj_equeue_t *equeue,

+					       const pj_time_val *timeout,

+					       pj_timer_entry *entry);

+

+/**

+ * Cancel timer.

+ */

+PJ_DECL(pj_status_t) pj_equeue_cancel_timer( pj_equeue_t *equeue,

+					     pj_timer_entry *entry);

+

+/**

+ * Poll for events.

+ */

+PJ_DECL(pj_status_t) pj_equeue_poll( pj_equeue_t *equeue,

+				     const pj_time_val *timeout );

+

+/**

+ * Run.

+ */

+PJ_DECL(pj_status_t) pj_equeue_run( pj_equeue_t *equeue );

+

+/**

+ * Stop all running threads.

+ */

+PJ_DECL(pj_status_t) pj_equeue_stop( pj_equeue_t *equeue );

+

+

+/** @} */

+

+PJ_END_DECL

+

+#endif	/* __PJ_EQUEUE_H__ */

diff --git a/pjlib/include/pj/errno.h b/pjlib/include/pj/errno.h
index b7c6253..741475f 100644
--- a/pjlib/include/pj/errno.h
+++ b/pjlib/include/pj/errno.h
@@ -1,215 +1,236 @@
-/* $Id$
- *
- */
-#ifndef __PJ_ERRNO_H__
-#define __PJ_ERRNO_H__
-
-/**
- * @file errno.h
- * @brief PJLIB Error Codes
- */
-#include <pj/types.h>
-#include <pj/compat/errno.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup pj_errno Error Codes
- * @ingroup PJ
- * @{
- *
- * In PJLIB, error/status codes from operating system are translated
- * into PJLIB error namespace, and stored in @a pj_status_t. All functions
- * that work with @a pj_status_t expect to get PJLIB error code instead
- * of native codes.
- *
- * @section pj_errno_retval Return Values
- *
- * All functions that returns @a pj_status_t returns @a PJ_SUCCESS if the
- * operation was completed successfully, or non-zero value to indicate 
- * error. If the error came from operating system, then the native error
- * code is translated/folded into PJLIB's error namespace by using
- * #PJ_STATUS_FROM_OS() macro. The function will do this automatically
- * before returning the error to caller.
- *
- * @section pj_errno_errmsg Error Message
- *
- * To get the error message corresponding to a particular code, use function
- * #pj_strerror(). This function expects error code in PJLIB error namespace,
- * not the native error code. Application can pass the value from the 
- * following sources to this function:
- *  - #pj_get_os_error()
- *  - #pj_get_netos_error()
- *  - any return value from function returning @a pj_status_t.
- *
- * Application MUST NOT pass native error code (such as error code from
- * functions like GetLastError() or errno) to PJLIB functions expecting
- * @a pj_status_t.
- *
- */
-
-/**
- * Get the last platform error/status, folded into pj_status_t.
- * @return	OS dependent error code, folded into pj_status_t.
- * @remark	This function gets errno, or calls GetLastError() function and
- *		convert the code into pj_status_t with PJ_STATUS_FROM_OS. Do
- *		not call this for socket functions!
- * @see	pj_get_netos_error()
- */
-PJ_DECL(pj_status_t) pj_get_os_error(void);
-
-/**
- * Set last error.
- * @param code	pj_status_t
- */
-PJ_DECL(void) pj_set_os_error(pj_status_t code);
-
-/**
- * Get the last error from socket operations.
- * @return	Last socket error, folded into pj_status_t.
- */
-PJ_DECL(pj_status_t) pj_get_netos_error(void);
-
-/**
- * Set error code.
- * @param code	pj_status_t.
- */
-PJ_DECL(void) pj_set_netos_error(pj_status_t code);
-
-
-/**
- * Get the error message for the specified error code. The message
- * string will be NULL terminated.
- *
- * @param statcode  The error code.
- * @param buf	    Buffer to hold the error message string.
- * @param bufsize   Size of the buffer.
- *
- * @return	    The error message as NULL terminated string,
- *                  wrapped with pj_str_t.
- */
-PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, 
-			       char *buf, pj_size_t bufsize);
-
-
-/**
- * @hideinitializer
- * Return platform os error code folded into pj_status_t code. This is
- * the macro that is used throughout the library for all PJLIB's functions
- * that returns error from operating system. Application may override
- * this macro to reduce size (e.g. by defining it to always return 
- * #PJ_EUNKNOWN).
- *
- * Note:
- *  This macro MUST return non-zero value regardless whether zero is
- *  passed as the argument. The reason is to protect logic error when
- *  the operating system doesn't report error codes properly.
- *
- * @param os_code   Platform OS error code. This value may be evaluated
- *		    more than once.
- * @return	    The platform os error code folded into pj_status_t.
- */
-#ifndef PJ_RETURN_OS_ERROR
-#   define PJ_RETURN_OS_ERROR(os_code)   (os_code ? \
-					    PJ_STATUS_FROM_OS(os_code) : -1)
-#endif
-
-
-/**
- * @hideinitializer
- * Fold a platform specific error into an pj_status_t code.
- *
- * @param e	The platform os error code.
- * @return	pj_status_t
- * @warning	Macro implementation; the syserr argument may be evaluated
- *		multiple times.
- */
-#define PJ_STATUS_FROM_OS(e) (e == 0 ? PJ_SUCCESS : e + PJ_ERRNO_START_SYS)
-
-/**
- * @hideinitializer
- * Fold an pj_status_t code back to the native platform defined error.
- *
- * @param e	The pj_status_t folded platform os error code.
- * @return	pj_os_err_type
- * @warning	macro implementation; the statcode argument may be evaluated
- *		multiple times.  If the statcode was not created by 
- *		pj_get_os_error or PJ_STATUS_FROM_OS, the results are undefined.
- */
-#define PJ_STATUS_TO_OS(e) (e == 0 ? PJ_SUCCESS : e - PJ_ERRNO_START_SYS)
-
-
-/**
- * @defgroup pj_errnum PJLIB's Own Error Codes
- * @ingroup pj_errno
- * @{
- */
-
-/**
- * @hideinitializer
- * Unknown error has been reported.
- */
-#define PJ_EUNKNOWN	    (PJ_ERRNO_START_STATUS + 1)
-/**
- * @hideinitializer
- * The operation is pending and will be completed later.
- */
-#define PJ_EPENDING	    (PJ_ERRNO_START_STATUS + 2)
-/**
- * @hideinitializer
- * Too many connecting sockets.
- */
-#define PJ_ETOOMANYCONN	    (PJ_ERRNO_START_STATUS + 3)
-/**
- * @hideinitializer
- * Invalid argument.
- */
-#define PJ_EINVAL	    (PJ_ERRNO_START_STATUS + 4)
-/**
- * @hideinitializer
- * Name too long (eg. hostname too long).
- */
-#define PJ_ENAMETOOLONG	    (PJ_ERRNO_START_STATUS + 5)
-/**
- * @hideinitializer
- * Not found.
- */
-#define PJ_ENOTFOUND	    (PJ_ERRNO_START_STATUS + 6)
-/**
- * @hideinitializer
- * Not enough memory.
- */
-#define PJ_ENOMEM	    (PJ_ERRNO_START_STATUS + 7)
-/**
- * @hideinitializer
- * Bug detected!
- */
-#define PJ_EBUG             (PJ_ERRNO_START_STATUS + 8)
-/**
- * @hideinitializer
- * Operation timed out.
- */
-#define PJ_ETIMEDOUT        (PJ_ERRNO_START_STATUS + 9)
-/**
- * @hideinitializer
- * Too many objects.
- */
-#define PJ_ETOOMANY         (PJ_ERRNO_START_STATUS + 10)
-/**
- * @hideinitializer
- * Object is busy.
- */
-#define PJ_EBUSY            (PJ_ERRNO_START_STATUS + 11)
-/**
- * @hideinitializer
- * The specified option is not supported.
- */
-#define PJ_ENOTSUP	    (PJ_ERRNO_START_STATUS + 12)
-/**
- * @hideinitializer
- * Invalid operation.
- */
-#define PJ_EINVALIDOP	    (PJ_ERRNO_START_STATUS + 13)
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_ERRNO_H__

+#define __PJ_ERRNO_H__

+

+/**

+ * @file errno.h

+ * @brief PJLIB Error Codes

+ */

+#include <pj/types.h>

+#include <pj/compat/errno.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup pj_errno Error Codes

+ * @ingroup PJ

+ * @{

+ *

+ * In PJLIB, error/status codes from operating system are translated

+ * into PJLIB error namespace, and stored in @a pj_status_t. All functions

+ * that work with @a pj_status_t expect to get PJLIB error code instead

+ * of native codes.

+ *

+ * @section pj_errno_retval Return Values

+ *

+ * All functions that returns @a pj_status_t returns @a PJ_SUCCESS if the

+ * operation was completed successfully, or non-zero value to indicate 

+ * error. If the error came from operating system, then the native error

+ * code is translated/folded into PJLIB's error namespace by using

+ * #PJ_STATUS_FROM_OS() macro. The function will do this automatically

+ * before returning the error to caller.

+ *

+ * @section pj_errno_errmsg Error Message

+ *

+ * To get the error message corresponding to a particular code, use function

+ * #pj_strerror(). This function expects error code in PJLIB error namespace,

+ * not the native error code. Application can pass the value from the 

+ * following sources to this function:

+ *  - #pj_get_os_error()

+ *  - #pj_get_netos_error()

+ *  - any return value from function returning @a pj_status_t.

+ *

+ * Application MUST NOT pass native error code (such as error code from

+ * functions like GetLastError() or errno) to PJLIB functions expecting

+ * @a pj_status_t.

+ *

+ */

+

+/**

+ * Get the last platform error/status, folded into pj_status_t.

+ * @return	OS dependent error code, folded into pj_status_t.

+ * @remark	This function gets errno, or calls GetLastError() function and

+ *		convert the code into pj_status_t with PJ_STATUS_FROM_OS. Do

+ *		not call this for socket functions!

+ * @see	pj_get_netos_error()

+ */

+PJ_DECL(pj_status_t) pj_get_os_error(void);

+

+/**

+ * Set last error.

+ * @param code	pj_status_t

+ */

+PJ_DECL(void) pj_set_os_error(pj_status_t code);

+

+/**

+ * Get the last error from socket operations.

+ * @return	Last socket error, folded into pj_status_t.

+ */

+PJ_DECL(pj_status_t) pj_get_netos_error(void);

+

+/**

+ * Set error code.

+ * @param code	pj_status_t.

+ */

+PJ_DECL(void) pj_set_netos_error(pj_status_t code);

+

+

+/**

+ * Get the error message for the specified error code. The message

+ * string will be NULL terminated.

+ *

+ * @param statcode  The error code.

+ * @param buf	    Buffer to hold the error message string.

+ * @param bufsize   Size of the buffer.

+ *

+ * @return	    The error message as NULL terminated string,

+ *                  wrapped with pj_str_t.

+ */

+PJ_DECL(pj_str_t) pj_strerror( pj_status_t statcode, 

+			       char *buf, pj_size_t bufsize);

+

+

+/**

+ * @hideinitializer

+ * Return platform os error code folded into pj_status_t code. This is

+ * the macro that is used throughout the library for all PJLIB's functions

+ * that returns error from operating system. Application may override

+ * this macro to reduce size (e.g. by defining it to always return 

+ * #PJ_EUNKNOWN).

+ *

+ * Note:

+ *  This macro MUST return non-zero value regardless whether zero is

+ *  passed as the argument. The reason is to protect logic error when

+ *  the operating system doesn't report error codes properly.

+ *

+ * @param os_code   Platform OS error code. This value may be evaluated

+ *		    more than once.

+ * @return	    The platform os error code folded into pj_status_t.

+ */

+#ifndef PJ_RETURN_OS_ERROR

+#   define PJ_RETURN_OS_ERROR(os_code)   (os_code ? \

+					    PJ_STATUS_FROM_OS(os_code) : -1)

+#endif

+

+

+/**

+ * @hideinitializer

+ * Fold a platform specific error into an pj_status_t code.

+ *

+ * @param e	The platform os error code.

+ * @return	pj_status_t

+ * @warning	Macro implementation; the syserr argument may be evaluated

+ *		multiple times.

+ */

+#define PJ_STATUS_FROM_OS(e) (e == 0 ? PJ_SUCCESS : e + PJ_ERRNO_START_SYS)

+

+/**

+ * @hideinitializer

+ * Fold an pj_status_t code back to the native platform defined error.

+ *

+ * @param e	The pj_status_t folded platform os error code.

+ * @return	pj_os_err_type

+ * @warning	macro implementation; the statcode argument may be evaluated

+ *		multiple times.  If the statcode was not created by 

+ *		pj_get_os_error or PJ_STATUS_FROM_OS, the results are undefined.

+ */

+#define PJ_STATUS_TO_OS(e) (e == 0 ? PJ_SUCCESS : e - PJ_ERRNO_START_SYS)

+

+

+/**

+ * @defgroup pj_errnum PJLIB's Own Error Codes

+ * @ingroup pj_errno

+ * @{

+ */

+

+/**

+ * @hideinitializer

+ * Unknown error has been reported.

+ */

+#define PJ_EUNKNOWN	    (PJ_ERRNO_START_STATUS + 1)

+/**

+ * @hideinitializer

+ * The operation is pending and will be completed later.

+ */

+#define PJ_EPENDING	    (PJ_ERRNO_START_STATUS + 2)

+/**

+ * @hideinitializer

+ * Too many connecting sockets.

+ */

+#define PJ_ETOOMANYCONN	    (PJ_ERRNO_START_STATUS + 3)

+/**

+ * @hideinitializer

+ * Invalid argument.

+ */

+#define PJ_EINVAL	    (PJ_ERRNO_START_STATUS + 4)

+/**

+ * @hideinitializer

+ * Name too long (eg. hostname too long).

+ */

+#define PJ_ENAMETOOLONG	    (PJ_ERRNO_START_STATUS + 5)

+/**

+ * @hideinitializer

+ * Not found.

+ */

+#define PJ_ENOTFOUND	    (PJ_ERRNO_START_STATUS + 6)

+/**

+ * @hideinitializer

+ * Not enough memory.

+ */

+#define PJ_ENOMEM	    (PJ_ERRNO_START_STATUS + 7)

+/**

+ * @hideinitializer

+ * Bug detected!

+ */

+#define PJ_EBUG             (PJ_ERRNO_START_STATUS + 8)

+/**

+ * @hideinitializer

+ * Operation timed out.

+ */

+#define PJ_ETIMEDOUT        (PJ_ERRNO_START_STATUS + 9)

+/**

+ * @hideinitializer

+ * Too many objects.

+ */

+#define PJ_ETOOMANY         (PJ_ERRNO_START_STATUS + 10)

+/**

+ * @hideinitializer

+ * Object is busy.

+ */

+#define PJ_EBUSY            (PJ_ERRNO_START_STATUS + 11)

+/**

+ * @hideinitializer

+ * The specified option is not supported.

+ */

+#define PJ_ENOTSUP	    (PJ_ERRNO_START_STATUS + 12)

+/**

+ * @hideinitializer

+ * Invalid operation.

+ */

+#define PJ_EINVALIDOP	    (PJ_ERRNO_START_STATUS + 13)

 /**

  * @hideinitializer

  * Operation is cancelled.

@@ -220,42 +241,42 @@
  * Object already exists.

  */

 #define PJ_EEXISTS          (PJ_ERRNO_START_STATUS + 14)

-
-/** @} */   /* pj_errnum */
-
-/** @} */   /* pj_errno */
-
-
-/**
- * PJ_ERRNO_START is where PJLIB specific error values start.
- */
-#define PJ_ERRNO_START		20000
-
-/**
- * PJ_ERRNO_SPACE_SIZE is the maximum number of errors in one of 
- * the error/status range below.
- */
-#define PJ_ERRNO_SPACE_SIZE	50000
-
-/**
- * PJ_ERRNO_START_STATUS is where PJLIB specific status codes start.
- */
-#define PJ_ERRNO_START_STATUS	(PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE)
-
-/**
- * PJ_ERRNO_START_SYS converts platform specific error codes into
- * pj_status_t values.
- */
-#define PJ_ERRNO_START_SYS	(PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE)
-
-/**
- * PJ_ERRNO_START_USER are reserved for applications that use error
- * codes along with PJLIB codes.
- */
-#define PJ_ERRNO_START_USER	(PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE)
-
-
-PJ_END_DECL
-
-#endif	/* __PJ_ERRNO_H__ */
-
+

+/** @} */   /* pj_errnum */

+

+/** @} */   /* pj_errno */

+

+

+/**

+ * PJ_ERRNO_START is where PJLIB specific error values start.

+ */

+#define PJ_ERRNO_START		20000

+

+/**

+ * PJ_ERRNO_SPACE_SIZE is the maximum number of errors in one of 

+ * the error/status range below.

+ */

+#define PJ_ERRNO_SPACE_SIZE	50000

+

+/**

+ * PJ_ERRNO_START_STATUS is where PJLIB specific status codes start.

+ */

+#define PJ_ERRNO_START_STATUS	(PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE)

+

+/**

+ * PJ_ERRNO_START_SYS converts platform specific error codes into

+ * pj_status_t values.

+ */

+#define PJ_ERRNO_START_SYS	(PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE)

+

+/**

+ * PJ_ERRNO_START_USER are reserved for applications that use error

+ * codes along with PJLIB codes.

+ */

+#define PJ_ERRNO_START_USER	(PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE)

+

+

+PJ_END_DECL

+

+#endif	/* __PJ_ERRNO_H__ */

+

diff --git a/pjlib/include/pj/except.h b/pjlib/include/pj/except.h
index 8bdda48..0405c69 100644
--- a/pjlib/include/pj/except.h
+++ b/pjlib/include/pj/except.h
@@ -1,270 +1,291 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_EXCEPTION_H__
-#define __PJ_EXCEPTION_H__
-
-/**
- * @file except.h
- * @brief Exception Handling in C.
- */
-
-#include <pj/types.h>
-#include <pj/compat/setjmp.h>
-
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJ_EXCEPT Exception Handling
- * @ingroup PJ_MISC
- * @{
- *
- * \section pj_except_sample_sec Quick Example
- *
- * For the impatient, take a look at some examples:
- *  - @ref page_pjlib_samples_except_c
- *  - @ref page_pjlib_exception_test
- *
- * \section pj_except_except Exception Handling
- *
- * This module provides exception handling syntactically similar to C++ in
- * C language. The underlying mechanism use setjmp() and longjmp(), and since
- * these constructs are ANSI standard, the mechanism here should be available
- * on most platforms/compilers which are ANSI compliant.
- *
- * If ANSI libc is not available, then setjmp()/longjmp() implementation will
- * be provided. See <pj/compat/setjmp.h> for compatibility.
- *
- * The exception handling mechanism is completely thread safe, so the exception
- * thrown by one thread will not interfere with other thread.
- *
- * CAVEATS:
- *  - unlike C++ exception, the scheme here won't call destructors of local
- *    objects if exception is thrown. Care must be taken when a function
- *    hold some resorce such as pool or mutex etc.
- *  - You CAN NOT make nested exception in one single function without using
- *    a nested PJ_USE_EXCEPTION.
- *  - Exceptions will always be caught by the first handle (unlike C++ where
- *    exception is only caught if the type matches.
- *
- * The exception handling constructs are similar to C++. The blocks will be
- * constructed similar to the following sample:
- *
- * \verbatim
-   #define NO_MEMORY     1
-   #define SYNTAX_ERROR  2
-  
-   int main()
-   {
-      PJ_USE_EXCEPTION;  // declare local exception stack.
-  
-      PJ_TRY {
-        ...// do something..
-      }
-      PJ_CATCH(NO_MEMORY) {
-        ... // handle exception 1
-      }
-      PJ_CATCH(SYNTAX_ERROR) {
-        ... // handle exception 2
-      }
-      PJ_DEFAULT {
-        ... // handle other exceptions.
-      }
-      PJ_END;
-   }
-   \endverbatim
- *
- * The above sample uses hard coded exception ID. It is @b strongly
- * recommended that applications request a unique exception ID instead
- * of hard coded value like above.
- *
- * \section pj_except_reg Exception ID Allocation
- *
- * To ensure that exception ID (number) are used consistently and to
- * prevent ID collisions in an application, it is strongly suggested that 
- * applications allocate an exception ID for each possible exception
- * type. As a bonus of this process, the application can identify
- * the name of the exception when the particular exception is thrown.
- *
- * Exception ID management are performed with the following APIs:
- *  - #pj_exception_id_alloc().
- *  - #pj_exception_id_free().
- *  - #pj_exception_id_name().
- *
- *
- * PJLIB itself automatically allocates one exception id, i.e.
- * #PJ_NO_MEMORY_EXCEPTION which is declared in <pj/pool.h>. This exception
- * ID is raised by default pool policy when it fails to allocate memory.
- *
- * \section PJ_EX_KEYWORDS Keywords
- *
- * \subsection PJ_THROW PJ_THROW(expression)
- * Throw an exception. The expression thrown is an integer as the result of
- * the \a expression. This keyword can be specified anywhere within the 
- * program.
- *
- * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION
- * Specify this in the variable definition section of the function block 
- * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception 
- * block. 
- * Actually, this is just a macro to declare local variable which is used to
- * push the exception state to the exception stack.
- *
- * \subsection PJ_TRY PJ_TRY
- * The \a PJ_TRY keyword is typically followed by a block. If an exception is
- * thrown in this block, then the execution will resume to the \a PJ_CATCH 
- * handler.
- *
- * \subsection PJ_CATCH PJ_CATCH(expression)
- * The \a PJ_CATCH is normally followed by a block. This block will be executed
- * if the exception being thrown is equal to the expression specified in the
- * \a PJ_CATCH.
- *
- * \subsection PJ_DEFAULT PJ_DEFAULT
- * The \a PJ_DEFAULT keyword is normally followed by a block. This block will
- * be executed if the exception being thrown doesn't match any of the \a
- * PJ_CATCH specification. The \a PJ_DEFAULT block \b MUST be placed as the
- * last block of the handlers.
- *
- * \subsection PJ_END PJ_END
- * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks.
- *
- * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void)
- * Get the last exception thrown. This macro is normally called inside the
- * \a PJ_CATCH or \a PJ_DEFAULT block, altough it can be used anywhere where
- * the \a PJ_USE_EXCEPTION definition is in scope.
- *
- * 
- * \section pj_except_examples_sec Examples
- *
- * For some examples on how to use the exception construct, please see:
- *  - @ref page_pjlib_samples_except_c
- *  - @ref page_pjlib_exception_test
- */
-
-/**
- * Allocate a unique exception id.
- * Applications don't have to allocate a unique exception ID before using
- * the exception construct. However, by doing so it ensures that there is
- * no collisions of exception ID.
- *
- * As a bonus, when exception number is acquired through this function,
- * the library can assign name to the exception (only if 
- * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the
- * exception name when it catches an exception.
- *
- * @param name      Name to be associated with the exception ID.
- * @param id        Pointer to receive the ID.
- *
- * @return          PJ_SUCCESS on success or PJ_ETOOMANY if the library 
- *                  is running out out ids.
- */
-PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name,
-                                           pj_exception_id_t *id);
-
-/**
- * Free an exception id.
- *
- * @param id        The exception ID.
- *
- * @return          PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id);
-
-/**
- * Retrieve name associated with the exception id.
- *
- * @param id        The exception ID.
- *
- * @return          The name associated with the specified ID.
- */
-PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id);
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 

-
-/** @} */
-
-/**
- * This structure (which should be invisible to user) manages the TRY handler
- * stack.
- */
-struct pj_exception_state_t
-{
-    struct pj_exception_state_t *prev;  /**< Previous state in the list. */
-    pj_jmp_buf state;                   /**< jmp_buf.                    */
-};
-
-/**
- * Throw exception.
- * @param id    Exception Id.
- */
-PJ_DECL_NO_RETURN(void) 
-pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN;
-
-/**
- * Push exception handler.
- */
-PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec);
-
-/**
- * Pop exception handler.
- */
-PJ_DECL(void) pj_pop_exception_handler_(void);
-
-/**
- * Declare that the function will use exception.
- * @hideinitializer
- */
-#define PJ_USE_EXCEPTION    struct pj_exception_state_t pj_x_except__; int pj_x_code__
-
-/**
- * Start exception specification block.
- * @hideinitializer
- */
-#define PJ_TRY		    if (1) { \
-				pj_push_exception_handler_(&pj_x_except__); \
-				pj_x_code__ = pj_setjmp(pj_x_except__.state); \
-				if (pj_x_code__ == 0)
-/**
- * Catch the specified exception Id.
- * @param id    The exception number to catch.
- * @hideinitializer
- */
-#define PJ_CATCH(id)	    else if (pj_x_code__ == (id))
-
-/**
- * Catch any exception number.
- * @hideinitializer
- */
-#define PJ_DEFAULT	    else
-
-/**
- * End of exception specification block.
- * @hideinitializer
- */
-#define PJ_END			pj_pop_exception_handler_(); \
-			    } else {}
-
-/**
- * Throw exception.
- * @param exception_id  The exception number.
- * @hideinitializer
- */
-#define PJ_THROW(exception_id)	pj_throw_exception_(exception_id)
-
-/**
- * Get current exception.
- * @return      Current exception code.
- * @hideinitializer
- */
-#define PJ_GET_EXCEPTION()	(pj_x_code__)
-
-PJ_END_DECL
-
-
-
-#endif	/* __PJ_EXCEPTION_H__ */
-
-
+#ifndef __PJ_EXCEPTION_H__

+#define __PJ_EXCEPTION_H__

+

+/**

+ * @file except.h

+ * @brief Exception Handling in C.

+ */

+

+#include <pj/types.h>

+#include <pj/compat/setjmp.h>

+

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJ_EXCEPT Exception Handling

+ * @ingroup PJ_MISC

+ * @{

+ *

+ * \section pj_except_sample_sec Quick Example

+ *

+ * For the impatient, take a look at some examples:

+ *  - @ref page_pjlib_samples_except_c

+ *  - @ref page_pjlib_exception_test

+ *

+ * \section pj_except_except Exception Handling

+ *

+ * This module provides exception handling syntactically similar to C++ in

+ * C language. The underlying mechanism use setjmp() and longjmp(), and since

+ * these constructs are ANSI standard, the mechanism here should be available

+ * on most platforms/compilers which are ANSI compliant.

+ *

+ * If ANSI libc is not available, then setjmp()/longjmp() implementation will

+ * be provided. See <pj/compat/setjmp.h> for compatibility.

+ *

+ * The exception handling mechanism is completely thread safe, so the exception

+ * thrown by one thread will not interfere with other thread.

+ *

+ * CAVEATS:

+ *  - unlike C++ exception, the scheme here won't call destructors of local

+ *    objects if exception is thrown. Care must be taken when a function

+ *    hold some resorce such as pool or mutex etc.

+ *  - You CAN NOT make nested exception in one single function without using

+ *    a nested PJ_USE_EXCEPTION.

+ *  - Exceptions will always be caught by the first handle (unlike C++ where

+ *    exception is only caught if the type matches.

+ *

+ * The exception handling constructs are similar to C++. The blocks will be

+ * constructed similar to the following sample:

+ *

+ * \verbatim

+   #define NO_MEMORY     1

+   #define SYNTAX_ERROR  2

+  

+   int main()

+   {

+      PJ_USE_EXCEPTION;  // declare local exception stack.

+  

+      PJ_TRY {

+        ...// do something..

+      }

+      PJ_CATCH(NO_MEMORY) {

+        ... // handle exception 1

+      }

+      PJ_CATCH(SYNTAX_ERROR) {

+        ... // handle exception 2

+      }

+      PJ_DEFAULT {

+        ... // handle other exceptions.

+      }

+      PJ_END;

+   }

+   \endverbatim

+ *

+ * The above sample uses hard coded exception ID. It is @b strongly

+ * recommended that applications request a unique exception ID instead

+ * of hard coded value like above.

+ *

+ * \section pj_except_reg Exception ID Allocation

+ *

+ * To ensure that exception ID (number) are used consistently and to

+ * prevent ID collisions in an application, it is strongly suggested that 

+ * applications allocate an exception ID for each possible exception

+ * type. As a bonus of this process, the application can identify

+ * the name of the exception when the particular exception is thrown.

+ *

+ * Exception ID management are performed with the following APIs:

+ *  - #pj_exception_id_alloc().

+ *  - #pj_exception_id_free().

+ *  - #pj_exception_id_name().

+ *

+ *

+ * PJLIB itself automatically allocates one exception id, i.e.

+ * #PJ_NO_MEMORY_EXCEPTION which is declared in <pj/pool.h>. This exception

+ * ID is raised by default pool policy when it fails to allocate memory.

+ *

+ * \section PJ_EX_KEYWORDS Keywords

+ *

+ * \subsection PJ_THROW PJ_THROW(expression)

+ * Throw an exception. The expression thrown is an integer as the result of

+ * the \a expression. This keyword can be specified anywhere within the 

+ * program.

+ *

+ * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION

+ * Specify this in the variable definition section of the function block 

+ * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception 

+ * block. 

+ * Actually, this is just a macro to declare local variable which is used to

+ * push the exception state to the exception stack.

+ *

+ * \subsection PJ_TRY PJ_TRY

+ * The \a PJ_TRY keyword is typically followed by a block. If an exception is

+ * thrown in this block, then the execution will resume to the \a PJ_CATCH 

+ * handler.

+ *

+ * \subsection PJ_CATCH PJ_CATCH(expression)

+ * The \a PJ_CATCH is normally followed by a block. This block will be executed

+ * if the exception being thrown is equal to the expression specified in the

+ * \a PJ_CATCH.

+ *

+ * \subsection PJ_DEFAULT PJ_DEFAULT

+ * The \a PJ_DEFAULT keyword is normally followed by a block. This block will

+ * be executed if the exception being thrown doesn't match any of the \a

+ * PJ_CATCH specification. The \a PJ_DEFAULT block \b MUST be placed as the

+ * last block of the handlers.

+ *

+ * \subsection PJ_END PJ_END

+ * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks.

+ *

+ * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void)

+ * Get the last exception thrown. This macro is normally called inside the

+ * \a PJ_CATCH or \a PJ_DEFAULT block, altough it can be used anywhere where

+ * the \a PJ_USE_EXCEPTION definition is in scope.

+ *

+ * 

+ * \section pj_except_examples_sec Examples

+ *

+ * For some examples on how to use the exception construct, please see:

+ *  - @ref page_pjlib_samples_except_c

+ *  - @ref page_pjlib_exception_test

+ */

+

+/**

+ * Allocate a unique exception id.

+ * Applications don't have to allocate a unique exception ID before using

+ * the exception construct. However, by doing so it ensures that there is

+ * no collisions of exception ID.

+ *

+ * As a bonus, when exception number is acquired through this function,

+ * the library can assign name to the exception (only if 

+ * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the

+ * exception name when it catches an exception.

+ *

+ * @param name      Name to be associated with the exception ID.

+ * @param id        Pointer to receive the ID.

+ *

+ * @return          PJ_SUCCESS on success or PJ_ETOOMANY if the library 

+ *                  is running out out ids.

+ */

+PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name,

+                                           pj_exception_id_t *id);

+

+/**

+ * Free an exception id.

+ *

+ * @param id        The exception ID.

+ *

+ * @return          PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id);

+

+/**

+ * Retrieve name associated with the exception id.

+ *

+ * @param id        The exception ID.

+ *

+ * @return          The name associated with the specified ID.

+ */

+PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id);

+

+

+/** @} */

+

+/**

+ * This structure (which should be invisible to user) manages the TRY handler

+ * stack.

+ */

+struct pj_exception_state_t

+{

+    struct pj_exception_state_t *prev;  /**< Previous state in the list. */

+    pj_jmp_buf state;                   /**< jmp_buf.                    */

+};

+

+/**

+ * Throw exception.

+ * @param id    Exception Id.

+ */

+PJ_DECL_NO_RETURN(void) 

+pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN;

+

+/**

+ * Push exception handler.

+ */

+PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec);

+

+/**

+ * Pop exception handler.

+ */

+PJ_DECL(void) pj_pop_exception_handler_(void);

+

+/**

+ * Declare that the function will use exception.

+ * @hideinitializer

+ */

+#define PJ_USE_EXCEPTION    struct pj_exception_state_t pj_x_except__; int pj_x_code__

+

+/**

+ * Start exception specification block.

+ * @hideinitializer

+ */

+#define PJ_TRY		    if (1) { \

+				pj_push_exception_handler_(&pj_x_except__); \

+				pj_x_code__ = pj_setjmp(pj_x_except__.state); \

+				if (pj_x_code__ == 0)

+/**

+ * Catch the specified exception Id.

+ * @param id    The exception number to catch.

+ * @hideinitializer

+ */

+#define PJ_CATCH(id)	    else if (pj_x_code__ == (id))

+

+/**

+ * Catch any exception number.

+ * @hideinitializer

+ */

+#define PJ_DEFAULT	    else

+

+/**

+ * End of exception specification block.

+ * @hideinitializer

+ */

+#define PJ_END			pj_pop_exception_handler_(); \

+			    } else {}

+

+/**

+ * Throw exception.

+ * @param exception_id  The exception number.

+ * @hideinitializer

+ */

+#define PJ_THROW(exception_id)	pj_throw_exception_(exception_id)

+

+/**

+ * Get current exception.

+ * @return      Current exception code.

+ * @hideinitializer

+ */

+#define PJ_GET_EXCEPTION()	(pj_x_code__)

+

+PJ_END_DECL

+

+

+

+#endif	/* __PJ_EXCEPTION_H__ */

+

+

diff --git a/pjlib/include/pj/fifobuf.h b/pjlib/include/pj/fifobuf.h
index 7f0b33d..8c770e0 100644
--- a/pjlib/include/pj/fifobuf.h
+++ b/pjlib/include/pj/fifobuf.h
@@ -1,29 +1,50 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_FIFOBUF_H__
-#define __PJ_FIFOBUF_H__
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-typedef struct pj_fifobuf_t pj_fifobuf_t;
-struct pj_fifobuf_t
-{
-    char *first, *last;
-    char *ubegin, *uend;
-    int full;
-};
-
-PJ_DECL(void)	     pj_fifobuf_init (pj_fifobuf_t *fb, void *buffer, unsigned size);
-PJ_DECL(unsigned)    pj_fifobuf_max_size (pj_fifobuf_t *fb);
-PJ_DECL(void*)	     pj_fifobuf_alloc (pj_fifobuf_t *fb, unsigned size);
-PJ_DECL(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fb, void *buf);
-PJ_DECL(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fb, void *buf);
-
-PJ_END_DECL
-
-#endif	/* __PJ_FIFOBUF_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_FIFOBUF_H__

+#define __PJ_FIFOBUF_H__

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+typedef struct pj_fifobuf_t pj_fifobuf_t;

+struct pj_fifobuf_t

+{

+    char *first, *last;

+    char *ubegin, *uend;

+    int full;

+};

+

+PJ_DECL(void)	     pj_fifobuf_init (pj_fifobuf_t *fb, void *buffer, unsigned size);

+PJ_DECL(unsigned)    pj_fifobuf_max_size (pj_fifobuf_t *fb);

+PJ_DECL(void*)	     pj_fifobuf_alloc (pj_fifobuf_t *fb, unsigned size);

+PJ_DECL(pj_status_t) pj_fifobuf_unalloc (pj_fifobuf_t *fb, void *buf);

+PJ_DECL(pj_status_t) pj_fifobuf_free (pj_fifobuf_t *fb, void *buf);

+

+PJ_END_DECL

+

+#endif	/* __PJ_FIFOBUF_H__ */

+

diff --git a/pjlib/include/pj/file_access.h b/pjlib/include/pj/file_access.h
index 473484d..1034aa8 100644
--- a/pjlib/include/pj/file_access.h
+++ b/pjlib/include/pj/file_access.h
@@ -1,4 +1,25 @@
 /* $Id */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #ifndef __PJ_FILE_ACCESS_H__

 #define __PJ_FILE_ACCESS_H__

 

diff --git a/pjlib/include/pj/file_io.h b/pjlib/include/pj/file_io.h
index 7e5fa3e..708950b 100644
--- a/pjlib/include/pj/file_io.h
+++ b/pjlib/include/pj/file_io.h
@@ -1,155 +1,176 @@
-/* $Id$ */
-#ifndef __PJ_FILE_IO_H__
-#define __PJ_FILE_IO_H__
-
-/**
- * @file file_io.h
- * @brief Simple file I/O abstraction.
- */
-#include <pj/types.h>
-
-PJ_BEGIN_DECL 
-
-/**
- * @defgroup PJ_FILE_IO File I/O
- * @ingroup PJ_IO
- * @{
- *
- * This file contains functionalities to perform file I/O. The file
- * I/O can be implemented with various back-end, either using native
- * file API or ANSI stream. 
- *
- * @section pj_file_size_limit_sec Size Limits
- *
- * There may be limitation on the size that can be handled by the
- * #pj_file_setpos() or #pj_file_getpos() functions. The API itself
- * uses 64-bit integer for the file offset/position (where available); 
- * however some backends (such as ANSI) may only support signed 32-bit 
- * offset resolution.
- *
- * Reading and writing operation uses signed 32-bit integer to indicate
- * the size.
- *
- *
- */
-
-/**
- * These enumerations are used when opening file. Values PJ_O_RDONLY,
- * PJ_O_WRONLY, and PJ_O_RDWR are mutually exclusive. Value PJ_O_APPEND
- * can only be used when the file is opened for writing. 
- */
-enum pj_file_access
-{
-    PJ_O_RDONLY     = 0x1101,   /**< Open file for reading.             */
-    PJ_O_WRONLY     = 0x1102,   /**< Open file for writing.             */
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_FILE_IO_H__

+#define __PJ_FILE_IO_H__

+

+/**

+ * @file file_io.h

+ * @brief Simple file I/O abstraction.

+ */

+#include <pj/types.h>

+

+PJ_BEGIN_DECL 

+

+/**

+ * @defgroup PJ_FILE_IO File I/O

+ * @ingroup PJ_IO

+ * @{

+ *

+ * This file contains functionalities to perform file I/O. The file

+ * I/O can be implemented with various back-end, either using native

+ * file API or ANSI stream. 

+ *

+ * @section pj_file_size_limit_sec Size Limits

+ *

+ * There may be limitation on the size that can be handled by the

+ * #pj_file_setpos() or #pj_file_getpos() functions. The API itself

+ * uses 64-bit integer for the file offset/position (where available); 

+ * however some backends (such as ANSI) may only support signed 32-bit 

+ * offset resolution.

+ *

+ * Reading and writing operation uses signed 32-bit integer to indicate

+ * the size.

+ *

+ *

+ */

+

+/**

+ * These enumerations are used when opening file. Values PJ_O_RDONLY,

+ * PJ_O_WRONLY, and PJ_O_RDWR are mutually exclusive. Value PJ_O_APPEND

+ * can only be used when the file is opened for writing. 

+ */

+enum pj_file_access

+{

+    PJ_O_RDONLY     = 0x1101,   /**< Open file for reading.             */

+    PJ_O_WRONLY     = 0x1102,   /**< Open file for writing.             */

     PJ_O_RDWR       = 0x1103,   /**< Open file for reading and writing. 

-                                     File will be truncated.            */
+                                     File will be truncated.            */

     PJ_O_APPEND     = 0x1108,   /**< Append to existing file.           */

-};
-
-/**
- * The seek directive when setting the file position with #pj_file_setpos.
- */
-enum pj_file_seek_type
-{
-    PJ_SEEK_SET     = 0x1201,   /**< Offset from beginning of the file. */
-    PJ_SEEK_CUR     = 0x1202,   /**< Offset from current position.      */
-    PJ_SEEK_END     = 0x1203,   /**< Size of the file plus offset.      */
-};
-
-/**
- * Open the file as specified in \c pathname with the specified
- * mode, and return the handle in \c fd. All files will be opened
- * as binary.
- *
- * @param pool          Pool to allocate memory for the new file descriptor.
- * @param pathname      The file name to open.
- * @param flags         Open flags, which is bitmask combination of
- *                      #pj_file_access enum. The flag must be either
- *                      PJ_O_RDONLY, PJ_O_WRONLY, or PJ_O_RDWR. When file
- *                      writing is specified, existing file will be 
+};

+

+/**

+ * The seek directive when setting the file position with #pj_file_setpos.

+ */

+enum pj_file_seek_type

+{

+    PJ_SEEK_SET     = 0x1201,   /**< Offset from beginning of the file. */

+    PJ_SEEK_CUR     = 0x1202,   /**< Offset from current position.      */

+    PJ_SEEK_END     = 0x1203,   /**< Size of the file plus offset.      */

+};

+

+/**

+ * Open the file as specified in \c pathname with the specified

+ * mode, and return the handle in \c fd. All files will be opened

+ * as binary.

+ *

+ * @param pool          Pool to allocate memory for the new file descriptor.

+ * @param pathname      The file name to open.

+ * @param flags         Open flags, which is bitmask combination of

+ *                      #pj_file_access enum. The flag must be either

+ *                      PJ_O_RDONLY, PJ_O_WRONLY, or PJ_O_RDWR. When file

+ *                      writing is specified, existing file will be 

  *                      truncated unless PJ_O_APPEND is specified.

- * @param fd            The returned descriptor.
- *
- * @return              PJ_SUCCESS or the appropriate error code on error.
- */
-PJ_DECL(pj_status_t) pj_file_open(pj_pool_t *pool,
-                                  const char *pathname, 
-                                  unsigned flags,
-                                  pj_oshandle_t *fd);
-
-/**
- * Close an opened file descriptor.
- *
- * @param fd            The file descriptor.
- *
- * @return              PJ_SUCCESS or the appropriate error code on error.
- */
-PJ_DECL(pj_status_t) pj_file_close(pj_oshandle_t fd);
-
-/**
- * Write data with the specified size to an opened file.
- *
- * @param fd            The file descriptor.
- * @param data          Data to be written to the file.
- * @param size          On input, specifies the size of data to be written.
- *                      On return, it contains the number of data actually
- *                      written to the file.
- *
- * @return              PJ_SUCCESS or the appropriate error code on error.
- */
-PJ_DECL(pj_status_t) pj_file_write(pj_oshandle_t fd,
-                                   const void *data,
-                                   pj_ssize_t *size);
-
-/**
+ * @param fd            The returned descriptor.

+ *

+ * @return              PJ_SUCCESS or the appropriate error code on error.

+ */

+PJ_DECL(pj_status_t) pj_file_open(pj_pool_t *pool,

+                                  const char *pathname, 

+                                  unsigned flags,

+                                  pj_oshandle_t *fd);

+

+/**

+ * Close an opened file descriptor.

+ *

+ * @param fd            The file descriptor.

+ *

+ * @return              PJ_SUCCESS or the appropriate error code on error.

+ */

+PJ_DECL(pj_status_t) pj_file_close(pj_oshandle_t fd);

+

+/**

+ * Write data with the specified size to an opened file.

+ *

+ * @param fd            The file descriptor.

+ * @param data          Data to be written to the file.

+ * @param size          On input, specifies the size of data to be written.

+ *                      On return, it contains the number of data actually

+ *                      written to the file.

+ *

+ * @return              PJ_SUCCESS or the appropriate error code on error.

+ */

+PJ_DECL(pj_status_t) pj_file_write(pj_oshandle_t fd,

+                                   const void *data,

+                                   pj_ssize_t *size);

+

+/**

  * Read data from the specified file. When end-of-file condition is set,

- * this function will return PJ_SUCCESS but the size will contain zero.
- *
- * @param fd            The file descriptor.
- * @param data          Pointer to buffer to receive the data.
- * @param size          On input, specifies the maximum number of data to
- *                      read from the file. On output, it contains the size
+ * this function will return PJ_SUCCESS but the size will contain zero.

+ *

+ * @param fd            The file descriptor.

+ * @param data          Pointer to buffer to receive the data.

+ * @param size          On input, specifies the maximum number of data to

+ *                      read from the file. On output, it contains the size

  *                      of data actually read from the file. It will contain

- *                      zero when EOF occurs.
- *
+ *                      zero when EOF occurs.

+ *

  * @return              PJ_SUCCESS or the appropriate error code on error.

  *                      When EOF occurs, the return is PJ_SUCCESS but size

- *                      will report zero.
- */
-PJ_DECL(pj_status_t) pj_file_read(pj_oshandle_t fd,
-                                  void *data,
-                                  pj_ssize_t *size);
+ *                      will report zero.

+ */

+PJ_DECL(pj_status_t) pj_file_read(pj_oshandle_t fd,

+                                  void *data,

+                                  pj_ssize_t *size);

 

-/**
- * Set file position to new offset according to directive \c whence.
- *
- * @param fd            The file descriptor.
- * @param offset        The new file position to set.
- * @param whence        The directive.
- *
- * @return              PJ_SUCCESS or the appropriate error code on error.
- */
-PJ_DECL(pj_status_t) pj_file_setpos(pj_oshandle_t fd,
-                                    pj_off_t offset,
-                                    enum pj_file_seek_type whence);
-
-/**
- * Get current file position.
- *
- * @param fd            The file descriptor.
- * @param pos           On return contains the file position as measured
- *                      from the beginning of the file.
- *
- * @return              PJ_SUCCESS or the appropriate error code on error.
- */
-PJ_DECL(pj_status_t) pj_file_getpos(pj_oshandle_t fd,
-                                    pj_off_t *pos);
-
-/** @} */
-
-
-PJ_END_DECL
-
-#endif  /* __PJ_FILE_IO_H__ */
-
+/**

+ * Set file position to new offset according to directive \c whence.

+ *

+ * @param fd            The file descriptor.

+ * @param offset        The new file position to set.

+ * @param whence        The directive.

+ *

+ * @return              PJ_SUCCESS or the appropriate error code on error.

+ */

+PJ_DECL(pj_status_t) pj_file_setpos(pj_oshandle_t fd,

+                                    pj_off_t offset,

+                                    enum pj_file_seek_type whence);

+

+/**

+ * Get current file position.

+ *

+ * @param fd            The file descriptor.

+ * @param pos           On return contains the file position as measured

+ *                      from the beginning of the file.

+ *

+ * @return              PJ_SUCCESS or the appropriate error code on error.

+ */

+PJ_DECL(pj_status_t) pj_file_getpos(pj_oshandle_t fd,

+                                    pj_off_t *pos);

+

+/** @} */

+

+

+PJ_END_DECL

+

+#endif  /* __PJ_FILE_IO_H__ */

+

diff --git a/pjlib/include/pj/guid.h b/pjlib/include/pj/guid.h
index 652b547..230ae1b 100644
--- a/pjlib/include/pj/guid.h
+++ b/pjlib/include/pj/guid.h
@@ -1,75 +1,96 @@
-/* $header: $ */
-
-#ifndef __PJ_GUID_H__
-#define __PJ_GUID_H__
-
-
-/**
- * @file guid.h
- * @brief GUID Globally Unique Identifier.
- */
-#include <pj/types.h>
-
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJ_DS Data Structure.
- * @ingroup PJ
- */
-/**
- * @defgroup PJ_GUID Globally Unique Identifier
- * @ingroup PJ_DS
- * @{
- *
- * This module provides API to create string that is globally unique.
- * If application doesn't require that strong requirement, it can just
- * use #pj_create_random_string() instead.
- */
-
-
-/**
- * PJ_GUID_STRING_LENGTH specifies length of GUID string. The value is
- * dependent on the algorithm used internally to generate the GUID string.
- * If real GUID generator is used, then the length will be 128bit or 
- * 32 bytes. If shadow GUID generator is used, then the length
- * will be 20 bytes. Application should not assume which algorithm will
- * be used by GUID generator.
- */
-extern const unsigned PJ_GUID_STRING_LENGTH;
-
-/**
- * PJ_GUID_MAX_LENGTH specifies the maximum length of GUID string,
- * regardless of which algorithm to use.
- */
-#define PJ_GUID_MAX_LENGTH  32
-
-/**
- * Create a globally unique string, which length is PJ_GUID_STRING_LENGTH
- * characters. Caller is responsible for preallocating the storage used
- * in the string.
- *
- * @param str       The string to store the result.
- *
- * @return          The string.
- */
-PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str);
-
-/**
- * Generate a unique string.
- *
- * @param pool	    Pool to allocate memory from.
- * @param str	    The string.
- */
-PJ_DECL(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str);
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif/* __PJ_GUID_H__ */
-
+/* $header: $ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_GUID_H__

+#define __PJ_GUID_H__

+

+

+/**

+ * @file guid.h

+ * @brief GUID Globally Unique Identifier.

+ */

+#include <pj/types.h>

+

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJ_DS Data Structure.

+ * @ingroup PJ

+ */

+/**

+ * @defgroup PJ_GUID Globally Unique Identifier

+ * @ingroup PJ_DS

+ * @{

+ *

+ * This module provides API to create string that is globally unique.

+ * If application doesn't require that strong requirement, it can just

+ * use #pj_create_random_string() instead.

+ */

+

+

+/**

+ * PJ_GUID_STRING_LENGTH specifies length of GUID string. The value is

+ * dependent on the algorithm used internally to generate the GUID string.

+ * If real GUID generator is used, then the length will be 128bit or 

+ * 32 bytes. If shadow GUID generator is used, then the length

+ * will be 20 bytes. Application should not assume which algorithm will

+ * be used by GUID generator.

+ */

+extern const unsigned PJ_GUID_STRING_LENGTH;

+

+/**

+ * PJ_GUID_MAX_LENGTH specifies the maximum length of GUID string,

+ * regardless of which algorithm to use.

+ */

+#define PJ_GUID_MAX_LENGTH  32

+

+/**

+ * Create a globally unique string, which length is PJ_GUID_STRING_LENGTH

+ * characters. Caller is responsible for preallocating the storage used

+ * in the string.

+ *

+ * @param str       The string to store the result.

+ *

+ * @return          The string.

+ */

+PJ_DECL(pj_str_t*) pj_generate_unique_string(pj_str_t *str);

+

+/**

+ * Generate a unique string.

+ *

+ * @param pool	    Pool to allocate memory from.

+ * @param str	    The string.

+ */

+PJ_DECL(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str);

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif/* __PJ_GUID_H__ */

+

diff --git a/pjlib/include/pj/hash.h b/pjlib/include/pj/hash.h
index b1eb9d9..2c4fca4 100644
--- a/pjlib/include/pj/hash.h
+++ b/pjlib/include/pj/hash.h
@@ -1,49 +1,70 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_HASH_H__
-#define __PJ_HASH_H__
-
-/**
- * @file hash.h
- * @brief Hash Table.
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_HASH Hash Table
- * @ingroup PJ_DS
- * @{
- * A hash table is a dictionary in which keys are mapped to array positions by
- * hash functions. Having the keys of more than one item map to the same 
- * position is called a collision. In this library, we will chain the nodes
- * that have the same key in a list.
- */
-
-/**
- * If this constant is used as keylen, then the key is interpreted as
- * NULL terminated string.
- */
-#define PJ_HASH_KEY_STRING	((unsigned)-1)
-
-/**
- * This is the function that is used by the hash table to calculate hash value
- * of the specified key.
- *
- * @param hval	    the initial hash value, or zero.
- * @param key	    the key to calculate.
- * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to treat 
- *		    the key as null terminated string.
- *
- * @return          the hash value.
- */
-PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval, 
-				  const void *key, unsigned keylen);
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_HASH_H__

+#define __PJ_HASH_H__

+

+/**

+ * @file hash.h

+ * @brief Hash Table.

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_HASH Hash Table

+ * @ingroup PJ_DS

+ * @{

+ * A hash table is a dictionary in which keys are mapped to array positions by

+ * hash functions. Having the keys of more than one item map to the same 

+ * position is called a collision. In this library, we will chain the nodes

+ * that have the same key in a list.

+ */

+

+/**

+ * If this constant is used as keylen, then the key is interpreted as

+ * NULL terminated string.

+ */

+#define PJ_HASH_KEY_STRING	((unsigned)-1)

+

+/**

+ * This is the function that is used by the hash table to calculate hash value

+ * of the specified key.

+ *

+ * @param hval	    the initial hash value, or zero.

+ * @param key	    the key to calculate.

+ * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to treat 

+ *		    the key as null terminated string.

+ *

+ * @return          the hash value.

+ */

+PJ_DECL(pj_uint32_t) pj_hash_calc(pj_uint32_t hval, 

+				  const void *key, unsigned keylen);

+

 

 /**

  * Convert the key to lowercase and calculate the hash value. The resulting

@@ -59,99 +80,99 @@
 PJ_DECL(pj_uint32_t) pj_hash_calc_tolower(pj_uint32_t hval,

                                           char *result,

                                           const pj_str_t *key);

-
-/**
- * Create a hash table with the specified 'bucket' size.
- *
- * @param pool	the pool from which the hash table will be allocated from.
- * @param size	the bucket size, which will be round-up to the nearest 2^n+1
- *
- * @return the hash table.
- */
-PJ_DECL(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size);
-
-
-/**
- * Get the value associated with the specified key.
- *
- * @param ht	    the hash table.
- * @param key	    the key to look for.
- * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the
- *		    string length of the key.
- *
- * @return the value associated with the key, or NULL if the key is not found.
- */
-PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,
-			     const void *key, unsigned keylen );
-
-
-/**
- * Associate/disassociate a value with the specified key.
- *
- * @param pool	    the pool to allocate the new entry if a new entry has to be
- *		    created.
- * @param ht	    the hash table.
- * @param key	    the key.
- * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the 
- *		    string length of the key.
- * @param value	    value to be associated, or NULL to delete the entry with
- *		    the specified key.
- */
-PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
-			   const void *key, unsigned keylen,
-			   void *value );
-
-/**
- * Get the total number of entries in the hash table.
- *
- * @param ht	the hash table.
- *
- * @return the number of entries in the hash table.
- */
-PJ_DECL(unsigned) pj_hash_count( pj_hash_table_t *ht );
-
-
-/**
- * Get the iterator to the first element in the hash table. 
- *
- * @param ht	the hash table.
- * @param it	the iterator for iterating hash elements.
- *
- * @return the iterator to the hash element, or NULL if no element presents.
- */
-PJ_DECL(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,
-					    pj_hash_iterator_t *it );
-
-
-/**
- * Get the next element from the iterator.
- *
- * @param ht	the hash table.
- * @param it	the hash iterator.
- *
- * @return the next iterator, or NULL if there's no more element.
- */
-PJ_DECL(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, 
-					   pj_hash_iterator_t *it );
-
-/**
- * Get the value associated with a hash iterator.
- *
- * @param ht	the hash table.
- * @param it	the hash iterator.
- *
- * @return the value associated with the current element in iterator.
- */
-PJ_DECL(void*) pj_hash_this( pj_hash_table_t *ht,
-			     pj_hash_iterator_t *it );
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif
-
-
+

+/**

+ * Create a hash table with the specified 'bucket' size.

+ *

+ * @param pool	the pool from which the hash table will be allocated from.

+ * @param size	the bucket size, which will be round-up to the nearest 2^n+1

+ *

+ * @return the hash table.

+ */

+PJ_DECL(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size);

+

+

+/**

+ * Get the value associated with the specified key.

+ *

+ * @param ht	    the hash table.

+ * @param key	    the key to look for.

+ * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the

+ *		    string length of the key.

+ *

+ * @return the value associated with the key, or NULL if the key is not found.

+ */

+PJ_DECL(void *) pj_hash_get( pj_hash_table_t *ht,

+			     const void *key, unsigned keylen );

+

+

+/**

+ * Associate/disassociate a value with the specified key.

+ *

+ * @param pool	    the pool to allocate the new entry if a new entry has to be

+ *		    created.

+ * @param ht	    the hash table.

+ * @param key	    the key.

+ * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the 

+ *		    string length of the key.

+ * @param value	    value to be associated, or NULL to delete the entry with

+ *		    the specified key.

+ */

+PJ_DECL(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,

+			   const void *key, unsigned keylen,

+			   void *value );

+

+/**

+ * Get the total number of entries in the hash table.

+ *

+ * @param ht	the hash table.

+ *

+ * @return the number of entries in the hash table.

+ */

+PJ_DECL(unsigned) pj_hash_count( pj_hash_table_t *ht );

+

+

+/**

+ * Get the iterator to the first element in the hash table. 

+ *

+ * @param ht	the hash table.

+ * @param it	the iterator for iterating hash elements.

+ *

+ * @return the iterator to the hash element, or NULL if no element presents.

+ */

+PJ_DECL(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,

+					    pj_hash_iterator_t *it );

+

+

+/**

+ * Get the next element from the iterator.

+ *

+ * @param ht	the hash table.

+ * @param it	the hash iterator.

+ *

+ * @return the next iterator, or NULL if there's no more element.

+ */

+PJ_DECL(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, 

+					   pj_hash_iterator_t *it );

+

+/**

+ * Get the value associated with a hash iterator.

+ *

+ * @param ht	the hash table.

+ * @param it	the hash iterator.

+ *

+ * @return the value associated with the current element in iterator.

+ */

+PJ_DECL(void*) pj_hash_this( pj_hash_table_t *ht,

+			     pj_hash_iterator_t *it );

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif

+

+

diff --git a/pjlib/include/pj/ioqueue.h b/pjlib/include/pj/ioqueue.h
index d1aea69..87f9c10 100644
--- a/pjlib/include/pj/ioqueue.h
+++ b/pjlib/include/pj/ioqueue.h
@@ -1,344 +1,365 @@
-/* $Id$
- */
-
-#ifndef __PJ_IOQUEUE_H__
-#define __PJ_IOQUEUE_H__
-
-/**
- * @file ioqueue.h
- * @brief I/O Dispatching Mechanism
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_IO Input/Output
- * @brief Input/Output
- * @ingroup PJ_OS
- *
- * This section contains API building blocks to perform network I/O and 
- * communications. If provides:
- *  - @ref PJ_SOCK
- *\n
- *    A highly portable socket abstraction, runs on all kind of
- *    network APIs such as standard BSD socket, Windows socket, Linux
- *    \b kernel socket, PalmOS networking API, etc.
- *
- *  - @ref pj_addr_resolve
- *\n
- *    Portable address resolution, which implements #pj_gethostbyname().
- *
- *  - @ref PJ_SOCK_SELECT
- *\n
- *    A portable \a select() like API (#pj_sock_select()) which can be
- *    implemented with various back-ends.
- *
- *  - @ref PJ_IOQUEUE
- *\n
- *    Framework for dispatching network events.
- *
- * For more information see the modules below.
- */
-
-/**
- * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue
- * @ingroup PJ_IO
- * @{
- *
- * I/O Queue provides API for performing asynchronous I/O operations. It
- * conforms to proactor pattern, which allows application to submit an
- * asynchronous operation and to be notified later when the operation has
- * completed.
- *
- * The I/O Queue can work on both socket and file descriptors. For 
- * asynchronous file operations however, one must make sure that the correct
- * file I/O back-end is used, because not all file I/O back-end can be
- * used with the ioqueue. Please see \ref PJ_FILE_IO for more details.
- *
- * The framework works natively in platforms where asynchronous operation API
- * exists, such as in Windows NT with IoCompletionPort/IOCP. In other 
- * platforms, the I/O queue abstracts the operating system's event poll API
- * to provide semantics similar to IoCompletionPort with minimal penalties
- * (i.e. per ioqueue and per handle mutex protection).
- *
- * The I/O queue provides more than just unified abstraction. It also:
- *  - makes sure that the operation uses the most effective way to utilize
- *    the underlying mechanism, to achieve the maximum theoritical
- *    throughput possible on a given platform.
- *  - choose the most efficient mechanism for event polling on a given
- *    platform.
- *
- * Currently, the I/O Queue is implemented using:
- *  - <tt><b>select()</b></tt>, as the common denominator, but the least 
- *    efficient. Also the number of descriptor is limited to 
- *    \c PJ_IOQUEUE_MAX_HANDLES (which by default is 64).
- *  - <tt><b>/dev/epoll</b></tt> on Linux (user mode and kernel mode), 
- *    a much faster replacement for select() on Linux (and more importantly
- *    doesn't have limitation on number of descriptors).
- *  - <b>I/O Completion ports</b> on Windows NT/2000/XP, which is the most 
- *    efficient way to dispatch events in Windows NT based OSes, and most 
- *    importantly, it doesn't have the limit on how many handles to monitor.
- *    And it works with files (not only sockets) as well.
- *
- *
- * \section pj_ioqueue_concurrency_sec Concurrency Rules
- *
- * The items below describe rules that must be obeyed when using the I/O 
- * queue, with regard to concurrency:
- *  - simultaneous operations (by different threads) to different key is safe.
- *  - simultaneous operations to the same key is also safe, except
- *    <b>unregistration</b>, which is described below.
- *  - <b>care must be taken when unregistering a key</b> from the
- *    ioqueue. Application must take care that when one thread is issuing
- *    an unregistration, other thread is not simultaneously invoking an
- *    operation <b>to the same key</b>.
- *\n
- *    This happens because the ioqueue functions are working with a pointer
- *    to the key, and there is a possible race condition where the pointer
- *    has been rendered invalid by other threads before the ioqueue has a
- *    chance to acquire mutex on it.
- *
- * \section pj_ioqeuue_examples_sec Examples
- *
- * For some examples on how to use the I/O Queue, please see:
- *
- *  - \ref page_pjlib_ioqueue_tcp_test
- *  - \ref page_pjlib_ioqueue_udp_test
- *  - \ref page_pjlib_ioqueue_perf_test
- */
-
-
-/**
- * This structure describes operation specific key to be submitted to
- * I/O Queue when performing the asynchronous operation. This key will
- * be returned to the application when completion callback is called.
- *
- * Application normally wants to attach it's specific data in the
- * \c user_data field so that it can keep track of which operation has
- * completed when the callback is called. Alternatively, application can
- * also extend this struct to include its data, because the pointer that
- * is returned in the completion callback will be exactly the same as
- * the pointer supplied when the asynchronous function is called.
- */
-typedef struct pj_ioqueue_op_key_t
-{ 
-    void *internal__[32];           /**< Internal I/O Queue data.   */
-    void *user_data;                /**< Application data.          */
-} pj_ioqueue_op_key_t;
-
-/**
- * This structure describes the callbacks to be called when I/O operation
- * completes.
- */
-typedef struct pj_ioqueue_callback
-{
-    /**
-     * This callback is called when #pj_ioqueue_recv or #pj_ioqueue_recvfrom
-     * completes.
-     *
-     * @param key	    The key.
-     * @param op_key        Operation key.
-     * @param bytes_read    >= 0 to indicate the amount of data read, 
-     *                      otherwise negative value containing the error
-     *                      code. To obtain the pj_status_t error code, use
-     *                      (pj_status_t code = -bytes_read).
-     */
-    void (*on_read_complete)(pj_ioqueue_key_t *key, 
-                             pj_ioqueue_op_key_t *op_key, 
-                             pj_ssize_t bytes_read);
-
-    /**
-     * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto
-     * completes.
-     *
-     * @param key	    The key.
-     * @param op_key        Operation key.
-     * @param bytes_sent    >= 0 to indicate the amount of data written, 
-     *                      otherwise negative value containing the error
-     *                      code. To obtain the pj_status_t error code, use
-     *                      (pj_status_t code = -bytes_sent).
-     */
-    void (*on_write_complete)(pj_ioqueue_key_t *key, 
-                              pj_ioqueue_op_key_t *op_key, 
-                              pj_ssize_t bytes_sent);
-
-    /**
-     * This callback is called when #pj_ioqueue_accept completes.
-     *
-     * @param key	    The key.
-     * @param op_key        Operation key.
-     * @param sock          Newly connected socket.
-     * @param status	    Zero if the operation completes successfully.
-     */
-    void (*on_accept_complete)(pj_ioqueue_key_t *key, 
-                               pj_ioqueue_op_key_t *op_key, 
-                               pj_sock_t sock, 
-                               pj_status_t status);
-
-    /**
-     * This callback is called when #pj_ioqueue_connect completes.
-     *
-     * @param key	    The key.
-     * @param status	    PJ_SUCCESS if the operation completes successfully.
-     */
-    void (*on_connect_complete)(pj_ioqueue_key_t *key, 
-                                pj_status_t status);
-} pj_ioqueue_callback;
-
-
-/**
- * Types of pending I/O Queue operation. This enumeration is only used
- * internally within the ioqueue.
- */
-typedef enum pj_ioqueue_operation_e
-{
-    PJ_IOQUEUE_OP_NONE		= 0,	/**< No operation.          */
-    PJ_IOQUEUE_OP_READ		= 1,	/**< read() operation.      */
-    PJ_IOQUEUE_OP_RECV          = 2,    /**< recv() operation.      */
-    PJ_IOQUEUE_OP_RECV_FROM	= 4,	/**< recvfrom() operation.  */
-    PJ_IOQUEUE_OP_WRITE		= 8,	/**< write() operation.     */
-    PJ_IOQUEUE_OP_SEND          = 16,   /**< send() operation.      */
-    PJ_IOQUEUE_OP_SEND_TO	= 32,	/**< sendto() operation.    */
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-    PJ_IOQUEUE_OP_ACCEPT	= 64,	/**< accept() operation.    */
-    PJ_IOQUEUE_OP_CONNECT	= 128,	/**< connect() operation.   */
-#endif	/* PJ_HAS_TCP */
-} pj_ioqueue_operation_e;
-
-
-/**
- * This macro specifies the maximum number of events that can be
- * processed by the ioqueue on a single poll cycle, on implementation
- * that supports it. The value is only meaningfull when specified
- * during PJLIB build.
- */
-#ifndef PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL
-#   define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL     (16)
-#endif
-
-/**
- * Return the name of the ioqueue implementation.
- *
- * @return		Implementation name.
- */
-PJ_DECL(const char*) pj_ioqueue_name(void);
-
-
-/**
- * Create a new I/O Queue framework.
- *
- * @param pool		The pool to allocate the I/O queue structure. 
- * @param max_fd	The maximum number of handles to be supported, which 
- *			should not exceed PJ_IOQUEUE_MAX_HANDLES.
- * @param ioqueue	Pointer to hold the newly created I/O Queue.
- *
- * @return		PJ_SUCCESS on success.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
-					pj_size_t max_fd,
-					pj_ioqueue_t **ioqueue);
-
-/**
- * Destroy the I/O queue.
- *
- * @param ioque	        The I/O Queue to be destroyed.
- *
- * @return              PJ_SUCCESS if success.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque );
-
-/**
- * Set the lock object to be used by the I/O Queue. This function can only
- * be called right after the I/O queue is created, before any handle is
- * registered to the I/O queue.
- *
- * Initially the I/O queue is created with non-recursive mutex protection. 
- * Applications can supply alternative lock to be used by calling this 
- * function.
- *
- * @param ioque         The ioqueue instance.
- * @param lock          The lock to be used by the ioqueue.
- * @param auto_delete   In non-zero, the lock will be deleted by the ioqueue.
- *
- * @return              PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 
-					  pj_lock_t *lock,
-					  pj_bool_t auto_delete );
-
-/**
- * Register a socket to the I/O queue framework. 
- * When a socket is registered to the IOQueue, it may be modified to use
- * non-blocking IO. If it is modified, there is no guarantee that this 
- * modification will be restored after the socket is unregistered.
- *
- * @param pool	    To allocate the resource for the specified handle, 
- *		    which must be valid until the handle/key is unregistered 
- *		    from I/O Queue.
- * @param ioque	    The I/O Queue.
- * @param sock	    The socket.
- * @param user_data User data to be associated with the key, which can be
- *		    retrieved later.
- * @param cb	    Callback to be called when I/O operation completes. 
- * @param key       Pointer to receive the key to be associated with this
- *                  socket. Subsequent I/O queue operation will need this
- *                  key.
- *
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
-					       pj_ioqueue_t *ioque,
-					       pj_sock_t sock,
-					       void *user_data,
-					       const pj_ioqueue_callback *cb,
-                                               pj_ioqueue_key_t **key );
-
-/**
- * Unregister from the I/O Queue framework. Caller must make sure that
- * the key doesn't have any pending operations before calling this function,
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_IOQUEUE_H__

+#define __PJ_IOQUEUE_H__

+

+/**

+ * @file ioqueue.h

+ * @brief I/O Dispatching Mechanism

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_IO Input/Output

+ * @brief Input/Output

+ * @ingroup PJ_OS

+ *

+ * This section contains API building blocks to perform network I/O and 

+ * communications. If provides:

+ *  - @ref PJ_SOCK

+ *\n

+ *    A highly portable socket abstraction, runs on all kind of

+ *    network APIs such as standard BSD socket, Windows socket, Linux

+ *    \b kernel socket, PalmOS networking API, etc.

+ *

+ *  - @ref pj_addr_resolve

+ *\n

+ *    Portable address resolution, which implements #pj_gethostbyname().

+ *

+ *  - @ref PJ_SOCK_SELECT

+ *\n

+ *    A portable \a select() like API (#pj_sock_select()) which can be

+ *    implemented with various back-ends.

+ *

+ *  - @ref PJ_IOQUEUE

+ *\n

+ *    Framework for dispatching network events.

+ *

+ * For more information see the modules below.

+ */

+

+/**

+ * @defgroup PJ_IOQUEUE I/O Event Dispatching Queue

+ * @ingroup PJ_IO

+ * @{

+ *

+ * I/O Queue provides API for performing asynchronous I/O operations. It

+ * conforms to proactor pattern, which allows application to submit an

+ * asynchronous operation and to be notified later when the operation has

+ * completed.

+ *

+ * The I/O Queue can work on both socket and file descriptors. For 

+ * asynchronous file operations however, one must make sure that the correct

+ * file I/O back-end is used, because not all file I/O back-end can be

+ * used with the ioqueue. Please see \ref PJ_FILE_IO for more details.

+ *

+ * The framework works natively in platforms where asynchronous operation API

+ * exists, such as in Windows NT with IoCompletionPort/IOCP. In other 

+ * platforms, the I/O queue abstracts the operating system's event poll API

+ * to provide semantics similar to IoCompletionPort with minimal penalties

+ * (i.e. per ioqueue and per handle mutex protection).

+ *

+ * The I/O queue provides more than just unified abstraction. It also:

+ *  - makes sure that the operation uses the most effective way to utilize

+ *    the underlying mechanism, to achieve the maximum theoritical

+ *    throughput possible on a given platform.

+ *  - choose the most efficient mechanism for event polling on a given

+ *    platform.

+ *

+ * Currently, the I/O Queue is implemented using:

+ *  - <tt><b>select()</b></tt>, as the common denominator, but the least 

+ *    efficient. Also the number of descriptor is limited to 

+ *    \c PJ_IOQUEUE_MAX_HANDLES (which by default is 64).

+ *  - <tt><b>/dev/epoll</b></tt> on Linux (user mode and kernel mode), 

+ *    a much faster replacement for select() on Linux (and more importantly

+ *    doesn't have limitation on number of descriptors).

+ *  - <b>I/O Completion ports</b> on Windows NT/2000/XP, which is the most 

+ *    efficient way to dispatch events in Windows NT based OSes, and most 

+ *    importantly, it doesn't have the limit on how many handles to monitor.

+ *    And it works with files (not only sockets) as well.

+ *

+ *

+ * \section pj_ioqueue_concurrency_sec Concurrency Rules

+ *

+ * The items below describe rules that must be obeyed when using the I/O 

+ * queue, with regard to concurrency:

+ *  - simultaneous operations (by different threads) to different key is safe.

+ *  - simultaneous operations to the same key is also safe, except

+ *    <b>unregistration</b>, which is described below.

+ *  - <b>care must be taken when unregistering a key</b> from the

+ *    ioqueue. Application must take care that when one thread is issuing

+ *    an unregistration, other thread is not simultaneously invoking an

+ *    operation <b>to the same key</b>.

+ *\n

+ *    This happens because the ioqueue functions are working with a pointer

+ *    to the key, and there is a possible race condition where the pointer

+ *    has been rendered invalid by other threads before the ioqueue has a

+ *    chance to acquire mutex on it.

+ *

+ * \section pj_ioqeuue_examples_sec Examples

+ *

+ * For some examples on how to use the I/O Queue, please see:

+ *

+ *  - \ref page_pjlib_ioqueue_tcp_test

+ *  - \ref page_pjlib_ioqueue_udp_test

+ *  - \ref page_pjlib_ioqueue_perf_test

+ */

+

+

+/**

+ * This structure describes operation specific key to be submitted to

+ * I/O Queue when performing the asynchronous operation. This key will

+ * be returned to the application when completion callback is called.

+ *

+ * Application normally wants to attach it's specific data in the

+ * \c user_data field so that it can keep track of which operation has

+ * completed when the callback is called. Alternatively, application can

+ * also extend this struct to include its data, because the pointer that

+ * is returned in the completion callback will be exactly the same as

+ * the pointer supplied when the asynchronous function is called.

+ */

+typedef struct pj_ioqueue_op_key_t

+{ 

+    void *internal__[32];           /**< Internal I/O Queue data.   */

+    void *user_data;                /**< Application data.          */

+} pj_ioqueue_op_key_t;

+

+/**

+ * This structure describes the callbacks to be called when I/O operation

+ * completes.

+ */

+typedef struct pj_ioqueue_callback

+{

+    /**

+     * This callback is called when #pj_ioqueue_recv or #pj_ioqueue_recvfrom

+     * completes.

+     *

+     * @param key	    The key.

+     * @param op_key        Operation key.

+     * @param bytes_read    >= 0 to indicate the amount of data read, 

+     *                      otherwise negative value containing the error

+     *                      code. To obtain the pj_status_t error code, use

+     *                      (pj_status_t code = -bytes_read).

+     */

+    void (*on_read_complete)(pj_ioqueue_key_t *key, 

+                             pj_ioqueue_op_key_t *op_key, 

+                             pj_ssize_t bytes_read);

+

+    /**

+     * This callback is called when #pj_ioqueue_write or #pj_ioqueue_sendto

+     * completes.

+     *

+     * @param key	    The key.

+     * @param op_key        Operation key.

+     * @param bytes_sent    >= 0 to indicate the amount of data written, 

+     *                      otherwise negative value containing the error

+     *                      code. To obtain the pj_status_t error code, use

+     *                      (pj_status_t code = -bytes_sent).

+     */

+    void (*on_write_complete)(pj_ioqueue_key_t *key, 

+                              pj_ioqueue_op_key_t *op_key, 

+                              pj_ssize_t bytes_sent);

+

+    /**

+     * This callback is called when #pj_ioqueue_accept completes.

+     *

+     * @param key	    The key.

+     * @param op_key        Operation key.

+     * @param sock          Newly connected socket.

+     * @param status	    Zero if the operation completes successfully.

+     */

+    void (*on_accept_complete)(pj_ioqueue_key_t *key, 

+                               pj_ioqueue_op_key_t *op_key, 

+                               pj_sock_t sock, 

+                               pj_status_t status);

+

+    /**

+     * This callback is called when #pj_ioqueue_connect completes.

+     *

+     * @param key	    The key.

+     * @param status	    PJ_SUCCESS if the operation completes successfully.

+     */

+    void (*on_connect_complete)(pj_ioqueue_key_t *key, 

+                                pj_status_t status);

+} pj_ioqueue_callback;

+

+

+/**

+ * Types of pending I/O Queue operation. This enumeration is only used

+ * internally within the ioqueue.

+ */

+typedef enum pj_ioqueue_operation_e

+{

+    PJ_IOQUEUE_OP_NONE		= 0,	/**< No operation.          */

+    PJ_IOQUEUE_OP_READ		= 1,	/**< read() operation.      */

+    PJ_IOQUEUE_OP_RECV          = 2,    /**< recv() operation.      */

+    PJ_IOQUEUE_OP_RECV_FROM	= 4,	/**< recvfrom() operation.  */

+    PJ_IOQUEUE_OP_WRITE		= 8,	/**< write() operation.     */

+    PJ_IOQUEUE_OP_SEND          = 16,   /**< send() operation.      */

+    PJ_IOQUEUE_OP_SEND_TO	= 32,	/**< sendto() operation.    */

+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

+    PJ_IOQUEUE_OP_ACCEPT	= 64,	/**< accept() operation.    */

+    PJ_IOQUEUE_OP_CONNECT	= 128,	/**< connect() operation.   */

+#endif	/* PJ_HAS_TCP */

+} pj_ioqueue_operation_e;

+

+

+/**

+ * This macro specifies the maximum number of events that can be

+ * processed by the ioqueue on a single poll cycle, on implementation

+ * that supports it. The value is only meaningfull when specified

+ * during PJLIB build.

+ */

+#ifndef PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL

+#   define PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL     (16)

+#endif

+

+/**

+ * Return the name of the ioqueue implementation.

+ *

+ * @return		Implementation name.

+ */

+PJ_DECL(const char*) pj_ioqueue_name(void);

+

+

+/**

+ * Create a new I/O Queue framework.

+ *

+ * @param pool		The pool to allocate the I/O queue structure. 

+ * @param max_fd	The maximum number of handles to be supported, which 

+ *			should not exceed PJ_IOQUEUE_MAX_HANDLES.

+ * @param ioqueue	Pointer to hold the newly created I/O Queue.

+ *

+ * @return		PJ_SUCCESS on success.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 

+					pj_size_t max_fd,

+					pj_ioqueue_t **ioqueue);

+

+/**

+ * Destroy the I/O queue.

+ *

+ * @param ioque	        The I/O Queue to be destroyed.

+ *

+ * @return              PJ_SUCCESS if success.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioque );

+

+/**

+ * Set the lock object to be used by the I/O Queue. This function can only

+ * be called right after the I/O queue is created, before any handle is

+ * registered to the I/O queue.

+ *

+ * Initially the I/O queue is created with non-recursive mutex protection. 

+ * Applications can supply alternative lock to be used by calling this 

+ * function.

+ *

+ * @param ioque         The ioqueue instance.

+ * @param lock          The lock to be used by the ioqueue.

+ * @param auto_delete   In non-zero, the lock will be deleted by the ioqueue.

+ *

+ * @return              PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 

+					  pj_lock_t *lock,

+					  pj_bool_t auto_delete );

+

+/**

+ * Register a socket to the I/O queue framework. 

+ * When a socket is registered to the IOQueue, it may be modified to use

+ * non-blocking IO. If it is modified, there is no guarantee that this 

+ * modification will be restored after the socket is unregistered.

+ *

+ * @param pool	    To allocate the resource for the specified handle, 

+ *		    which must be valid until the handle/key is unregistered 

+ *		    from I/O Queue.

+ * @param ioque	    The I/O Queue.

+ * @param sock	    The socket.

+ * @param user_data User data to be associated with the key, which can be

+ *		    retrieved later.

+ * @param cb	    Callback to be called when I/O operation completes. 

+ * @param key       Pointer to receive the key to be associated with this

+ *                  socket. Subsequent I/O queue operation will need this

+ *                  key.

+ *

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

+					       pj_ioqueue_t *ioque,

+					       pj_sock_t sock,

+					       void *user_data,

+					       const pj_ioqueue_callback *cb,

+                                               pj_ioqueue_key_t **key );

+

+/**

+ * Unregister from the I/O Queue framework. Caller must make sure that

+ * the key doesn't have any pending operations before calling this function,

  * by calling #pj_ioqueue_is_pending() for all previously submitted

  * operations except asynchronous connect, and if necessary call

  * #pj_ioqueue_post_completion() to cancel the pending operations.

  *

  * Note that asynchronous connect operation will automatically be 

- * cancelled during the unregistration.
- *
- * @param key	    The key that was previously obtained from registration.
- *
+ * cancelled during the unregistration.

+ *

+ * @param key	    The key that was previously obtained from registration.

+ *

  * @return          PJ_SUCCESS on success or the error code.

  *

- * @see pj_ioqueue_is_pending
- */
-PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key );
-
-
-/**
- * Get user data associated with an ioqueue key.
- *
- * @param key	    The key that was previously obtained from registration.
- *
- * @return          The user data associated with the descriptor, or NULL 
- *                  on error or if no data is associated with the key during
- *                  registration.
- */
-PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key );
-
-/**
- * Set or change the user data to be associated with the file descriptor or
- * handle or socket descriptor.
- *
- * @param key	    The key that was previously obtained from registration.
- * @param user_data User data to be associated with the descriptor.
- * @param old_data  Optional parameter to retrieve the old user data.
- *
- * @return          PJ_SUCCESS on success or the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
-                                               void *user_data,
-                                               void **old_data);
-
+ * @see pj_ioqueue_is_pending

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key );

+

+

+/**

+ * Get user data associated with an ioqueue key.

+ *

+ * @param key	    The key that was previously obtained from registration.

+ *

+ * @return          The user data associated with the descriptor, or NULL 

+ *                  on error or if no data is associated with the key during

+ *                  registration.

+ */

+PJ_DECL(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key );

+

+/**

+ * Set or change the user data to be associated with the file descriptor or

+ * handle or socket descriptor.

+ *

+ * @param key	    The key that was previously obtained from registration.

+ * @param user_data User data to be associated with the descriptor.

+ * @param old_data  Optional parameter to retrieve the old user data.

+ *

+ * @return          PJ_SUCCESS on success or the error code.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,

+                                               void *user_data,

+                                               void **old_data);

+

 

 /**

  * Initialize operation key.

@@ -384,256 +405,256 @@
                                                  pj_ssize_t bytes_status );

 

 

-
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-/**
- * Instruct I/O Queue to accept incoming connection on the specified 
- * listening socket. This function will return immediately (i.e. non-blocking)
- * regardless whether a connection is immediately available. If the function
- * can't complete immediately, the caller will be notified about the incoming
- * connection when it calls pj_ioqueue_poll(). If a new connection is
- * immediately available, the function returns PJ_SUCCESS with the new
- * connection; in this case, the callback WILL NOT be called.
- *
- * @param key	    The key which registered to the server socket.
- * @param op_key    An operation specific key to be associated with the
- *                  pending operation, so that application can keep track of
- *                  which operation has been completed when the callback is
- *                  called.
- * @param new_sock  Argument which contain pointer to receive the new socket
- *                  for the incoming connection.
- * @param local	    Optional argument which contain pointer to variable to 
- *                  receive local address.
- * @param remote    Optional argument which contain pointer to variable to 
- *                  receive the remote address.
- * @param addrlen   On input, contains the length of the buffer for the
- *		    address, and on output, contains the actual length of the
- *		    address. This argument is optional.
- * @return
- *  - PJ_SUCCESS    When connection is available immediately, and the 
- *                  parameters will be updated to contain information about 
- *                  the new connection. In this case, a completion callback
- *                  WILL NOT be called.
- *  - PJ_EPENDING   If no connection is available immediately. When a new
- *                  connection arrives, the callback will be called.
- *  - non-zero      which indicates the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
-                                        pj_ioqueue_op_key_t *op_key,
-					pj_sock_t *sock,
-					pj_sockaddr_t *local,
-					pj_sockaddr_t *remote,
-					int *addrlen );
-
-/**
- * Initiate non-blocking socket connect. If the socket can NOT be connected
- * immediately, asynchronous connect() will be scheduled and caller will be
- * notified via completion callback when it calls pj_ioqueue_poll(). If
- * socket is connected immediately, the function returns PJ_SUCCESS and
- * completion callback WILL NOT be called.
- *
- * @param key	    The key associated with TCP socket
- * @param addr	    The remote address.
- * @param addrlen   The remote address length.
- *
- * @return
- *  - PJ_SUCCESS    If socket is connected immediately. In this case, the
- *                  completion callback WILL NOT be called.
- *  - PJ_EPENDING   If operation is queued, or 
- *  - non-zero      Indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
-					 const pj_sockaddr_t *addr,
-					 int addrlen );
-
-#endif	/* PJ_HAS_TCP */
-
-/**
- * Poll the I/O Queue for completed events.
- *
- * @param ioque		the I/O Queue.
- * @param timeout	polling timeout, or NULL if the thread wishes to wait
- *			indefinetely for the event.
- *
- * @return 
- *  - zero if timed out (no event).
- *  - (<0) if error occured during polling. Callback will NOT be called.
- *  - (>1) to indicate numbers of events. Callbacks have been called.
- */
-PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque,
-			      const pj_time_val *timeout);
-
-
-/**
- * Instruct the I/O Queue to read from the specified handle. This function
- * returns immediately (i.e. non-blocking) regardless whether some data has 
- * been transfered. If the operation can't complete immediately, caller will 
- * be notified about the completion when it calls pj_ioqueue_poll(). If data
- * is immediately available, the function will return PJ_SUCCESS and the
- * callback WILL NOT be called.
- *
- * @param key	    The key that uniquely identifies the handle.
- * @param op_key    An operation specific key to be associated with the
- *                  pending operation, so that application can keep track of
- *                  which operation has been completed when the callback is
- *                  called. Caller must make sure that this key remains 
- *                  valid until the function completes.
- * @param buffer    The buffer to hold the read data. The caller MUST make sure
- *		    that this buffer remain valid until the framework completes
- *		    reading the handle.
- * @param length    On input, it specifies the size of the buffer. If data is
- *                  available to be read immediately, the function returns
- *                  PJ_SUCCESS and this argument will be filled with the
- *                  amount of data read. If the function is pending, caller
- *                  will be notified about the amount of data read in the
- *                  callback. This parameter can point to local variable in
- *                  caller's stack and doesn't have to remain valid for the
- *                  duration of pending operation.
- * @param flags     Recv flag.
- *
- * @return
- *  - PJ_SUCCESS    If immediate data has been received in the buffer. In this
- *                  case, the callback WILL NOT be called.
- *  - PJ_EPENDING   If the operation has been queued, and the callback will be
- *                  called when data has been received.
- *  - non-zero      The return value indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,
-                                      pj_ioqueue_op_key_t *op_key,
-				      void *buffer,
-				      pj_ssize_t *length,
-				      unsigned flags );
-
-/**
- * This function behaves similarly as #pj_ioqueue_recv(), except that it is
- * normally called for socket, and the remote address will also be returned
- * along with the data. Caller MUST make sure that both buffer and addr
- * remain valid until the framework completes reading the data.
- *
- * @param key	    The key that uniquely identifies the handle.
- * @param op_key    An operation specific key to be associated with the
- *                  pending operation, so that application can keep track of
- *                  which operation has been completed when the callback is
- *                  called.
- * @param buffer    The buffer to hold the read data. The caller MUST make sure
- *		    that this buffer remain valid until the framework completes
- *		    reading the handle.
- * @param length    On input, it specifies the size of the buffer. If data is
- *                  available to be read immediately, the function returns
- *                  PJ_SUCCESS and this argument will be filled with the
- *                  amount of data read. If the function is pending, caller
- *                  will be notified about the amount of data read in the
- *                  callback. This parameter can point to local variable in
- *                  caller's stack and doesn't have to remain valid for the
- *                  duration of pending operation.
- * @param flags     Recv flag.
- * @param addr      Optional Pointer to buffer to receive the address.
- * @param addrlen   On input, specifies the length of the address buffer.
- *                  On output, it will be filled with the actual length of
- *                  the address. This argument can be NULL if \c addr is not
- *                  specified.
- *
- * @return
- *  - PJ_SUCCESS    If immediate data has been received. In this case, the 
- *		    callback must have been called before this function 
- *		    returns, and no pending operation is scheduled.
- *  - PJ_EPENDING   If the operation has been queued.
- *  - non-zero      The return value indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
-                                          pj_ioqueue_op_key_t *op_key,
-					  void *buffer,
-					  pj_ssize_t *length,
-                                          unsigned flags,
-					  pj_sockaddr_t *addr,
-					  int *addrlen);
-
-/**
- * Instruct the I/O Queue to write to the handle. This function will return
- * immediately (i.e. non-blocking) regardless whether some data has been 
- * transfered. If the function can't complete immediately, the caller will
- * be notified about the completion when it calls pj_ioqueue_poll(). If 
- * operation completes immediately and data has been transfered, the function
- * returns PJ_SUCCESS and the callback will NOT be called.
- *
- * @param key	    The key that identifies the handle.
- * @param op_key    An operation specific key to be associated with the
- *                  pending operation, so that application can keep track of
- *                  which operation has been completed when the callback is
- *                  called.
- * @param data	    The data to send. Caller MUST make sure that this buffer 
- *		    remains valid until the write operation completes.
- * @param length    On input, it specifies the length of data to send. When
- *                  data was sent immediately, this function returns PJ_SUCCESS
- *                  and this parameter contains the length of data sent. If
- *                  data can not be sent immediately, an asynchronous operation
- *                  is scheduled and caller will be notified via callback the
- *                  number of bytes sent. This parameter can point to local 
- *                  variable on caller's stack and doesn't have to remain 
- *                  valid until the operation has completed.
- * @param flags     Send flags.
- *
- * @return
- *  - PJ_SUCCESS    If data was immediately transfered. In this case, no
- *                  pending operation has been scheduled and the callback
- *                  WILL NOT be called.
- *  - PJ_EPENDING   If the operation has been queued. Once data base been
- *                  transfered, the callback will be called.
- *  - non-zero      The return value indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
-                                      pj_ioqueue_op_key_t *op_key,
-				      const void *data,
-				      pj_ssize_t *length,
-				      unsigned flags );
-
-
-/**
- * Instruct the I/O Queue to write to the handle. This function will return
- * immediately (i.e. non-blocking) regardless whether some data has been 
- * transfered. If the function can't complete immediately, the caller will
- * be notified about the completion when it calls pj_ioqueue_poll(). If 
- * operation completes immediately and data has been transfered, the function
- * returns PJ_SUCCESS and the callback will NOT be called.
- *
- * @param key	    the key that identifies the handle.
- * @param op_key    An operation specific key to be associated with the
- *                  pending operation, so that application can keep track of
- *                  which operation has been completed when the callback is
- *                  called.
- * @param data	    the data to send. Caller MUST make sure that this buffer 
- *		    remains valid until the write operation completes.
- * @param length    On input, it specifies the length of data to send. When
- *                  data was sent immediately, this function returns PJ_SUCCESS
- *                  and this parameter contains the length of data sent. If
- *                  data can not be sent immediately, an asynchronous operation
- *                  is scheduled and caller will be notified via callback the
- *                  number of bytes sent. This parameter can point to local 
- *                  variable on caller's stack and doesn't have to remain 
- *                  valid until the operation has completed.
- * @param flags     send flags.
- * @param addr      Optional remote address.
- * @param addrlen   Remote address length, \c addr is specified.
- *
- * @return
- *  - PJ_SUCCESS    If data was immediately written.
- *  - PJ_EPENDING   If the operation has been queued.
- *  - non-zero      The return value indicates the error code.
- */
-PJ_DECL(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
-                                        pj_ioqueue_op_key_t *op_key,
-					const void *data,
-					pj_ssize_t *length,
-                                        unsigned flags,
-					const pj_sockaddr_t *addr,
-					int addrlen);
-
-
-/**
- * !}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJ_IOQUEUE_H__ */
-
+

+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

+/**

+ * Instruct I/O Queue to accept incoming connection on the specified 

+ * listening socket. This function will return immediately (i.e. non-blocking)

+ * regardless whether a connection is immediately available. If the function

+ * can't complete immediately, the caller will be notified about the incoming

+ * connection when it calls pj_ioqueue_poll(). If a new connection is

+ * immediately available, the function returns PJ_SUCCESS with the new

+ * connection; in this case, the callback WILL NOT be called.

+ *

+ * @param key	    The key which registered to the server socket.

+ * @param op_key    An operation specific key to be associated with the

+ *                  pending operation, so that application can keep track of

+ *                  which operation has been completed when the callback is

+ *                  called.

+ * @param new_sock  Argument which contain pointer to receive the new socket

+ *                  for the incoming connection.

+ * @param local	    Optional argument which contain pointer to variable to 

+ *                  receive local address.

+ * @param remote    Optional argument which contain pointer to variable to 

+ *                  receive the remote address.

+ * @param addrlen   On input, contains the length of the buffer for the

+ *		    address, and on output, contains the actual length of the

+ *		    address. This argument is optional.

+ * @return

+ *  - PJ_SUCCESS    When connection is available immediately, and the 

+ *                  parameters will be updated to contain information about 

+ *                  the new connection. In this case, a completion callback

+ *                  WILL NOT be called.

+ *  - PJ_EPENDING   If no connection is available immediately. When a new

+ *                  connection arrives, the callback will be called.

+ *  - non-zero      which indicates the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,

+                                        pj_ioqueue_op_key_t *op_key,

+					pj_sock_t *sock,

+					pj_sockaddr_t *local,

+					pj_sockaddr_t *remote,

+					int *addrlen );

+

+/**

+ * Initiate non-blocking socket connect. If the socket can NOT be connected

+ * immediately, asynchronous connect() will be scheduled and caller will be

+ * notified via completion callback when it calls pj_ioqueue_poll(). If

+ * socket is connected immediately, the function returns PJ_SUCCESS and

+ * completion callback WILL NOT be called.

+ *

+ * @param key	    The key associated with TCP socket

+ * @param addr	    The remote address.

+ * @param addrlen   The remote address length.

+ *

+ * @return

+ *  - PJ_SUCCESS    If socket is connected immediately. In this case, the

+ *                  completion callback WILL NOT be called.

+ *  - PJ_EPENDING   If operation is queued, or 

+ *  - non-zero      Indicates the error code.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,

+					 const pj_sockaddr_t *addr,

+					 int addrlen );

+

+#endif	/* PJ_HAS_TCP */

+

+/**

+ * Poll the I/O Queue for completed events.

+ *

+ * @param ioque		the I/O Queue.

+ * @param timeout	polling timeout, or NULL if the thread wishes to wait

+ *			indefinetely for the event.

+ *

+ * @return 

+ *  - zero if timed out (no event).

+ *  - (<0) if error occured during polling. Callback will NOT be called.

+ *  - (>1) to indicate numbers of events. Callbacks have been called.

+ */

+PJ_DECL(int) pj_ioqueue_poll( pj_ioqueue_t *ioque,

+			      const pj_time_val *timeout);

+

+

+/**

+ * Instruct the I/O Queue to read from the specified handle. This function

+ * returns immediately (i.e. non-blocking) regardless whether some data has 

+ * been transfered. If the operation can't complete immediately, caller will 

+ * be notified about the completion when it calls pj_ioqueue_poll(). If data

+ * is immediately available, the function will return PJ_SUCCESS and the

+ * callback WILL NOT be called.

+ *

+ * @param key	    The key that uniquely identifies the handle.

+ * @param op_key    An operation specific key to be associated with the

+ *                  pending operation, so that application can keep track of

+ *                  which operation has been completed when the callback is

+ *                  called. Caller must make sure that this key remains 

+ *                  valid until the function completes.

+ * @param buffer    The buffer to hold the read data. The caller MUST make sure

+ *		    that this buffer remain valid until the framework completes

+ *		    reading the handle.

+ * @param length    On input, it specifies the size of the buffer. If data is

+ *                  available to be read immediately, the function returns

+ *                  PJ_SUCCESS and this argument will be filled with the

+ *                  amount of data read. If the function is pending, caller

+ *                  will be notified about the amount of data read in the

+ *                  callback. This parameter can point to local variable in

+ *                  caller's stack and doesn't have to remain valid for the

+ *                  duration of pending operation.

+ * @param flags     Recv flag.

+ *

+ * @return

+ *  - PJ_SUCCESS    If immediate data has been received in the buffer. In this

+ *                  case, the callback WILL NOT be called.

+ *  - PJ_EPENDING   If the operation has been queued, and the callback will be

+ *                  called when data has been received.

+ *  - non-zero      The return value indicates the error code.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_recv( pj_ioqueue_key_t *key,

+                                      pj_ioqueue_op_key_t *op_key,

+				      void *buffer,

+				      pj_ssize_t *length,

+				      unsigned flags );

+

+/**

+ * This function behaves similarly as #pj_ioqueue_recv(), except that it is

+ * normally called for socket, and the remote address will also be returned

+ * along with the data. Caller MUST make sure that both buffer and addr

+ * remain valid until the framework completes reading the data.

+ *

+ * @param key	    The key that uniquely identifies the handle.

+ * @param op_key    An operation specific key to be associated with the

+ *                  pending operation, so that application can keep track of

+ *                  which operation has been completed when the callback is

+ *                  called.

+ * @param buffer    The buffer to hold the read data. The caller MUST make sure

+ *		    that this buffer remain valid until the framework completes

+ *		    reading the handle.

+ * @param length    On input, it specifies the size of the buffer. If data is

+ *                  available to be read immediately, the function returns

+ *                  PJ_SUCCESS and this argument will be filled with the

+ *                  amount of data read. If the function is pending, caller

+ *                  will be notified about the amount of data read in the

+ *                  callback. This parameter can point to local variable in

+ *                  caller's stack and doesn't have to remain valid for the

+ *                  duration of pending operation.

+ * @param flags     Recv flag.

+ * @param addr      Optional Pointer to buffer to receive the address.

+ * @param addrlen   On input, specifies the length of the address buffer.

+ *                  On output, it will be filled with the actual length of

+ *                  the address. This argument can be NULL if \c addr is not

+ *                  specified.

+ *

+ * @return

+ *  - PJ_SUCCESS    If immediate data has been received. In this case, the 

+ *		    callback must have been called before this function 

+ *		    returns, and no pending operation is scheduled.

+ *  - PJ_EPENDING   If the operation has been queued.

+ *  - non-zero      The return value indicates the error code.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,

+                                          pj_ioqueue_op_key_t *op_key,

+					  void *buffer,

+					  pj_ssize_t *length,

+                                          unsigned flags,

+					  pj_sockaddr_t *addr,

+					  int *addrlen);

+

+/**

+ * Instruct the I/O Queue to write to the handle. This function will return

+ * immediately (i.e. non-blocking) regardless whether some data has been 

+ * transfered. If the function can't complete immediately, the caller will

+ * be notified about the completion when it calls pj_ioqueue_poll(). If 

+ * operation completes immediately and data has been transfered, the function

+ * returns PJ_SUCCESS and the callback will NOT be called.

+ *

+ * @param key	    The key that identifies the handle.

+ * @param op_key    An operation specific key to be associated with the

+ *                  pending operation, so that application can keep track of

+ *                  which operation has been completed when the callback is

+ *                  called.

+ * @param data	    The data to send. Caller MUST make sure that this buffer 

+ *		    remains valid until the write operation completes.

+ * @param length    On input, it specifies the length of data to send. When

+ *                  data was sent immediately, this function returns PJ_SUCCESS

+ *                  and this parameter contains the length of data sent. If

+ *                  data can not be sent immediately, an asynchronous operation

+ *                  is scheduled and caller will be notified via callback the

+ *                  number of bytes sent. This parameter can point to local 

+ *                  variable on caller's stack and doesn't have to remain 

+ *                  valid until the operation has completed.

+ * @param flags     Send flags.

+ *

+ * @return

+ *  - PJ_SUCCESS    If data was immediately transfered. In this case, no

+ *                  pending operation has been scheduled and the callback

+ *                  WILL NOT be called.

+ *  - PJ_EPENDING   If the operation has been queued. Once data base been

+ *                  transfered, the callback will be called.

+ *  - non-zero      The return value indicates the error code.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,

+                                      pj_ioqueue_op_key_t *op_key,

+				      const void *data,

+				      pj_ssize_t *length,

+				      unsigned flags );

+

+

+/**

+ * Instruct the I/O Queue to write to the handle. This function will return

+ * immediately (i.e. non-blocking) regardless whether some data has been 

+ * transfered. If the function can't complete immediately, the caller will

+ * be notified about the completion when it calls pj_ioqueue_poll(). If 

+ * operation completes immediately and data has been transfered, the function

+ * returns PJ_SUCCESS and the callback will NOT be called.

+ *

+ * @param key	    the key that identifies the handle.

+ * @param op_key    An operation specific key to be associated with the

+ *                  pending operation, so that application can keep track of

+ *                  which operation has been completed when the callback is

+ *                  called.

+ * @param data	    the data to send. Caller MUST make sure that this buffer 

+ *		    remains valid until the write operation completes.

+ * @param length    On input, it specifies the length of data to send. When

+ *                  data was sent immediately, this function returns PJ_SUCCESS

+ *                  and this parameter contains the length of data sent. If

+ *                  data can not be sent immediately, an asynchronous operation

+ *                  is scheduled and caller will be notified via callback the

+ *                  number of bytes sent. This parameter can point to local 

+ *                  variable on caller's stack and doesn't have to remain 

+ *                  valid until the operation has completed.

+ * @param flags     send flags.

+ * @param addr      Optional remote address.

+ * @param addrlen   Remote address length, \c addr is specified.

+ *

+ * @return

+ *  - PJ_SUCCESS    If data was immediately written.

+ *  - PJ_EPENDING   If the operation has been queued.

+ *  - non-zero      The return value indicates the error code.

+ */

+PJ_DECL(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,

+                                        pj_ioqueue_op_key_t *op_key,

+					const void *data,

+					pj_ssize_t *length,

+                                        unsigned flags,

+					const pj_sockaddr_t *addr,

+					int addrlen);

+

+

+/**

+ * !}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJ_IOQUEUE_H__ */

+

diff --git a/pjlib/include/pj/list.h b/pjlib/include/pj/list.h
index f6662eb..72dd009 100644
--- a/pjlib/include/pj/list.h
+++ b/pjlib/include/pj/list.h
@@ -1,222 +1,243 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_LIST_H__
-#define __PJ_LIST_H__
-
-/**
- * @file list.h
- * @brief Linked List data structure.
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/*
- * @defgroup PJ_DS Data Structure.
- * @ingroup PJ
- */
-
-/**
- * @defgroup PJ_LIST Linked List
- * @ingroup PJ_DS
- * @{
- *
- * List in PJLIB is implemented as doubly-linked list, and it won't require
- * dynamic memory allocation (just as all PJLIB data structures). The list here
- * should be viewed more like a low level C list instead of high level C++ list
- * (which normally are easier to use but require dynamic memory allocations),
- * therefore all caveats with C list apply here too (such as you can NOT put
- * a node in more than one lists).
- *
- * \section pj_list_example_sec Examples
- *
- * See below for examples on how to manipulate linked list:
- *  - @ref page_pjlib_samples_list_c
- *  - @ref page_pjlib_list_test
- */
-
-
-/**
- * Use this macro in the start of the structure declaration to declare that
- * the structure can be used in the linked list operation. This macro simply
- * declares additional member @a prev and @a next to the structure.
- * @hideinitializer
- */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_LIST_H__

+#define __PJ_LIST_H__

+

+/**

+ * @file list.h

+ * @brief Linked List data structure.

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/*

+ * @defgroup PJ_DS Data Structure.

+ * @ingroup PJ

+ */

+

+/**

+ * @defgroup PJ_LIST Linked List

+ * @ingroup PJ_DS

+ * @{

+ *

+ * List in PJLIB is implemented as doubly-linked list, and it won't require

+ * dynamic memory allocation (just as all PJLIB data structures). The list here

+ * should be viewed more like a low level C list instead of high level C++ list

+ * (which normally are easier to use but require dynamic memory allocations),

+ * therefore all caveats with C list apply here too (such as you can NOT put

+ * a node in more than one lists).

+ *

+ * \section pj_list_example_sec Examples

+ *

+ * See below for examples on how to manipulate linked list:

+ *  - @ref page_pjlib_samples_list_c

+ *  - @ref page_pjlib_list_test

+ */

+

+

+/**

+ * Use this macro in the start of the structure declaration to declare that

+ * the structure can be used in the linked list operation. This macro simply

+ * declares additional member @a prev and @a next to the structure.

+ * @hideinitializer

+ */

 #define PJ_DECL_LIST_MEMBER(type)                       \

                                    /** List @a prev. */ \

                                    type *prev;          \

-                                   /** List @a next. */ \
-                                   type *next 
-
-
-/**
- * This structure describes generic list node and list. The owner of this list
- * must initialize the 'value' member to an appropriate value (typically the
- * owner itself).
- */
-struct pj_list
-{
-    PJ_DECL_LIST_MEMBER(void);
-};
-
-
-/**
- * Initialize the list.
- * Initially, the list will have no member, and function pj_list_empty() will
- * always return nonzero (which indicates TRUE) for the newly initialized 
- * list.
- *
- * @param node The list head.
- */
-PJ_INLINE(void) pj_list_init(pj_list_type * node)
-{
-    ((pj_list*)node)->next = ((pj_list*)node)->prev = node;
-}
-
-
-/**
- * Check that the list is empty.
- *
- * @param node	The list head.
- *
- * @return Non-zero if the list is not-empty, or zero if it is empty.
- *
- */
-PJ_INLINE(int) pj_list_empty(const pj_list_type * node)
-{
-    return ((pj_list*)node)->next == node;
-}
-
-
-/**
- * Insert the node to the list before the specified element position.
- *
- * @param pos	The element to which the node will be inserted before. 
- * @param node	The element to be inserted.
- *
- * @return void.
- */
-PJ_IDECL(void)	pj_list_insert_before(pj_list_type *pos, pj_list_type *node);
-
-
-/**
- * Inserts all nodes in \a nodes to the target list.
- *
- * @param lst	    The target list.
- * @param nodes	    Nodes list.
- */
-PJ_IDECL(void) pj_list_insert_nodes_before(pj_list_type *lst,
-					   pj_list_type *nodes);
-
-/**
- * Insert a node to the list after the specified element position.
- *
- * @param pos	    The element in the list which will precede the inserted 
- *		    element.
- * @param node	    The element to be inserted after the position element.
- *
- * @return void.
- */
-PJ_IDECL(void) pj_list_insert_after(pj_list_type *pos, pj_list_type *node);
-
-/**
- * Insert all nodes in \a nodes to the target list.
- *
- * @param lst	    The target list.
- * @param nodes	    Nodes list.
- */
-PJ_IDECL(void) pj_list_insert_nodes_after(pj_list_type *lst,
-					  pj_list_type *nodes);
-
-
-/**
- * Remove elements from the source list, and insert them to the destination
- * list. The elements of the source list will occupy the
- * front elements of the target list. Note that the node pointed by \a list2
- * itself is not considered as a node, but rather as the list descriptor, so
- * it will not be inserted to the \a list1. The elements to be inserted starts
- * at \a list2->next. If \a list2 is to be included in the operation, use
- * \a pj_list_insert_nodes_before.
- *
- * @param list1	The destination list.
- * @param list2	The source list.
- *
- * @return void.
- */
-PJ_IDECL(void) pj_list_merge_first(pj_list_type *list1, pj_list_type *list2);
-
-
-/**
- * Remove elements from the second list argument, and insert them to the list 
- * in the first argument. The elements from the second list will be appended
- * to the first list. Note that the node pointed by \a list2
- * itself is not considered as a node, but rather as the list descriptor, so
- * it will not be inserted to the \a list1. The elements to be inserted starts
- * at \a list2->next. If \a list2 is to be included in the operation, use
- * \a pj_list_insert_nodes_before.
- *
- * @param list1	    The element in the list which will precede the inserted 
- *		    element.
- * @param list2	    The element in the list to be inserted.
- *
- * @return void.
- */
-PJ_IDECL(void) pj_list_merge_last( pj_list_type *list1, pj_list_type *list2);
-
-
-/**
- * Erase the node from the list it currently belongs.
- *
- * @param node	    The element to be erased.
- */
-PJ_IDECL(void) pj_list_erase(pj_list_type *node);
-
-
-/**
- * Find node in the list.
- *
- * @param list	    The list head.
- * @param node	    The node element to be searched.
- *
- * @return The node itself if it is found in the list, or NULL if it is not 
- *         found in the list.
- */
-PJ_IDECL(pj_list_type*) pj_list_find_node(pj_list_type *list, 
-					  pj_list_type *node);
-
-
-/**
- * Search the list for the specified value, using the specified comparison
- * function. This function iterates on nodes in the list, started with the
- * first node, and call the user supplied comparison function until the
- * comparison function returns ZERO.
- *
- * @param list	    The list head.
- * @param value	    The user defined value to be passed in the comparison 
- *		    function
- * @param comp	    The comparison function, which should return ZERO to 
- *		    indicate that the searched value is found.
- *
- * @return The first node that matched, or NULL if it is not found.
- */
-PJ_IDECL(pj_list_type*) pj_list_search(pj_list_type *list, void *value,
-				       int (*comp)(void *value, 
-						   const pj_list_type *node)
-				       );
-
-
-/**
- * @}
- */
-
-#if PJ_FUNCTIONS_ARE_INLINED
-#  include "list_i.h"
-#endif
-
-PJ_END_DECL
-
-#endif	/* __PJ_LIST_H__ */
-
+                                   /** List @a next. */ \

+                                   type *next 

+

+

+/**

+ * This structure describes generic list node and list. The owner of this list

+ * must initialize the 'value' member to an appropriate value (typically the

+ * owner itself).

+ */

+struct pj_list

+{

+    PJ_DECL_LIST_MEMBER(void);

+};

+

+

+/**

+ * Initialize the list.

+ * Initially, the list will have no member, and function pj_list_empty() will

+ * always return nonzero (which indicates TRUE) for the newly initialized 

+ * list.

+ *

+ * @param node The list head.

+ */

+PJ_INLINE(void) pj_list_init(pj_list_type * node)

+{

+    ((pj_list*)node)->next = ((pj_list*)node)->prev = node;

+}

+

+

+/**

+ * Check that the list is empty.

+ *

+ * @param node	The list head.

+ *

+ * @return Non-zero if the list is not-empty, or zero if it is empty.

+ *

+ */

+PJ_INLINE(int) pj_list_empty(const pj_list_type * node)

+{

+    return ((pj_list*)node)->next == node;

+}

+

+

+/**

+ * Insert the node to the list before the specified element position.

+ *

+ * @param pos	The element to which the node will be inserted before. 

+ * @param node	The element to be inserted.

+ *

+ * @return void.

+ */

+PJ_IDECL(void)	pj_list_insert_before(pj_list_type *pos, pj_list_type *node);

+

+

+/**

+ * Inserts all nodes in \a nodes to the target list.

+ *

+ * @param lst	    The target list.

+ * @param nodes	    Nodes list.

+ */

+PJ_IDECL(void) pj_list_insert_nodes_before(pj_list_type *lst,

+					   pj_list_type *nodes);

+

+/**

+ * Insert a node to the list after the specified element position.

+ *

+ * @param pos	    The element in the list which will precede the inserted 

+ *		    element.

+ * @param node	    The element to be inserted after the position element.

+ *

+ * @return void.

+ */

+PJ_IDECL(void) pj_list_insert_after(pj_list_type *pos, pj_list_type *node);

+

+/**

+ * Insert all nodes in \a nodes to the target list.

+ *

+ * @param lst	    The target list.

+ * @param nodes	    Nodes list.

+ */

+PJ_IDECL(void) pj_list_insert_nodes_after(pj_list_type *lst,

+					  pj_list_type *nodes);

+

+

+/**

+ * Remove elements from the source list, and insert them to the destination

+ * list. The elements of the source list will occupy the

+ * front elements of the target list. Note that the node pointed by \a list2

+ * itself is not considered as a node, but rather as the list descriptor, so

+ * it will not be inserted to the \a list1. The elements to be inserted starts

+ * at \a list2->next. If \a list2 is to be included in the operation, use

+ * \a pj_list_insert_nodes_before.

+ *

+ * @param list1	The destination list.

+ * @param list2	The source list.

+ *

+ * @return void.

+ */

+PJ_IDECL(void) pj_list_merge_first(pj_list_type *list1, pj_list_type *list2);

+

+

+/**

+ * Remove elements from the second list argument, and insert them to the list 

+ * in the first argument. The elements from the second list will be appended

+ * to the first list. Note that the node pointed by \a list2

+ * itself is not considered as a node, but rather as the list descriptor, so

+ * it will not be inserted to the \a list1. The elements to be inserted starts

+ * at \a list2->next. If \a list2 is to be included in the operation, use

+ * \a pj_list_insert_nodes_before.

+ *

+ * @param list1	    The element in the list which will precede the inserted 

+ *		    element.

+ * @param list2	    The element in the list to be inserted.

+ *

+ * @return void.

+ */

+PJ_IDECL(void) pj_list_merge_last( pj_list_type *list1, pj_list_type *list2);

+

+

+/**

+ * Erase the node from the list it currently belongs.

+ *

+ * @param node	    The element to be erased.

+ */

+PJ_IDECL(void) pj_list_erase(pj_list_type *node);

+

+

+/**

+ * Find node in the list.

+ *

+ * @param list	    The list head.

+ * @param node	    The node element to be searched.

+ *

+ * @return The node itself if it is found in the list, or NULL if it is not 

+ *         found in the list.

+ */

+PJ_IDECL(pj_list_type*) pj_list_find_node(pj_list_type *list, 

+					  pj_list_type *node);

+

+

+/**

+ * Search the list for the specified value, using the specified comparison

+ * function. This function iterates on nodes in the list, started with the

+ * first node, and call the user supplied comparison function until the

+ * comparison function returns ZERO.

+ *

+ * @param list	    The list head.

+ * @param value	    The user defined value to be passed in the comparison 

+ *		    function

+ * @param comp	    The comparison function, which should return ZERO to 

+ *		    indicate that the searched value is found.

+ *

+ * @return The first node that matched, or NULL if it is not found.

+ */

+PJ_IDECL(pj_list_type*) pj_list_search(pj_list_type *list, void *value,

+				       int (*comp)(void *value, 

+						   const pj_list_type *node)

+				       );

+

+

+/**

+ * @}

+ */

+

+#if PJ_FUNCTIONS_ARE_INLINED

+#  include "list_i.h"

+#endif

+

+PJ_END_DECL

+

+#endif	/* __PJ_LIST_H__ */

+

diff --git a/pjlib/include/pj/list_i.h b/pjlib/include/pj/list_i.h
index 9ca6e1d..4f2fd00 100644
--- a/pjlib/include/pj/list_i.h
+++ b/pjlib/include/pj/list_i.h
@@ -1,103 +1,124 @@
-/* $Id$
- *
- */
-
-
-/* Internal */
-PJ_IDEF(void) pj_link_node(pj_list_type *prev, pj_list_type *next)
-{
-    ((pj_list*)prev)->next = next;
-    ((pj_list*)next)->prev = prev;
-}
-
-/*
-PJ_IDEF(void) 
-pj_list_init(pj_list_type * node)
-{
-    ((pj_list*)node)->next = ((pj_list*)node)->prev = node;
-}
-
-PJ_IDEF(int) pj_list_empty(const pj_list_type * node)
-{
-    return ((pj_list*)node)->next == node;
-}
-*/
-
-PJ_IDEF(void) 
-pj_list_insert_after(pj_list_type *pos, pj_list_type *node)
-{
-    ((pj_list*)node)->prev = pos;
-    ((pj_list*)node)->next = ((pj_list*)pos)->next;
-    ((pj_list*) ((pj_list*)pos)->next) ->prev = node;
-    ((pj_list*)pos)->next = node;
-}
-
-
-PJ_IDEF(void) 
-pj_list_insert_before(pj_list_type *pos, pj_list_type *node)
-{
-    pj_list_insert_after(((pj_list*)pos)->prev, node);
-}
-
-
-PJ_IDEF(void)	    
-pj_list_insert_nodes_after(pj_list_type *pos, pj_list_type *lst)
-{
-    pj_list *lst_last = (pj_list *) ((pj_list*)lst)->prev;
-    pj_list *pos_next = (pj_list *) ((pj_list*)pos)->next;
-
-    pj_link_node(pos, lst);
-    pj_link_node(lst_last, pos_next);
-}
-
-PJ_IDEF(void) 
-pj_list_insert_nodes_before(pj_list_type *pos, pj_list_type *lst)
-{
-    pj_list_insert_nodes_after(((pj_list*)pos)->prev, lst);
-}
-
-PJ_IDEF(void)
-pj_list_merge_last(pj_list_type *lst1, pj_list_type *lst2)
-{
-    pj_link_node(((pj_list*)lst1)->prev, ((pj_list*)lst2)->next);
-    pj_link_node(((pj_list*)lst2)->prev, lst1);
-    pj_list_init(lst2);
-}
-
-PJ_IDEF(void)
-pj_list_merge_first(pj_list_type *lst1, pj_list_type *lst2)
-{
-    pj_link_node(((pj_list*)lst2)->prev, ((pj_list*)lst1)->next);
-    pj_link_node(((pj_list*)lst1), ((pj_list*)lst2)->next);
-    pj_list_init(lst2);
-}
-
-PJ_IDEF(void) 
-pj_list_erase(pj_list_type *node)
-{
-    pj_link_node( ((pj_list*)node)->prev, ((pj_list*)node)->next);
-}
-
-
-PJ_IDEF(pj_list_type*) 
-pj_list_find_node(pj_list_type *list, pj_list_type *node)
-{
-    pj_list *p = (pj_list *) ((pj_list*)list)->next;
-    while (p != list && p != node)
-	p = (pj_list *) p->next;
-
-    return p==node ? p : NULL;
-}
-
-
-PJ_IDEF(pj_list_type*) 
-pj_list_search(pj_list_type *list, void *value,
-	       int (*comp)(void *value, const pj_list_type *node))
-{
-    pj_list *p = (pj_list *) ((pj_list*)list)->next;
-    while (p != list && (*comp)(value, p) != 0)
-	p = (pj_list *) p->next;
-
-    return p==list ? NULL : p;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+

+/* Internal */

+PJ_IDEF(void) pj_link_node(pj_list_type *prev, pj_list_type *next)

+{

+    ((pj_list*)prev)->next = next;

+    ((pj_list*)next)->prev = prev;

+}

+

+/*

+PJ_IDEF(void) 

+pj_list_init(pj_list_type * node)

+{

+    ((pj_list*)node)->next = ((pj_list*)node)->prev = node;

+}

+

+PJ_IDEF(int) pj_list_empty(const pj_list_type * node)

+{

+    return ((pj_list*)node)->next == node;

+}

+*/

+

+PJ_IDEF(void) 

+pj_list_insert_after(pj_list_type *pos, pj_list_type *node)

+{

+    ((pj_list*)node)->prev = pos;

+    ((pj_list*)node)->next = ((pj_list*)pos)->next;

+    ((pj_list*) ((pj_list*)pos)->next) ->prev = node;

+    ((pj_list*)pos)->next = node;

+}

+

+

+PJ_IDEF(void) 

+pj_list_insert_before(pj_list_type *pos, pj_list_type *node)

+{

+    pj_list_insert_after(((pj_list*)pos)->prev, node);

+}

+

+

+PJ_IDEF(void)	    

+pj_list_insert_nodes_after(pj_list_type *pos, pj_list_type *lst)

+{

+    pj_list *lst_last = (pj_list *) ((pj_list*)lst)->prev;

+    pj_list *pos_next = (pj_list *) ((pj_list*)pos)->next;

+

+    pj_link_node(pos, lst);

+    pj_link_node(lst_last, pos_next);

+}

+

+PJ_IDEF(void) 

+pj_list_insert_nodes_before(pj_list_type *pos, pj_list_type *lst)

+{

+    pj_list_insert_nodes_after(((pj_list*)pos)->prev, lst);

+}

+

+PJ_IDEF(void)

+pj_list_merge_last(pj_list_type *lst1, pj_list_type *lst2)

+{

+    pj_link_node(((pj_list*)lst1)->prev, ((pj_list*)lst2)->next);

+    pj_link_node(((pj_list*)lst2)->prev, lst1);

+    pj_list_init(lst2);

+}

+

+PJ_IDEF(void)

+pj_list_merge_first(pj_list_type *lst1, pj_list_type *lst2)

+{

+    pj_link_node(((pj_list*)lst2)->prev, ((pj_list*)lst1)->next);

+    pj_link_node(((pj_list*)lst1), ((pj_list*)lst2)->next);

+    pj_list_init(lst2);

+}

+

+PJ_IDEF(void) 

+pj_list_erase(pj_list_type *node)

+{

+    pj_link_node( ((pj_list*)node)->prev, ((pj_list*)node)->next);

+}

+

+

+PJ_IDEF(pj_list_type*) 

+pj_list_find_node(pj_list_type *list, pj_list_type *node)

+{

+    pj_list *p = (pj_list *) ((pj_list*)list)->next;

+    while (p != list && p != node)

+	p = (pj_list *) p->next;

+

+    return p==node ? p : NULL;

+}

+

+

+PJ_IDEF(pj_list_type*) 

+pj_list_search(pj_list_type *list, void *value,

+	       int (*comp)(void *value, const pj_list_type *node))

+{

+    pj_list *p = (pj_list *) ((pj_list*)list)->next;

+    while (p != list && (*comp)(value, p) != 0)

+	p = (pj_list *) p->next;

+

+    return p==list ? NULL : p;

+}

+

diff --git a/pjlib/include/pj/lock.h b/pjlib/include/pj/lock.h
index 8c29204..e15eaf6 100644
--- a/pjlib/include/pj/lock.h
+++ b/pjlib/include/pj/lock.h
@@ -1,138 +1,159 @@
-/* $Id$
- *
- */
-#ifndef __PJ_LOCK_H__
-#define __PJ_LOCK_H__
-
-/**
- * @file lock.h
- * @brief Higher abstraction for locking objects.
- */
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_LOCK Lock Objects
- * @ingroup PJ_OS
- * @{
- *
- * <b>Lock Objects</b> are higher abstraction for different lock mechanisms.
- * It offers the same API for manipulating different lock types (e.g.
- * @ref PJ_MUTEX "mutex", @ref PJ_SEM "semaphores", or null locks).
- * Because Lock Objects have the same API for different types of lock
- * implementation, it can be passed around in function arguments. As the
- * result, it can be used to control locking policy for  a particular
- * feature.
- */
-
-
-/**
- * Create simple, non recursive mutex lock object.
- *
- * @param pool	    Memory pool.
- * @param name	    Lock object's name.
- * @param lock	    Pointer to store the returned handle.
- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,
-						  const char *name,
-						  pj_lock_t **lock );
-
-/**
- * Create recursive mutex lock object.
- *
- * @param pool	    Memory pool.
- * @param name	    Lock object's name.
- * @param lock	    Pointer to store the returned handle.
- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,
-						     const char *name,
-						     pj_lock_t **lock );
-
-
-/**
- * Create NULL mutex. A NULL mutex doesn't actually have any synchronization
- * object attached to it.
- *
- * @param pool	    Memory pool.
- * @param name	    Lock object's name.
- * @param lock	    Pointer to store the returned handle.
- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,
-						const char *name,
-						pj_lock_t **lock );
-
-
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-/**
- * Create semaphore lock object.
- *
- * @param pool	    Memory pool.
- * @param name	    Lock object's name.
- * @param initial   Initial value of the semaphore.
- * @param max	    Maximum value of the semaphore.
- * @param lock	    Pointer to store the returned handle.
- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool,
-					       const char *name,
-					       unsigned initial,
-					       unsigned max,
-					       pj_lock_t **lock );
-
-#endif	/* PJ_HAS_SEMAPHORE */
-
-/**
- * Acquire lock on the specified lock object.
- *
- * @param lock	    The lock object.
- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_lock_acquire( pj_lock_t *lock );
-
-
-/**
- * Try to acquire lock on the specified lock object.
- *
- * @param lock	    The lock object.
- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock );
-
-
-/**
- * Release lock on the specified lock object.
- *
- * @param lock	    The lock object.
- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_lock_release( pj_lock_t *lock );
-
-
-/**
- * Destroy the lock object.
- *
- * @param lock	    The lock object.
- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_lock_destroy( pj_lock_t *lock );
-
-
-/** @} */
-
-PJ_END_DECL
-
-
-#endif	/* __PJ_LOCK_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJ_LOCK_H__

+#define __PJ_LOCK_H__

+

+/**

+ * @file lock.h

+ * @brief Higher abstraction for locking objects.

+ */

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_LOCK Lock Objects

+ * @ingroup PJ_OS

+ * @{

+ *

+ * <b>Lock Objects</b> are higher abstraction for different lock mechanisms.

+ * It offers the same API for manipulating different lock types (e.g.

+ * @ref PJ_MUTEX "mutex", @ref PJ_SEM "semaphores", or null locks).

+ * Because Lock Objects have the same API for different types of lock

+ * implementation, it can be passed around in function arguments. As the

+ * result, it can be used to control locking policy for  a particular

+ * feature.

+ */

+

+

+/**

+ * Create simple, non recursive mutex lock object.

+ *

+ * @param pool	    Memory pool.

+ * @param name	    Lock object's name.

+ * @param lock	    Pointer to store the returned handle.

+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,

+						  const char *name,

+						  pj_lock_t **lock );

+

+/**

+ * Create recursive mutex lock object.

+ *

+ * @param pool	    Memory pool.

+ * @param name	    Lock object's name.

+ * @param lock	    Pointer to store the returned handle.

+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,

+						     const char *name,

+						     pj_lock_t **lock );

+

+

+/**

+ * Create NULL mutex. A NULL mutex doesn't actually have any synchronization

+ * object attached to it.

+ *

+ * @param pool	    Memory pool.

+ * @param name	    Lock object's name.

+ * @param lock	    Pointer to store the returned handle.

+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,

+						const char *name,

+						pj_lock_t **lock );

+

+

+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

+/**

+ * Create semaphore lock object.

+ *

+ * @param pool	    Memory pool.

+ * @param name	    Lock object's name.

+ * @param initial   Initial value of the semaphore.

+ * @param max	    Maximum value of the semaphore.

+ * @param lock	    Pointer to store the returned handle.

+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_lock_create_semaphore( pj_pool_t *pool,

+					       const char *name,

+					       unsigned initial,

+					       unsigned max,

+					       pj_lock_t **lock );

+

+#endif	/* PJ_HAS_SEMAPHORE */

+

+/**

+ * Acquire lock on the specified lock object.

+ *

+ * @param lock	    The lock object.

+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_lock_acquire( pj_lock_t *lock );

+

+

+/**

+ * Try to acquire lock on the specified lock object.

+ *

+ * @param lock	    The lock object.

+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock );

+

+

+/**

+ * Release lock on the specified lock object.

+ *

+ * @param lock	    The lock object.

+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_lock_release( pj_lock_t *lock );

+

+

+/**

+ * Destroy the lock object.

+ *

+ * @param lock	    The lock object.

+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_lock_destroy( pj_lock_t *lock );

+

+

+/** @} */

+

+PJ_END_DECL

+

+

+#endif	/* __PJ_LOCK_H__ */

+

diff --git a/pjlib/include/pj/log.h b/pjlib/include/pj/log.h
index 5dfe17c..6e89d72 100644
--- a/pjlib/include/pj/log.h
+++ b/pjlib/include/pj/log.h
@@ -1,306 +1,327 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_LOG_H__
-#define __PJ_LOG_H__
-
-/**
- * @file log.h
- * @brief Logging Utility.
- */
-
-#include <pj/types.h>
-
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_MISC Miscelaneous
- * @ingroup PJ
- */
-
-/**
- * @defgroup PJ_LOG Logging Facility
- * @ingroup PJ_MISC
- * @{
- *
- * The PJLIB logging facility is a configurable, flexible, and convenient
- * way to write logging or trace information.
- *
- * To write to the log, one uses construct like below:
- *
- * <pre>
- *   ...
- *   PJ_LOG(3, ("main.c", "Starting hello..."));
- *   ...
- *   PJ_LOG(3, ("main.c", "Hello world from process %d", pj_getpid()));
- *   ...
- * </pre>
- *
- * In the above example, the number @b 3 controls the verbosity level of
- * the information (which means "information", by convention). The string
- * "main.c" specifies the source or sender of the message.
- *
- *
- * \section pj_log_quick_sample_sec Examples
- *
- * For examples, see:
- *  - @ref page_pjlib_samples_log_c.
- *
- */
-
-/**
- * Log decoration flag, to be specified with #pj_log_set_decor().
- */
-enum pj_log_decoration
-{
-    PJ_LOG_HAS_DAY_NAME   =   1, /**< Include day name [default: no].	     */
-    PJ_LOG_HAS_YEAR       =   2, /**< Include year digit [default: no]	     */
-    PJ_LOG_HAS_MONTH	  =   4, /**< Include month [default: no]	     */
-    PJ_LOG_HAS_DAY_OF_MON =   8, /**< Include day of month [default: no]     */
-    PJ_LOG_HAS_TIME	  =  16, /**< Include time [default: yes].	     */
-    PJ_LOG_HAS_MICRO_SEC  =  32, /**< Include microseconds [yes]             */
-    PJ_LOG_HAS_SENDER	  =  64, /**< Include sender in the log [yes].	     */
-    PJ_LOG_HAS_NEWLINE	  = 128, /**< Terminate each call with newline [yes].*/
-};
-
-/**
- * Write log message.
- * This is the main macro used to write text to the logging backend. 
- *
- * @param level	    The logging verbosity level. Lower number indicates higher
- *		    importance, with level zero indicates fatal error. Only
- *		    numeral argument is permitted (e.g. not variable).
- * @param arg	    Enclosed 'printf' like arguments, with the first 
- *		    argument is the sender, the second argument is format 
- *		    string and the following arguments are variable number of 
- *		    arguments suitable for the format string.
- *
- * Sample:
- * \verbatim
-   PJ_LOG(2, (__FILE__, "current value is %d", value));
-   \endverbatim
- * @hideinitializer
- */
-#define PJ_LOG(level,arg)	pj_log_wrapper_##level(arg)
-
-/**
- * Signature for function to be registered to the logging subsystem to
- * write the actual log message to some output device.
- *
- * @param level	    Log level.
- * @param data	    Log message.
- * @param len	    Message length.
- */
-typedef void pj_log_func(int level, const char *data, int len);
-
-/**
- * Default logging writer function used by front end logger function.
- * Application normally should NOT need to call this function, but
- * rather use the PJ_LOG macro.
- *
- * @param level	    Log level.
- * @param buffer    Log message.
- * @param len	    Message length.
- */
-PJ_DECL(void) pj_log_write(int level, const char *buffer, int len);
-
-
-#if PJ_LOG_MAX_LEVEL >= 1
-
-/**
- * Change log output function. The front-end logging functions will call
- * this function to write the actual message to the desired device. 
- * By default, the front-end functions use pj_log_write() to write
- * the messages, unless it's changed by calling this function.
- *
- * @param func	    The function that will be called to write the log
- *		    messages to the desired device.
- */
-PJ_DECL(void) pj_log_set_log_func( pj_log_func *func );
-
-/**
- * Get the current log output function that is used to write log messages.
- *
- * @return	    Current log output function.
- */
-PJ_DECL(pj_log_func*) pj_log_get_log_func(void);
-
-/**
- * Set maximum log level. Application can call this function to set 
- * the desired level of verbosity of the logging messages. The bigger the
- * value, the more verbose the logging messages will be printed. However,
- * the maximum level of verbosity can not exceed compile time value of
- * PJ_LOG_MAX_LEVEL.
- *
- * @param level	    The maximum level of verbosity of the logging
- *		    messages (6=very detailed..1=error only, 0=disabled)
- */
-PJ_DECL(void) pj_log_set_level(int level);
-
-/**
- * Get current maximum log verbositylevel.
- *
- * @return	    Current log maximum level.
- */
-PJ_DECL(int) pj_log_get_level(void);
-
-/**
- * Set log decoration. The log decoration flag controls what are printed
- * to output device alongside the actual message. For example, application
- * can specify that date/time information should be displayed with each
- * log message.
- *
- * @param decor	    Bitmask combination of #pj_log_decoration to control
- *		    the layout of the log message.
- */
-PJ_DECL(void) pj_log_set_decor(unsigned decor);
-
-/**
- * Get current log decoration flag.
- *
- * @return	    Log decoration flag.
- */
-PJ_DECL(unsigned) pj_log_get_decor(void);
-
-
-#else	/* #if PJ_LOG_MAX_LEVEL >= 1 */
-
-/**
- * Change log output function. The front-end logging functions will call
- * this function to write the actual message to the desired device. 
- * By default, the front-end functions use pj_log_write() to write
- * the messages, unless it's changed by calling this function.
- *
- * @param func	    The function that will be called to write the log
- *		    messages to the desired device.
- */
-#  define pj_log_set_log_func(func)
-
-/**
- * Set maximum log level. Application can call this function to set 
- * the desired level of verbosity of the logging messages. The bigger the
- * value, the more verbose the logging messages will be printed. However,
- * the maximum level of verbosity can not exceed compile time value of
- * PJ_LOG_MAX_LEVEL.
- *
- * @param level	    The maximum level of verbosity of the logging
- *		    messages (6=very detailed..1=error only, 0=disabled)
- */
-#  define pj_log_set_level(level)
-
-/**
- * Set log decoration. The log decoration flag controls what are printed
- * to output device alongside the actual message. For example, application
- * can specify that date/time information should be displayed with each
- * log message.
- *
- * @param decor	    Bitmask combination of #pj_log_decoration to control
- *		    the layout of the log message.
- */
-#  define pj_log_set_decor(decor)
-
-#endif	/* #if PJ_LOG_MAX_LEVEL >= 1 */
-
-/** 
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Log functions implementation prototypes.
- * These functions are called by PJ_LOG macros according to verbosity
- * level specified when calling the macro. Applications should not normally
- * need to call these functions directly.
- */
-
-/**
- * @def pj_log_wrapper_1(arg)
- * Internal function to write log with verbosity 1. Will evaluate to
- * empty expression if PJ_LOG_MAX_LEVEL is below 1.
- * @param arg       Log expression.
- */
-#if PJ_LOG_MAX_LEVEL >= 1
-    #define pj_log_wrapper_1(arg)	pj_log_1 arg
-    /** Internal function. */
-    PJ_DECL(void) pj_log_1(const char *src, const char *format, ...);
-#else
-    #define pj_log_wrapper_1(arg)
-#endif
-
-/**
- * @def pj_log_wrapper_2(arg)
- * Internal function to write log with verbosity 2. Will evaluate to
- * empty expression if PJ_LOG_MAX_LEVEL is below 2.
- * @param arg       Log expression.
- */
-#if PJ_LOG_MAX_LEVEL >= 2
-    #define pj_log_wrapper_2(arg)	pj_log_2 arg
-    /** Internal function. */
-    PJ_DECL(void) pj_log_2(const char *src, const char *format, ...);
-#else
-    #define pj_log_wrapper_2(arg)
-#endif
-
-/**
- * @def pj_log_wrapper_3(arg)
- * Internal function to write log with verbosity 3. Will evaluate to
- * empty expression if PJ_LOG_MAX_LEVEL is below 3.
- * @param arg       Log expression.
- */
-#if PJ_LOG_MAX_LEVEL >= 3
-    #define pj_log_wrapper_3(arg)	pj_log_3 arg
-    /** Internal function. */
-    PJ_DECL(void) pj_log_3(const char *src, const char *format, ...);
-#else
-    #define pj_log_wrapper_3(arg)
-#endif
-
-/**
- * @def pj_log_wrapper_4(arg)
- * Internal function to write log with verbosity 4. Will evaluate to
- * empty expression if PJ_LOG_MAX_LEVEL is below 4.
- * @param arg       Log expression.
- */
-#if PJ_LOG_MAX_LEVEL >= 4
-    #define pj_log_wrapper_4(arg)	pj_log_4 arg
-    /** Internal function. */
-    PJ_DECL(void) pj_log_4(const char *src, const char *format, ...);
-#else
-    #define pj_log_wrapper_4(arg)
-#endif
-
-/**
- * @def pj_log_wrapper_5(arg)
- * Internal function to write log with verbosity 5. Will evaluate to
- * empty expression if PJ_LOG_MAX_LEVEL is below 5.
- * @param arg       Log expression.
- */
-#if PJ_LOG_MAX_LEVEL >= 5
-    #define pj_log_wrapper_5(arg)	pj_log_5 arg
-    /** Internal function. */
-    PJ_DECL(void) pj_log_5(const char *src, const char *format, ...);
-#else
-    #define pj_log_wrapper_5(arg)
-#endif
-
-/**
- * @def pj_log_wrapper_6(arg)
- * Internal function to write log with verbosity 6. Will evaluate to
- * empty expression if PJ_LOG_MAX_LEVEL is below 6.
- * @param arg       Log expression.
- */
-#if PJ_LOG_MAX_LEVEL >= 6
-    #define pj_log_wrapper_6(arg)	pj_log_6 arg
-    /** Internal function. */
-    PJ_DECL(void) pj_log_6(const char *src, const char *format, ...);
-#else
-    #define pj_log_wrapper_6(arg)
-#endif
-
-
-PJ_END_DECL 
-
-#endif  /* __PJ_LOG_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_LOG_H__

+#define __PJ_LOG_H__

+

+/**

+ * @file log.h

+ * @brief Logging Utility.

+ */

+

+#include <pj/types.h>

+

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_MISC Miscelaneous

+ * @ingroup PJ

+ */

+

+/**

+ * @defgroup PJ_LOG Logging Facility

+ * @ingroup PJ_MISC

+ * @{

+ *

+ * The PJLIB logging facility is a configurable, flexible, and convenient

+ * way to write logging or trace information.

+ *

+ * To write to the log, one uses construct like below:

+ *

+ * <pre>

+ *   ...

+ *   PJ_LOG(3, ("main.c", "Starting hello..."));

+ *   ...

+ *   PJ_LOG(3, ("main.c", "Hello world from process %d", pj_getpid()));

+ *   ...

+ * </pre>

+ *

+ * In the above example, the number @b 3 controls the verbosity level of

+ * the information (which means "information", by convention). The string

+ * "main.c" specifies the source or sender of the message.

+ *

+ *

+ * \section pj_log_quick_sample_sec Examples

+ *

+ * For examples, see:

+ *  - @ref page_pjlib_samples_log_c.

+ *

+ */

+

+/**

+ * Log decoration flag, to be specified with #pj_log_set_decor().

+ */

+enum pj_log_decoration

+{

+    PJ_LOG_HAS_DAY_NAME   =   1, /**< Include day name [default: no].	     */

+    PJ_LOG_HAS_YEAR       =   2, /**< Include year digit [default: no]	     */

+    PJ_LOG_HAS_MONTH	  =   4, /**< Include month [default: no]	     */

+    PJ_LOG_HAS_DAY_OF_MON =   8, /**< Include day of month [default: no]     */

+    PJ_LOG_HAS_TIME	  =  16, /**< Include time [default: yes].	     */

+    PJ_LOG_HAS_MICRO_SEC  =  32, /**< Include microseconds [yes]             */

+    PJ_LOG_HAS_SENDER	  =  64, /**< Include sender in the log [yes].	     */

+    PJ_LOG_HAS_NEWLINE	  = 128, /**< Terminate each call with newline [yes].*/

+};

+

+/**

+ * Write log message.

+ * This is the main macro used to write text to the logging backend. 

+ *

+ * @param level	    The logging verbosity level. Lower number indicates higher

+ *		    importance, with level zero indicates fatal error. Only

+ *		    numeral argument is permitted (e.g. not variable).

+ * @param arg	    Enclosed 'printf' like arguments, with the first 

+ *		    argument is the sender, the second argument is format 

+ *		    string and the following arguments are variable number of 

+ *		    arguments suitable for the format string.

+ *

+ * Sample:

+ * \verbatim

+   PJ_LOG(2, (__FILE__, "current value is %d", value));

+   \endverbatim

+ * @hideinitializer

+ */

+#define PJ_LOG(level,arg)	pj_log_wrapper_##level(arg)

+

+/**

+ * Signature for function to be registered to the logging subsystem to

+ * write the actual log message to some output device.

+ *

+ * @param level	    Log level.

+ * @param data	    Log message.

+ * @param len	    Message length.

+ */

+typedef void pj_log_func(int level, const char *data, int len);

+

+/**

+ * Default logging writer function used by front end logger function.

+ * Application normally should NOT need to call this function, but

+ * rather use the PJ_LOG macro.

+ *

+ * @param level	    Log level.

+ * @param buffer    Log message.

+ * @param len	    Message length.

+ */

+PJ_DECL(void) pj_log_write(int level, const char *buffer, int len);

+

+

+#if PJ_LOG_MAX_LEVEL >= 1

+

+/**

+ * Change log output function. The front-end logging functions will call

+ * this function to write the actual message to the desired device. 

+ * By default, the front-end functions use pj_log_write() to write

+ * the messages, unless it's changed by calling this function.

+ *

+ * @param func	    The function that will be called to write the log

+ *		    messages to the desired device.

+ */

+PJ_DECL(void) pj_log_set_log_func( pj_log_func *func );

+

+/**

+ * Get the current log output function that is used to write log messages.

+ *

+ * @return	    Current log output function.

+ */

+PJ_DECL(pj_log_func*) pj_log_get_log_func(void);

+

+/**

+ * Set maximum log level. Application can call this function to set 

+ * the desired level of verbosity of the logging messages. The bigger the

+ * value, the more verbose the logging messages will be printed. However,

+ * the maximum level of verbosity can not exceed compile time value of

+ * PJ_LOG_MAX_LEVEL.

+ *

+ * @param level	    The maximum level of verbosity of the logging

+ *		    messages (6=very detailed..1=error only, 0=disabled)

+ */

+PJ_DECL(void) pj_log_set_level(int level);

+

+/**

+ * Get current maximum log verbositylevel.

+ *

+ * @return	    Current log maximum level.

+ */

+PJ_DECL(int) pj_log_get_level(void);

+

+/**

+ * Set log decoration. The log decoration flag controls what are printed

+ * to output device alongside the actual message. For example, application

+ * can specify that date/time information should be displayed with each

+ * log message.

+ *

+ * @param decor	    Bitmask combination of #pj_log_decoration to control

+ *		    the layout of the log message.

+ */

+PJ_DECL(void) pj_log_set_decor(unsigned decor);

+

+/**

+ * Get current log decoration flag.

+ *

+ * @return	    Log decoration flag.

+ */

+PJ_DECL(unsigned) pj_log_get_decor(void);

+

+

+#else	/* #if PJ_LOG_MAX_LEVEL >= 1 */

+

+/**

+ * Change log output function. The front-end logging functions will call

+ * this function to write the actual message to the desired device. 

+ * By default, the front-end functions use pj_log_write() to write

+ * the messages, unless it's changed by calling this function.

+ *

+ * @param func	    The function that will be called to write the log

+ *		    messages to the desired device.

+ */

+#  define pj_log_set_log_func(func)

+

+/**

+ * Set maximum log level. Application can call this function to set 

+ * the desired level of verbosity of the logging messages. The bigger the

+ * value, the more verbose the logging messages will be printed. However,

+ * the maximum level of verbosity can not exceed compile time value of

+ * PJ_LOG_MAX_LEVEL.

+ *

+ * @param level	    The maximum level of verbosity of the logging

+ *		    messages (6=very detailed..1=error only, 0=disabled)

+ */

+#  define pj_log_set_level(level)

+

+/**

+ * Set log decoration. The log decoration flag controls what are printed

+ * to output device alongside the actual message. For example, application

+ * can specify that date/time information should be displayed with each

+ * log message.

+ *

+ * @param decor	    Bitmask combination of #pj_log_decoration to control

+ *		    the layout of the log message.

+ */

+#  define pj_log_set_decor(decor)

+

+#endif	/* #if PJ_LOG_MAX_LEVEL >= 1 */

+

+/** 

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Log functions implementation prototypes.

+ * These functions are called by PJ_LOG macros according to verbosity

+ * level specified when calling the macro. Applications should not normally

+ * need to call these functions directly.

+ */

+

+/**

+ * @def pj_log_wrapper_1(arg)

+ * Internal function to write log with verbosity 1. Will evaluate to

+ * empty expression if PJ_LOG_MAX_LEVEL is below 1.

+ * @param arg       Log expression.

+ */

+#if PJ_LOG_MAX_LEVEL >= 1

+    #define pj_log_wrapper_1(arg)	pj_log_1 arg

+    /** Internal function. */

+    PJ_DECL(void) pj_log_1(const char *src, const char *format, ...);

+#else

+    #define pj_log_wrapper_1(arg)

+#endif

+

+/**

+ * @def pj_log_wrapper_2(arg)

+ * Internal function to write log with verbosity 2. Will evaluate to

+ * empty expression if PJ_LOG_MAX_LEVEL is below 2.

+ * @param arg       Log expression.

+ */

+#if PJ_LOG_MAX_LEVEL >= 2

+    #define pj_log_wrapper_2(arg)	pj_log_2 arg

+    /** Internal function. */

+    PJ_DECL(void) pj_log_2(const char *src, const char *format, ...);

+#else

+    #define pj_log_wrapper_2(arg)

+#endif

+

+/**

+ * @def pj_log_wrapper_3(arg)

+ * Internal function to write log with verbosity 3. Will evaluate to

+ * empty expression if PJ_LOG_MAX_LEVEL is below 3.

+ * @param arg       Log expression.

+ */

+#if PJ_LOG_MAX_LEVEL >= 3

+    #define pj_log_wrapper_3(arg)	pj_log_3 arg

+    /** Internal function. */

+    PJ_DECL(void) pj_log_3(const char *src, const char *format, ...);

+#else

+    #define pj_log_wrapper_3(arg)

+#endif

+

+/**

+ * @def pj_log_wrapper_4(arg)

+ * Internal function to write log with verbosity 4. Will evaluate to

+ * empty expression if PJ_LOG_MAX_LEVEL is below 4.

+ * @param arg       Log expression.

+ */

+#if PJ_LOG_MAX_LEVEL >= 4

+    #define pj_log_wrapper_4(arg)	pj_log_4 arg

+    /** Internal function. */

+    PJ_DECL(void) pj_log_4(const char *src, const char *format, ...);

+#else

+    #define pj_log_wrapper_4(arg)

+#endif

+

+/**

+ * @def pj_log_wrapper_5(arg)

+ * Internal function to write log with verbosity 5. Will evaluate to

+ * empty expression if PJ_LOG_MAX_LEVEL is below 5.

+ * @param arg       Log expression.

+ */

+#if PJ_LOG_MAX_LEVEL >= 5

+    #define pj_log_wrapper_5(arg)	pj_log_5 arg

+    /** Internal function. */

+    PJ_DECL(void) pj_log_5(const char *src, const char *format, ...);

+#else

+    #define pj_log_wrapper_5(arg)

+#endif

+

+/**

+ * @def pj_log_wrapper_6(arg)

+ * Internal function to write log with verbosity 6. Will evaluate to

+ * empty expression if PJ_LOG_MAX_LEVEL is below 6.

+ * @param arg       Log expression.

+ */

+#if PJ_LOG_MAX_LEVEL >= 6

+    #define pj_log_wrapper_6(arg)	pj_log_6 arg

+    /** Internal function. */

+    PJ_DECL(void) pj_log_6(const char *src, const char *format, ...);

+#else

+    #define pj_log_wrapper_6(arg)

+#endif

+

+

+PJ_END_DECL 

+

+#endif  /* __PJ_LOG_H__ */

+

diff --git a/pjlib/include/pj/os.h b/pjlib/include/pj/os.h
index a1fef6b..5e24450 100644
--- a/pjlib/include/pj/os.h
+++ b/pjlib/include/pj/os.h
@@ -1,329 +1,350 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_OS_H__
-#define __PJ_OS_H__
-
-/**
- * @file os.h
- * @brief OS dependent functions
- */
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_OS Operating System Dependent Functionality.
- * @ingroup PJ
- */
-
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJ_THREAD Threads
- * @ingroup PJ_OS
- * @{
- * This module provides multithreading API.
- *
- * \section pj_thread_examples_sec Examples
- *
- * For examples, please see:
- *  - \ref page_pjlib_thread_test
- *  - \ref page_pjlib_sleep_test
- *
- */
-
-/**
- * Thread creation flags:
- * - PJ_THREAD_SUSPENDED: specify that the thread should be created suspended.
- */
-typedef enum pj_thread_create_flags
-{
-    PJ_THREAD_SUSPENDED = 1
-} pj_thread_create_flags;
-
-
-/**
- * Specify this as \a stack_size argument in #pj_thread_create() to specify
- * that thread should use default stack size for the current platform.
- */
-#define PJ_THREAD_DEFAULT_STACK_SIZE    0
-
-/**
- * Type of thread entry function.
- */
-typedef int (PJ_THREAD_FUNC pj_thread_proc)(void*);
-
-/**
- * Size of thread struct.
- */
-#if !defined(PJ_THREAD_DESC_SIZE)
-#   define PJ_THREAD_DESC_SIZE	    (16)
-#endif
-
-/**
- * Thread structure, to thread's state when the thread is created by external
- * or native API. 
- */
-typedef long pj_thread_desc[PJ_THREAD_DESC_SIZE];
-
-/**
- * Get process ID.
- * @return process ID.
- */
-PJ_DECL(pj_uint32_t) pj_getpid(void);
-
-/**
- * Create a new thread.
- *
- * @param pool          The memory pool from which the thread record 
- *                      will be allocated from.
- * @param thread_name   The optional name to be assigned to the thread.
- * @param proc          Thread entry function.
- * @param arg           Argument to be passed to the thread entry function.
- * @param stack_size    The size of the stack for the new thread, or ZERO or
- *                      PJ_THREAD_DEFAULT_STACK_SIZE to let the 
- *		        library choose the reasonable size for the stack. 
- *                      For some systems, the stack will be allocated from 
- *                      the pool, so the pool must have suitable capacity.
- * @param flags         Flags for thread creation, which is bitmask combination 
- *                      from enum pj_thread_create_flags.
- * @param thread        Pointer to hold the newly created thread.
- *
- * @return	        PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_thread_create(  pj_pool_t *pool, 
-                                        const char *thread_name,
-				        pj_thread_proc *proc, 
-                                        void *arg,
-				        pj_size_t stack_size, 
-                                        unsigned flags,
-					pj_thread_t **thread );
-
-/**
- * Register a thread that was created by external or native API to PJLIB.
- * This function must be called in the context of the thread being registered.
- * When the thread is created by external function or API call,
- * it must be 'registered' to PJLIB using pj_thread_register(), so that it can
- * cooperate with PJLIB's framework. During registration, some data needs to
- * be maintained, and this data must remain available during the thread's 
- * lifetime.
- *
- * @param thread_name   The optional name to be assigned to the thread.
- * @param desc          Thread descriptor, which must be available throughout 
- *                      the lifetime of the thread.
- * @param thread        Pointer to hold the created thread handle.
- *
- * @return              PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_thread_register ( const char *thread_name,
-					  pj_thread_desc desc,
-					  pj_thread_t **thread);
-
-/**
- * Get thread name.
- *
- * @param thread    The thread handle.
- *
- * @return Thread name as null terminated string.
- */
-PJ_DECL(const char*) pj_thread_get_name(pj_thread_t *thread);
-
-/**
- * Resume a suspended thread.
- *
- * @param thread    The thread handle.
- *
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pj_thread_resume(pj_thread_t *thread);
-
-/**
- * Get the current thread.
- *
- * @return Thread handle of current thread.
- */
-PJ_DECL(pj_thread_t*) pj_thread_this(void);
-
-/**
- * Join thread.
- * This function will block the caller thread until the specified thread exits.
- *
- * @param thread    The thread handle.
- *
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pj_thread_join(pj_thread_t *thread);
-
-
-/**
- * Destroy thread and release resources allocated for the thread.
- * However, the memory allocated for the pj_thread_t itself will only be released
- * when the pool used to create the thread is destroyed.
- *
- * @param thread    The thread handle.
- *
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pj_thread_destroy(pj_thread_t *thread);
-
-
-/**
- * Put the current thread to sleep for the specified miliseconds.
- *
- * @param msec Miliseconds delay.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_thread_sleep(unsigned msec);
-
-/**
- * @def PJ_CHECK_STACK()
- * PJ_CHECK_STACK() macro is used to check the sanity of the stack.
- * The OS implementation may check that no stack overflow occurs, and
- * it also may collect statistic about stack usage.
- */
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-
-#  define PJ_CHECK_STACK() pj_thread_check_stack(__FILE__, __LINE__)
-
-/** @internal
- * The implementation of stack checking. 
- */
-PJ_DECL(void) pj_thread_check_stack(const char *file, int line);
-
-/** @internal
- * Get maximum stack usage statistic. 
- */
-PJ_DECL(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread);
-
-/** @internal
- * Dump thread stack status. 
- */
-PJ_DECL(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread,
-					      const char **file,
-					      int *line);
-#else
-
-#  define PJ_CHECK_STACK()
-/** pj_thread_get_stack_max_usage() for the thread */
-#  define pj_thread_get_stack_max_usage(thread)	    0
-/** pj_thread_get_stack_info() for the thread */
-#  define pj_thread_get_stack_info(thread,f,l)	    (*(f)="",*(l)=0)
-#endif	/* PJ_OS_HAS_CHECK_STACK */
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJ_TLS Thread Local Storage.
- * @ingroup PJ_OS
- * @{
- */
-
-/** 
- * Allocate thread local storage index. The initial value of the variable at
- * the index is zero.
- *
- * @param index	    Pointer to hold the return value.
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_thread_local_alloc(long *index);
-
-/**
- * Deallocate thread local variable.
- *
- * @param index	    The variable index.
- */
-PJ_DECL(void) pj_thread_local_free(long index);
-
-/**
- * Set the value of thread local variable.
- *
- * @param index	    The index of the variable.
- * @param value	    The value.
- */
-PJ_DECL(pj_status_t) pj_thread_local_set(long index, void *value);
-
-/**
- * Get the value of thread local variable.
- *
- * @param index	    The index of the variable.
- * @return	    The value.
- */
-PJ_DECL(void*) pj_thread_local_get(long index);
-
-
-/**
- * @}
- */
-
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJ_ATOMIC Atomic Variables
- * @ingroup PJ_OS
- * @{
- *
- * This module provides API to manipulate atomic variables.
- *
- * \section pj_atomic_examples_sec Examples
- *
- * For some example codes, please see:
- *  - @ref page_pjlib_atomic_test
- */
-
-
-/**
- * Create atomic variable.
- *
- * @param pool	    The pool.
- * @param initial   The initial value of the atomic variable.
- * @param atomic    Pointer to hold the atomic variable upon return.
- *
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
-				       pj_atomic_value_t initial,
-				       pj_atomic_t **atomic );
-
-/**
- * Destroy atomic variable.
- *
- * @param atomic_var	the atomic variable.
- *
- * @return PJ_SUCCESS if success.
- */
-PJ_DECL(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var );
-
-/**
- * Set the value of an atomic type, and return the previous value.
- *
- * @param atomic_var	the atomic variable.
- * @param value		value to be set to the variable.
- */
-PJ_DECL(void) pj_atomic_set( pj_atomic_t *atomic_var, 
-			     pj_atomic_value_t value);
-
-/**
- * Get the value of an atomic type.
- *
- * @param atomic_var	the atomic variable.
- *
- * @return the value of the atomic variable.
- */
-PJ_DECL(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var);
-
-/**
- * Increment the value of an atomic type.
- *
- * @param atomic_var	the atomic variable.
- */
-PJ_DECL(void) pj_atomic_inc(pj_atomic_t *atomic_var);
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_OS_H__

+#define __PJ_OS_H__

+

+/**

+ * @file os.h

+ * @brief OS dependent functions

+ */

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_OS Operating System Dependent Functionality.

+ * @ingroup PJ

+ */

+

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJ_THREAD Threads

+ * @ingroup PJ_OS

+ * @{

+ * This module provides multithreading API.

+ *

+ * \section pj_thread_examples_sec Examples

+ *

+ * For examples, please see:

+ *  - \ref page_pjlib_thread_test

+ *  - \ref page_pjlib_sleep_test

+ *

+ */

+

+/**

+ * Thread creation flags:

+ * - PJ_THREAD_SUSPENDED: specify that the thread should be created suspended.

+ */

+typedef enum pj_thread_create_flags

+{

+    PJ_THREAD_SUSPENDED = 1

+} pj_thread_create_flags;

+

+

+/**

+ * Specify this as \a stack_size argument in #pj_thread_create() to specify

+ * that thread should use default stack size for the current platform.

+ */

+#define PJ_THREAD_DEFAULT_STACK_SIZE    0

+

+/**

+ * Type of thread entry function.

+ */

+typedef int (PJ_THREAD_FUNC pj_thread_proc)(void*);

+

+/**

+ * Size of thread struct.

+ */

+#if !defined(PJ_THREAD_DESC_SIZE)

+#   define PJ_THREAD_DESC_SIZE	    (16)

+#endif

+

+/**

+ * Thread structure, to thread's state when the thread is created by external

+ * or native API. 

+ */

+typedef long pj_thread_desc[PJ_THREAD_DESC_SIZE];

+

+/**

+ * Get process ID.

+ * @return process ID.

+ */

+PJ_DECL(pj_uint32_t) pj_getpid(void);

+

+/**

+ * Create a new thread.

+ *

+ * @param pool          The memory pool from which the thread record 

+ *                      will be allocated from.

+ * @param thread_name   The optional name to be assigned to the thread.

+ * @param proc          Thread entry function.

+ * @param arg           Argument to be passed to the thread entry function.

+ * @param stack_size    The size of the stack for the new thread, or ZERO or

+ *                      PJ_THREAD_DEFAULT_STACK_SIZE to let the 

+ *		        library choose the reasonable size for the stack. 

+ *                      For some systems, the stack will be allocated from 

+ *                      the pool, so the pool must have suitable capacity.

+ * @param flags         Flags for thread creation, which is bitmask combination 

+ *                      from enum pj_thread_create_flags.

+ * @param thread        Pointer to hold the newly created thread.

+ *

+ * @return	        PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_thread_create(  pj_pool_t *pool, 

+                                        const char *thread_name,

+				        pj_thread_proc *proc, 

+                                        void *arg,

+				        pj_size_t stack_size, 

+                                        unsigned flags,

+					pj_thread_t **thread );

+

+/**

+ * Register a thread that was created by external or native API to PJLIB.

+ * This function must be called in the context of the thread being registered.

+ * When the thread is created by external function or API call,

+ * it must be 'registered' to PJLIB using pj_thread_register(), so that it can

+ * cooperate with PJLIB's framework. During registration, some data needs to

+ * be maintained, and this data must remain available during the thread's 

+ * lifetime.

+ *

+ * @param thread_name   The optional name to be assigned to the thread.

+ * @param desc          Thread descriptor, which must be available throughout 

+ *                      the lifetime of the thread.

+ * @param thread        Pointer to hold the created thread handle.

+ *

+ * @return              PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_thread_register ( const char *thread_name,

+					  pj_thread_desc desc,

+					  pj_thread_t **thread);

+

+/**

+ * Get thread name.

+ *

+ * @param thread    The thread handle.

+ *

+ * @return Thread name as null terminated string.

+ */

+PJ_DECL(const char*) pj_thread_get_name(pj_thread_t *thread);

+

+/**

+ * Resume a suspended thread.

+ *

+ * @param thread    The thread handle.

+ *

+ * @return zero on success.

+ */

+PJ_DECL(pj_status_t) pj_thread_resume(pj_thread_t *thread);

+

+/**

+ * Get the current thread.

+ *

+ * @return Thread handle of current thread.

+ */

+PJ_DECL(pj_thread_t*) pj_thread_this(void);

+

+/**

+ * Join thread.

+ * This function will block the caller thread until the specified thread exits.

+ *

+ * @param thread    The thread handle.

+ *

+ * @return zero on success.

+ */

+PJ_DECL(pj_status_t) pj_thread_join(pj_thread_t *thread);

+

+

+/**

+ * Destroy thread and release resources allocated for the thread.

+ * However, the memory allocated for the pj_thread_t itself will only be released

+ * when the pool used to create the thread is destroyed.

+ *

+ * @param thread    The thread handle.

+ *

+ * @return zero on success.

+ */

+PJ_DECL(pj_status_t) pj_thread_destroy(pj_thread_t *thread);

+

+

+/**

+ * Put the current thread to sleep for the specified miliseconds.

+ *

+ * @param msec Miliseconds delay.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_thread_sleep(unsigned msec);

+

+/**

+ * @def PJ_CHECK_STACK()

+ * PJ_CHECK_STACK() macro is used to check the sanity of the stack.

+ * The OS implementation may check that no stack overflow occurs, and

+ * it also may collect statistic about stack usage.

+ */

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+

+#  define PJ_CHECK_STACK() pj_thread_check_stack(__FILE__, __LINE__)

+

+/** @internal

+ * The implementation of stack checking. 

+ */

+PJ_DECL(void) pj_thread_check_stack(const char *file, int line);

+

+/** @internal

+ * Get maximum stack usage statistic. 

+ */

+PJ_DECL(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread);

+

+/** @internal

+ * Dump thread stack status. 

+ */

+PJ_DECL(pj_status_t) pj_thread_get_stack_info(pj_thread_t *thread,

+					      const char **file,

+					      int *line);

+#else

+

+#  define PJ_CHECK_STACK()

+/** pj_thread_get_stack_max_usage() for the thread */

+#  define pj_thread_get_stack_max_usage(thread)	    0

+/** pj_thread_get_stack_info() for the thread */

+#  define pj_thread_get_stack_info(thread,f,l)	    (*(f)="",*(l)=0)

+#endif	/* PJ_OS_HAS_CHECK_STACK */

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJ_TLS Thread Local Storage.

+ * @ingroup PJ_OS

+ * @{

+ */

+

+/** 

+ * Allocate thread local storage index. The initial value of the variable at

+ * the index is zero.

+ *

+ * @param index	    Pointer to hold the return value.

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_thread_local_alloc(long *index);

+

+/**

+ * Deallocate thread local variable.

+ *

+ * @param index	    The variable index.

+ */

+PJ_DECL(void) pj_thread_local_free(long index);

+

+/**

+ * Set the value of thread local variable.

+ *

+ * @param index	    The index of the variable.

+ * @param value	    The value.

+ */

+PJ_DECL(pj_status_t) pj_thread_local_set(long index, void *value);

+

+/**

+ * Get the value of thread local variable.

+ *

+ * @param index	    The index of the variable.

+ * @return	    The value.

+ */

+PJ_DECL(void*) pj_thread_local_get(long index);

+

+

+/**

+ * @}

+ */

+

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJ_ATOMIC Atomic Variables

+ * @ingroup PJ_OS

+ * @{

+ *

+ * This module provides API to manipulate atomic variables.

+ *

+ * \section pj_atomic_examples_sec Examples

+ *

+ * For some example codes, please see:

+ *  - @ref page_pjlib_atomic_test

+ */

+

+

+/**

+ * Create atomic variable.

+ *

+ * @param pool	    The pool.

+ * @param initial   The initial value of the atomic variable.

+ * @param atomic    Pointer to hold the atomic variable upon return.

+ *

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_atomic_create( pj_pool_t *pool, 

+				       pj_atomic_value_t initial,

+				       pj_atomic_t **atomic );

+

+/**

+ * Destroy atomic variable.

+ *

+ * @param atomic_var	the atomic variable.

+ *

+ * @return PJ_SUCCESS if success.

+ */

+PJ_DECL(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var );

+

+/**

+ * Set the value of an atomic type, and return the previous value.

+ *

+ * @param atomic_var	the atomic variable.

+ * @param value		value to be set to the variable.

+ */

+PJ_DECL(void) pj_atomic_set( pj_atomic_t *atomic_var, 

+			     pj_atomic_value_t value);

+

+/**

+ * Get the value of an atomic type.

+ *

+ * @param atomic_var	the atomic variable.

+ *

+ * @return the value of the atomic variable.

+ */

+PJ_DECL(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var);

+

+/**

+ * Increment the value of an atomic type.

+ *

+ * @param atomic_var	the atomic variable.

+ */

+PJ_DECL(void) pj_atomic_inc(pj_atomic_t *atomic_var);

+

 /**

  * Increment the value of an atomic type and get the result.

  *

@@ -333,12 +354,12 @@
  */

 PJ_DECL(pj_atomic_value_t) pj_atomic_inc_and_get(pj_atomic_t *atomic_var);

 

-/**
- * Decrement the value of an atomic type.
- *
- * @param atomic_var	the atomic variable.
- */
-PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var);
+/**

+ * Decrement the value of an atomic type.

+ *

+ * @param atomic_var	the atomic variable.

+ */

+PJ_DECL(void) pj_atomic_dec(pj_atomic_t *atomic_var);

 

 /**

  * Decrement the value of an atomic type and get the result.

@@ -348,15 +369,15 @@
  * @return              The decremented value.

  */

 PJ_DECL(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var);

-
-/**
- * Add a value to an atomic type.
- *
- * @param atomic_var	The atomic variable.
- * @param value		Value to be added.
- */
-PJ_DECL(void) pj_atomic_add( pj_atomic_t *atomic_var,
-			     pj_atomic_value_t value);
+

+/**

+ * Add a value to an atomic type.

+ *

+ * @param atomic_var	The atomic variable.

+ * @param value		Value to be added.

+ */

+PJ_DECL(void) pj_atomic_add( pj_atomic_t *atomic_var,

+			     pj_atomic_value_t value);

 

 /**

  * Add a value to an atomic type and get the result.

@@ -368,576 +389,576 @@
  */

 PJ_DECL(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var,

 			                          pj_atomic_value_t value);

-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJ_MUTEX Mutexes.
- * @ingroup PJ_OS
- * @{
- *
- * Mutex manipulation. Alternatively, application can use higher abstraction
- * for lock objects, which provides uniform API for all kinds of lock 
- * mechanisms, including mutex. See @ref PJ_LOCK for more information.
- */
-
-/**
- * Mutex types:
- *  - PJ_MUTEX_DEFAULT: default mutex type, which is system dependent.
- *  - PJ_MUTEX_SIMPLE: non-recursive mutex.
- *  - PJ_MUTEX_RECURSIVE: recursive mutex.
- */
-typedef enum pj_mutex_type_e
-{
-    PJ_MUTEX_DEFAULT,
-    PJ_MUTEX_SIMPLE,
-    PJ_MUTEX_RECURSE,
-} pj_mutex_type_e;
-
-
-/**
- * Create mutex of the specified type.
- *
- * @param pool	    The pool.
- * @param name	    Name to be associated with the mutex (for debugging).
- * @param type	    The type of the mutex, of type #pj_mutex_type_e.
- * @param mutex	    Pointer to hold the returned mutex instance.
- *
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_mutex_create(pj_pool_t *pool, 
-                                     const char *name,
-				     int type, 
-                                     pj_mutex_t **mutex);
-
-/**
- * Create simple, non-recursive mutex.
- * This function is a simple wrapper for #pj_mutex_create to create 
- * non-recursive mutex.
- *
- * @param pool	    The pool.
- * @param name	    Mutex name.
- * @param mutex	    Pointer to hold the returned mutex instance.
- *
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
-					     pj_mutex_t **mutex );
-
-/**
- * Create recursive mutex.
- * This function is a simple wrapper for #pj_mutex_create to create 
- * recursive mutex.
- *
- * @param pool	    The pool.
- * @param name	    Mutex name.
- * @param mutex	    Pointer to hold the returned mutex instance.
- *
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
-					        const char *name,
-						pj_mutex_t **mutex );
-
-/**
- * Acquire mutex lock.
- *
- * @param mutex	    The mutex.
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex);
-
-/**
- * Release mutex lock.
- *
- * @param mutex	    The mutex.
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex);
-
-/**
- * Try to acquire mutex lock.
- *
- * @param mutex	    The mutex.
- * @return	    PJ_SUCCESS on success, or the error code if the
- *		    lock couldn't be acquired.
- */
-PJ_DECL(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex);
-
-/**
- * Destroy mutex.
- *
- * @param mutex	    Te mutex.
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex);
-
-/**
- * Determine whether calling thread is owning the mutex (only available when
- * PJ_DEBUG is set).
- * @param mutex	    The mutex.
- * @return	    Non-zero if yes.
- */
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-   PJ_DECL(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex);
-#else
-#  define pj_mutex_is_locked(mutex)	    1
-#endif
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJ_CRIT_SEC Critical sections.
- * @ingroup PJ_OS
- * @{
- * Critical section protection can be used to protect regions where:
- *  - mutual exclusion protection is needed.
- *  - it's rather too expensive to create a mutex.
- *  - the time spent in the region is very very brief.
- *
- * Critical section is a global object, and it prevents any threads from
- * entering any regions that are protected by critical section once a thread
- * is already in the section.
- *
- * Critial section is \a not recursive!
- *
- * Application <b>MUST NOT</b> call any functions that may cause current
- * thread to block (such as allocating memory, performing I/O, locking mutex,
- * etc.) while holding the critical section.
- */
-/**
- * Enter critical section.
- */
-PJ_DECL(void) pj_enter_critical_section(void);
-
-/**
- * Leave critical section.
- */
-PJ_DECL(void) pj_leave_critical_section(void);
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-/**
- * @defgroup PJ_SEM Semaphores.
- * @ingroup PJ_OS
- * @{
- *
- * This module provides abstraction for semaphores, where available.
- */
-
-/**
- * Create semaphore.
- *
- * @param pool	    The pool.
- * @param name	    Name to be assigned to the semaphore (for logging purpose)
- * @param initial   The initial count of the semaphore.
- * @param max	    The maximum count of the semaphore.
- * @param sem	    Pointer to hold the semaphore created.
- *
- * @return	    PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_sem_create( pj_pool_t *pool, 
-                                    const char *name,
-				    unsigned initial, 
-                                    unsigned max,
-				    pj_sem_t **sem);
-
-/**
- * Wait for semaphore.
- *
- * @param sem	The semaphore.
- *
- * @return	PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_sem_wait(pj_sem_t *sem);
-
-/**
- * Try wait for semaphore.
- *
- * @param sem	The semaphore.
- *
- * @return	PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_sem_trywait(pj_sem_t *sem);
-
-/**
- * Release semaphore.
- *
- * @param sem	The semaphore.
- *
- * @return	PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_sem_post(pj_sem_t *sem);
-
-/**
- * Destroy semaphore.
- *
- * @param sem	The semaphore.
- *
- * @return	PJ_SUCCESS on success, or the error code.
- */
-PJ_DECL(pj_status_t) pj_sem_destroy(pj_sem_t *sem);
-
-/**
- * @}
- */
-#endif	/* PJ_HAS_SEMAPHORE */
-
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
-/**
- * @defgroup PJ_EVENT Event Object.
- * @ingroup PJ_OS
- * @{
- *
- * This module provides abstraction to event object (e.g. Win32 Event) where
- * available. Event objects can be used for synchronization among threads.
- */
-
-/**
- * Create event object.
- *
- * @param pool		The pool.
- * @param name		The name of the event object (for logging purpose).
- * @param manual_reset	Specify whether the event is manual-reset
- * @param initial	Specify the initial state of the event object.
- * @param event		Pointer to hold the returned event object.
- *
- * @return event handle, or NULL if failed.
- */
-PJ_DECL(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,
-				     pj_bool_t manual_reset, pj_bool_t initial,
-				     pj_event_t **event);
-
-/**
- * Wait for event to be signaled.
- *
- * @param event	    The event object.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_event_wait(pj_event_t *event);
-
-/**
- * Try wait for event object to be signalled.
- *
- * @param event The event object.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_event_trywait(pj_event_t *event);
-
-/**
- * Set the event object state to signaled. For auto-reset event, this 
- * will only release the first thread that are waiting on the event. For
- * manual reset event, the state remains signaled until the event is reset.
- * If there is no thread waiting on the event, the event object state 
- * remains signaled.
- *
- * @param event	    The event object.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_event_set(pj_event_t *event);
-
-/**
- * Set the event object to signaled state to release appropriate number of
- * waiting threads and then reset the event object to non-signaled. For
- * manual-reset event, this function will release all waiting threads. For
- * auto-reset event, this function will only release one waiting thread.
- *
- * @param event	    The event object.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_event_pulse(pj_event_t *event);
-
-/**
- * Set the event object state to non-signaled.
- *
- * @param event	    The event object.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_event_reset(pj_event_t *event);
-
-/**
- * Destroy the event object.
- *
- * @param event	    The event object.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_event_destroy(pj_event_t *event);
-
-/**
- * @}
- */
-#endif	/* PJ_HAS_EVENT_OBJ */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @addtogroup PJ_TIME Time Data Type and Manipulation.
- * @ingroup PJ_OS
- * @{
- * This module provides API for manipulating time.
- *
- * \section pj_time_examples_sec Examples
- *
- * For examples, please see:
- *  - \ref page_pjlib_sleep_test
- */
-
-/**
- * Get current time of day in local representation.
- *
- * @param tv	Variable to store the result.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_gettimeofday(pj_time_val *tv);
-
-
-/**
- * Parse time value into date/time representation.
- *
- * @param tv	The time.
- * @param pt	Variable to store the date time result.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt);
-
-/**
- * Encode date/time to time value.
- *
- * @param pt	The date/time.
- * @param tv	Variable to store time value result.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
-
-/**
- * Convert local time to GMT.
- *
- * @param tv	Time to convert.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
-
-/**
- * Convert GMT to local time.
- *
- * @param tv	Time to convert.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
-
-/**
- * @defgroup PJ_TERM Terminal
- * @ingroup PJ_OS
- * @{
- */
-
-/**
- * Set current terminal color.
- *
- * @param color	    The RGB color.
- *
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pj_term_set_color(pj_color_t color);
-
-/**
- * Get current terminal foreground color.
- *
- * @return RGB color.
- */
-PJ_DECL(pj_color_t) pj_term_get_color(void);
-
-/**
- * @}
- */
-
-#endif	/* PJ_TERM_HAS_COLOR */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJ_TIMESTAMP High Resolution Timestamp
- * @ingroup PJ_OS
- * @{
- *
- * PJLIB provides <b>High Resolution Timestamp</b> API to access highest 
- * resolution timestamp value provided by the platform. The API is usefull
- * to measure precise elapsed time, and can be used in applications such
- * as profiling.
- *
- * The timestamp value is represented in cycles, and can be related to
- * normal time (in seconds or sub-seconds) using various functions provided.
- *
- * \section pj_timestamp_examples_sec Examples
- *
- * For examples, please see:
- *  - \ref page_pjlib_sleep_test
- *  - \ref page_pjlib_timestamp_test
- */
-
-/*
- * High resolution timer.
- */
-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
-
-/**
- * This structure represents high resolution (64bit) time value. The time
- * values represent time in cycles, which is retrieved by calling
- * #pj_get_timestamp().
- */
-typedef union pj_timestamp
-{
-    struct
-    {
-#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
-	pj_uint32_t lo;     /**< Low 32-bit value of the 64-bit value. */
-	pj_uint32_t hi;     /**< high 32-bit value of the 64-bit value. */
-#else
-	pj_uint32_t hi;     /**< high 32-bit value of the 64-bit value. */
-	pj_uint32_t lo;     /**< Low 32-bit value of the 64-bit value. */
-#endif
-    } u32;                  /**< The 64-bit value as two 32-bit values. */
-
-#if PJ_HAS_INT64
-    pj_uint64_t u64;        /**< The whole 64-bit value, where available. */
-#endif
-} pj_timestamp;
-
-
-/**
- * Acquire high resolution timer value. The time value are stored
- * in cycles.
- *
- * @param ts	    High resolution timer value.
- * @return	    PJ_SUCCESS or the appropriate error code.
- *
- * @see pj_get_timestamp_freq().
- */
-PJ_DECL(pj_status_t) pj_get_timestamp(pj_timestamp *ts);
-
-/**
- * Get high resolution timer frequency, in cycles per second.
- *
- * @param freq	    Timer frequency, in cycles per second.
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq);
-
-/**
- * Calculate the elapsed time, and store it in pj_time_val.
- * This function calculates the elapsed time using highest precision
- * calculation that is available for current platform, considering
- * whether floating point or 64-bit precision arithmetic is available. 
- * For maximum portability, application should prefer to use this function
- * rather than calculating the elapsed time by itself.
- *
- * @param start     The starting timestamp.
- * @param stop      The end timestamp.
- *
- * @return	    Elapsed time as #pj_time_val.
- *
- * @see pj_elapsed_usec(), pj_elapsed_cycle(), pj_elapsed_nanosec()
- */
-PJ_DECL(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
-                                      const pj_timestamp *stop );
-
-/**
- * Calculate the elapsed time in 32-bit microseconds.
- * This function calculates the elapsed time using highest precision
- * calculation that is available for current platform, considering
- * whether floating point or 64-bit precision arithmetic is available. 
- * For maximum portability, application should prefer to use this function
- * rather than calculating the elapsed time by itself.
- *
- * @param start     The starting timestamp.
- * @param stop      The end timestamp.
- *
- * @return	    Elapsed time in microsecond.
- *
- * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_nanosec()
- */
-PJ_DECL(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
-                                      const pj_timestamp *stop );
-
-/**
- * Calculate the elapsed time in 32-bit nanoseconds.
- * This function calculates the elapsed time using highest precision
- * calculation that is available for current platform, considering
- * whether floating point or 64-bit precision arithmetic is available. 
- * For maximum portability, application should prefer to use this function
- * rather than calculating the elapsed time by itself.
- *
- * @param start     The starting timestamp.
- * @param stop      The end timestamp.
- *
- * @return	    Elapsed time in nanoseconds.
- *
- * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_usec()
- */
-PJ_DECL(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
-                                         const pj_timestamp *stop );
-
-/**
- * Calculate the elapsed time in 32-bit cycles.
- * This function calculates the elapsed time using highest precision
- * calculation that is available for current platform, considering
- * whether floating point or 64-bit precision arithmetic is available. 
- * For maximum portability, application should prefer to use this function
- * rather than calculating the elapsed time by itself.
- *
- * @param start     The starting timestamp.
- * @param stop      The end timestamp.
- *
- * @return	    Elapsed time in cycles.
- *
- * @see pj_elapsed_usec(), pj_elapsed_time(), pj_elapsed_nanosec()
- */
-PJ_DECL(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
-                                       const pj_timestamp *stop );
-
-
-#endif	/* PJ_HAS_HIGH_RES_TIMER */
-
-/** @} */
-
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * Internal PJLIB function to initialize the threading subsystem.
- * @return          PJ_SUCCESS or the appropriate error code.
- */
-pj_status_t pj_thread_init(void);
-
-
-PJ_END_DECL
-
-#endif  /* __PJ_OS_H__ */
-
+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJ_MUTEX Mutexes.

+ * @ingroup PJ_OS

+ * @{

+ *

+ * Mutex manipulation. Alternatively, application can use higher abstraction

+ * for lock objects, which provides uniform API for all kinds of lock 

+ * mechanisms, including mutex. See @ref PJ_LOCK for more information.

+ */

+

+/**

+ * Mutex types:

+ *  - PJ_MUTEX_DEFAULT: default mutex type, which is system dependent.

+ *  - PJ_MUTEX_SIMPLE: non-recursive mutex.

+ *  - PJ_MUTEX_RECURSIVE: recursive mutex.

+ */

+typedef enum pj_mutex_type_e

+{

+    PJ_MUTEX_DEFAULT,

+    PJ_MUTEX_SIMPLE,

+    PJ_MUTEX_RECURSE,

+} pj_mutex_type_e;

+

+

+/**

+ * Create mutex of the specified type.

+ *

+ * @param pool	    The pool.

+ * @param name	    Name to be associated with the mutex (for debugging).

+ * @param type	    The type of the mutex, of type #pj_mutex_type_e.

+ * @param mutex	    Pointer to hold the returned mutex instance.

+ *

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_mutex_create(pj_pool_t *pool, 

+                                     const char *name,

+				     int type, 

+                                     pj_mutex_t **mutex);

+

+/**

+ * Create simple, non-recursive mutex.

+ * This function is a simple wrapper for #pj_mutex_create to create 

+ * non-recursive mutex.

+ *

+ * @param pool	    The pool.

+ * @param name	    Mutex name.

+ * @param mutex	    Pointer to hold the returned mutex instance.

+ *

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,

+					     pj_mutex_t **mutex );

+

+/**

+ * Create recursive mutex.

+ * This function is a simple wrapper for #pj_mutex_create to create 

+ * recursive mutex.

+ *

+ * @param pool	    The pool.

+ * @param name	    Mutex name.

+ * @param mutex	    Pointer to hold the returned mutex instance.

+ *

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,

+					        const char *name,

+						pj_mutex_t **mutex );

+

+/**

+ * Acquire mutex lock.

+ *

+ * @param mutex	    The mutex.

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex);

+

+/**

+ * Release mutex lock.

+ *

+ * @param mutex	    The mutex.

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex);

+

+/**

+ * Try to acquire mutex lock.

+ *

+ * @param mutex	    The mutex.

+ * @return	    PJ_SUCCESS on success, or the error code if the

+ *		    lock couldn't be acquired.

+ */

+PJ_DECL(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex);

+

+/**

+ * Destroy mutex.

+ *

+ * @param mutex	    Te mutex.

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex);

+

+/**

+ * Determine whether calling thread is owning the mutex (only available when

+ * PJ_DEBUG is set).

+ * @param mutex	    The mutex.

+ * @return	    Non-zero if yes.

+ */

+#if defined(PJ_DEBUG) && PJ_DEBUG != 0

+   PJ_DECL(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex);

+#else

+#  define pj_mutex_is_locked(mutex)	    1

+#endif

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJ_CRIT_SEC Critical sections.

+ * @ingroup PJ_OS

+ * @{

+ * Critical section protection can be used to protect regions where:

+ *  - mutual exclusion protection is needed.

+ *  - it's rather too expensive to create a mutex.

+ *  - the time spent in the region is very very brief.

+ *

+ * Critical section is a global object, and it prevents any threads from

+ * entering any regions that are protected by critical section once a thread

+ * is already in the section.

+ *

+ * Critial section is \a not recursive!

+ *

+ * Application <b>MUST NOT</b> call any functions that may cause current

+ * thread to block (such as allocating memory, performing I/O, locking mutex,

+ * etc.) while holding the critical section.

+ */

+/**

+ * Enter critical section.

+ */

+PJ_DECL(void) pj_enter_critical_section(void);

+

+/**

+ * Leave critical section.

+ */

+PJ_DECL(void) pj_leave_critical_section(void);

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

+/**

+ * @defgroup PJ_SEM Semaphores.

+ * @ingroup PJ_OS

+ * @{

+ *

+ * This module provides abstraction for semaphores, where available.

+ */

+

+/**

+ * Create semaphore.

+ *

+ * @param pool	    The pool.

+ * @param name	    Name to be assigned to the semaphore (for logging purpose)

+ * @param initial   The initial count of the semaphore.

+ * @param max	    The maximum count of the semaphore.

+ * @param sem	    Pointer to hold the semaphore created.

+ *

+ * @return	    PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_sem_create( pj_pool_t *pool, 

+                                    const char *name,

+				    unsigned initial, 

+                                    unsigned max,

+				    pj_sem_t **sem);

+

+/**

+ * Wait for semaphore.

+ *

+ * @param sem	The semaphore.

+ *

+ * @return	PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_sem_wait(pj_sem_t *sem);

+

+/**

+ * Try wait for semaphore.

+ *

+ * @param sem	The semaphore.

+ *

+ * @return	PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_sem_trywait(pj_sem_t *sem);

+

+/**

+ * Release semaphore.

+ *

+ * @param sem	The semaphore.

+ *

+ * @return	PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_sem_post(pj_sem_t *sem);

+

+/**

+ * Destroy semaphore.

+ *

+ * @param sem	The semaphore.

+ *

+ * @return	PJ_SUCCESS on success, or the error code.

+ */

+PJ_DECL(pj_status_t) pj_sem_destroy(pj_sem_t *sem);

+

+/**

+ * @}

+ */

+#endif	/* PJ_HAS_SEMAPHORE */

+

+

+///////////////////////////////////////////////////////////////////////////////

+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0

+/**

+ * @defgroup PJ_EVENT Event Object.

+ * @ingroup PJ_OS

+ * @{

+ *

+ * This module provides abstraction to event object (e.g. Win32 Event) where

+ * available. Event objects can be used for synchronization among threads.

+ */

+

+/**

+ * Create event object.

+ *

+ * @param pool		The pool.

+ * @param name		The name of the event object (for logging purpose).

+ * @param manual_reset	Specify whether the event is manual-reset

+ * @param initial	Specify the initial state of the event object.

+ * @param event		Pointer to hold the returned event object.

+ *

+ * @return event handle, or NULL if failed.

+ */

+PJ_DECL(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,

+				     pj_bool_t manual_reset, pj_bool_t initial,

+				     pj_event_t **event);

+

+/**

+ * Wait for event to be signaled.

+ *

+ * @param event	    The event object.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_event_wait(pj_event_t *event);

+

+/**

+ * Try wait for event object to be signalled.

+ *

+ * @param event The event object.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_event_trywait(pj_event_t *event);

+

+/**

+ * Set the event object state to signaled. For auto-reset event, this 

+ * will only release the first thread that are waiting on the event. For

+ * manual reset event, the state remains signaled until the event is reset.

+ * If there is no thread waiting on the event, the event object state 

+ * remains signaled.

+ *

+ * @param event	    The event object.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_event_set(pj_event_t *event);

+

+/**

+ * Set the event object to signaled state to release appropriate number of

+ * waiting threads and then reset the event object to non-signaled. For

+ * manual-reset event, this function will release all waiting threads. For

+ * auto-reset event, this function will only release one waiting thread.

+ *

+ * @param event	    The event object.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_event_pulse(pj_event_t *event);

+

+/**

+ * Set the event object state to non-signaled.

+ *

+ * @param event	    The event object.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_event_reset(pj_event_t *event);

+

+/**

+ * Destroy the event object.

+ *

+ * @param event	    The event object.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_event_destroy(pj_event_t *event);

+

+/**

+ * @}

+ */

+#endif	/* PJ_HAS_EVENT_OBJ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @addtogroup PJ_TIME Time Data Type and Manipulation.

+ * @ingroup PJ_OS

+ * @{

+ * This module provides API for manipulating time.

+ *

+ * \section pj_time_examples_sec Examples

+ *

+ * For examples, please see:

+ *  - \ref page_pjlib_sleep_test

+ */

+

+/**

+ * Get current time of day in local representation.

+ *

+ * @param tv	Variable to store the result.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_gettimeofday(pj_time_val *tv);

+

+

+/**

+ * Parse time value into date/time representation.

+ *

+ * @param tv	The time.

+ * @param pt	Variable to store the date time result.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt);

+

+/**

+ * Encode date/time to time value.

+ *

+ * @param pt	The date/time.

+ * @param tv	Variable to store time value result.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);

+

+/**

+ * Convert local time to GMT.

+ *

+ * @param tv	Time to convert.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);

+

+/**

+ * Convert GMT to local time.

+ *

+ * @param tv	Time to convert.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

+

+/**

+ * @defgroup PJ_TERM Terminal

+ * @ingroup PJ_OS

+ * @{

+ */

+

+/**

+ * Set current terminal color.

+ *

+ * @param color	    The RGB color.

+ *

+ * @return zero on success.

+ */

+PJ_DECL(pj_status_t) pj_term_set_color(pj_color_t color);

+

+/**

+ * Get current terminal foreground color.

+ *

+ * @return RGB color.

+ */

+PJ_DECL(pj_color_t) pj_term_get_color(void);

+

+/**

+ * @}

+ */

+

+#endif	/* PJ_TERM_HAS_COLOR */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJ_TIMESTAMP High Resolution Timestamp

+ * @ingroup PJ_OS

+ * @{

+ *

+ * PJLIB provides <b>High Resolution Timestamp</b> API to access highest 

+ * resolution timestamp value provided by the platform. The API is usefull

+ * to measure precise elapsed time, and can be used in applications such

+ * as profiling.

+ *

+ * The timestamp value is represented in cycles, and can be related to

+ * normal time (in seconds or sub-seconds) using various functions provided.

+ *

+ * \section pj_timestamp_examples_sec Examples

+ *

+ * For examples, please see:

+ *  - \ref page_pjlib_sleep_test

+ *  - \ref page_pjlib_timestamp_test

+ */

+

+/*

+ * High resolution timer.

+ */

+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

+

+/**

+ * This structure represents high resolution (64bit) time value. The time

+ * values represent time in cycles, which is retrieved by calling

+ * #pj_get_timestamp().

+ */

+typedef union pj_timestamp

+{

+    struct

+    {

+#if defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0

+	pj_uint32_t lo;     /**< Low 32-bit value of the 64-bit value. */

+	pj_uint32_t hi;     /**< high 32-bit value of the 64-bit value. */

+#else

+	pj_uint32_t hi;     /**< high 32-bit value of the 64-bit value. */

+	pj_uint32_t lo;     /**< Low 32-bit value of the 64-bit value. */

+#endif

+    } u32;                  /**< The 64-bit value as two 32-bit values. */

+

+#if PJ_HAS_INT64

+    pj_uint64_t u64;        /**< The whole 64-bit value, where available. */

+#endif

+} pj_timestamp;

+

+

+/**

+ * Acquire high resolution timer value. The time value are stored

+ * in cycles.

+ *

+ * @param ts	    High resolution timer value.

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ *

+ * @see pj_get_timestamp_freq().

+ */

+PJ_DECL(pj_status_t) pj_get_timestamp(pj_timestamp *ts);

+

+/**

+ * Get high resolution timer frequency, in cycles per second.

+ *

+ * @param freq	    Timer frequency, in cycles per second.

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq);

+

+/**

+ * Calculate the elapsed time, and store it in pj_time_val.

+ * This function calculates the elapsed time using highest precision

+ * calculation that is available for current platform, considering

+ * whether floating point or 64-bit precision arithmetic is available. 

+ * For maximum portability, application should prefer to use this function

+ * rather than calculating the elapsed time by itself.

+ *

+ * @param start     The starting timestamp.

+ * @param stop      The end timestamp.

+ *

+ * @return	    Elapsed time as #pj_time_val.

+ *

+ * @see pj_elapsed_usec(), pj_elapsed_cycle(), pj_elapsed_nanosec()

+ */

+PJ_DECL(pj_time_val) pj_elapsed_time( const pj_timestamp *start,

+                                      const pj_timestamp *stop );

+

+/**

+ * Calculate the elapsed time in 32-bit microseconds.

+ * This function calculates the elapsed time using highest precision

+ * calculation that is available for current platform, considering

+ * whether floating point or 64-bit precision arithmetic is available. 

+ * For maximum portability, application should prefer to use this function

+ * rather than calculating the elapsed time by itself.

+ *

+ * @param start     The starting timestamp.

+ * @param stop      The end timestamp.

+ *

+ * @return	    Elapsed time in microsecond.

+ *

+ * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_nanosec()

+ */

+PJ_DECL(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,

+                                      const pj_timestamp *stop );

+

+/**

+ * Calculate the elapsed time in 32-bit nanoseconds.

+ * This function calculates the elapsed time using highest precision

+ * calculation that is available for current platform, considering

+ * whether floating point or 64-bit precision arithmetic is available. 

+ * For maximum portability, application should prefer to use this function

+ * rather than calculating the elapsed time by itself.

+ *

+ * @param start     The starting timestamp.

+ * @param stop      The end timestamp.

+ *

+ * @return	    Elapsed time in nanoseconds.

+ *

+ * @see pj_elapsed_time(), pj_elapsed_cycle(), pj_elapsed_usec()

+ */

+PJ_DECL(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,

+                                         const pj_timestamp *stop );

+

+/**

+ * Calculate the elapsed time in 32-bit cycles.

+ * This function calculates the elapsed time using highest precision

+ * calculation that is available for current platform, considering

+ * whether floating point or 64-bit precision arithmetic is available. 

+ * For maximum portability, application should prefer to use this function

+ * rather than calculating the elapsed time by itself.

+ *

+ * @param start     The starting timestamp.

+ * @param stop      The end timestamp.

+ *

+ * @return	    Elapsed time in cycles.

+ *

+ * @see pj_elapsed_usec(), pj_elapsed_time(), pj_elapsed_nanosec()

+ */

+PJ_DECL(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,

+                                       const pj_timestamp *stop );

+

+

+#endif	/* PJ_HAS_HIGH_RES_TIMER */

+

+/** @} */

+

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * Internal PJLIB function to initialize the threading subsystem.

+ * @return          PJ_SUCCESS or the appropriate error code.

+ */

+pj_status_t pj_thread_init(void);

+

+

+PJ_END_DECL

+

+#endif  /* __PJ_OS_H__ */

+

diff --git a/pjlib/include/pj/pool.h b/pjlib/include/pj/pool.h
index 4be4d24..a8ad7e8 100644
--- a/pjlib/include/pj/pool.h
+++ b/pjlib/include/pj/pool.h
@@ -1,572 +1,593 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_POOL_H__
-#define __PJ_POOL_H__
-
-/**
- * @file pool.h
- * @brief Memory Pool.
- */
-
-#include <pj/list.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_POOL_GROUP Memory Pool Management
- * @ingroup PJ
- * @brief
- * Memory pool management provides API to allocate and deallocate memory from
- * memory pool and to manage and establish policy for pool creation and
- * destruction in pool factory.
- *
- * \section PJ_POOL_FACTORY_SEC Pool Factory
- * See: \ref PJ_POOL_FACTORY "Pool Factory"
- *
- * A memory pool must be created through a factory. A factory not only provides
- * generic interface functions to create and release pool, but also provides 
- * strategy to manage the life time of pools. One sample implementation, 
- * \a pj_caching_pool, can be set to keep the pools released by application for
- * future use as long as the total memory is below the limit.
- * 
- * The pool factory interface declared in PJLIB is designed to be extensible.
- * Application can define its own strategy by creating it's own pool factory
- * implementation, and this strategy can be used even by existing library
- * without recompilation.
- *
- *
- * \section PJ_POOL_POLICY_SEC Pool Factory Policy
- * See: \ref PJ_POOL_FACTORY "Pool Factory Policy"
- *
- * A pool factory only defines functions to create and release pool and how
- * to manage pools, but the rest of the functionalities are controlled by
- * policy. A pool policy defines:
- *  - how memory block is allocated and deallocated (the default implementation
- *    allocates and deallocate memory by calling malloc() and free()).
- *  - callback to be called when memory allocation inside a pool fails (the
- *    default implementation will throw PJ_NO_MEMORY_EXCEPTION exception).
- *  - concurrency when creating and releasing pool from/to the factory.
- *
- * A pool factory can be given different policy during creation to make
- * it behave differently. For example, caching pool factory can be configured
- * to allocate and deallocate from a static/contiguous/preallocated memory 
- * instead of using malloc()/free().
- * 
- * What strategy/factory and what policy to use is not defined by PJLIB, but
- * instead is left to application to make use whichever is most efficient for
- * itself.
- *
- *
- * \section PJ_POOL_POOL_SEC The Pool
- * See: \ref PJ_POOL "Pool"
- *
- * The memory pool is an opaque object created by pool factory.
- * Application uses this object to request a memory chunk, by calling
- * #pj_pool_alloc or #pj_pool_calloc. When the application has finished using
- * the pool, it must call #pj_pool_release to free all the chunks previously
- * allocated and release the pool back to the factory.
- *
- * \section PJ_POOL_THREADING_SEC More on Threading Policies:
- * - By design, memory allocation from a pool is not thread safe. We assumed 
- *   that a pool will be owned by an object, and thread safety should be 
- *   handled by that object. Thus these functions are not thread safe: 
- *	- #pj_pool_alloc, 
- *	- #pj_pool_calloc, 
- *	- and other pool statistic functions.
- * - Threading in the pool factory is decided by the policy set for the
- *   factory when it was created.
- *
- * \section PJ_POOL_EXAMPLES_SEC Examples
- *
- * For some sample codes on how to use the pool, please see:
- *  - @ref page_pjlib_pool_test
- */
-
-/**
- * @defgroup PJ_POOL Memory Pool.
- * @ingroup PJ_POOL_GROUP
- * @brief
- * A memory pool is initialized with an initial amount of memory, which is
- * called a block. Pool can be configured to dynamically allocate more memory 
- * blocks when it runs out of memory. Subsequent memory allocations by user 
- * will use up portions of these block. 
- * The pool doesn't keep track of individual memory allocations
- * by user, and the user doesn't have to free these indidual allocations. This
- * makes memory allocation simple and very fast. All the memory allocated from
- * the pool will be destroyed when the pool itself is destroyed.
- * @{
- */
-
-/**
- * The type for function to receive callback from the pool when it is unable
- * to allocate memory. The elegant way to handle this condition is to throw
- * exception, and this is what is expected by most of this library 
- * components.
- */
-typedef void pj_pool_callback(pj_pool_t *pool, pj_size_t size);
-
-/**
- * This class, which is used internally by the pool, describes a single 
- * block of memory from which user memory allocations will be allocated from.
- */
-typedef struct pj_pool_block
-{
-    PJ_DECL_LIST_MEMBER(struct pj_pool_block);  /**< List's prev and next.  */
-    unsigned char    *buf;                      /**< Start of buffer.       */
-    unsigned char    *cur;                      /**< Current alloc ptr.     */
-    unsigned char    *end;                      /**< End of buffer.         */
-} pj_pool_block;
-
-
-/**
- * This structure describes the memory pool. Only implementors of pool factory
- * need to care about the contents of this structure.
- */
-struct pj_pool_t
-{
-    PJ_DECL_LIST_MEMBER(struct pj_pool_t);  /**< Standard list elements.    */
-
-    /** Pool name */
-    char	    obj_name[PJ_MAX_OBJ_NAME];
-
-    /** Pool factory. */
-    pj_pool_factory *factory;
-
-    /** Current capacity allocated by the pool. */
-    pj_size_t	    capacity;
-
-    /** Number of memory used/allocated. */
-    pj_size_t	    used_size;
-
-    /** Size of memory block to be allocated when the pool runs out of memory */
-    pj_size_t	    increment_size;
-
-    /** List of memory blocks allcoated by the pool. */
-    pj_pool_block   block_list;
-
-    /** The callback to be called when the pool is unable to allocate memory. */
-    pj_pool_callback *callback;
-
-};
-
-
-/**
- * Guidance on how much memory required for initial pool administrative data.
- */
-#define PJ_POOL_SIZE	        (sizeof(struct pj_pool_t))
-
-/** 
- * Pool memory alignment (must be power of 2). 
- */
-#ifndef PJ_POOL_ALIGNMENT
-#   define PJ_POOL_ALIGNMENT    4
-#endif
-
-/**
- * Create a new pool from the pool factory. This wrapper will call create_pool
- * member of the pool factory.
- *
- * @param factory	    The pool factory.
- * @param name		    The name to be assigned to the pool. The name should 
- *			    not be longer than PJ_MAX_OBJ_NAME (32 chars), or 
- *			    otherwise it will be truncated.
- * @param initial_size	    The size of initial memory blocks taken by the pool.
- *			    Note that the pool will take 68+20 bytes for 
- *			    administrative area from this block.
- * @param increment_size    the size of each additional blocks to be allocated
- *			    when the pool is running out of memory. If user 
- *			    requests memory which is larger than this size, then 
- *			    an error occurs.
- *			    Note that each time a pool allocates additional block, 
- *			    it needs PJ_POOL_SIZE more to store some 
- *			    administrative info.
- * @param callback	    Callback to be called when error occurs in the pool.
- *			    If this value is NULL, then the callback from pool
- *			    factory policy will be used.
- *			    Note that when an error occurs during pool creation, 
- *			    the callback itself is not called. Instead, NULL 
- *			    will be returned.
- *
- * @return                  The memory pool, or NULL.
- */
-PJ_IDECL(pj_pool_t*) pj_pool_create(pj_pool_factory *factory, 
-				    const char *name,
-				    pj_size_t initial_size, 
-				    pj_size_t increment_size,
-				    pj_pool_callback *callback);
-
-/**
- * Release the pool back to pool factory.
- *
- * @param pool	    Memory pool.
- */
-PJ_IDECL(void) pj_pool_release( pj_pool_t *pool );
-
-/**
- * Get pool object name.
- *
- * @param pool the pool.
- *
- * @return pool name as NULL terminated string.
- */
-PJ_IDECL(const char *) pj_pool_getobjname( const pj_pool_t *pool );
-
-/**
- * Reset the pool to its state when it was initialized.
- * This means that if additional blocks have been allocated during runtime, 
- * then they will be freed. Only the original block allocated during 
- * initialization is retained. This function will also reset the internal 
- * counters, such as pool capacity and used size.
- *
- * @param pool the pool.
- */
-PJ_DECL(void) pj_pool_reset( pj_pool_t *pool );
-
-
-/**
- * Get the pool capacity, that is, the system storage that have been allocated
- * by the pool, and have been used/will be used to allocate user requests.
- * There's no guarantee that the returned value represent a single
- * contiguous block, because the capacity may be spread in several blocks.
- *
- * @param pool	the pool.
- *
- * @return the capacity.
- */
-PJ_IDECL(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool );
-
-/**
- * Get the total size of user allocation request.
- *
- * @param pool	the pool.
- *
- * @return the total size.
- */
-PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool );
-
-/**
- * Allocate storage with the specified size from the pool.
- * If there's no storage available in the pool, then the pool can allocate more
- * blocks if the increment size is larger than the requested size.
- *
- * @param pool	    the pool.
- * @param size	    the requested size.
- *
- * @return pointer to the allocated memory.
- */
-PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size);
-
-/**
- * Allocate storage  from the pool, and initialize it to zero.
- * This function behaves like pj_pool_alloc(), except that the storage will
- * be initialized to zero.
- *
- * @param pool	    the pool.
- * @param count	    the number of elements in the array.
- * @param elem	    the size of individual element.
- *
- * @return pointer to the allocated memory.
- */
-PJ_IDECL(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, 
-				pj_size_t elem);
-
-
-/**
- * @def pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)
- * Allocate storage from the pool and initialize it to zero.
- *
- * @param pool	    The pool.
- * @param size	    The size to be allocated.
- *
- * @return	    Pointer to the allocated memory.
- */
-#define pj_pool_zalloc(pool, size)  pj_pool_calloc(pool, 1, size)
-
-
-/**
- * @}	// PJ_POOL
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJ_POOL_FACTORY Pool Factory and Policy.
- * @ingroup PJ_POOL_GROUP
- * @brief
- * Pool factory declares an interface to create and destroy pool. There may
- * be several strategies for pool creation, and these strategies should 
- * implement the interface defined by pool factory.
- *
- * \section PJ_POOL_FACTORY_ITF Pool Factory Interface
- * The pool factory defines the following interface:
- *  - \a policy: the memory pool factory policy.
- *  - \a create_pool(): create a new memory pool.
- *  - \a release_pool(): release memory pool back to factory.
- *
- * \section PJ_POOL_FACTORY_POL Pool Factory Policy.
- * The pool factory policy controls the behaviour of memory factories, and
- * defines the following interface:
- *  - \a block_alloc(): allocate memory block from backend memory mgmt/system.
- *  - \a block_free(): free memory block back to backend memory mgmt/system.
- * @{
- */
-
-/* We unfortunately don't have support for factory policy options as now,
-   so we keep this commented at the moment.
-enum PJ_POOL_FACTORY_OPTION
-{
-    PJ_POOL_FACTORY_SERIALIZE = 1
-};
-*/
-
-/**
- * This structure declares pool factory interface.
- */
-typedef struct pj_pool_factory_policy
-{
-    /**
-     * Allocate memory block (for use by pool). This function is called
-     * by memory pool to allocate memory block.
-     * 
-     * @param factory	Pool factory.
-     * @param size	The size of memory block to allocate.
-     *
-     * @return		Memory block.
-     */
-    void* (*block_alloc)(pj_pool_factory *factory, pj_size_t size);
-
-    /**
-     * Free memory block.
-     *
-     * @param factory	Pool factory.
-     * @param mem	Memory block previously allocated by block_alloc().
-     * @param size	The size of memory block.
-     */
-    void (*block_free)(pj_pool_factory *factory, void *mem, pj_size_t size);
-
-    /**
-     * Default callback to be called when memory allocation fails.
-     */
-    pj_pool_callback *callback;
-
-    /**
-     * Option flags.
-     */
-    unsigned flags;
-
-} pj_pool_factory_policy;
-
-/**
- * This constant denotes the exception number that will be thrown by default
- * memory factory policy when memory allocation fails.
- */
-extern int PJ_NO_MEMORY_EXCEPTION;
-
-/**
- * This global variable points to default memory pool factory policy.
- * The behaviour of the default policy is:
- *  - block allocation and deallocation use malloc() and free().
- *  - callback will raise PJ_NO_MEMORY_EXCEPTION exception.
- *  - access to pool factory is not serialized (i.e. not thread safe).
- */
-extern pj_pool_factory_policy pj_pool_factory_default_policy;
-
-/**
- * This structure contains the declaration for pool factory interface.
- */
-struct pj_pool_factory
-{
-    /**
-     * Memory pool policy.
-     */
-    pj_pool_factory_policy policy;
-
-    /**
-    * Create a new pool from the pool factory.
-    *
-    * @param factory	The pool factory.
-    * @param name	the name to be assigned to the pool. The name should 
-    *			not be longer than PJ_MAX_OBJ_NAME (32 chars), or 
-    *			otherwise it will be truncated.
-    * @param initial_size the size of initial memory blocks taken by the pool.
-    *			Note that the pool will take 68+20 bytes for 
-    *			administrative area from this block.
-    * @param increment_size the size of each additional blocks to be allocated
-    *			when the pool is running out of memory. If user 
-    *			requests memory which is larger than this size, then 
-    *			an error occurs.
-    *			Note that each time a pool allocates additional block, 
-    *			it needs 20 bytes (equal to sizeof(pj_pool_block)) to 
-    *			store some administrative info.
-    * @param callback	Cllback to be called when error occurs in the pool.
-    *			Note that when an error occurs during pool creation, 
-    *			the callback itself is not called. Instead, NULL 
-    *			will be returned.
-    *
-    * @return the memory pool, or NULL.
-    */
-    pj_pool_t*	(*create_pool)( pj_pool_factory *factory,
-				const char *name,
-				pj_size_t initial_size, 
-				pj_size_t increment_size,
-				pj_pool_callback *callback);
-
-    /**
-     * Release the pool to the pool factory.
-     *
-     * @param factory	The pool factory.
-     * @param pool	The pool to be released.
-    */
-    void (*release_pool)( pj_pool_factory *factory, pj_pool_t *pool );
-
-    /**
-     * Dump pool status to log.
-     *
-     * @param factory	The pool factory.
-     */
-    void (*dump_status)( pj_pool_factory *factory, pj_bool_t detail );
-};
-
-/**
- * This function is intended to be used by pool factory implementors.
- * @param factory           Pool factory.
- * @param name              Pool name.
- * @param initial_size      Initial size.
- * @param increment_size    Increment size.
- * @param callback          Callback.
- * @return                  The pool object, or NULL.
- */
-PJ_DECL(pj_pool_t*) pj_pool_create_int(	pj_pool_factory *factory, 
-					const char *name,
-					pj_size_t initial_size, 
-					pj_size_t increment_size,
-					pj_pool_callback *callback);
-
-/**
- * This function is intended to be used by pool factory implementors.
- * @param pool              The pool.
- * @param name              Pool name.
- * @param increment_size    Increment size.
- * @param callback          Callback function.
- */
-PJ_DECL(void) pj_pool_init_int( pj_pool_t *pool, 
-				const char *name,
-				pj_size_t increment_size,
-				pj_pool_callback *callback);
-
-/**
- * This function is intended to be used by pool factory implementors.
- * @param pool      The memory pool.
- */
-PJ_DECL(void) pj_pool_destroy_int( pj_pool_t *pool );
-
-
-/**
- *  @}	// PJ_POOL_FACTORY
- */
-
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * @defgroup PJ_CACHING_POOL Caching Pool Factory.
- * @ingroup PJ_POOL_GROUP
- * @brief
- * Caching pool is one sample implementation of pool factory where the
- * factory can reuse memory to create a pool. Application defines what the 
- * maximum memory the factory can hold, and when a pool is released the
- * factory decides whether to destroy the pool or to keep it for future use.
- * If the total amount of memory in the internal cache is still within the
- * limit, the factory will keep the pool in the internal cache, otherwise the
- * pool will be destroyed, thus releasing the memory back to the system.
- *
- * @{
- */
-
-/**
- * Number of unique sizes, to be used as index to the free list.
- * Each pool in the free list is organized by it's size.
- */
-#define PJ_CACHING_POOL_ARRAY_SIZE	16
-
-/**
- * Declaration for caching pool. Application doesn't normally need to
- * care about the contents of this struct, it is only provided here because
- * application need to define an instance of this struct (we can not allocate
- * the struct from a pool since there is no pool factory yet!).
- */
-struct pj_caching_pool 
-{
-    /** Pool factory interface, must be declared first. */
-    pj_pool_factory factory;
-
-    /** Current factory's capacity, i.e. number of bytes that are allocated
-     *  and available for application in this factory. The factory's
-     *  capacity represents the size of all pools kept by this factory
-     *  in it's free list, which will be returned to application when it
-     *  requests to create a new pool.
-     */
-    pj_size_t	    capacity;
-
-    /** Maximum size that can be held by this factory. Once the capacity
-     *  has exceeded @a max_capacity, further #pj_pool_release() will
-     *  flush the pool. If the capacity is still below the @a max_capacity,
-     *  #pj_pool_release() will save the pool to the factory's free list.
-     */
-    pj_size_t       max_capacity;
-
-    /**
-     * Number of pools currently held by applications. This number gets
-     * incremented everytime #pj_pool_create() is called, and gets
-     * decremented when #pj_pool_release() is called.
-     */
-    pj_size_t       used_count;
-
-    /**
-     * Lists of pools in the cache, indexed by pool size.
-     */
-    pj_list	    free_list[PJ_CACHING_POOL_ARRAY_SIZE];
-
-    /**
-     * List of pools currently allocated by applications.
-     */
-    pj_list	    used_list;
-};
-
-
-
-/**
- * Initialize caching pool.
- *
- * @param ch_pool	The caching pool factory to be initialized.
- * @param policy	Pool factory policy.
- * @param max_capacity	The total capacity to be retained in the cache. When
- *			the pool is returned to the cache, it will be kept in
- *			recycling list if the total capacity of pools in this
- *			list plus the capacity of the pool is still below this
- *			value.
- */
-PJ_DECL(void) pj_caching_pool_init( pj_caching_pool *ch_pool, 
-				    const pj_pool_factory_policy *policy,
-				    pj_size_t max_capacity);
-
-
-/**
- * Destroy caching pool, and release all the pools in the recycling list.
- *
- * @param ch_pool	The caching pool.
- */
-PJ_DECL(void) pj_caching_pool_destroy( pj_caching_pool *ch_pool );
-
-/**
- * @}	// PJ_CACHING_POOL
- */
-
-#  if PJ_FUNCTIONS_ARE_INLINED
-#    include "pool_i.h"
-#  endif
-
-PJ_END_DECL
-    
-#endif	/* __PJ_POOL_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_POOL_H__

+#define __PJ_POOL_H__

+

+/**

+ * @file pool.h

+ * @brief Memory Pool.

+ */

+

+#include <pj/list.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_POOL_GROUP Memory Pool Management

+ * @ingroup PJ

+ * @brief

+ * Memory pool management provides API to allocate and deallocate memory from

+ * memory pool and to manage and establish policy for pool creation and

+ * destruction in pool factory.

+ *

+ * \section PJ_POOL_FACTORY_SEC Pool Factory

+ * See: \ref PJ_POOL_FACTORY "Pool Factory"

+ *

+ * A memory pool must be created through a factory. A factory not only provides

+ * generic interface functions to create and release pool, but also provides 

+ * strategy to manage the life time of pools. One sample implementation, 

+ * \a pj_caching_pool, can be set to keep the pools released by application for

+ * future use as long as the total memory is below the limit.

+ * 

+ * The pool factory interface declared in PJLIB is designed to be extensible.

+ * Application can define its own strategy by creating it's own pool factory

+ * implementation, and this strategy can be used even by existing library

+ * without recompilation.

+ *

+ *

+ * \section PJ_POOL_POLICY_SEC Pool Factory Policy

+ * See: \ref PJ_POOL_FACTORY "Pool Factory Policy"

+ *

+ * A pool factory only defines functions to create and release pool and how

+ * to manage pools, but the rest of the functionalities are controlled by

+ * policy. A pool policy defines:

+ *  - how memory block is allocated and deallocated (the default implementation

+ *    allocates and deallocate memory by calling malloc() and free()).

+ *  - callback to be called when memory allocation inside a pool fails (the

+ *    default implementation will throw PJ_NO_MEMORY_EXCEPTION exception).

+ *  - concurrency when creating and releasing pool from/to the factory.

+ *

+ * A pool factory can be given different policy during creation to make

+ * it behave differently. For example, caching pool factory can be configured

+ * to allocate and deallocate from a static/contiguous/preallocated memory 

+ * instead of using malloc()/free().

+ * 

+ * What strategy/factory and what policy to use is not defined by PJLIB, but

+ * instead is left to application to make use whichever is most efficient for

+ * itself.

+ *

+ *

+ * \section PJ_POOL_POOL_SEC The Pool

+ * See: \ref PJ_POOL "Pool"

+ *

+ * The memory pool is an opaque object created by pool factory.

+ * Application uses this object to request a memory chunk, by calling

+ * #pj_pool_alloc or #pj_pool_calloc. When the application has finished using

+ * the pool, it must call #pj_pool_release to free all the chunks previously

+ * allocated and release the pool back to the factory.

+ *

+ * \section PJ_POOL_THREADING_SEC More on Threading Policies:

+ * - By design, memory allocation from a pool is not thread safe. We assumed 

+ *   that a pool will be owned by an object, and thread safety should be 

+ *   handled by that object. Thus these functions are not thread safe: 

+ *	- #pj_pool_alloc, 

+ *	- #pj_pool_calloc, 

+ *	- and other pool statistic functions.

+ * - Threading in the pool factory is decided by the policy set for the

+ *   factory when it was created.

+ *

+ * \section PJ_POOL_EXAMPLES_SEC Examples

+ *

+ * For some sample codes on how to use the pool, please see:

+ *  - @ref page_pjlib_pool_test

+ */

+

+/**

+ * @defgroup PJ_POOL Memory Pool.

+ * @ingroup PJ_POOL_GROUP

+ * @brief

+ * A memory pool is initialized with an initial amount of memory, which is

+ * called a block. Pool can be configured to dynamically allocate more memory 

+ * blocks when it runs out of memory. Subsequent memory allocations by user 

+ * will use up portions of these block. 

+ * The pool doesn't keep track of individual memory allocations

+ * by user, and the user doesn't have to free these indidual allocations. This

+ * makes memory allocation simple and very fast. All the memory allocated from

+ * the pool will be destroyed when the pool itself is destroyed.

+ * @{

+ */

+

+/**

+ * The type for function to receive callback from the pool when it is unable

+ * to allocate memory. The elegant way to handle this condition is to throw

+ * exception, and this is what is expected by most of this library 

+ * components.

+ */

+typedef void pj_pool_callback(pj_pool_t *pool, pj_size_t size);

+

+/**

+ * This class, which is used internally by the pool, describes a single 

+ * block of memory from which user memory allocations will be allocated from.

+ */

+typedef struct pj_pool_block

+{

+    PJ_DECL_LIST_MEMBER(struct pj_pool_block);  /**< List's prev and next.  */

+    unsigned char    *buf;                      /**< Start of buffer.       */

+    unsigned char    *cur;                      /**< Current alloc ptr.     */

+    unsigned char    *end;                      /**< End of buffer.         */

+} pj_pool_block;

+

+

+/**

+ * This structure describes the memory pool. Only implementors of pool factory

+ * need to care about the contents of this structure.

+ */

+struct pj_pool_t

+{

+    PJ_DECL_LIST_MEMBER(struct pj_pool_t);  /**< Standard list elements.    */

+

+    /** Pool name */

+    char	    obj_name[PJ_MAX_OBJ_NAME];

+

+    /** Pool factory. */

+    pj_pool_factory *factory;

+

+    /** Current capacity allocated by the pool. */

+    pj_size_t	    capacity;

+

+    /** Number of memory used/allocated. */

+    pj_size_t	    used_size;

+

+    /** Size of memory block to be allocated when the pool runs out of memory */

+    pj_size_t	    increment_size;

+

+    /** List of memory blocks allcoated by the pool. */

+    pj_pool_block   block_list;

+

+    /** The callback to be called when the pool is unable to allocate memory. */

+    pj_pool_callback *callback;

+

+};

+

+

+/**

+ * Guidance on how much memory required for initial pool administrative data.

+ */

+#define PJ_POOL_SIZE	        (sizeof(struct pj_pool_t))

+

+/** 

+ * Pool memory alignment (must be power of 2). 

+ */

+#ifndef PJ_POOL_ALIGNMENT

+#   define PJ_POOL_ALIGNMENT    4

+#endif

+

+/**

+ * Create a new pool from the pool factory. This wrapper will call create_pool

+ * member of the pool factory.

+ *

+ * @param factory	    The pool factory.

+ * @param name		    The name to be assigned to the pool. The name should 

+ *			    not be longer than PJ_MAX_OBJ_NAME (32 chars), or 

+ *			    otherwise it will be truncated.

+ * @param initial_size	    The size of initial memory blocks taken by the pool.

+ *			    Note that the pool will take 68+20 bytes for 

+ *			    administrative area from this block.

+ * @param increment_size    the size of each additional blocks to be allocated

+ *			    when the pool is running out of memory. If user 

+ *			    requests memory which is larger than this size, then 

+ *			    an error occurs.

+ *			    Note that each time a pool allocates additional block, 

+ *			    it needs PJ_POOL_SIZE more to store some 

+ *			    administrative info.

+ * @param callback	    Callback to be called when error occurs in the pool.

+ *			    If this value is NULL, then the callback from pool

+ *			    factory policy will be used.

+ *			    Note that when an error occurs during pool creation, 

+ *			    the callback itself is not called. Instead, NULL 

+ *			    will be returned.

+ *

+ * @return                  The memory pool, or NULL.

+ */

+PJ_IDECL(pj_pool_t*) pj_pool_create(pj_pool_factory *factory, 

+				    const char *name,

+				    pj_size_t initial_size, 

+				    pj_size_t increment_size,

+				    pj_pool_callback *callback);

+

+/**

+ * Release the pool back to pool factory.

+ *

+ * @param pool	    Memory pool.

+ */

+PJ_IDECL(void) pj_pool_release( pj_pool_t *pool );

+

+/**

+ * Get pool object name.

+ *

+ * @param pool the pool.

+ *

+ * @return pool name as NULL terminated string.

+ */

+PJ_IDECL(const char *) pj_pool_getobjname( const pj_pool_t *pool );

+

+/**

+ * Reset the pool to its state when it was initialized.

+ * This means that if additional blocks have been allocated during runtime, 

+ * then they will be freed. Only the original block allocated during 

+ * initialization is retained. This function will also reset the internal 

+ * counters, such as pool capacity and used size.

+ *

+ * @param pool the pool.

+ */

+PJ_DECL(void) pj_pool_reset( pj_pool_t *pool );

+

+

+/**

+ * Get the pool capacity, that is, the system storage that have been allocated

+ * by the pool, and have been used/will be used to allocate user requests.

+ * There's no guarantee that the returned value represent a single

+ * contiguous block, because the capacity may be spread in several blocks.

+ *

+ * @param pool	the pool.

+ *

+ * @return the capacity.

+ */

+PJ_IDECL(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool );

+

+/**

+ * Get the total size of user allocation request.

+ *

+ * @param pool	the pool.

+ *

+ * @return the total size.

+ */

+PJ_IDECL(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool );

+

+/**

+ * Allocate storage with the specified size from the pool.

+ * If there's no storage available in the pool, then the pool can allocate more

+ * blocks if the increment size is larger than the requested size.

+ *

+ * @param pool	    the pool.

+ * @param size	    the requested size.

+ *

+ * @return pointer to the allocated memory.

+ */

+PJ_IDECL(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size);

+

+/**

+ * Allocate storage  from the pool, and initialize it to zero.

+ * This function behaves like pj_pool_alloc(), except that the storage will

+ * be initialized to zero.

+ *

+ * @param pool	    the pool.

+ * @param count	    the number of elements in the array.

+ * @param elem	    the size of individual element.

+ *

+ * @return pointer to the allocated memory.

+ */

+PJ_IDECL(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, 

+				pj_size_t elem);

+

+

+/**

+ * @def pj_pool_zalloc(pj_pool_t *pool, pj_size_t size)

+ * Allocate storage from the pool and initialize it to zero.

+ *

+ * @param pool	    The pool.

+ * @param size	    The size to be allocated.

+ *

+ * @return	    Pointer to the allocated memory.

+ */

+#define pj_pool_zalloc(pool, size)  pj_pool_calloc(pool, 1, size)

+

+

+/**

+ * @}	// PJ_POOL

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJ_POOL_FACTORY Pool Factory and Policy.

+ * @ingroup PJ_POOL_GROUP

+ * @brief

+ * Pool factory declares an interface to create and destroy pool. There may

+ * be several strategies for pool creation, and these strategies should 

+ * implement the interface defined by pool factory.

+ *

+ * \section PJ_POOL_FACTORY_ITF Pool Factory Interface

+ * The pool factory defines the following interface:

+ *  - \a policy: the memory pool factory policy.

+ *  - \a create_pool(): create a new memory pool.

+ *  - \a release_pool(): release memory pool back to factory.

+ *

+ * \section PJ_POOL_FACTORY_POL Pool Factory Policy.

+ * The pool factory policy controls the behaviour of memory factories, and

+ * defines the following interface:

+ *  - \a block_alloc(): allocate memory block from backend memory mgmt/system.

+ *  - \a block_free(): free memory block back to backend memory mgmt/system.

+ * @{

+ */

+

+/* We unfortunately don't have support for factory policy options as now,

+   so we keep this commented at the moment.

+enum PJ_POOL_FACTORY_OPTION

+{

+    PJ_POOL_FACTORY_SERIALIZE = 1

+};

+*/

+

+/**

+ * This structure declares pool factory interface.

+ */

+typedef struct pj_pool_factory_policy

+{

+    /**

+     * Allocate memory block (for use by pool). This function is called

+     * by memory pool to allocate memory block.

+     * 

+     * @param factory	Pool factory.

+     * @param size	The size of memory block to allocate.

+     *

+     * @return		Memory block.

+     */

+    void* (*block_alloc)(pj_pool_factory *factory, pj_size_t size);

+

+    /**

+     * Free memory block.

+     *

+     * @param factory	Pool factory.

+     * @param mem	Memory block previously allocated by block_alloc().

+     * @param size	The size of memory block.

+     */

+    void (*block_free)(pj_pool_factory *factory, void *mem, pj_size_t size);

+

+    /**

+     * Default callback to be called when memory allocation fails.

+     */

+    pj_pool_callback *callback;

+

+    /**

+     * Option flags.

+     */

+    unsigned flags;

+

+} pj_pool_factory_policy;

+

+/**

+ * This constant denotes the exception number that will be thrown by default

+ * memory factory policy when memory allocation fails.

+ */

+extern int PJ_NO_MEMORY_EXCEPTION;

+

+/**

+ * This global variable points to default memory pool factory policy.

+ * The behaviour of the default policy is:

+ *  - block allocation and deallocation use malloc() and free().

+ *  - callback will raise PJ_NO_MEMORY_EXCEPTION exception.

+ *  - access to pool factory is not serialized (i.e. not thread safe).

+ */

+extern pj_pool_factory_policy pj_pool_factory_default_policy;

+

+/**

+ * This structure contains the declaration for pool factory interface.

+ */

+struct pj_pool_factory

+{

+    /**

+     * Memory pool policy.

+     */

+    pj_pool_factory_policy policy;

+

+    /**

+    * Create a new pool from the pool factory.

+    *

+    * @param factory	The pool factory.

+    * @param name	the name to be assigned to the pool. The name should 

+    *			not be longer than PJ_MAX_OBJ_NAME (32 chars), or 

+    *			otherwise it will be truncated.

+    * @param initial_size the size of initial memory blocks taken by the pool.

+    *			Note that the pool will take 68+20 bytes for 

+    *			administrative area from this block.

+    * @param increment_size the size of each additional blocks to be allocated

+    *			when the pool is running out of memory. If user 

+    *			requests memory which is larger than this size, then 

+    *			an error occurs.

+    *			Note that each time a pool allocates additional block, 

+    *			it needs 20 bytes (equal to sizeof(pj_pool_block)) to 

+    *			store some administrative info.

+    * @param callback	Cllback to be called when error occurs in the pool.

+    *			Note that when an error occurs during pool creation, 

+    *			the callback itself is not called. Instead, NULL 

+    *			will be returned.

+    *

+    * @return the memory pool, or NULL.

+    */

+    pj_pool_t*	(*create_pool)( pj_pool_factory *factory,

+				const char *name,

+				pj_size_t initial_size, 

+				pj_size_t increment_size,

+				pj_pool_callback *callback);

+

+    /**

+     * Release the pool to the pool factory.

+     *

+     * @param factory	The pool factory.

+     * @param pool	The pool to be released.

+    */

+    void (*release_pool)( pj_pool_factory *factory, pj_pool_t *pool );

+

+    /**

+     * Dump pool status to log.

+     *

+     * @param factory	The pool factory.

+     */

+    void (*dump_status)( pj_pool_factory *factory, pj_bool_t detail );

+};

+

+/**

+ * This function is intended to be used by pool factory implementors.

+ * @param factory           Pool factory.

+ * @param name              Pool name.

+ * @param initial_size      Initial size.

+ * @param increment_size    Increment size.

+ * @param callback          Callback.

+ * @return                  The pool object, or NULL.

+ */

+PJ_DECL(pj_pool_t*) pj_pool_create_int(	pj_pool_factory *factory, 

+					const char *name,

+					pj_size_t initial_size, 

+					pj_size_t increment_size,

+					pj_pool_callback *callback);

+

+/**

+ * This function is intended to be used by pool factory implementors.

+ * @param pool              The pool.

+ * @param name              Pool name.

+ * @param increment_size    Increment size.

+ * @param callback          Callback function.

+ */

+PJ_DECL(void) pj_pool_init_int( pj_pool_t *pool, 

+				const char *name,

+				pj_size_t increment_size,

+				pj_pool_callback *callback);

+

+/**

+ * This function is intended to be used by pool factory implementors.

+ * @param pool      The memory pool.

+ */

+PJ_DECL(void) pj_pool_destroy_int( pj_pool_t *pool );

+

+

+/**

+ *  @}	// PJ_POOL_FACTORY

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+

+/**

+ * @defgroup PJ_CACHING_POOL Caching Pool Factory.

+ * @ingroup PJ_POOL_GROUP

+ * @brief

+ * Caching pool is one sample implementation of pool factory where the

+ * factory can reuse memory to create a pool. Application defines what the 

+ * maximum memory the factory can hold, and when a pool is released the

+ * factory decides whether to destroy the pool or to keep it for future use.

+ * If the total amount of memory in the internal cache is still within the

+ * limit, the factory will keep the pool in the internal cache, otherwise the

+ * pool will be destroyed, thus releasing the memory back to the system.

+ *

+ * @{

+ */

+

+/**

+ * Number of unique sizes, to be used as index to the free list.

+ * Each pool in the free list is organized by it's size.

+ */

+#define PJ_CACHING_POOL_ARRAY_SIZE	16

+

+/**

+ * Declaration for caching pool. Application doesn't normally need to

+ * care about the contents of this struct, it is only provided here because

+ * application need to define an instance of this struct (we can not allocate

+ * the struct from a pool since there is no pool factory yet!).

+ */

+struct pj_caching_pool 

+{

+    /** Pool factory interface, must be declared first. */

+    pj_pool_factory factory;

+

+    /** Current factory's capacity, i.e. number of bytes that are allocated

+     *  and available for application in this factory. The factory's

+     *  capacity represents the size of all pools kept by this factory

+     *  in it's free list, which will be returned to application when it

+     *  requests to create a new pool.

+     */

+    pj_size_t	    capacity;

+

+    /** Maximum size that can be held by this factory. Once the capacity

+     *  has exceeded @a max_capacity, further #pj_pool_release() will

+     *  flush the pool. If the capacity is still below the @a max_capacity,

+     *  #pj_pool_release() will save the pool to the factory's free list.

+     */

+    pj_size_t       max_capacity;

+

+    /**

+     * Number of pools currently held by applications. This number gets

+     * incremented everytime #pj_pool_create() is called, and gets

+     * decremented when #pj_pool_release() is called.

+     */

+    pj_size_t       used_count;

+

+    /**

+     * Lists of pools in the cache, indexed by pool size.

+     */

+    pj_list	    free_list[PJ_CACHING_POOL_ARRAY_SIZE];

+

+    /**

+     * List of pools currently allocated by applications.

+     */

+    pj_list	    used_list;

+};

+

+

+

+/**

+ * Initialize caching pool.

+ *

+ * @param ch_pool	The caching pool factory to be initialized.

+ * @param policy	Pool factory policy.

+ * @param max_capacity	The total capacity to be retained in the cache. When

+ *			the pool is returned to the cache, it will be kept in

+ *			recycling list if the total capacity of pools in this

+ *			list plus the capacity of the pool is still below this

+ *			value.

+ */

+PJ_DECL(void) pj_caching_pool_init( pj_caching_pool *ch_pool, 

+				    const pj_pool_factory_policy *policy,

+				    pj_size_t max_capacity);

+

+

+/**

+ * Destroy caching pool, and release all the pools in the recycling list.

+ *

+ * @param ch_pool	The caching pool.

+ */

+PJ_DECL(void) pj_caching_pool_destroy( pj_caching_pool *ch_pool );

+

+/**

+ * @}	// PJ_CACHING_POOL

+ */

+

+#  if PJ_FUNCTIONS_ARE_INLINED

+#    include "pool_i.h"

+#  endif

+

+PJ_END_DECL

+    

+#endif	/* __PJ_POOL_H__ */

+

diff --git a/pjlib/include/pj/pool_i.h b/pjlib/include/pj/pool_i.h
index 4a99908..f23b52a 100644
--- a/pjlib/include/pj/pool_i.h
+++ b/pjlib/include/pj/pool_i.h
@@ -1,76 +1,97 @@
-/* $Id$
- *
- */
-
-
-#include <pj/string.h>
-
-PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size);
-
-PJ_IDEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )
-{
-    return pool->capacity;
-}
-
-PJ_IDEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )
-{
-    return pool->used_size;
-}
-
-PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_t *pool,
-					 pj_pool_block *block, pj_size_t size )
-{
-    /* The operation below is valid for size==0. 
-     * When size==0, the function will return the pointer to the pool
-     * memory address, but no memory will be allocated.
-     */
-    if (size & (PJ_POOL_ALIGNMENT-1)) {
-	size &= ~(PJ_POOL_ALIGNMENT-1);
-	size += PJ_POOL_ALIGNMENT;
-    }
-    if ((unsigned)(block->end - block->cur) >= size) {
-	void *ptr = block->cur;
-	block->cur += size;
-	pool->used_size += size;
-	return ptr;
-    }
-    return NULL;
-}
-
-PJ_IDEF(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size)
-{
-    pj_pool_block *block = pool->block_list.next;
-    void *ptr = pj_pool_alloc_from_block(pool, block, size);
-    if (!ptr)
-	ptr = pj_pool_allocate_find(pool, size);
-    return ptr;
-}
-
-
-PJ_IDEF(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, pj_size_t size)
-{
-    void *buf = pj_pool_alloc( pool, size*count);
-    if (buf)
-	pj_memset(buf, 0, size * count);
-    return buf;
-}
-
-PJ_IDEF(const char *) pj_pool_getobjname( const pj_pool_t *pool )
-{
-    return pool->obj_name;
-}
-
-PJ_IDEF(pj_pool_t*) pj_pool_create( pj_pool_factory *f, 
-				    const char *name,
-				    pj_size_t initial_size, 
-				    pj_size_t increment_size,
-				    pj_pool_callback *callback)
-{
-    return (*f->create_pool)(f, name, initial_size, increment_size, callback);
-}
-
-PJ_IDEF(void) pj_pool_release( pj_pool_t *pool )
-{
-    (*pool->factory->release_pool)(pool->factory, pool);
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+

+#include <pj/string.h>

+

+PJ_DECL(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size);

+

+PJ_IDEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )

+{

+    return pool->capacity;

+}

+

+PJ_IDEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )

+{

+    return pool->used_size;

+}

+

+PJ_IDEF(void*) pj_pool_alloc_from_block( pj_pool_t *pool,

+					 pj_pool_block *block, pj_size_t size )

+{

+    /* The operation below is valid for size==0. 

+     * When size==0, the function will return the pointer to the pool

+     * memory address, but no memory will be allocated.

+     */

+    if (size & (PJ_POOL_ALIGNMENT-1)) {

+	size &= ~(PJ_POOL_ALIGNMENT-1);

+	size += PJ_POOL_ALIGNMENT;

+    }

+    if ((unsigned)(block->end - block->cur) >= size) {

+	void *ptr = block->cur;

+	block->cur += size;

+	pool->used_size += size;

+	return ptr;

+    }

+    return NULL;

+}

+

+PJ_IDEF(void*) pj_pool_alloc( pj_pool_t *pool, pj_size_t size)

+{

+    pj_pool_block *block = pool->block_list.next;

+    void *ptr = pj_pool_alloc_from_block(pool, block, size);

+    if (!ptr)

+	ptr = pj_pool_allocate_find(pool, size);

+    return ptr;

+}

+

+

+PJ_IDEF(void*) pj_pool_calloc( pj_pool_t *pool, pj_size_t count, pj_size_t size)

+{

+    void *buf = pj_pool_alloc( pool, size*count);

+    if (buf)

+	pj_memset(buf, 0, size * count);

+    return buf;

+}

+

+PJ_IDEF(const char *) pj_pool_getobjname( const pj_pool_t *pool )

+{

+    return pool->obj_name;

+}

+

+PJ_IDEF(pj_pool_t*) pj_pool_create( pj_pool_factory *f, 

+				    const char *name,

+				    pj_size_t initial_size, 

+				    pj_size_t increment_size,

+				    pj_pool_callback *callback)

+{

+    return (*f->create_pool)(f, name, initial_size, increment_size, callback);

+}

+

+PJ_IDEF(void) pj_pool_release( pj_pool_t *pool )

+{

+    (*pool->factory->release_pool)(pool->factory, pool);

+}

+

diff --git a/pjlib/include/pj/rand.h b/pjlib/include/pj/rand.h
index 0549c72..f431cd8 100644
--- a/pjlib/include/pj/rand.h
+++ b/pjlib/include/pj/rand.h
@@ -1,62 +1,83 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/rand.h $
- * 
- * 3     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 2     9/17/05 10:37a Bennylp
- * Major reorganization towards version 0.3.
- * 
- * 1     9/15/05 8:40p Bennylp
- * Created.
- */
-#ifndef __PJ_RAND_H__
-#define __PJ_RAND_H__
-
-/**
- * @file rand.h
- * @brief Random Number Generator.
- */
-
-#include <pj/config.h>
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJ_RAND Random Number Generator
- * @ingroup PJ_MISC
- * @{
- * This module contains functions for generating random numbers.
- * This abstraction is needed not only because not all platforms have
- * \a rand() and \a srand(), but also on some platforms \a rand()
- * only has 16-bit randomness, which is not good enough.
- */
-
-/**
- * Put in seed to random number generator.
- *
- * @param seed	    Seed value.
- */
-PJ_DECL(void) pj_srand(unsigned int seed);
-
-
-/**
- * Generate random integer with 32bit randomness.
- *
- * @return a random integer.
- */
-PJ_DECL(int) pj_rand(void);
-
-
-/** @} */
-
-
-PJ_END_DECL
-
-
-#endif	/* __PJ_RAND_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/rand.h $

+ * 

+ * 3     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 2     9/17/05 10:37a Bennylp

+ * Major reorganization towards version 0.3.

+ * 

+ * 1     9/15/05 8:40p Bennylp

+ * Created.

+ */

+#ifndef __PJ_RAND_H__

+#define __PJ_RAND_H__

+

+/**

+ * @file rand.h

+ * @brief Random Number Generator.

+ */

+

+#include <pj/config.h>

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJ_RAND Random Number Generator

+ * @ingroup PJ_MISC

+ * @{

+ * This module contains functions for generating random numbers.

+ * This abstraction is needed not only because not all platforms have

+ * \a rand() and \a srand(), but also on some platforms \a rand()

+ * only has 16-bit randomness, which is not good enough.

+ */

+

+/**

+ * Put in seed to random number generator.

+ *

+ * @param seed	    Seed value.

+ */

+PJ_DECL(void) pj_srand(unsigned int seed);

+

+

+/**

+ * Generate random integer with 32bit randomness.

+ *

+ * @return a random integer.

+ */

+PJ_DECL(int) pj_rand(void);

+

+

+/** @} */

+

+

+PJ_END_DECL

+

+

+#endif	/* __PJ_RAND_H__ */

+

diff --git a/pjlib/include/pj/rbtree.h b/pjlib/include/pj/rbtree.h
index 67efe2e..06523a4 100644
--- a/pjlib/include/pj/rbtree.h
+++ b/pjlib/include/pj/rbtree.h
@@ -1,195 +1,216 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_RBTREE_H__
-#define __PJ_RBTREE_H__
-
-/**
- * @file rbtree.h
- * @brief Red/Black Tree
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_RBTREE Red/Black Balanced Tree
- * @ingroup PJ_DS
- * @brief
- * Red/Black tree is the variant of balanced tree, where the search, insert, 
- * and delete operation is \b guaranteed to take at most \a O( lg(n) ).
- * @{
- */
-/**
- * Color type for Red-Black tree.
- */ 
-typedef enum pj_rbcolor_t
-{
-    PJ_RBCOLOR_BLACK,
-    PJ_RBCOLOR_RED
-} pj_rbcolor_t;
-
-/**
- * The type of the node of the R/B Tree.
- */
-typedef struct pj_rbtree_node 
-{
-    /** Pointers to the node's parent, and left and right siblings. */
-    struct pj_rbtree_node *parent, *left, *right;
-
-    /** Key associated with the node. */
-    const void *key;
-
-    /** User data associated with the node. */
-    void *user_data;
-
-    /** The R/B Tree node color. */
-    pj_rbcolor_t color;
-
-} pj_rbtree_node;
-
-
-/**
- * The type of function use to compare key value of tree node.
- * @return
- *  0 if the keys are equal
- * <0 if key1 is lower than key2
- * >0 if key1 is greater than key2.
- */
-typedef int pj_rbtree_comp(const void *key1, const void *key2);
-
-
-/**
- * Declaration of a red-black tree. All elements in the tree must have UNIQUE
- * key.
- * A red black tree always maintains the balance of the tree, so that the
- * tree height will not be greater than lg(N). Insert, search, and delete
- * operation will take lg(N) on the worst case. But for insert and delete,
- * there is additional time needed to maintain the balance of the tree.
- */
-typedef struct pj_rbtree
-{
-    pj_rbtree_node null_node;   /**< Constant to indicate NULL node.    */
-    pj_rbtree_node *null;       /**< Constant to indicate NULL node.    */
-    pj_rbtree_node *root;       /**< Root tree node.                    */
-    unsigned size;              /**< Number of elements in the tree.    */
-    pj_rbtree_comp *comp;       /**< Key comparison function.           */
-} pj_rbtree;
-
-
-/**
- * Guidance on how much memory required for each of the node.
- */
-#define PJ_RBTREE_NODE_SIZE	    (sizeof(pj_rbtree_node))
-
-
-/**
- * Guidance on memory required for the tree.
- */
-#define PJ_RBTREE_SIZE		    (sizeof(pj_rbtree))
-
-
-/**
- * Initialize the tree.
- * @param tree the tree to be initialized.
- * @param comp key comparison function to be used for this tree.
- */
-PJ_DECL(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp);
-
-/**
- * Get the first element in the tree.
- * The first element always has the least value for the key, according to
- * the comparison function.
- * @param tree the tree.
- * @return the tree node, or NULL if the tree has no element.
- */
-PJ_DECL(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree );
-
-/**
- * Get the last element in the tree.
- * The last element always has the greatest key value, according to the
- * comparison function defined for the tree.
- * @param tree the tree.
- * @return the tree node, or NULL if the tree has no element.
- */
-PJ_DECL(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree );
-
-/**
- * Get the successive element for the specified node.
- * The successive element is an element with greater key value.
- * @param tree the tree.
- * @param node the node.
- * @return the successive node, or NULL if the node has no successor.
- */
-PJ_DECL(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, 
-					 pj_rbtree_node *node );
-
-/**
- * The the previous node for the specified node.
- * The previous node is an element with less key value.
- * @param tree the tree.
- * @param node the node.
- * @return the previous node, or NULL if the node has no previous node.
- */
-PJ_DECL(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, 
-					 pj_rbtree_node *node );
-
-/**
- * Insert a new node. 
- * The node will be inserted at sorted location. The key of the node must 
- * be UNIQUE, i.e. it hasn't existed in the tree.
- * @param tree the tree.
- * @param node the node to be inserted.
- * @return zero on success, or -1 if the key already exist.
- */
-PJ_DECL(int) pj_rbtree_insert( pj_rbtree *tree, 
-			       pj_rbtree_node *node );
-
-/**
- * Find a node which has the specified key.
- * @param tree the tree.
- * @param key the key to search.
- * @return the tree node with the specified key, or NULL if the key can not
- *         be found.
- */
-PJ_DECL(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,
-					 const void *key );
-
-/**
- * Erase a node from the tree.
- * @param tree the tree.
- * @param node the node to be erased.
- * @return the tree node itself.
- */
-PJ_DECL(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,
-					  pj_rbtree_node *node );
-
-/**
- * Get the maximum tree height from the specified node.
- * @param tree the tree.
- * @param node the node, or NULL to get the root of the tree.
- * @return the maximum height, which should be at most lg(N)
- */
-PJ_DECL(unsigned) pj_rbtree_max_height( pj_rbtree *tree,
-					pj_rbtree_node *node );
-
-/**
- * Get the minumum tree height from the specified node.
- * @param tree the tree.
- * @param node the node, or NULL to get the root of the tree.
- * @return the height
- */
-PJ_DECL(unsigned) pj_rbtree_min_height( pj_rbtree *tree,
-					pj_rbtree_node *node );
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJ_RBTREE_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_RBTREE_H__

+#define __PJ_RBTREE_H__

+

+/**

+ * @file rbtree.h

+ * @brief Red/Black Tree

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_RBTREE Red/Black Balanced Tree

+ * @ingroup PJ_DS

+ * @brief

+ * Red/Black tree is the variant of balanced tree, where the search, insert, 

+ * and delete operation is \b guaranteed to take at most \a O( lg(n) ).

+ * @{

+ */

+/**

+ * Color type for Red-Black tree.

+ */ 

+typedef enum pj_rbcolor_t

+{

+    PJ_RBCOLOR_BLACK,

+    PJ_RBCOLOR_RED

+} pj_rbcolor_t;

+

+/**

+ * The type of the node of the R/B Tree.

+ */

+typedef struct pj_rbtree_node 

+{

+    /** Pointers to the node's parent, and left and right siblings. */

+    struct pj_rbtree_node *parent, *left, *right;

+

+    /** Key associated with the node. */

+    const void *key;

+

+    /** User data associated with the node. */

+    void *user_data;

+

+    /** The R/B Tree node color. */

+    pj_rbcolor_t color;

+

+} pj_rbtree_node;

+

+

+/**

+ * The type of function use to compare key value of tree node.

+ * @return

+ *  0 if the keys are equal

+ * <0 if key1 is lower than key2

+ * >0 if key1 is greater than key2.

+ */

+typedef int pj_rbtree_comp(const void *key1, const void *key2);

+

+

+/**

+ * Declaration of a red-black tree. All elements in the tree must have UNIQUE

+ * key.

+ * A red black tree always maintains the balance of the tree, so that the

+ * tree height will not be greater than lg(N). Insert, search, and delete

+ * operation will take lg(N) on the worst case. But for insert and delete,

+ * there is additional time needed to maintain the balance of the tree.

+ */

+typedef struct pj_rbtree

+{

+    pj_rbtree_node null_node;   /**< Constant to indicate NULL node.    */

+    pj_rbtree_node *null;       /**< Constant to indicate NULL node.    */

+    pj_rbtree_node *root;       /**< Root tree node.                    */

+    unsigned size;              /**< Number of elements in the tree.    */

+    pj_rbtree_comp *comp;       /**< Key comparison function.           */

+} pj_rbtree;

+

+

+/**

+ * Guidance on how much memory required for each of the node.

+ */

+#define PJ_RBTREE_NODE_SIZE	    (sizeof(pj_rbtree_node))

+

+

+/**

+ * Guidance on memory required for the tree.

+ */

+#define PJ_RBTREE_SIZE		    (sizeof(pj_rbtree))

+

+

+/**

+ * Initialize the tree.

+ * @param tree the tree to be initialized.

+ * @param comp key comparison function to be used for this tree.

+ */

+PJ_DECL(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp);

+

+/**

+ * Get the first element in the tree.

+ * The first element always has the least value for the key, according to

+ * the comparison function.

+ * @param tree the tree.

+ * @return the tree node, or NULL if the tree has no element.

+ */

+PJ_DECL(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree );

+

+/**

+ * Get the last element in the tree.

+ * The last element always has the greatest key value, according to the

+ * comparison function defined for the tree.

+ * @param tree the tree.

+ * @return the tree node, or NULL if the tree has no element.

+ */

+PJ_DECL(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree );

+

+/**

+ * Get the successive element for the specified node.

+ * The successive element is an element with greater key value.

+ * @param tree the tree.

+ * @param node the node.

+ * @return the successive node, or NULL if the node has no successor.

+ */

+PJ_DECL(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, 

+					 pj_rbtree_node *node );

+

+/**

+ * The the previous node for the specified node.

+ * The previous node is an element with less key value.

+ * @param tree the tree.

+ * @param node the node.

+ * @return the previous node, or NULL if the node has no previous node.

+ */

+PJ_DECL(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, 

+					 pj_rbtree_node *node );

+

+/**

+ * Insert a new node. 

+ * The node will be inserted at sorted location. The key of the node must 

+ * be UNIQUE, i.e. it hasn't existed in the tree.

+ * @param tree the tree.

+ * @param node the node to be inserted.

+ * @return zero on success, or -1 if the key already exist.

+ */

+PJ_DECL(int) pj_rbtree_insert( pj_rbtree *tree, 

+			       pj_rbtree_node *node );

+

+/**

+ * Find a node which has the specified key.

+ * @param tree the tree.

+ * @param key the key to search.

+ * @return the tree node with the specified key, or NULL if the key can not

+ *         be found.

+ */

+PJ_DECL(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,

+					 const void *key );

+

+/**

+ * Erase a node from the tree.

+ * @param tree the tree.

+ * @param node the node to be erased.

+ * @return the tree node itself.

+ */

+PJ_DECL(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,

+					  pj_rbtree_node *node );

+

+/**

+ * Get the maximum tree height from the specified node.

+ * @param tree the tree.

+ * @param node the node, or NULL to get the root of the tree.

+ * @return the maximum height, which should be at most lg(N)

+ */

+PJ_DECL(unsigned) pj_rbtree_max_height( pj_rbtree *tree,

+					pj_rbtree_node *node );

+

+/**

+ * Get the minumum tree height from the specified node.

+ * @param tree the tree.

+ * @param node the node, or NULL to get the root of the tree.

+ * @return the height

+ */

+PJ_DECL(unsigned) pj_rbtree_min_height( pj_rbtree *tree,

+					pj_rbtree_node *node );

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJ_RBTREE_H__ */

+

diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h
index 6dfbaf2..28d40b4 100644
--- a/pjlib/include/pj/sock.h
+++ b/pjlib/include/pj/sock.h
@@ -1,83 +1,104 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_SOCK_H__
-#define __PJ_SOCK_H__
-
-/**
- * @file sock.h
- * @brief Socket Abstraction.
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL 
-
-
-/**
- * @defgroup PJ_SOCK Socket Abstraction
- * @ingroup PJ_IO
- * @{
- *
- * The PJLIB socket abstraction layer is a thin and very portable abstraction
- * for socket API. It provides API similar to BSD socket API. The abstraction
- * is needed because BSD socket API is not always available on all platforms,
- * therefore it wouldn't be possible to create a trully portable network
- * programs unless we provide such abstraction.
- *
- * Applications can use this API directly in their application, just
- * as they would when using traditional BSD socket API, provided they
- * call #pj_init() first.
- *
- * \section pj_sock_examples_sec Examples
- *
- * For some examples on how to use the socket API, please see:
- *
- *  - \ref page_pjlib_sock_test
- *  - \ref page_pjlib_select_test
- *  - \ref page_pjlib_sock_perf_test
- */
-
-
-/**
- * Supported address families. 
- * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL AF_*, BECAUSE
- * THE LIBRARY WILL DO TRANSLATION TO THE NATIVE VALUE.
- */
-extern const pj_uint16_t PJ_AF_UNIX;    /**< Unix domain socket.	*/
-#define PJ_AF_LOCAL	 PJ_AF_UNIX;    /**< POSIX name for AF_UNIX	*/
-extern const pj_uint16_t PJ_AF_INET;    /**< Internet IP protocol.	*/
-extern const pj_uint16_t PJ_AF_INET6;   /**< IP version 6.		*/
-extern const pj_uint16_t PJ_AF_PACKET;  /**< Packet family.		*/
-extern const pj_uint16_t PJ_AF_IRDA;    /**< IRDA sockets.		*/
-
-
-/**
- * Supported types of sockets.
- * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOCK_*, BECAUSE
- * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.
- */
-
-extern const pj_uint16_t PJ_SOCK_STREAM; /**< Sequenced, reliable, connection-
-					      based byte streams.           */
-extern const pj_uint16_t PJ_SOCK_DGRAM;  /**< Connectionless, unreliable 
-					      datagrams of fixed maximum 
-					      lengths.                      */
-extern const pj_uint16_t PJ_SOCK_RAW;    /**< Raw protocol interface.       */
-extern const pj_uint16_t PJ_SOCK_RDM;    /**< Reliably-delivered messages.  */
-
-
-/**
- * Socket level specified in #pj_sock_setsockopt() or #pj_sock_getsockopt().
- * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOL_*, BECAUSE
- * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.
- */
-extern const pj_uint16_t PJ_SOL_SOCKET;	/**< Socket level.  */
-extern const pj_uint16_t PJ_SOL_IP;	/**< IP level.	    */
-extern const pj_uint16_t PJ_SOL_TCP;	/**< TCP level.	    */
-extern const pj_uint16_t PJ_SOL_UDP;	/**< UDP level.	    */
-extern const pj_uint16_t PJ_SOL_IPV6;	/**< IP version 6   */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_SOCK_H__

+#define __PJ_SOCK_H__

+

+/**

+ * @file sock.h

+ * @brief Socket Abstraction.

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL 

+

+

+/**

+ * @defgroup PJ_SOCK Socket Abstraction

+ * @ingroup PJ_IO

+ * @{

+ *

+ * The PJLIB socket abstraction layer is a thin and very portable abstraction

+ * for socket API. It provides API similar to BSD socket API. The abstraction

+ * is needed because BSD socket API is not always available on all platforms,

+ * therefore it wouldn't be possible to create a trully portable network

+ * programs unless we provide such abstraction.

+ *

+ * Applications can use this API directly in their application, just

+ * as they would when using traditional BSD socket API, provided they

+ * call #pj_init() first.

+ *

+ * \section pj_sock_examples_sec Examples

+ *

+ * For some examples on how to use the socket API, please see:

+ *

+ *  - \ref page_pjlib_sock_test

+ *  - \ref page_pjlib_select_test

+ *  - \ref page_pjlib_sock_perf_test

+ */

+

+

+/**

+ * Supported address families. 

+ * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL AF_*, BECAUSE

+ * THE LIBRARY WILL DO TRANSLATION TO THE NATIVE VALUE.

+ */

+extern const pj_uint16_t PJ_AF_UNIX;    /**< Unix domain socket.	*/

+#define PJ_AF_LOCAL	 PJ_AF_UNIX;    /**< POSIX name for AF_UNIX	*/

+extern const pj_uint16_t PJ_AF_INET;    /**< Internet IP protocol.	*/

+extern const pj_uint16_t PJ_AF_INET6;   /**< IP version 6.		*/

+extern const pj_uint16_t PJ_AF_PACKET;  /**< Packet family.		*/

+extern const pj_uint16_t PJ_AF_IRDA;    /**< IRDA sockets.		*/

+

+

+/**

+ * Supported types of sockets.

+ * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOCK_*, BECAUSE

+ * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.

+ */

+

+extern const pj_uint16_t PJ_SOCK_STREAM; /**< Sequenced, reliable, connection-

+					      based byte streams.           */

+extern const pj_uint16_t PJ_SOCK_DGRAM;  /**< Connectionless, unreliable 

+					      datagrams of fixed maximum 

+					      lengths.                      */

+extern const pj_uint16_t PJ_SOCK_RAW;    /**< Raw protocol interface.       */

+extern const pj_uint16_t PJ_SOCK_RDM;    /**< Reliably-delivered messages.  */

+

+

+/**

+ * Socket level specified in #pj_sock_setsockopt() or #pj_sock_getsockopt().

+ * APPLICATION MUST USE THESE VALUES INSTEAD OF NORMAL SOL_*, BECAUSE

+ * THE LIBRARY WILL TRANSLATE THE VALUE TO THE NATIVE VALUE.

+ */

+extern const pj_uint16_t PJ_SOL_SOCKET;	/**< Socket level.  */

+extern const pj_uint16_t PJ_SOL_IP;	/**< IP level.	    */

+extern const pj_uint16_t PJ_SOL_TCP;	/**< TCP level.	    */

+extern const pj_uint16_t PJ_SOL_UDP;	/**< UDP level.	    */

+extern const pj_uint16_t PJ_SOL_IPV6;	/**< IP version 6   */

 

 /**

  * Values to be specified as \c optname when calling #pj_sock_setsockopt() 

@@ -87,600 +108,600 @@
 extern const pj_uint16_t PJ_SO_RCVBUF;  /**< Buffer size for receive.   */

 extern const pj_uint16_t PJ_SO_SNDBUF;  /**< Buffer size for send.      */

 

-
-/**
- * Flags to be specified in #pj_sock_recv, #pj_sock_send, etc.
- */
-typedef enum pj_sock_msg_flag
-{
-    PJ_MSG_OOB		= 0x01,	    /**< Out-of-band messages.		 */
-    PJ_MSG_PEEK		= 0x02,	    /**< Peek, don't remove from buffer. */
-    PJ_MSG_DONTROUTE	= 0x04,	    /**< Don't route.			 */
-} pj_sock_msg_flag;
-
-
-/**
- * Flag to be specified in #pj_sock_shutdown.
- */
-typedef enum pj_socket_sd_type
-{
-    PJ_SD_RECEIVE   = 0,    /**< No more receive.	    */
-    PJ_SHUT_RD	    = 0,    /**< Alias for SD_RECEIVE.	    */
-    PJ_SD_SEND	    = 1,    /**< No more sending.	    */
-    PJ_SHUT_WR	    = 1,    /**< Alias for SD_SEND.	    */
-    PJ_SD_BOTH	    = 2,    /**< No more send and receive.  */
-    PJ_SHUT_RDWR    = 2,    /**< Alias for SD_BOTH.	    */
-} pj_socket_sd_type;
-
-
-
-/** Address to accept any incoming messages. */
-#define PJ_INADDR_ANY	    ((pj_uint32_t)0)
-
-/** Address indicating an error return */
-#define PJ_INADDR_NONE	    ((pj_uint32_t)0xffffffff)
-
-/** Address to send to all hosts. */
-#define PJ_INADDR_BROADCAST ((pj_uint32_t)0xffffffff)
-
-
-/** 
- * Maximum length specifiable by #pj_sock_listen().
- * If the build system doesn't override this value, then the lowest 
- * denominator (five, in Win32 systems) will be used.
- */
-#if !defined(PJ_SOMAXCONN)
-#  define PJ_SOMAXCONN	5
-#endif
-
-
-/**
- * Constant for invalid socket returned by #pj_sock_socket() and
- * #pj_sock_accept().
- */
-#define PJ_INVALID_SOCKET   (-1)
-
-/**
- * Structure describing a generic socket address.
- */
-typedef struct pj_sockaddr
-{
-    pj_uint16_t	sa_family;	/**< Common data: address family.   */
-    char	sa_data[14];	/**< Address data.		    */
-} pj_sockaddr;
-
-
-/**
- * This structure describes Internet address.
- */
-typedef struct pj_in_addr
-{
-    pj_uint32_t	s_addr;		/**< The 32bit IP address.	    */
-} pj_in_addr;
-
-
-/**
- * This structure describes Internet socket address.
- */
-typedef struct pj_sockaddr_in
-{
-    pj_uint16_t	sin_family;	/**< Address family.		    */
-    pj_uint16_t	sin_port;	/**< Transport layer port number.   */
-    pj_in_addr	sin_addr;	/**< IP address.		    */
-    char	sin_zero[8];	/**< Padding.			    */
-} pj_sockaddr_in;
-
-
-/**
- * This structure describes IPv6 address.
- */
-typedef struct pj_in6_addr
-{
-    /** Union of address formats. */
-    union {
-	pj_uint8_t  u6_addr8[16];   /**< u6_addr8   */
-	pj_uint16_t u6_addr16[8];   /**< u6_addr16  */
-	pj_uint32_t u6_addr32[4];   /**< u6_addr32  */
-    } in6_u;
-/** Shortcut to access in6_u.u6_addr8. */
-#define s6_addr                 in6_u.u6_addr8
-/** Shortcut to access in6_u.u6_addr16. */
-#define s6_addr16               in6_u.u6_addr16
-/** Shortcut to access in6_u.u6_addr32. */
-#define s6_addr32               in6_u.u6_addr32
-} pj_in6_addr;
-
-/** Initializer value for pj_in6_addr. */
-#define PJ_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }
-
-/** Initializer value for pj_in6_addr. */
-#define PJ_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }
-
-/**
- * This structure describes IPv6 socket address.
- */
-typedef struct pj_sockaddr_in6
-{
-    pj_uint16_t	sin6_family;	    /**< Address family		    */
-    pj_uint16_t	sin6_port;	    /**< Transport layer port number. */
-    pj_uint32_t	sin6_flowinfo;	    /**< IPv6 flow information	    */
-    pj_in6_addr sin6_addr;	    /**< IPv6 address.		    */
-    pj_uint32_t sin6_scope_id;	    /**< IPv6 scope-id		    */
-} pj_sockaddr_in6;
-
-
-/*****************************************************************************
- *
- * SOCKET ADDRESS MANIPULATION.
- *
- *****************************************************************************
- */
-
-/**
- * Convert 16-bit value from network byte order to host byte order.
- *
- * @param netshort  16-bit network value.
- * @return	    16-bit host value.
- */
-PJ_DECL(pj_uint16_t) pj_ntohs(pj_uint16_t netshort);
-
-/**
- * Convert 16-bit value from host byte order to network byte order.
- *
- * @param hostshort 16-bit host value.
- * @return	    16-bit network value.
- */
-PJ_DECL(pj_uint16_t) pj_htons(pj_uint16_t hostshort);
-
-/**
- * Convert 32-bit value from network byte order to host byte order.
- *
- * @param netlong   32-bit network value.
- * @return	    32-bit host value.
- */
-PJ_DECL(pj_uint32_t) pj_ntohl(pj_uint32_t netlong);
-
-/**
- * Convert 32-bit value from host byte order to network byte order.
- *
- * @param hostlong  32-bit host value.
- * @return	    32-bit network value.
- */
-PJ_DECL(pj_uint32_t) pj_htonl(pj_uint32_t hostlong);
-
-/**
- * Convert an Internet host address given in network byte order
- * to string in standard numbers and dots notation.
- *
- * @param inaddr    The host address.
- * @return	    The string address.
- */
-PJ_DECL(char*) pj_inet_ntoa(pj_in_addr inaddr);
-
-/**
- * This function converts the Internet host address cp from the standard
- * numbers-and-dots notation into binary data and stores it in the structure
- * that inp points to. 
- *
- * @param cp	IP address in standard numbers-and-dots notation.
- * @param inp	Structure that holds the output of the conversion.
- *
- * @return	nonzero if the address is valid, zero if not.
- */
-PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp);
-
-/**
- * Convert address string with numbers and dots to binary IP address.
- * 
- * @param cp	    The IP address in numbers and dots notation.
- * @return	    If success, the IP address is returned in network
- *		    byte order. If failed, PJ_INADDR_NONE will be
- *		    returned.
- * @remark
- * This is an obsolete interface to #pj_inet_aton(); it is obsolete
- * because -1 is a valid address (255.255.255.255), and #pj_inet_aton()
- * provides a cleaner way to indicate error return.
- */
-PJ_DECL(pj_in_addr) pj_inet_addr(const pj_str_t *cp);
-
-
-/**
- * Get the transport layer port number of an Internet socket address.
- * The port is returned in host byte order.
- *
- * @param addr	    The IP socket address.
- * @return	    Port number, in host byte order.
- */
-PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)
-{
-    return pj_ntohs(addr->sin_port);
-}
-
-/**
- * Set the port number of an Internet socket address.
- *
- * @param addr	    The IP socket address.
- * @param hostport  The port number, in host byte order.
- */
-PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, 
-					pj_uint16_t hostport)
-{
-    addr->sin_port = pj_htons(hostport);
-}
-
-/**
- * Get the IP address of an Internet socket address.
- * The address is returned as 32bit value in host byte order.
- *
- * @param addr	    The IP socket address.
- * @return	    32bit address, in host byte order.
- */
-PJ_INLINE(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr)
-{
-    pj_in_addr in_addr;
-    in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr);
-    return in_addr;
-};
-
-/**
- * Set the IP address of an Internet socket address.
- *
- * @param addr	    The IP socket address.
- * @param hostaddr  The host address, in host byte order.
- */
-PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,
-					pj_uint32_t hostaddr)
-{
-    addr->sin_addr.s_addr = pj_htonl(hostaddr);
-}
-
-/**
- * Set the IP address of an IP socket address from string address, 
- * with resolving the host if necessary. The string address may be in a
- * standard numbers and dots notation or may be a hostname. If hostname
- * is specified, then the function will resolve the host into the IP
- * address.
- *
- * @param addr	    The IP socket address to be set.
- * @param cp	    The address string, which can be in a standard 
- *		    dotted numbers or a hostname to be resolved.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
-					          const pj_str_t *cp);
-
-/**
- * Set the IP address and port of an IP socket address.
- * The string address may be in a standard numbers and dots notation or 
- * may be a hostname. If hostname is specified, then the function will 
- * resolve the host into the IP address.
- *
- * @param addr	    The IP socket address to be set.
- * @param cp	    The address string, which can be in a standard 
- *		    dotted numbers or a hostname to be resolved.
- * @param port	    The port number, in host byte order.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
-				          const pj_str_t *cp,
-					  pj_uint16_t port);
-
-
-/*****************************************************************************
- *
- * HOST NAME AND ADDRESS.
- *
- *****************************************************************************
- */
-
-/**
- * Get system's host name.
- *
- * @return	    The hostname, or empty string if the hostname can not
- *		    be identified.
- */
-PJ_DECL(const pj_str_t*) pj_gethostname(void);
-
-/**
- * Get host's IP address, which the the first IP address that is resolved
- * from the hostname.
- *
- * @return	    The host's IP address, PJ_INADDR_NONE if the host
- *		    IP address can not be identified.
- */
-PJ_DECL(pj_in_addr) pj_gethostaddr(void);
-
-
-/*****************************************************************************
- *
- * SOCKET API.
- *
- *****************************************************************************
- */
-
-/**
- * Create new socket/endpoint for communication.
- *
- * @param family    Specifies a communication domain; this selects the
- *		    protocol family which will be used for communication.
- * @param type	    The socket has the indicated type, which specifies the 
- *		    communication semantics.
- * @param protocol  Specifies  a  particular  protocol  to  be used with the
- *		    socket.  Normally only a single protocol exists to support 
- *		    a particular socket  type  within  a given protocol family, 
- *		    in which a case protocol can be specified as 0.
- * @param sock	    New socket descriptor, or PJ_INVALID_SOCKET on error.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_socket(int family, 
-				    int type, 
-				    int protocol,
-				    pj_sock_t *sock);
-
-/**
- * Close the socket descriptor.
- *
- * @param sockfd    The socket descriptor.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_close(pj_sock_t sockfd);
 

-
-/**
- * This function gives the socket sockfd the local address my_addr. my_addr is
- * addrlen bytes long.  Traditionally, this is called assigning a name to
- * a socket. When a socket is created with #pj_sock_socket(), it exists in a
- * name space (address family) but has no name assigned.
- *
- * @param sockfd    The socket desriptor.
- * @param my_addr   The local address to bind the socket to.
- * @param addrlen   The length of the address.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_bind( pj_sock_t sockfd, 
-				   const pj_sockaddr_t *my_addr,
-				   int addrlen);
-
-/**
- * Bind the IP socket sockfd to the given address and port.
- *
- * @param sockfd    The socket descriptor.
- * @param addr	    Local address to bind the socket to, in host byte order.
- * @param port	    The local port to bind the socket to, in host byte order.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, 
-				      pj_uint32_t addr,
-				      pj_uint16_t port);
-
-#if PJ_HAS_TCP
-/**
- * Listen for incoming connection. This function only applies to connection
- * oriented sockets (such as PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET), and it
- * indicates the willingness to accept incoming connections.
- *
- * @param sockfd	The socket descriptor.
- * @param backlog	Defines the maximum length the queue of pending
- *			connections may grow to.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_listen( pj_sock_t sockfd, 
-				     int backlog );
-
-/**
- * Accept new connection on the specified connection oriented server socket.
- *
- * @param serverfd  The server socket.
- * @param newsock   New socket on success, of PJ_INVALID_SOCKET if failed.
- * @param addr	    A pointer to sockaddr type. If the argument is not NULL,
- *		    it will be filled by the address of connecting entity.
- * @param addrlen   Initially specifies the length of the address, and upon
- *		    return will be filled with the exact address length.
- *
- * @return	    Zero on success, or the error number.
- */
-PJ_DECL(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
-				     pj_sock_t *newsock,
-				     pj_sockaddr_t *addr,
-				     int *addrlen);
-#endif
-
-/**
- * The file descriptor sockfd must refer to a socket.  If the socket is of
- * type PJ_SOCK_DGRAM  then the serv_addr address is the address to which
- * datagrams are sent by default, and the only address from which datagrams
- * are received. If the socket is of type PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET,
- * this call attempts to make a connection to another socket.  The
- * other socket is specified by serv_addr, which is an address (of length
- * addrlen) in the communications space of the  socket.  Each  communications
- * space interprets the serv_addr parameter in its own way.
- *
- * @param sockfd	The socket descriptor.
- * @param serv_addr	Server address to connect to.
- * @param addrlen	The length of server address.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_connect( pj_sock_t sockfd,
-				      const pj_sockaddr_t *serv_addr,
-				      int addrlen);
-
-/**
- * Return the address of peer which is connected to socket sockfd.
- *
- * @param sockfd	The socket descriptor.
- * @param addr		Pointer to sockaddr structure to which the address
- *			will be returned.
- * @param namelen	Initially the length of the addr. Upon return the value
- *			will be set to the actual length of the address.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_getpeername(pj_sock_t sockfd,
-					  pj_sockaddr_t *addr,
-					  int *namelen);
-
-/**
- * Return the current name of the specified socket.
- *
- * @param sockfd	The socket descriptor.
- * @param addr		Pointer to sockaddr structure to which the address
- *			will be returned.
- * @param namelen	Initially the length of the addr. Upon return the value
- *			will be set to the actual length of the address.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,
-					  pj_sockaddr_t *addr,
-					  int *namelen);
-
-/**
- * Get socket option associated with a socket. Options may exist at multiple
- * protocol levels; they are always present at the uppermost socket level.
- *
- * @param sockfd	The socket descriptor.
- * @param level		The level which to get the option from.
- * @param optname	The option name.
- * @param optval	Identifies the buffer which the value will be
- *			returned.
- * @param optlen	Initially contains the length of the buffer, upon
- *			return will be set to the actual size of the value.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,
-					 pj_uint16_t level,
-					 pj_uint16_t optname,
-					 void *optval,
-					 int *optlen);
-/**
- * Manipulate the options associated with a socket. Options may exist at 
- * multiple protocol levels; they are always present at the uppermost socket 
- * level.
- *
- * @param sockfd	The socket descriptor.
- * @param level		The level which to get the option from.
- * @param optname	The option name.
- * @param optval	Identifies the buffer which contain the value.
- * @param optlen	The length of the value.
- *
- * @return		PJ_SUCCESS or the status code.
- */
-PJ_DECL(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,
-					 pj_uint16_t level,
-					 pj_uint16_t optname,
-					 const void *optval,
-					 int optlen);
-
-
-/**
- * Receives data stream or message coming to the specified socket.
- *
- * @param sockfd	The socket descriptor.
- * @param buf		The buffer to receive the data or message.
- * @param len		On input, the length of the buffer. On return,
- *			contains the length of data received.
- * @param flags		Combination of #pj_sock_msg_flag.
- *
- * @return		PJ_SUCCESS or the error code.
- */
-PJ_DECL(pj_status_t) pj_sock_recv(pj_sock_t sockfd,
-				  void *buf,
-				  pj_ssize_t *len,
-				  unsigned flags);
-
-/**
- * Receives data stream or message coming to the specified socket.
- *
- * @param sockfd	The socket descriptor.
- * @param buf		The buffer to receive the data or message.
- * @param len		On input, the length of the buffer. On return,
- *			contains the length of data received.
- * @param flags		Bitmask combination of #pj_sock_msg_flag.
- * @param from		If not NULL, it will be filled with the source
- *			address of the connection.
- * @param fromlen	Initially contains the length of from address,
- *			and upon return will be filled with the actual
- *			length of the address.
- *
- * @return		PJ_SUCCESS or the error code.
- */
-PJ_DECL(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,
-				      void *buf,
-				      pj_ssize_t *len,
-				      unsigned flags,
-				      pj_sockaddr_t *from,
-				      int *fromlen);
-
-/**
- * Transmit data to the socket.
- *
- * @param sockfd	Socket descriptor.
- * @param buf		Buffer containing data to be sent.
- * @param len		On input, the length of the data in the buffer.
- *			Upon return, it will be filled with the length
- *			of data sent.
- * @param flags		Bitmask combination of #pj_sock_msg_flag.
- *
- * @return		PJ_SUCCESS or the status code.
- */
-PJ_DECL(pj_status_t) pj_sock_send(pj_sock_t sockfd,
-				  const void *buf,
-				  pj_ssize_t *len,
-				  unsigned flags);
-
-/**
- * Transmit data to the socket to the specified address.
- *
- * @param sockfd	Socket descriptor.
- * @param buf		Buffer containing data to be sent.
- * @param len		On input, the length of the data in the buffer.
- *			Upon return, it will be filled with the length
- *			of data sent.
- * @param flags		Bitmask combination of #pj_sock_msg_flag.
- * @param to		The address to send.
- * @param tolen		The length of the address in bytes.
- *
- * @return		The length of data successfully sent.
- */
-PJ_DECL(pj_status_t) pj_sock_sendto(pj_sock_t sockfd,
-				    const void *buf,
-				    pj_ssize_t *len,
-				    unsigned flags,
-				    const pj_sockaddr_t *to,
-				    int tolen);
-
-#if PJ_HAS_TCP
-/**
- * The shutdown call causes all or part of a full-duplex connection on the
- * socket associated with sockfd to be shut down.
- *
- * @param sockfd	The socket descriptor.
- * @param how		If how is PJ_SHUT_RD, further receptions will be 
- *			disallowed. If how is PJ_SHUT_WR, further transmissions
- *			will be disallowed. If how is PJ_SHUT_RDWR, further 
- *			receptions andtransmissions will be disallowed.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,
-				       int how);
-#endif
-
-/**
- * @}
- */
-
-
-PJ_END_DECL
-
-#endif	/* __PJ_SOCK_H__ */
-
+/**

+ * Flags to be specified in #pj_sock_recv, #pj_sock_send, etc.

+ */

+typedef enum pj_sock_msg_flag

+{

+    PJ_MSG_OOB		= 0x01,	    /**< Out-of-band messages.		 */

+    PJ_MSG_PEEK		= 0x02,	    /**< Peek, don't remove from buffer. */

+    PJ_MSG_DONTROUTE	= 0x04,	    /**< Don't route.			 */

+} pj_sock_msg_flag;

+

+

+/**

+ * Flag to be specified in #pj_sock_shutdown.

+ */

+typedef enum pj_socket_sd_type

+{

+    PJ_SD_RECEIVE   = 0,    /**< No more receive.	    */

+    PJ_SHUT_RD	    = 0,    /**< Alias for SD_RECEIVE.	    */

+    PJ_SD_SEND	    = 1,    /**< No more sending.	    */

+    PJ_SHUT_WR	    = 1,    /**< Alias for SD_SEND.	    */

+    PJ_SD_BOTH	    = 2,    /**< No more send and receive.  */

+    PJ_SHUT_RDWR    = 2,    /**< Alias for SD_BOTH.	    */

+} pj_socket_sd_type;

+

+

+

+/** Address to accept any incoming messages. */

+#define PJ_INADDR_ANY	    ((pj_uint32_t)0)

+

+/** Address indicating an error return */

+#define PJ_INADDR_NONE	    ((pj_uint32_t)0xffffffff)

+

+/** Address to send to all hosts. */

+#define PJ_INADDR_BROADCAST ((pj_uint32_t)0xffffffff)

+

+

+/** 

+ * Maximum length specifiable by #pj_sock_listen().

+ * If the build system doesn't override this value, then the lowest 

+ * denominator (five, in Win32 systems) will be used.

+ */

+#if !defined(PJ_SOMAXCONN)

+#  define PJ_SOMAXCONN	5

+#endif

+

+

+/**

+ * Constant for invalid socket returned by #pj_sock_socket() and

+ * #pj_sock_accept().

+ */

+#define PJ_INVALID_SOCKET   (-1)

+

+/**

+ * Structure describing a generic socket address.

+ */

+typedef struct pj_sockaddr

+{

+    pj_uint16_t	sa_family;	/**< Common data: address family.   */

+    char	sa_data[14];	/**< Address data.		    */

+} pj_sockaddr;

+

+

+/**

+ * This structure describes Internet address.

+ */

+typedef struct pj_in_addr

+{

+    pj_uint32_t	s_addr;		/**< The 32bit IP address.	    */

+} pj_in_addr;

+

+

+/**

+ * This structure describes Internet socket address.

+ */

+typedef struct pj_sockaddr_in

+{

+    pj_uint16_t	sin_family;	/**< Address family.		    */

+    pj_uint16_t	sin_port;	/**< Transport layer port number.   */

+    pj_in_addr	sin_addr;	/**< IP address.		    */

+    char	sin_zero[8];	/**< Padding.			    */

+} pj_sockaddr_in;

+

+

+/**

+ * This structure describes IPv6 address.

+ */

+typedef struct pj_in6_addr

+{

+    /** Union of address formats. */

+    union {

+	pj_uint8_t  u6_addr8[16];   /**< u6_addr8   */

+	pj_uint16_t u6_addr16[8];   /**< u6_addr16  */

+	pj_uint32_t u6_addr32[4];   /**< u6_addr32  */

+    } in6_u;

+/** Shortcut to access in6_u.u6_addr8. */

+#define s6_addr                 in6_u.u6_addr8

+/** Shortcut to access in6_u.u6_addr16. */

+#define s6_addr16               in6_u.u6_addr16

+/** Shortcut to access in6_u.u6_addr32. */

+#define s6_addr32               in6_u.u6_addr32

+} pj_in6_addr;

+

+/** Initializer value for pj_in6_addr. */

+#define PJ_IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }

+

+/** Initializer value for pj_in6_addr. */

+#define PJ_IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }

+

+/**

+ * This structure describes IPv6 socket address.

+ */

+typedef struct pj_sockaddr_in6

+{

+    pj_uint16_t	sin6_family;	    /**< Address family		    */

+    pj_uint16_t	sin6_port;	    /**< Transport layer port number. */

+    pj_uint32_t	sin6_flowinfo;	    /**< IPv6 flow information	    */

+    pj_in6_addr sin6_addr;	    /**< IPv6 address.		    */

+    pj_uint32_t sin6_scope_id;	    /**< IPv6 scope-id		    */

+} pj_sockaddr_in6;

+

+

+/*****************************************************************************

+ *

+ * SOCKET ADDRESS MANIPULATION.

+ *

+ *****************************************************************************

+ */

+

+/**

+ * Convert 16-bit value from network byte order to host byte order.

+ *

+ * @param netshort  16-bit network value.

+ * @return	    16-bit host value.

+ */

+PJ_DECL(pj_uint16_t) pj_ntohs(pj_uint16_t netshort);

+

+/**

+ * Convert 16-bit value from host byte order to network byte order.

+ *

+ * @param hostshort 16-bit host value.

+ * @return	    16-bit network value.

+ */

+PJ_DECL(pj_uint16_t) pj_htons(pj_uint16_t hostshort);

+

+/**

+ * Convert 32-bit value from network byte order to host byte order.

+ *

+ * @param netlong   32-bit network value.

+ * @return	    32-bit host value.

+ */

+PJ_DECL(pj_uint32_t) pj_ntohl(pj_uint32_t netlong);

+

+/**

+ * Convert 32-bit value from host byte order to network byte order.

+ *

+ * @param hostlong  32-bit host value.

+ * @return	    32-bit network value.

+ */

+PJ_DECL(pj_uint32_t) pj_htonl(pj_uint32_t hostlong);

+

+/**

+ * Convert an Internet host address given in network byte order

+ * to string in standard numbers and dots notation.

+ *

+ * @param inaddr    The host address.

+ * @return	    The string address.

+ */

+PJ_DECL(char*) pj_inet_ntoa(pj_in_addr inaddr);

+

+/**

+ * This function converts the Internet host address cp from the standard

+ * numbers-and-dots notation into binary data and stores it in the structure

+ * that inp points to. 

+ *

+ * @param cp	IP address in standard numbers-and-dots notation.

+ * @param inp	Structure that holds the output of the conversion.

+ *

+ * @return	nonzero if the address is valid, zero if not.

+ */

+PJ_DECL(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp);

+

+/**

+ * Convert address string with numbers and dots to binary IP address.

+ * 

+ * @param cp	    The IP address in numbers and dots notation.

+ * @return	    If success, the IP address is returned in network

+ *		    byte order. If failed, PJ_INADDR_NONE will be

+ *		    returned.

+ * @remark

+ * This is an obsolete interface to #pj_inet_aton(); it is obsolete

+ * because -1 is a valid address (255.255.255.255), and #pj_inet_aton()

+ * provides a cleaner way to indicate error return.

+ */

+PJ_DECL(pj_in_addr) pj_inet_addr(const pj_str_t *cp);

+

+

+/**

+ * Get the transport layer port number of an Internet socket address.

+ * The port is returned in host byte order.

+ *

+ * @param addr	    The IP socket address.

+ * @return	    Port number, in host byte order.

+ */

+PJ_INLINE(pj_uint16_t) pj_sockaddr_in_get_port(const pj_sockaddr_in *addr)

+{

+    return pj_ntohs(addr->sin_port);

+}

+

+/**

+ * Set the port number of an Internet socket address.

+ *

+ * @param addr	    The IP socket address.

+ * @param hostport  The port number, in host byte order.

+ */

+PJ_INLINE(void) pj_sockaddr_in_set_port(pj_sockaddr_in *addr, 

+					pj_uint16_t hostport)

+{

+    addr->sin_port = pj_htons(hostport);

+}

+

+/**

+ * Get the IP address of an Internet socket address.

+ * The address is returned as 32bit value in host byte order.

+ *

+ * @param addr	    The IP socket address.

+ * @return	    32bit address, in host byte order.

+ */

+PJ_INLINE(pj_in_addr) pj_sockaddr_in_get_addr(const pj_sockaddr_in *addr)

+{

+    pj_in_addr in_addr;

+    in_addr.s_addr = pj_ntohl(addr->sin_addr.s_addr);

+    return in_addr;

+};

+

+/**

+ * Set the IP address of an Internet socket address.

+ *

+ * @param addr	    The IP socket address.

+ * @param hostaddr  The host address, in host byte order.

+ */

+PJ_INLINE(void) pj_sockaddr_in_set_addr(pj_sockaddr_in *addr,

+					pj_uint32_t hostaddr)

+{

+    addr->sin_addr.s_addr = pj_htonl(hostaddr);

+}

+

+/**

+ * Set the IP address of an IP socket address from string address, 

+ * with resolving the host if necessary. The string address may be in a

+ * standard numbers and dots notation or may be a hostname. If hostname

+ * is specified, then the function will resolve the host into the IP

+ * address.

+ *

+ * @param addr	    The IP socket address to be set.

+ * @param cp	    The address string, which can be in a standard 

+ *		    dotted numbers or a hostname to be resolved.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,

+					          const pj_str_t *cp);

+

+/**

+ * Set the IP address and port of an IP socket address.

+ * The string address may be in a standard numbers and dots notation or 

+ * may be a hostname. If hostname is specified, then the function will 

+ * resolve the host into the IP address.

+ *

+ * @param addr	    The IP socket address to be set.

+ * @param cp	    The address string, which can be in a standard 

+ *		    dotted numbers or a hostname to be resolved.

+ * @param port	    The port number, in host byte order.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,

+				          const pj_str_t *cp,

+					  pj_uint16_t port);

+

+

+/*****************************************************************************

+ *

+ * HOST NAME AND ADDRESS.

+ *

+ *****************************************************************************

+ */

+

+/**

+ * Get system's host name.

+ *

+ * @return	    The hostname, or empty string if the hostname can not

+ *		    be identified.

+ */

+PJ_DECL(const pj_str_t*) pj_gethostname(void);

+

+/**

+ * Get host's IP address, which the the first IP address that is resolved

+ * from the hostname.

+ *

+ * @return	    The host's IP address, PJ_INADDR_NONE if the host

+ *		    IP address can not be identified.

+ */

+PJ_DECL(pj_in_addr) pj_gethostaddr(void);

+

+

+/*****************************************************************************

+ *

+ * SOCKET API.

+ *

+ *****************************************************************************

+ */

+

+/**

+ * Create new socket/endpoint for communication.

+ *

+ * @param family    Specifies a communication domain; this selects the

+ *		    protocol family which will be used for communication.

+ * @param type	    The socket has the indicated type, which specifies the 

+ *		    communication semantics.

+ * @param protocol  Specifies  a  particular  protocol  to  be used with the

+ *		    socket.  Normally only a single protocol exists to support 

+ *		    a particular socket  type  within  a given protocol family, 

+ *		    in which a case protocol can be specified as 0.

+ * @param sock	    New socket descriptor, or PJ_INVALID_SOCKET on error.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_socket(int family, 

+				    int type, 

+				    int protocol,

+				    pj_sock_t *sock);

+

+/**

+ * Close the socket descriptor.

+ *

+ * @param sockfd    The socket descriptor.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_close(pj_sock_t sockfd);

+

+

+/**

+ * This function gives the socket sockfd the local address my_addr. my_addr is

+ * addrlen bytes long.  Traditionally, this is called assigning a name to

+ * a socket. When a socket is created with #pj_sock_socket(), it exists in a

+ * name space (address family) but has no name assigned.

+ *

+ * @param sockfd    The socket desriptor.

+ * @param my_addr   The local address to bind the socket to.

+ * @param addrlen   The length of the address.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_bind( pj_sock_t sockfd, 

+				   const pj_sockaddr_t *my_addr,

+				   int addrlen);

+

+/**

+ * Bind the IP socket sockfd to the given address and port.

+ *

+ * @param sockfd    The socket descriptor.

+ * @param addr	    Local address to bind the socket to, in host byte order.

+ * @param port	    The local port to bind the socket to, in host byte order.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, 

+				      pj_uint32_t addr,

+				      pj_uint16_t port);

+

+#if PJ_HAS_TCP

+/**

+ * Listen for incoming connection. This function only applies to connection

+ * oriented sockets (such as PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET), and it

+ * indicates the willingness to accept incoming connections.

+ *

+ * @param sockfd	The socket descriptor.

+ * @param backlog	Defines the maximum length the queue of pending

+ *			connections may grow to.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_listen( pj_sock_t sockfd, 

+				     int backlog );

+

+/**

+ * Accept new connection on the specified connection oriented server socket.

+ *

+ * @param serverfd  The server socket.

+ * @param newsock   New socket on success, of PJ_INVALID_SOCKET if failed.

+ * @param addr	    A pointer to sockaddr type. If the argument is not NULL,

+ *		    it will be filled by the address of connecting entity.

+ * @param addrlen   Initially specifies the length of the address, and upon

+ *		    return will be filled with the exact address length.

+ *

+ * @return	    Zero on success, or the error number.

+ */

+PJ_DECL(pj_status_t) pj_sock_accept( pj_sock_t serverfd,

+				     pj_sock_t *newsock,

+				     pj_sockaddr_t *addr,

+				     int *addrlen);

+#endif

+

+/**

+ * The file descriptor sockfd must refer to a socket.  If the socket is of

+ * type PJ_SOCK_DGRAM  then the serv_addr address is the address to which

+ * datagrams are sent by default, and the only address from which datagrams

+ * are received. If the socket is of type PJ_SOCK_STREAM or PJ_SOCK_SEQPACKET,

+ * this call attempts to make a connection to another socket.  The

+ * other socket is specified by serv_addr, which is an address (of length

+ * addrlen) in the communications space of the  socket.  Each  communications

+ * space interprets the serv_addr parameter in its own way.

+ *

+ * @param sockfd	The socket descriptor.

+ * @param serv_addr	Server address to connect to.

+ * @param addrlen	The length of server address.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_connect( pj_sock_t sockfd,

+				      const pj_sockaddr_t *serv_addr,

+				      int addrlen);

+

+/**

+ * Return the address of peer which is connected to socket sockfd.

+ *

+ * @param sockfd	The socket descriptor.

+ * @param addr		Pointer to sockaddr structure to which the address

+ *			will be returned.

+ * @param namelen	Initially the length of the addr. Upon return the value

+ *			will be set to the actual length of the address.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_getpeername(pj_sock_t sockfd,

+					  pj_sockaddr_t *addr,

+					  int *namelen);

+

+/**

+ * Return the current name of the specified socket.

+ *

+ * @param sockfd	The socket descriptor.

+ * @param addr		Pointer to sockaddr structure to which the address

+ *			will be returned.

+ * @param namelen	Initially the length of the addr. Upon return the value

+ *			will be set to the actual length of the address.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,

+					  pj_sockaddr_t *addr,

+					  int *namelen);

+

+/**

+ * Get socket option associated with a socket. Options may exist at multiple

+ * protocol levels; they are always present at the uppermost socket level.

+ *

+ * @param sockfd	The socket descriptor.

+ * @param level		The level which to get the option from.

+ * @param optname	The option name.

+ * @param optval	Identifies the buffer which the value will be

+ *			returned.

+ * @param optlen	Initially contains the length of the buffer, upon

+ *			return will be set to the actual size of the value.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,

+					 pj_uint16_t level,

+					 pj_uint16_t optname,

+					 void *optval,

+					 int *optlen);

+/**

+ * Manipulate the options associated with a socket. Options may exist at 

+ * multiple protocol levels; they are always present at the uppermost socket 

+ * level.

+ *

+ * @param sockfd	The socket descriptor.

+ * @param level		The level which to get the option from.

+ * @param optname	The option name.

+ * @param optval	Identifies the buffer which contain the value.

+ * @param optlen	The length of the value.

+ *

+ * @return		PJ_SUCCESS or the status code.

+ */

+PJ_DECL(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,

+					 pj_uint16_t level,

+					 pj_uint16_t optname,

+					 const void *optval,

+					 int optlen);

+

+

+/**

+ * Receives data stream or message coming to the specified socket.

+ *

+ * @param sockfd	The socket descriptor.

+ * @param buf		The buffer to receive the data or message.

+ * @param len		On input, the length of the buffer. On return,

+ *			contains the length of data received.

+ * @param flags		Combination of #pj_sock_msg_flag.

+ *

+ * @return		PJ_SUCCESS or the error code.

+ */

+PJ_DECL(pj_status_t) pj_sock_recv(pj_sock_t sockfd,

+				  void *buf,

+				  pj_ssize_t *len,

+				  unsigned flags);

+

+/**

+ * Receives data stream or message coming to the specified socket.

+ *

+ * @param sockfd	The socket descriptor.

+ * @param buf		The buffer to receive the data or message.

+ * @param len		On input, the length of the buffer. On return,

+ *			contains the length of data received.

+ * @param flags		Bitmask combination of #pj_sock_msg_flag.

+ * @param from		If not NULL, it will be filled with the source

+ *			address of the connection.

+ * @param fromlen	Initially contains the length of from address,

+ *			and upon return will be filled with the actual

+ *			length of the address.

+ *

+ * @return		PJ_SUCCESS or the error code.

+ */

+PJ_DECL(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,

+				      void *buf,

+				      pj_ssize_t *len,

+				      unsigned flags,

+				      pj_sockaddr_t *from,

+				      int *fromlen);

+

+/**

+ * Transmit data to the socket.

+ *

+ * @param sockfd	Socket descriptor.

+ * @param buf		Buffer containing data to be sent.

+ * @param len		On input, the length of the data in the buffer.

+ *			Upon return, it will be filled with the length

+ *			of data sent.

+ * @param flags		Bitmask combination of #pj_sock_msg_flag.

+ *

+ * @return		PJ_SUCCESS or the status code.

+ */

+PJ_DECL(pj_status_t) pj_sock_send(pj_sock_t sockfd,

+				  const void *buf,

+				  pj_ssize_t *len,

+				  unsigned flags);

+

+/**

+ * Transmit data to the socket to the specified address.

+ *

+ * @param sockfd	Socket descriptor.

+ * @param buf		Buffer containing data to be sent.

+ * @param len		On input, the length of the data in the buffer.

+ *			Upon return, it will be filled with the length

+ *			of data sent.

+ * @param flags		Bitmask combination of #pj_sock_msg_flag.

+ * @param to		The address to send.

+ * @param tolen		The length of the address in bytes.

+ *

+ * @return		The length of data successfully sent.

+ */

+PJ_DECL(pj_status_t) pj_sock_sendto(pj_sock_t sockfd,

+				    const void *buf,

+				    pj_ssize_t *len,

+				    unsigned flags,

+				    const pj_sockaddr_t *to,

+				    int tolen);

+

+#if PJ_HAS_TCP

+/**

+ * The shutdown call causes all or part of a full-duplex connection on the

+ * socket associated with sockfd to be shut down.

+ *

+ * @param sockfd	The socket descriptor.

+ * @param how		If how is PJ_SHUT_RD, further receptions will be 

+ *			disallowed. If how is PJ_SHUT_WR, further transmissions

+ *			will be disallowed. If how is PJ_SHUT_RDWR, further 

+ *			receptions andtransmissions will be disallowed.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,

+				       int how);

+#endif

+

+/**

+ * @}

+ */

+

+

+PJ_END_DECL

+

+#endif	/* __PJ_SOCK_H__ */

+

diff --git a/pjlib/include/pj/sock_select.h b/pjlib/include/pj/sock_select.h
index 5b0c700..e515984 100644
--- a/pjlib/include/pj/sock_select.h
+++ b/pjlib/include/pj/sock_select.h
@@ -1,133 +1,154 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/include/pj/sock_select.h $
- * 
- * 3     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 2     9/21/05 1:39p Bennylp
- * Periodic checkin for backup.
- * 
- * 1     9/15/05 8:40p Bennylp
- * Created.
- */
-#ifndef __PJ_SELECT_H__
-#define __PJ_SELECT_H__
-
-/**
- * @file sock_select.h
- * @brief Socket select().
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL 
-
-/**
- * @defgroup PJ_SOCK_SELECT Socket select() API.
- * @ingroup PJ_IO
- * @{
- * This module provides portable abstraction for \a select() like API.
- * The abstraction is needed so that it can utilize various event
- * dispatching mechanisms that are available across platforms.
- *
- * The API is very similar to normal \a select() usage. 
- *
- * \section pj_sock_select_examples_sec Examples
- *
- * For some examples on how to use the select API, please see:
- *
- *  - \ref page_pjlib_select_test
- */
-
-/**
- * Portable structure declarations for pj_fd_set.
- * The implementation of pj_sock_select() does not use this structure 
- * per-se, but instead it will use the native fd_set structure. However,
- * we must make sure that the size of pj_fd_set_t can accomodate the
- * native fd_set structure.
- */
-typedef struct pj_fd_set_t
-{
-    pj_sock_t	data[FD_SETSIZE + 4];   /**< Opaque buffer for fd_set */
-} pj_fd_set_t;
-
-
-/**
- * Initialize the descriptor set pointed to by fdsetp to the null set.
- *
- * @param fdsetp    The descriptor set.
- */
-PJ_DECL(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp);
-
-
-/**
- * Add the file descriptor fd to the set pointed to by fdsetp. 
- * If the file descriptor fd is already in this set, there shall be no effect
- * on the set, nor will an error be returned.
- *
- * @param fd	    The socket descriptor.
- * @param fdsetp    The descriptor set.
- */
-PJ_DECL(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp);
-
-/**
- * Remove the file descriptor fd from the set pointed to by fdsetp. 
- * If fd is not a member of this set, there shall be no effect on the set, 
- * nor will an error be returned.
- *
- * @param fd	    The socket descriptor.
- * @param fdsetp    The descriptor set.
- */
-PJ_DECL(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp);
-
-
-/**
- * Evaluate to non-zero if the file descriptor fd is a member of the set 
- * pointed to by fdsetp, and shall evaluate to zero otherwise.
- *
- * @param fd	    The socket descriptor.
- * @param fdsetp    The descriptor set.
- *
- * @return	    Nonzero if fd is member of the descriptor set.
- */
-PJ_DECL(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp);
-
-
-/**
- * This function wait for a number of file  descriptors to change status.
- * The behaviour is the same as select() function call which appear in
- * standard BSD socket libraries.
- *
- * @param n	    On Unices, this specifies the highest-numbered
- *		    descriptor in any of the three set, plus 1. On Windows,
- *		    the value is ignored.
- * @param readfds   Optional pointer to a set of sockets to be checked for 
- *		    readability.
- * @param writefds  Optional pointer to a set of sockets to be checked for 
- *		    writability.
- * @param exceptfds Optional pointer to a set of sockets to be checked for 
- *		    errors.
- * @param timeout   Maximum time for select to wait, or null for blocking 
- *		    operations.
- *
- * @return	    The total number of socket handles that are ready, or
- *		    zero if the time limit expired, or -1 if an error occurred.
- */
-PJ_DECL(int) pj_sock_select( int n, 
-			     pj_fd_set_t *readfds, 
-			     pj_fd_set_t *writefds,
-			     pj_fd_set_t *exceptfds, 
-			     const pj_time_val *timeout);
-
-
-/**
- * @}
- */
-
-
-PJ_END_DECL
-
-#endif	/* __PJ_SELECT_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/include/pj/sock_select.h $

+ * 

+ * 3     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 2     9/21/05 1:39p Bennylp

+ * Periodic checkin for backup.

+ * 

+ * 1     9/15/05 8:40p Bennylp

+ * Created.

+ */

+#ifndef __PJ_SELECT_H__

+#define __PJ_SELECT_H__

+

+/**

+ * @file sock_select.h

+ * @brief Socket select().

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL 

+

+/**

+ * @defgroup PJ_SOCK_SELECT Socket select() API.

+ * @ingroup PJ_IO

+ * @{

+ * This module provides portable abstraction for \a select() like API.

+ * The abstraction is needed so that it can utilize various event

+ * dispatching mechanisms that are available across platforms.

+ *

+ * The API is very similar to normal \a select() usage. 

+ *

+ * \section pj_sock_select_examples_sec Examples

+ *

+ * For some examples on how to use the select API, please see:

+ *

+ *  - \ref page_pjlib_select_test

+ */

+

+/**

+ * Portable structure declarations for pj_fd_set.

+ * The implementation of pj_sock_select() does not use this structure 

+ * per-se, but instead it will use the native fd_set structure. However,

+ * we must make sure that the size of pj_fd_set_t can accomodate the

+ * native fd_set structure.

+ */

+typedef struct pj_fd_set_t

+{

+    pj_sock_t	data[FD_SETSIZE + 4];   /**< Opaque buffer for fd_set */

+} pj_fd_set_t;

+

+

+/**

+ * Initialize the descriptor set pointed to by fdsetp to the null set.

+ *

+ * @param fdsetp    The descriptor set.

+ */

+PJ_DECL(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp);

+

+

+/**

+ * Add the file descriptor fd to the set pointed to by fdsetp. 

+ * If the file descriptor fd is already in this set, there shall be no effect

+ * on the set, nor will an error be returned.

+ *

+ * @param fd	    The socket descriptor.

+ * @param fdsetp    The descriptor set.

+ */

+PJ_DECL(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp);

+

+/**

+ * Remove the file descriptor fd from the set pointed to by fdsetp. 

+ * If fd is not a member of this set, there shall be no effect on the set, 

+ * nor will an error be returned.

+ *

+ * @param fd	    The socket descriptor.

+ * @param fdsetp    The descriptor set.

+ */

+PJ_DECL(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp);

+

+

+/**

+ * Evaluate to non-zero if the file descriptor fd is a member of the set 

+ * pointed to by fdsetp, and shall evaluate to zero otherwise.

+ *

+ * @param fd	    The socket descriptor.

+ * @param fdsetp    The descriptor set.

+ *

+ * @return	    Nonzero if fd is member of the descriptor set.

+ */

+PJ_DECL(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp);

+

+

+/**

+ * This function wait for a number of file  descriptors to change status.

+ * The behaviour is the same as select() function call which appear in

+ * standard BSD socket libraries.

+ *

+ * @param n	    On Unices, this specifies the highest-numbered

+ *		    descriptor in any of the three set, plus 1. On Windows,

+ *		    the value is ignored.

+ * @param readfds   Optional pointer to a set of sockets to be checked for 

+ *		    readability.

+ * @param writefds  Optional pointer to a set of sockets to be checked for 

+ *		    writability.

+ * @param exceptfds Optional pointer to a set of sockets to be checked for 

+ *		    errors.

+ * @param timeout   Maximum time for select to wait, or null for blocking 

+ *		    operations.

+ *

+ * @return	    The total number of socket handles that are ready, or

+ *		    zero if the time limit expired, or -1 if an error occurred.

+ */

+PJ_DECL(int) pj_sock_select( int n, 

+			     pj_fd_set_t *readfds, 

+			     pj_fd_set_t *writefds,

+			     pj_fd_set_t *exceptfds, 

+			     const pj_time_val *timeout);

+

+

+/**

+ * @}

+ */

+

+

+PJ_END_DECL

+

+#endif	/* __PJ_SELECT_H__ */

diff --git a/pjlib/include/pj/string.h b/pjlib/include/pj/string.h
index 5b7ac13..22f107b 100644
--- a/pjlib/include/pj/string.h
+++ b/pjlib/include/pj/string.h
@@ -1,520 +1,541 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_STRING_H__
-#define __PJ_STRING_H__
-
-/**
- * @file string.h
- * @brief PJLIB String Operations.
- */
-
-#include <pj/types.h>
-#include <pj/compat/string.h>
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_STRING_H__

+#define __PJ_STRING_H__

+

+/**

+ * @file string.h

+ * @brief PJLIB String Operations.

+ */

+

+#include <pj/types.h>

+#include <pj/compat/string.h>

 #include <pj/compat/sprintf.h>

 #include <pj/compat/vsprintf.h>

 

-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_PSTR String Operations
- * @ingroup PJ_DS
- * @{
- * This module provides string manipulation API.
- *
- * \section pj_pstr_not_null_sec PJLIB String is NOT Null Terminated!
- *
- * That is the first information that developers need to know. Instead
- * of using normal C string, strings in PJLIB are represented as
- * pj_str_t structure below:
- *
- * <pre>
- *   typedef struct pj_str_t
- *   {
- *       char      *ptr;
- *       pj_size_t  slen;
- *   } pj_str_t;
- * </pre>
- *
- * There are some advantages of using this approach:
- *  - the string can point to arbitrary location in memory even
- *    if the string in that location is not null terminated. This is
- *    most usefull for text parsing, where the parsed text can just
- *    point to the original text in the input. If we use C string,
- *    then we will have to copy the text portion from the input
- *    to a string variable.
- *  - because the length of the string is known, string copy operation
- *    can be made more efficient.
- *
- * Most of APIs in PJLIB that expect or return string will represent
- * the string as pj_str_t instead of normal C string.
- *
- * \section pj_pstr_examples_sec Examples
- *
- * For some examples, please see:
- *  - @ref page_pjlib_string_test
- */
-
-/**
- * Create string initializer from a normal C string.
- *
- * @param str	Null terminated string to be stored.
- *
- * @return	pj_str_t.
- */
-PJ_IDECL(pj_str_t) pj_str(char *str);
-
-/**
- * Create constant string from normal C string.
- *
- * @param str	The string to be initialized.
- * @param s	Null terminated string.
- *
- * @return	pj_str_t.
- */
-PJ_INLINE(const pj_str_t*) pj_cstr(pj_str_t *str, const char *s)
-{
-    str->ptr = (char*)s;
-    str->slen = s ? strlen(s) : 0;
-    return str;
-}
-
-/**
- * Set the pointer and length to the specified value.
- *
- * @param str	    the string.
- * @param ptr	    pointer to set.
- * @param length    length to set.
- *
- * @return the string.
- */
-PJ_INLINE(pj_str_t*) pj_strset( pj_str_t *str, char *ptr, pj_size_t length)
-{
-    str->ptr = ptr;
-    str->slen = length;
-    return str;
-}
-
-/**
- * Set the pointer and length of the string to the source string, which
- * must be NULL terminated.
- *
- * @param str	    the string.
- * @param src	    pointer to set.
- *
- * @return the string.
- */
-PJ_INLINE(pj_str_t*) pj_strset2( pj_str_t *str, char *src)
-{
-    str->ptr = src;
-    str->slen = src ? strlen(src) : 0;
-    return str;
-}
-
-/**
- * Set the pointer and the length of the string.
- *
- * @param str	    The target string.
- * @param begin	    The start of the string.
- * @param end	    The end of the string.
- *
- * @return the target string.
- */
-PJ_INLINE(pj_str_t*) pj_strset3( pj_str_t *str, char *begin, char *end )
-{
-    str->ptr = begin;
-    str->slen = end-begin;
-    return str;
-}
-
-/**
- * Assign string.
- *
- * @param dst	    The target string.
- * @param src	    The source string.
- *
- * @return the target string.
- */
-PJ_IDECL(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src );
-
-/**
- * Copy string contents.
- *
- * @param dst	    The target string.
- * @param src	    The source string.
- *
- * @return the target string.
- */
-PJ_IDECL(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src);
-
-/**
- * Copy string contents.
- *
- * @param dst	    The target string.
- * @param src	    The source string.
- *
- * @return the target string.
- */
-PJ_IDECL(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src);
-
-/**
- * Duplicate string.
- *
- * @param pool	    The pool.
- * @param dst	    The string result.
- * @param src	    The string to duplicate.
- *
- * @return the string result.
- */
-PJ_IDECL(pj_str_t*) pj_strdup(pj_pool_t *pool,
-			      pj_str_t *dst,
-			      const pj_str_t *src);
-
-/**
- * Duplicate string and NULL terminate the destination string.
- *
- * @param pool
- * @param dst
- * @param src
- */
-PJ_IDECL(pj_str_t*) pj_strdup_with_null(pj_pool_t *pool,
-					pj_str_t *dst,
-					const pj_str_t *src);
-
-/**
- * Duplicate string.
- *
- * @param pool	    The pool.
- * @param dst	    The string result.
- * @param src	    The string to duplicate.
- *
- * @return the string result.
- */
-PJ_IDECL(pj_str_t*) pj_strdup2(pj_pool_t *pool,
-			       pj_str_t *dst,
-			       const char *src);
-
-/**
- * Duplicate string.
- *
- * @param pool	    The pool.
- * @param src	    The string to duplicate.
- *
- * @return the string result.
- */
-PJ_IDECL(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src);
-
-/**
- * Return the length of the string.
- *
- * @param str	    The string.
- *
- * @return the length of the string.
- */
-PJ_INLINE(pj_size_t) pj_strlen( const pj_str_t *str )
-{
-    return str->slen;
-}
-
-/**
- * Return the pointer to the string data.
- *
- * @param str	    The string.
- *
- * @return the pointer to the string buffer.
- */
-PJ_INLINE(const char*) pj_strbuf( const pj_str_t *str )
-{
-    return str->ptr;
-}
-
-/**
- * Compare strings. 
- *
- * @param str1	    The string to compare.
- * @param str2	    The string to compare.
- *
- * @return 
- *	- < 0 if str1 is less than str2
- *      - 0   if str1 is identical to str2
- *      - > 0 if str1 is greater than str2
- */
-PJ_IDECL(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2);
-
-/**
- * Compare strings.
- *
- * @param str1	    The string to compare.
- * @param str2	    The string to compare.
- *
- * @return 
- *	- < 0 if str1 is less than str2
- *      - 0   if str1 is identical to str2
- *      - > 0 if str1 is greater than str2
- */
-PJ_IDECL(int) pj_strcmp2( const pj_str_t *str1, const char *str2 );
-
-/**
- * Compare strings. 
- *
- * @param str1	    The string to compare.
- * @param str2	    The string to compare.
- * @param len	    The maximum number of characters to compare.
- *
- * @return 
- *	- < 0 if str1 is less than str2
- *      - 0   if str1 is identical to str2
- *      - > 0 if str1 is greater than str2
- */
-PJ_IDECL(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, 
-			  pj_size_t len);
-
-/**
- * Compare strings. 
- *
- * @param str1	    The string to compare.
- * @param str2	    The string to compare.
- * @param len	    The maximum number of characters to compare.
- *
- * @return 
- *	- < 0 if str1 is less than str2
- *      - 0   if str1 is identical to str2
- *      - > 0 if str1 is greater than str2
- */
-PJ_IDECL(int) pj_strncmp2( const pj_str_t *str1, const char *str2, 
-			   pj_size_t len);
-
-/**
- * Perform lowercase comparison to the strings.
- *
- * @param str1	    The string to compare.
- * @param str2	    The string to compare.
- *
- * @return 
- *	- < 0 if str1 is less than str2
- *      - 0   if str1 is identical to str2
- *      - > 0 if str1 is greater than str2
- */
-PJ_IDECL(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2);
-
-/**
- * Perform lowercase comparison to the strings.
- *
- * @param str1	    The string to compare.
- * @param str2	    The string to compare.
- *
- * @return 
- *	- < 0 if str1 is less than str2
- *      - 0   if str1 is identical to str2
- *      - > 0 if str1 is greater than str2
- */
-PJ_IDECL(int) pj_stricmp2( const pj_str_t *str1, const char *str2);
-
-/**
- * Perform lowercase comparison to the strings.
- *
- * @param str1	    The string to compare.
- * @param str2	    The string to compare.
- * @param len	    The maximum number of characters to compare.
- *
- * @return 
- *	- < 0 if str1 is less than str2
- *      - 0   if str1 is identical to str2
- *      - > 0 if str1 is greater than str2
- */
-PJ_IDECL(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, 
-			   pj_size_t len);
-
-/**
- * Perform lowercase comparison to the strings.
- *
- * @param str1	    The string to compare.
- * @param str2	    The string to compare.
- * @param len	    The maximum number of characters to compare.
- *
- * @return 
- *	- < 0 if str1 is less than str2
- *      - 0   if str1 is identical to str2
- *      - > 0 if str1 is greater than str2
- */
-PJ_IDECL(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, 
-			    pj_size_t len);
-
-/**
- * Concatenate strings.
- *
- * @param dst	    The destination string.
- * @param src	    The source string.
- */
-PJ_IDECL(void) pj_strcat(pj_str_t *dst, const pj_str_t *src);
-
-/**
- * Finds a character in a string.
- *
- * @param str	    The string.
- * @param chr	    The character to find.
- *
- * @return the pointer to first character found, or NULL.
- */
-PJ_INLINE(char*) pj_strchr( pj_str_t *str, int chr)
-{
-    return (char*) memchr(str->ptr, chr, str->slen);
-}
-
-/**
- * Remove (trim) leading whitespaces from the string.
- *
- * @param str	    The string.
- *
- * @return the string.
- */
-PJ_DECL(pj_str_t*) pj_strltrim( pj_str_t *str );
-
-/**
- * Remove (trim) the trailing whitespaces from the string.
- *
- * @param str	    The string.
- *
- * @return the string.
- */
-PJ_DECL(pj_str_t*) pj_strrtrim( pj_str_t *str );
-
-/**
- * Remove (trim) leading and trailing whitespaces from the string.
- *
- * @param str	    The string.
- *
- * @return the string.
- */
-PJ_IDECL(pj_str_t*) pj_strtrim( pj_str_t *str );
-
-/**
- * Initialize the buffer with some random string.
- *
- * @param str	    the string to store the result.
- * @param length    the length of the random string to generate.
- *
- * @return the string.
- */
-PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length);
-
-/**
- * Convert string to unsigned integer.
- *
- * @param str	the string.
- *
- * @return the unsigned integer.
- */
-PJ_DECL(unsigned long) pj_strtoul(const pj_str_t *str);
-
-/**
- * Utility to convert unsigned integer to string. Note that the
- * string will be NULL terminated.
- *
- * @param val	    the unsigned integer value.
- * @param buf	    the buffer
- *
- * @return the number of characters written
- */
-PJ_DECL(int) pj_utoa(unsigned long val, char *buf);
-
-/**
- * Convert unsigned integer to string with minimum digits. Note that the
- * string will be NULL terminated.
- *
- * @param val	    The unsigned integer value.
- * @param buf	    The buffer.
- * @param min_dig   Minimum digits to be printed, or zero to specify no
- *		    minimum digit.
- * @param pad	    The padding character to be put in front of the string
- *		    when the digits is less than minimum.
- *
- * @return the number of characters written.
- */
-PJ_DECL(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad);
-
-/**
- * Fill the memory location with value.
- *
- * @param dst	    The destination buffer.
- * @param c	    Character to set.
- * @param size	    The number of characters.
- *
- * @return the value of dst.
- */
-PJ_INLINE(void*) pj_memset(void *dst, int c, pj_size_t size)
-{
-    return memset(dst, c, size);
-}
-
-/**
- * Copy buffer.
- *
- * @param dst	    The destination buffer.
- * @param src	    The source buffer.
- * @param size	    The size to copy.
- *
- * @return the destination buffer.
- */
-PJ_INLINE(void*) pj_memcpy(void *dst, const void *src, pj_size_t size)
-{
-    return memcpy(dst, src, size);
-}
-
-/**
- * Move memory.
- *
- * @param dst	    The destination buffer.
- * @param src	    The source buffer.
- * @param size	    The size to copy.
- *
- * @return the destination buffer.
- */
-PJ_INLINE(void*) pj_memmove(void *dst, const void *src, pj_size_t size)
-{
-    return memmove(dst, src, size);
-}
-
-/**
- * Compare buffers.
- *
- * @param buf1	    The first buffer.
- * @param buf2	    The second buffer.
- * @param size	    The size to compare.
- *
- * @return negative, zero, or positive value.
- */
-PJ_INLINE(int) pj_memcmp(const void *buf1, const void *buf2, pj_size_t size)
-{
-    return memcmp(buf1, buf2, size);
-}
-
-/**
- * Find character in the buffer.
- *
- * @param buf	    The buffer.
- * @param c	    The character to find.
- * @param size	    The size to check.
- *
- * @return the pointer to location where the character is found, or NULL if
- *         not found.
- */
-PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size)
-{
-    return memchr(buf, c, size);
-}
-
-/**
- * @}
- */
-
-#if PJ_FUNCTIONS_ARE_INLINED
-#  include <pj/string_i.h>
-#endif
-
-PJ_END_DECL
-
-#endif	/* __PJ_STRING_H__ */
-
+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_PSTR String Operations

+ * @ingroup PJ_DS

+ * @{

+ * This module provides string manipulation API.

+ *

+ * \section pj_pstr_not_null_sec PJLIB String is NOT Null Terminated!

+ *

+ * That is the first information that developers need to know. Instead

+ * of using normal C string, strings in PJLIB are represented as

+ * pj_str_t structure below:

+ *

+ * <pre>

+ *   typedef struct pj_str_t

+ *   {

+ *       char      *ptr;

+ *       pj_size_t  slen;

+ *   } pj_str_t;

+ * </pre>

+ *

+ * There are some advantages of using this approach:

+ *  - the string can point to arbitrary location in memory even

+ *    if the string in that location is not null terminated. This is

+ *    most usefull for text parsing, where the parsed text can just

+ *    point to the original text in the input. If we use C string,

+ *    then we will have to copy the text portion from the input

+ *    to a string variable.

+ *  - because the length of the string is known, string copy operation

+ *    can be made more efficient.

+ *

+ * Most of APIs in PJLIB that expect or return string will represent

+ * the string as pj_str_t instead of normal C string.

+ *

+ * \section pj_pstr_examples_sec Examples

+ *

+ * For some examples, please see:

+ *  - @ref page_pjlib_string_test

+ */

+

+/**

+ * Create string initializer from a normal C string.

+ *

+ * @param str	Null terminated string to be stored.

+ *

+ * @return	pj_str_t.

+ */

+PJ_IDECL(pj_str_t) pj_str(char *str);

+

+/**

+ * Create constant string from normal C string.

+ *

+ * @param str	The string to be initialized.

+ * @param s	Null terminated string.

+ *

+ * @return	pj_str_t.

+ */

+PJ_INLINE(const pj_str_t*) pj_cstr(pj_str_t *str, const char *s)

+{

+    str->ptr = (char*)s;

+    str->slen = s ? strlen(s) : 0;

+    return str;

+}

+

+/**

+ * Set the pointer and length to the specified value.

+ *

+ * @param str	    the string.

+ * @param ptr	    pointer to set.

+ * @param length    length to set.

+ *

+ * @return the string.

+ */

+PJ_INLINE(pj_str_t*) pj_strset( pj_str_t *str, char *ptr, pj_size_t length)

+{

+    str->ptr = ptr;

+    str->slen = length;

+    return str;

+}

+

+/**

+ * Set the pointer and length of the string to the source string, which

+ * must be NULL terminated.

+ *

+ * @param str	    the string.

+ * @param src	    pointer to set.

+ *

+ * @return the string.

+ */

+PJ_INLINE(pj_str_t*) pj_strset2( pj_str_t *str, char *src)

+{

+    str->ptr = src;

+    str->slen = src ? strlen(src) : 0;

+    return str;

+}

+

+/**

+ * Set the pointer and the length of the string.

+ *

+ * @param str	    The target string.

+ * @param begin	    The start of the string.

+ * @param end	    The end of the string.

+ *

+ * @return the target string.

+ */

+PJ_INLINE(pj_str_t*) pj_strset3( pj_str_t *str, char *begin, char *end )

+{

+    str->ptr = begin;

+    str->slen = end-begin;

+    return str;

+}

+

+/**

+ * Assign string.

+ *

+ * @param dst	    The target string.

+ * @param src	    The source string.

+ *

+ * @return the target string.

+ */

+PJ_IDECL(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src );

+

+/**

+ * Copy string contents.

+ *

+ * @param dst	    The target string.

+ * @param src	    The source string.

+ *

+ * @return the target string.

+ */

+PJ_IDECL(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src);

+

+/**

+ * Copy string contents.

+ *

+ * @param dst	    The target string.

+ * @param src	    The source string.

+ *

+ * @return the target string.

+ */

+PJ_IDECL(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src);

+

+/**

+ * Duplicate string.

+ *

+ * @param pool	    The pool.

+ * @param dst	    The string result.

+ * @param src	    The string to duplicate.

+ *

+ * @return the string result.

+ */

+PJ_IDECL(pj_str_t*) pj_strdup(pj_pool_t *pool,

+			      pj_str_t *dst,

+			      const pj_str_t *src);

+

+/**

+ * Duplicate string and NULL terminate the destination string.

+ *

+ * @param pool

+ * @param dst

+ * @param src

+ */

+PJ_IDECL(pj_str_t*) pj_strdup_with_null(pj_pool_t *pool,

+					pj_str_t *dst,

+					const pj_str_t *src);

+

+/**

+ * Duplicate string.

+ *

+ * @param pool	    The pool.

+ * @param dst	    The string result.

+ * @param src	    The string to duplicate.

+ *

+ * @return the string result.

+ */

+PJ_IDECL(pj_str_t*) pj_strdup2(pj_pool_t *pool,

+			       pj_str_t *dst,

+			       const char *src);

+

+/**

+ * Duplicate string.

+ *

+ * @param pool	    The pool.

+ * @param src	    The string to duplicate.

+ *

+ * @return the string result.

+ */

+PJ_IDECL(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src);

+

+/**

+ * Return the length of the string.

+ *

+ * @param str	    The string.

+ *

+ * @return the length of the string.

+ */

+PJ_INLINE(pj_size_t) pj_strlen( const pj_str_t *str )

+{

+    return str->slen;

+}

+

+/**

+ * Return the pointer to the string data.

+ *

+ * @param str	    The string.

+ *

+ * @return the pointer to the string buffer.

+ */

+PJ_INLINE(const char*) pj_strbuf( const pj_str_t *str )

+{

+    return str->ptr;

+}

+

+/**

+ * Compare strings. 

+ *

+ * @param str1	    The string to compare.

+ * @param str2	    The string to compare.

+ *

+ * @return 

+ *	- < 0 if str1 is less than str2

+ *      - 0   if str1 is identical to str2

+ *      - > 0 if str1 is greater than str2

+ */

+PJ_IDECL(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2);

+

+/**

+ * Compare strings.

+ *

+ * @param str1	    The string to compare.

+ * @param str2	    The string to compare.

+ *

+ * @return 

+ *	- < 0 if str1 is less than str2

+ *      - 0   if str1 is identical to str2

+ *      - > 0 if str1 is greater than str2

+ */

+PJ_IDECL(int) pj_strcmp2( const pj_str_t *str1, const char *str2 );

+

+/**

+ * Compare strings. 

+ *

+ * @param str1	    The string to compare.

+ * @param str2	    The string to compare.

+ * @param len	    The maximum number of characters to compare.

+ *

+ * @return 

+ *	- < 0 if str1 is less than str2

+ *      - 0   if str1 is identical to str2

+ *      - > 0 if str1 is greater than str2

+ */

+PJ_IDECL(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, 

+			  pj_size_t len);

+

+/**

+ * Compare strings. 

+ *

+ * @param str1	    The string to compare.

+ * @param str2	    The string to compare.

+ * @param len	    The maximum number of characters to compare.

+ *

+ * @return 

+ *	- < 0 if str1 is less than str2

+ *      - 0   if str1 is identical to str2

+ *      - > 0 if str1 is greater than str2

+ */

+PJ_IDECL(int) pj_strncmp2( const pj_str_t *str1, const char *str2, 

+			   pj_size_t len);

+

+/**

+ * Perform lowercase comparison to the strings.

+ *

+ * @param str1	    The string to compare.

+ * @param str2	    The string to compare.

+ *

+ * @return 

+ *	- < 0 if str1 is less than str2

+ *      - 0   if str1 is identical to str2

+ *      - > 0 if str1 is greater than str2

+ */

+PJ_IDECL(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2);

+

+/**

+ * Perform lowercase comparison to the strings.

+ *

+ * @param str1	    The string to compare.

+ * @param str2	    The string to compare.

+ *

+ * @return 

+ *	- < 0 if str1 is less than str2

+ *      - 0   if str1 is identical to str2

+ *      - > 0 if str1 is greater than str2

+ */

+PJ_IDECL(int) pj_stricmp2( const pj_str_t *str1, const char *str2);

+

+/**

+ * Perform lowercase comparison to the strings.

+ *

+ * @param str1	    The string to compare.

+ * @param str2	    The string to compare.

+ * @param len	    The maximum number of characters to compare.

+ *

+ * @return 

+ *	- < 0 if str1 is less than str2

+ *      - 0   if str1 is identical to str2

+ *      - > 0 if str1 is greater than str2

+ */

+PJ_IDECL(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, 

+			   pj_size_t len);

+

+/**

+ * Perform lowercase comparison to the strings.

+ *

+ * @param str1	    The string to compare.

+ * @param str2	    The string to compare.

+ * @param len	    The maximum number of characters to compare.

+ *

+ * @return 

+ *	- < 0 if str1 is less than str2

+ *      - 0   if str1 is identical to str2

+ *      - > 0 if str1 is greater than str2

+ */

+PJ_IDECL(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, 

+			    pj_size_t len);

+

+/**

+ * Concatenate strings.

+ *

+ * @param dst	    The destination string.

+ * @param src	    The source string.

+ */

+PJ_IDECL(void) pj_strcat(pj_str_t *dst, const pj_str_t *src);

+

+/**

+ * Finds a character in a string.

+ *

+ * @param str	    The string.

+ * @param chr	    The character to find.

+ *

+ * @return the pointer to first character found, or NULL.

+ */

+PJ_INLINE(char*) pj_strchr( pj_str_t *str, int chr)

+{

+    return (char*) memchr(str->ptr, chr, str->slen);

+}

+

+/**

+ * Remove (trim) leading whitespaces from the string.

+ *

+ * @param str	    The string.

+ *

+ * @return the string.

+ */

+PJ_DECL(pj_str_t*) pj_strltrim( pj_str_t *str );

+

+/**

+ * Remove (trim) the trailing whitespaces from the string.

+ *

+ * @param str	    The string.

+ *

+ * @return the string.

+ */

+PJ_DECL(pj_str_t*) pj_strrtrim( pj_str_t *str );

+

+/**

+ * Remove (trim) leading and trailing whitespaces from the string.

+ *

+ * @param str	    The string.

+ *

+ * @return the string.

+ */

+PJ_IDECL(pj_str_t*) pj_strtrim( pj_str_t *str );

+

+/**

+ * Initialize the buffer with some random string.

+ *

+ * @param str	    the string to store the result.

+ * @param length    the length of the random string to generate.

+ *

+ * @return the string.

+ */

+PJ_DECL(char*) pj_create_random_string(char *str, pj_size_t length);

+

+/**

+ * Convert string to unsigned integer.

+ *

+ * @param str	the string.

+ *

+ * @return the unsigned integer.

+ */

+PJ_DECL(unsigned long) pj_strtoul(const pj_str_t *str);

+

+/**

+ * Utility to convert unsigned integer to string. Note that the

+ * string will be NULL terminated.

+ *

+ * @param val	    the unsigned integer value.

+ * @param buf	    the buffer

+ *

+ * @return the number of characters written

+ */

+PJ_DECL(int) pj_utoa(unsigned long val, char *buf);

+

+/**

+ * Convert unsigned integer to string with minimum digits. Note that the

+ * string will be NULL terminated.

+ *

+ * @param val	    The unsigned integer value.

+ * @param buf	    The buffer.

+ * @param min_dig   Minimum digits to be printed, or zero to specify no

+ *		    minimum digit.

+ * @param pad	    The padding character to be put in front of the string

+ *		    when the digits is less than minimum.

+ *

+ * @return the number of characters written.

+ */

+PJ_DECL(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad);

+

+/**

+ * Fill the memory location with value.

+ *

+ * @param dst	    The destination buffer.

+ * @param c	    Character to set.

+ * @param size	    The number of characters.

+ *

+ * @return the value of dst.

+ */

+PJ_INLINE(void*) pj_memset(void *dst, int c, pj_size_t size)

+{

+    return memset(dst, c, size);

+}

+

+/**

+ * Copy buffer.

+ *

+ * @param dst	    The destination buffer.

+ * @param src	    The source buffer.

+ * @param size	    The size to copy.

+ *

+ * @return the destination buffer.

+ */

+PJ_INLINE(void*) pj_memcpy(void *dst, const void *src, pj_size_t size)

+{

+    return memcpy(dst, src, size);

+}

+

+/**

+ * Move memory.

+ *

+ * @param dst	    The destination buffer.

+ * @param src	    The source buffer.

+ * @param size	    The size to copy.

+ *

+ * @return the destination buffer.

+ */

+PJ_INLINE(void*) pj_memmove(void *dst, const void *src, pj_size_t size)

+{

+    return memmove(dst, src, size);

+}

+

+/**

+ * Compare buffers.

+ *

+ * @param buf1	    The first buffer.

+ * @param buf2	    The second buffer.

+ * @param size	    The size to compare.

+ *

+ * @return negative, zero, or positive value.

+ */

+PJ_INLINE(int) pj_memcmp(const void *buf1, const void *buf2, pj_size_t size)

+{

+    return memcmp(buf1, buf2, size);

+}

+

+/**

+ * Find character in the buffer.

+ *

+ * @param buf	    The buffer.

+ * @param c	    The character to find.

+ * @param size	    The size to check.

+ *

+ * @return the pointer to location where the character is found, or NULL if

+ *         not found.

+ */

+PJ_INLINE(void*) pj_memchr(const void *buf, int c, pj_size_t size)

+{

+    return memchr(buf, c, size);

+}

+

+/**

+ * @}

+ */

+

+#if PJ_FUNCTIONS_ARE_INLINED

+#  include <pj/string_i.h>

+#endif

+

+PJ_END_DECL

+

+#endif	/* __PJ_STRING_H__ */

+

diff --git a/pjlib/include/pj/string_i.h b/pjlib/include/pj/string_i.h
index 46408b3..1d93c18 100644
--- a/pjlib/include/pj/string_i.h
+++ b/pjlib/include/pj/string_i.h
@@ -1,164 +1,185 @@
-/* $Id$
- *
- */
-
-PJ_IDEF(pj_str_t) pj_str(char *str)
-{
-    pj_str_t dst;
-    dst.ptr = str;
-    dst.slen = str ? strlen(str) : 0;
-    return dst;
-}
-
-PJ_IDEF(pj_str_t*) pj_strdup(pj_pool_t *pool,
-			      pj_str_t *dst,
-			      const pj_str_t *src)
-{
-    if (src->slen) {
-	dst->ptr = (char*)pj_pool_alloc(pool, src->slen);
-	pj_memcpy(dst->ptr, src->ptr, src->slen);
-    }
-    dst->slen = src->slen;
-    return dst;
-}
-
-PJ_IDEF(pj_str_t*) pj_strdup_with_null( pj_pool_t *pool,
-					pj_str_t *dst,
-					const pj_str_t *src)
-{
-    if (src->slen) {
-	dst->ptr = (char*)pj_pool_alloc(pool, src->slen+1);
-	pj_memcpy(dst->ptr, src->ptr, src->slen);
-    } else {
-	dst->ptr = (char*)pj_pool_alloc(pool, 1);
-    }
-    dst->slen = src->slen;
-    dst->ptr[dst->slen] = '\0';
-    return dst;
-}
-
-PJ_IDEF(pj_str_t*) pj_strdup2(pj_pool_t *pool,
-			      pj_str_t *dst,
-			      const char *src)
-{
-    dst->slen = src ? strlen(src) : 0;
-    if (dst->slen) {
-	dst->ptr = (char*)pj_pool_alloc(pool, dst->slen);
-	pj_memcpy(dst->ptr, src, dst->slen);
-    } else {
-	dst->ptr = NULL;
-    }
-    return dst;
-}
-
-
-PJ_IDEF(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src)
-{
-    pj_str_t temp;
-    pj_strdup2(pool, &temp, src);
-    return temp;
-}
-
-PJ_IDEF(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src )
-{
-    dst->ptr = src->ptr;
-    dst->slen = src->slen;
-    return dst;
-}
-
-PJ_IDEF(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src)
-{
-    dst->slen = src->slen;
-    if (src->slen > 0)
-	pj_memcpy(dst->ptr, src->ptr, src->slen);
-    return dst;
-}
-
-PJ_IDEF(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src)
-{
-    dst->slen = src ? strlen(src) : 0;
-    if (dst->slen > 0)
-	pj_memcpy(dst->ptr, src, dst->slen);
-    return dst;
-}
-
-PJ_IDEF(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2)
-{
-    pj_ssize_t diff;
-
-    diff = str1->slen - str2->slen;
-    if (diff) {
-	return (int)diff;
-    } else if (str1->ptr) {
-	return strncmp(str1->ptr, str2->ptr, str1->slen);
-    } else {
-	return 0;
-    }
-}
-
-PJ_IDEF(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, 
-			 pj_size_t len)
-{
-    return (str1->ptr && str2->ptr) ? strncmp(str1->ptr, str2->ptr, len) :
-	   (str1->ptr == str2->ptr ? 0 : 1);
-}
-
-PJ_IDEF(int) pj_strncmp2( const pj_str_t *str1, const char *str2, 
-			  pj_size_t len)
-{
-    return (str1->ptr && str2) ? strncmp(str1->ptr, str2, len) :
-	   (str1->ptr==str2 ? 0 : 1);
-}
-
-PJ_IDEF(int) pj_strcmp2( const pj_str_t *str1, const char *str2 )
-{
-    return pj_strncmp2( str1, str2, str1->slen);
-}
-
-PJ_IDEF(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2)
-{
-    pj_ssize_t diff;
-
-    diff = str1->slen - str2->slen;
-    if (diff) {
-	return (int)diff;
-    } else {
-	return strnicmp(str1->ptr, str2->ptr, str1->slen);
-    }
-}
-
-PJ_IDEF(int) pj_stricmp2( const pj_str_t *str1, const char *str2)
-{
-    return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, str1->slen) :
-	   (str1->ptr==str2 ? 0 : 1);
-}
-
-PJ_IDEF(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, 
-			  pj_size_t len)
-{
-    return (str1->ptr && str2->ptr) ? strnicmp(str1->ptr, str2->ptr, len) :
-	   (str1->ptr == str2->ptr ? 0 : 1);
-}
-
-PJ_IDEF(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, 
-			   pj_size_t len)
-{
-    return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, len) :
-	   (str1->ptr == str2 ? 0 : 1);
-}
-
-PJ_IDEF(void) pj_strcat(pj_str_t *dst, const pj_str_t *src)
-{
-    if (src->slen) {
-	pj_memcpy(dst->ptr + dst->slen, src->ptr, src->slen);
-	dst->slen += src->slen;
-    }
-}
-
-PJ_IDEF(pj_str_t*) pj_strtrim( pj_str_t *str )
-{
-    pj_strltrim(str);
-    pj_strrtrim(str);
-    return str;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+PJ_IDEF(pj_str_t) pj_str(char *str)

+{

+    pj_str_t dst;

+    dst.ptr = str;

+    dst.slen = str ? strlen(str) : 0;

+    return dst;

+}

+

+PJ_IDEF(pj_str_t*) pj_strdup(pj_pool_t *pool,

+			      pj_str_t *dst,

+			      const pj_str_t *src)

+{

+    if (src->slen) {

+	dst->ptr = (char*)pj_pool_alloc(pool, src->slen);

+	pj_memcpy(dst->ptr, src->ptr, src->slen);

+    }

+    dst->slen = src->slen;

+    return dst;

+}

+

+PJ_IDEF(pj_str_t*) pj_strdup_with_null( pj_pool_t *pool,

+					pj_str_t *dst,

+					const pj_str_t *src)

+{

+    if (src->slen) {

+	dst->ptr = (char*)pj_pool_alloc(pool, src->slen+1);

+	pj_memcpy(dst->ptr, src->ptr, src->slen);

+    } else {

+	dst->ptr = (char*)pj_pool_alloc(pool, 1);

+    }

+    dst->slen = src->slen;

+    dst->ptr[dst->slen] = '\0';

+    return dst;

+}

+

+PJ_IDEF(pj_str_t*) pj_strdup2(pj_pool_t *pool,

+			      pj_str_t *dst,

+			      const char *src)

+{

+    dst->slen = src ? strlen(src) : 0;

+    if (dst->slen) {

+	dst->ptr = (char*)pj_pool_alloc(pool, dst->slen);

+	pj_memcpy(dst->ptr, src, dst->slen);

+    } else {

+	dst->ptr = NULL;

+    }

+    return dst;

+}

+

+

+PJ_IDEF(pj_str_t) pj_strdup3(pj_pool_t *pool, const char *src)

+{

+    pj_str_t temp;

+    pj_strdup2(pool, &temp, src);

+    return temp;

+}

+

+PJ_IDEF(pj_str_t*) pj_strassign( pj_str_t *dst, pj_str_t *src )

+{

+    dst->ptr = src->ptr;

+    dst->slen = src->slen;

+    return dst;

+}

+

+PJ_IDEF(pj_str_t*) pj_strcpy(pj_str_t *dst, const pj_str_t *src)

+{

+    dst->slen = src->slen;

+    if (src->slen > 0)

+	pj_memcpy(dst->ptr, src->ptr, src->slen);

+    return dst;

+}

+

+PJ_IDEF(pj_str_t*) pj_strcpy2(pj_str_t *dst, const char *src)

+{

+    dst->slen = src ? strlen(src) : 0;

+    if (dst->slen > 0)

+	pj_memcpy(dst->ptr, src, dst->slen);

+    return dst;

+}

+

+PJ_IDEF(int) pj_strcmp( const pj_str_t *str1, const pj_str_t *str2)

+{

+    pj_ssize_t diff;

+

+    diff = str1->slen - str2->slen;

+    if (diff) {

+	return (int)diff;

+    } else if (str1->ptr) {

+	return strncmp(str1->ptr, str2->ptr, str1->slen);

+    } else {

+	return 0;

+    }

+}

+

+PJ_IDEF(int) pj_strncmp( const pj_str_t *str1, const pj_str_t *str2, 

+			 pj_size_t len)

+{

+    return (str1->ptr && str2->ptr) ? strncmp(str1->ptr, str2->ptr, len) :

+	   (str1->ptr == str2->ptr ? 0 : 1);

+}

+

+PJ_IDEF(int) pj_strncmp2( const pj_str_t *str1, const char *str2, 

+			  pj_size_t len)

+{

+    return (str1->ptr && str2) ? strncmp(str1->ptr, str2, len) :

+	   (str1->ptr==str2 ? 0 : 1);

+}

+

+PJ_IDEF(int) pj_strcmp2( const pj_str_t *str1, const char *str2 )

+{

+    return pj_strncmp2( str1, str2, str1->slen);

+}

+

+PJ_IDEF(int) pj_stricmp( const pj_str_t *str1, const pj_str_t *str2)

+{

+    pj_ssize_t diff;

+

+    diff = str1->slen - str2->slen;

+    if (diff) {

+	return (int)diff;

+    } else {

+	return strnicmp(str1->ptr, str2->ptr, str1->slen);

+    }

+}

+

+PJ_IDEF(int) pj_stricmp2( const pj_str_t *str1, const char *str2)

+{

+    return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, str1->slen) :

+	   (str1->ptr==str2 ? 0 : 1);

+}

+

+PJ_IDEF(int) pj_strnicmp( const pj_str_t *str1, const pj_str_t *str2, 

+			  pj_size_t len)

+{

+    return (str1->ptr && str2->ptr) ? strnicmp(str1->ptr, str2->ptr, len) :

+	   (str1->ptr == str2->ptr ? 0 : 1);

+}

+

+PJ_IDEF(int) pj_strnicmp2( const pj_str_t *str1, const char *str2, 

+			   pj_size_t len)

+{

+    return (str1->ptr && str2) ? strnicmp(str1->ptr, str2, len) :

+	   (str1->ptr == str2 ? 0 : 1);

+}

+

+PJ_IDEF(void) pj_strcat(pj_str_t *dst, const pj_str_t *src)

+{

+    if (src->slen) {

+	pj_memcpy(dst->ptr + dst->slen, src->ptr, src->slen);

+	dst->slen += src->slen;

+    }

+}

+

+PJ_IDEF(pj_str_t*) pj_strtrim( pj_str_t *str )

+{

+    pj_strltrim(str);

+    pj_strrtrim(str);

+    return str;

+}

+

diff --git a/pjlib/include/pj/timer.h b/pjlib/include/pj/timer.h
index e8772f2..7ad5e4f 100644
--- a/pjlib/include/pj/timer.h
+++ b/pjlib/include/pj/timer.h
@@ -1,140 +1,161 @@
-/* $Id$
- *
- */
-/* (C)1993-2003 Douglas C. Schmidt
- *
- * This file is originaly from ACE library by Doug Schmidt
- * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and his research 
- * group at Washington University, University of California, Irvine, and Vanderbilt 
- * University Copyright (c) 1993-2003, all rights reserved.
- *
- */
-
-#ifndef __PJ_TIMER_H__
-#define __PJ_TIMER_H__
-
-/**
- * @file timer.h
- * @brief Timer Heap
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJ_TIMER Timer Heap Management.
- * @ingroup PJ_MISC
- * @brief
- * The timer scheduling implementation here is based on ACE library's 
- * ACE_Timer_Heap, with only little modification to suit our library's style
- * (I even left most of the comments in the original source).
- *
- * To quote the original quote in ACE_Timer_Heap_T class:
- *
- *      This implementation uses a heap-based callout queue of
- *      absolute times.  Therefore, in the average and worst case,
- *      scheduling, canceling, and expiring timers is O(log N) (where
- *      N is the total number of timers).  In addition, we can also
- *      preallocate as many \a ACE_Timer_Nodes as there are slots in
- *      the heap.  This allows us to completely remove the need for
- *      dynamic memory allocation, which is important for real-time
- *      systems.
- * @{
- *
- * \section pj_timer_examples_sec Examples
- *
- * For some examples on how to use the timer heap, please see the link below.
- *
- *  - \ref page_pjlib_timer_test
- */
-
-
-/**
- * The type for internal timer ID.
- */
-typedef int pj_timer_id_t;
-
-/** 
- * Forward declaration for pj_timer_entry. 
- */
-struct pj_timer_entry;
-
-/**
- * The type of callback function to be called by timer scheduler when a timer
- * has expired.
- *
- * @param timer_heap    The timer heap.
- * @param entry         Timer entry which timer's has expired.
- */
-typedef void pj_timer_heap_callback(pj_timer_heap_t *timer_heap,
-				    struct pj_timer_entry *entry);
-
-
-/**
- * This structure represents an entry to the timer.
- */
-struct pj_timer_entry
-{
-    /** 
-     * User data to be associated with this entry. 
-     * Applications normally will put the instance of object that
-     * owns the timer entry in this field.
-     */
-    void *user_data;
-
-    /** 
-     * Arbitrary ID assigned by the user/owner of this entry. 
-     * Applications can use this ID to distinguish multiple
-     * timer entries that share the same callback and user_data.
-     */
-    int id;
-
-    /** 
-     * Callback to be called when the timer expires. 
-     */
-    pj_timer_heap_callback *cb;
-
-    /** 
-     * Internal unique timer ID, which is assigned by the timer heap. 
-     * Application should not touch this ID.
-     */
-    pj_timer_id_t _timer_id;
-
-    /** 
-     * The future time when the timer expires, which the value is updated
-     * by timer heap when the timer is scheduled.
-     */
-    pj_time_val _timer_value;
-};
-
-
-/**
- * Calculate memory size required to create a timer heap.
- *
- * @param count     Number of timer entries to be supported.
- * @return          Memory size requirement in bytes.
- */
-PJ_DECL(pj_size_t) pj_timer_heap_mem_size(pj_size_t count);
-
-/**
- * Create a timer heap.
- *
- * @param pool      The pool where allocations in the timer heap will be 
- *                  allocated. The timer heap will dynamicly allocate 
- *                  more storate from the pool if the number of timer 
- *                  entries registered is more than the size originally 
- *                  requested when calling this function.
- * @param count     The maximum number of timer entries to be supported 
- *                  initially. If the application registers more entries 
- *                  during runtime, then the timer heap will resize.
- * @param ht        Pointer to receive the created timer heap.
- *
- * @return          PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
-					   pj_size_t count,
-                                           pj_timer_heap_t **ht);
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* (C)1993-2003 Douglas C. Schmidt

+ *

+ * This file is originaly from ACE library by Doug Schmidt

+ * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and his research 

+ * group at Washington University, University of California, Irvine, and Vanderbilt 

+ * University Copyright (c) 1993-2003, all rights reserved.

+ *

+ */

+

+#ifndef __PJ_TIMER_H__

+#define __PJ_TIMER_H__

+

+/**

+ * @file timer.h

+ * @brief Timer Heap

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJ_TIMER Timer Heap Management.

+ * @ingroup PJ_MISC

+ * @brief

+ * The timer scheduling implementation here is based on ACE library's 

+ * ACE_Timer_Heap, with only little modification to suit our library's style

+ * (I even left most of the comments in the original source).

+ *

+ * To quote the original quote in ACE_Timer_Heap_T class:

+ *

+ *      This implementation uses a heap-based callout queue of

+ *      absolute times.  Therefore, in the average and worst case,

+ *      scheduling, canceling, and expiring timers is O(log N) (where

+ *      N is the total number of timers).  In addition, we can also

+ *      preallocate as many \a ACE_Timer_Nodes as there are slots in

+ *      the heap.  This allows us to completely remove the need for

+ *      dynamic memory allocation, which is important for real-time

+ *      systems.

+ * @{

+ *

+ * \section pj_timer_examples_sec Examples

+ *

+ * For some examples on how to use the timer heap, please see the link below.

+ *

+ *  - \ref page_pjlib_timer_test

+ */

+

+

+/**

+ * The type for internal timer ID.

+ */

+typedef int pj_timer_id_t;

+

+/** 

+ * Forward declaration for pj_timer_entry. 

+ */

+struct pj_timer_entry;

+

+/**

+ * The type of callback function to be called by timer scheduler when a timer

+ * has expired.

+ *

+ * @param timer_heap    The timer heap.

+ * @param entry         Timer entry which timer's has expired.

+ */

+typedef void pj_timer_heap_callback(pj_timer_heap_t *timer_heap,

+				    struct pj_timer_entry *entry);

+

+

+/**

+ * This structure represents an entry to the timer.

+ */

+struct pj_timer_entry

+{

+    /** 

+     * User data to be associated with this entry. 

+     * Applications normally will put the instance of object that

+     * owns the timer entry in this field.

+     */

+    void *user_data;

+

+    /** 

+     * Arbitrary ID assigned by the user/owner of this entry. 

+     * Applications can use this ID to distinguish multiple

+     * timer entries that share the same callback and user_data.

+     */

+    int id;

+

+    /** 

+     * Callback to be called when the timer expires. 

+     */

+    pj_timer_heap_callback *cb;

+

+    /** 

+     * Internal unique timer ID, which is assigned by the timer heap. 

+     * Application should not touch this ID.

+     */

+    pj_timer_id_t _timer_id;

+

+    /** 

+     * The future time when the timer expires, which the value is updated

+     * by timer heap when the timer is scheduled.

+     */

+    pj_time_val _timer_value;

+};

+

+

+/**

+ * Calculate memory size required to create a timer heap.

+ *

+ * @param count     Number of timer entries to be supported.

+ * @return          Memory size requirement in bytes.

+ */

+PJ_DECL(pj_size_t) pj_timer_heap_mem_size(pj_size_t count);

+

+/**

+ * Create a timer heap.

+ *

+ * @param pool      The pool where allocations in the timer heap will be 

+ *                  allocated. The timer heap will dynamicly allocate 

+ *                  more storate from the pool if the number of timer 

+ *                  entries registered is more than the size originally 

+ *                  requested when calling this function.

+ * @param count     The maximum number of timer entries to be supported 

+ *                  initially. If the application registers more entries 

+ *                  during runtime, then the timer heap will resize.

+ * @param ht        Pointer to receive the created timer heap.

+ *

+ * @return          PJ_SUCCESS, or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,

+					   pj_size_t count,

+                                           pj_timer_heap_t **ht);

 

 /**

  * Destroy the timer heap.

@@ -167,92 +188,92 @@
  */

 PJ_DECL(unsigned) pj_timer_heap_set_max_timed_out_per_poll(pj_timer_heap_t *ht,

                                                            unsigned count );

-
-/**
- * Initialize a timer entry. Application should call this function at least
- * once before scheduling the entry to the timer heap, to properly initialize
- * the timer entry.
- *
- * @param entry     The timer entry to be initialized.
- * @param id        Arbitrary ID assigned by the user/owner of this entry.
- *                  Applications can use this ID to distinguish multiple
- *                  timer entries that share the same callback and user_data.
- * @param user_data User data to be associated with this entry. 
- *                  Applications normally will put the instance of object that
- *                  owns the timer entry in this field.
- * @param cb        Callback function to be called when the timer elapses.
- *
- * @return          The timer entry itself.
- */
-PJ_DECL(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
-                                              int id,
-                                              void *user_data,
-                                              pj_timer_heap_callback *cb );
-
-/**
- * Schedule a timer entry which will expire AFTER the specified delay.
- *
- * @param ht        The timer heap.
- * @param entry     The entry to be registered. 
- * @param delay     The interval to expire.
- * @return          PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
-					     pj_timer_entry *entry, 
-					     const pj_time_val *delay);
-
-/**
- * Cancel a previously registered timer.
- *
- * @param ht        The timer heap.
- * @param entry     The entry to be cancelled.
- * @return          The number of timer cancelled, which should be one if the
- *                  entry has really been registered, or zero if no timer was
- *                  cancelled.
- */
-PJ_DECL(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
-				   pj_timer_entry *entry);
-
-/**
- * Get the number of timer entries.
- *
- * @param ht        The timer heap.
- * @return          The number of timer entries.
- */
-PJ_DECL(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht );
-
-/**
- * Get the earliest time registered in the timer heap. The timer heap
- * MUST have at least one timer being scheduled (application should use
- * #pj_timer_heap_count() before calling this function).
- *
- * @param ht        The timer heap.
- * @param timeval   The time deadline of the earliest timer entry.
- *
- * @return          PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled.
- */
-PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht, 
-					          pj_time_val *timeval);
-
-/**
- * Poll the timer heap, check for expired timers and call the callback for
- * each of the expired timers.
- *
- * @param ht         The timer heap.
- * @param next_delay If this parameter is not NULL, it will be filled up with
- *		     the time delay until the next timer elapsed, or -1 in
+

+/**

+ * Initialize a timer entry. Application should call this function at least

+ * once before scheduling the entry to the timer heap, to properly initialize

+ * the timer entry.

+ *

+ * @param entry     The timer entry to be initialized.

+ * @param id        Arbitrary ID assigned by the user/owner of this entry.

+ *                  Applications can use this ID to distinguish multiple

+ *                  timer entries that share the same callback and user_data.

+ * @param user_data User data to be associated with this entry. 

+ *                  Applications normally will put the instance of object that

+ *                  owns the timer entry in this field.

+ * @param cb        Callback function to be called when the timer elapses.

+ *

+ * @return          The timer entry itself.

+ */

+PJ_DECL(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,

+                                              int id,

+                                              void *user_data,

+                                              pj_timer_heap_callback *cb );

+

+/**

+ * Schedule a timer entry which will expire AFTER the specified delay.

+ *

+ * @param ht        The timer heap.

+ * @param entry     The entry to be registered. 

+ * @param delay     The interval to expire.

+ * @return          PJ_SUCCESS, or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,

+					     pj_timer_entry *entry, 

+					     const pj_time_val *delay);

+

+/**

+ * Cancel a previously registered timer.

+ *

+ * @param ht        The timer heap.

+ * @param entry     The entry to be cancelled.

+ * @return          The number of timer cancelled, which should be one if the

+ *                  entry has really been registered, or zero if no timer was

+ *                  cancelled.

+ */

+PJ_DECL(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,

+				   pj_timer_entry *entry);

+

+/**

+ * Get the number of timer entries.

+ *

+ * @param ht        The timer heap.

+ * @return          The number of timer entries.

+ */

+PJ_DECL(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht );

+

+/**

+ * Get the earliest time registered in the timer heap. The timer heap

+ * MUST have at least one timer being scheduled (application should use

+ * #pj_timer_heap_count() before calling this function).

+ *

+ * @param ht        The timer heap.

+ * @param timeval   The time deadline of the earliest timer entry.

+ *

+ * @return          PJ_SUCCESS, or PJ_ENOTFOUND if no entry is scheduled.

+ */

+PJ_DECL(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t *ht, 

+					          pj_time_val *timeval);

+

+/**

+ * Poll the timer heap, check for expired timers and call the callback for

+ * each of the expired timers.

+ *

+ * @param ht         The timer heap.

+ * @param next_delay If this parameter is not NULL, it will be filled up with

+ *		     the time delay until the next timer elapsed, or -1 in

  *		     the sec part if no entry exist.

- *
- * @return           The number of timers expired.
- */
+ *

+ * @return           The number of timers expired.

+ */

 PJ_DECL(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, 

-                                      pj_time_val *next_delay);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJ_TIMER_H__ */
-
+                                      pj_time_val *next_delay);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJ_TIMER_H__ */

+

diff --git a/pjlib/include/pj/types.h b/pjlib/include/pj/types.h
index ec3df2c..acdfbd2 100644
--- a/pjlib/include/pj/types.h
+++ b/pjlib/include/pj/types.h
@@ -1,68 +1,87 @@
-/* $Id$
- *
- */
-
-#ifndef __PJ_TYPES_H__
-#define __PJ_TYPES_H__
-
-
-/**
- * @defgroup PJ PJ Library
- */
-/**
- * @file types.h
- * @brief Declaration of basic types and utility.
- */
-/**
- * @defgroup PJ_BASIC Basic Data Types and Library Functionality.
- * @ingroup PJ_DS
- * @{
- */
-#include <pj/config.h>
-
-PJ_BEGIN_DECL
-
-///////////////////////////////////////////////////////////////////////////////
-
-/** Unsigned 32bit integer. */
-typedef int		pj_int32_t;
-
-/** Signed 32bit integer. */
-typedef unsigned int	pj_uint32_t;
-
-/** Unsigned 16bit integer. */
-typedef short		pj_int16_t;
-
-/** Signed 16bit integer. */
-typedef unsigned short	pj_uint16_t;
-
-/** Unsigned 8bit integer. */
-typedef signed char	pj_int8_t;
-
-/** Signed 16bit integer. */
-typedef unsigned char	pj_uint8_t;
-
-/** Large unsigned integer. */
-typedef size_t		pj_size_t;
-
-/** Large signed integer. */
-typedef long		pj_ssize_t;
-
-/** Status code. */
-typedef int		pj_status_t;
-
-/** Boolean. */
-typedef int		pj_bool_t;
-
-/** Status is OK. */
-#define PJ_SUCCESS  0
-
-/** True value. */
-#define PJ_TRUE	    1
-
-/** False value. */
-#define PJ_FALSE    0
-
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJ_TYPES_H__

+#define __PJ_TYPES_H__

+

+

+/**

+ * @defgroup PJ PJ Library

+ */

+/**

+ * @file types.h

+ * @brief Declaration of basic types and utility.

+ */

+/**

+ * @defgroup PJ_BASIC Basic Data Types and Library Functionality.

+ * @ingroup PJ_DS

+ * @{

+ */

+#include <pj/config.h>

+

+PJ_BEGIN_DECL

+

+///////////////////////////////////////////////////////////////////////////////

+

+/** Unsigned 32bit integer. */

+typedef int		pj_int32_t;

+

+/** Signed 32bit integer. */

+typedef unsigned int	pj_uint32_t;

+

+/** Unsigned 16bit integer. */

+typedef short		pj_int16_t;

+

+/** Signed 16bit integer. */

+typedef unsigned short	pj_uint16_t;

+

+/** Unsigned 8bit integer. */

+typedef signed char	pj_int8_t;

+

+/** Signed 16bit integer. */

+typedef unsigned char	pj_uint8_t;

+

+/** Large unsigned integer. */

+typedef size_t		pj_size_t;

+

+/** Large signed integer. */

+typedef long		pj_ssize_t;

+

+/** Status code. */

+typedef int		pj_status_t;

+

+/** Boolean. */

+typedef int		pj_bool_t;

+

+/** Status is OK. */

+#define PJ_SUCCESS  0

+

+/** True value. */

+#define PJ_TRUE	    1

+

+/** False value. */

+#define PJ_FALSE    0

+

 /**

  * File offset type.

  */

@@ -71,358 +90,358 @@
 #else

 typedef pj_ssize_t pj_off_t;

 #endif

-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Data structure types.
- */
-/**
- * This type is used as replacement to legacy C string, and used throughout
- * the library. By convention, the string is NOT null terminated.
- */
-struct pj_str_t
-{
-    /** Buffer pointer, which is by convention NOT null terminated. */
-    char       *ptr;
-
-    /** The length of the string. */
-    pj_ssize_t  slen;
-};
-
-
-/**
- * The opaque data type for linked list, which is used as arguments throughout
- * the linked list operations.
- */
-typedef void pj_list_type;
-
-/** 
- * List.
- */
-typedef struct pj_list pj_list;
-
-/**
- * Opaque data type for hash tables.
- */
-typedef struct pj_hash_table_t pj_hash_table_t;
-
-/**
- * Opaque data type for hash entry (only used internally by hash table).
- */
-typedef struct pj_hash_entry pj_hash_entry;
-
-/**
- * Data type for hash search iterator.
- * This structure should be opaque, however applications need to declare
- * concrete variable of this type, that's why the declaration is visible here.
- */
-typedef struct pj_hash_iterator_t
-{
-    pj_uint32_t	     index;     /**< Internal index.     */
-    pj_hash_entry   *entry;     /**< Internal entry.     */
-} pj_hash_iterator_t;
-
-
-/**
- * Forward declaration for memory pool factory.
- */
-typedef struct pj_pool_factory pj_pool_factory;
-
-/**
- * Opaque data type for memory pool.
- */
-typedef struct pj_pool_t pj_pool_t;
-
-/**
- * Forward declaration for caching pool, a pool factory implementation.
- */
-typedef struct pj_caching_pool pj_caching_pool;
-
-/**
- * This type is used as replacement to legacy C string, and used throughout
- * the library.
- */
-typedef struct pj_str_t pj_str_t;
-
-/**
- * Opaque data type for I/O Queue structure.
- */
-typedef struct pj_ioqueue_t pj_ioqueue_t;
-
-/**
- * Opaque data type for key that identifies a handle registered to the
- * I/O queue framework.
- */
-typedef struct pj_ioqueue_key_t pj_ioqueue_key_t;
-
-/**
- * Opaque data to identify timer heap.
- */
-typedef struct pj_timer_heap_t pj_timer_heap_t;
-
-/**
- * Forward declaration for timer entry.
- */
-typedef struct pj_timer_entry pj_timer_entry;
-
-/** 
- * Opaque data type for atomic operations.
- */
-typedef struct pj_atomic_t pj_atomic_t;
-
-/**
- * Value type of an atomic variable.
- */
-typedef PJ_ATOMIC_VALUE_TYPE pj_atomic_value_t;
- 
-///////////////////////////////////////////////////////////////////////////////
-
-/** Thread handle. */
-typedef struct pj_thread_t pj_thread_t;
-
-/** Lock object. */
-typedef struct pj_lock_t pj_lock_t;
-
-/** Mutex handle. */
-typedef struct pj_mutex_t pj_mutex_t;
-
-/** Semaphore handle. */
-typedef struct pj_sem_t pj_sem_t;
-
-/** Event object. */
-typedef struct pj_event_t pj_event_t;
-
-/** Unidirectional stream pipe object. */
-typedef struct pj_pipe_t pj_pipe_t;
-
-/** Operating system handle. */
-typedef void *pj_oshandle_t;
-
-/** Socket handle. */
-typedef long pj_sock_t;
-
-/** Generic socket address. */
-typedef void pj_sockaddr_t;
-
-/** Color type. */
-typedef unsigned int pj_color_t;
-
-/** Exception id. */
-typedef int pj_exception_id_t;
-
-///////////////////////////////////////////////////////////////////////////////
-
-/** Utility macro to compute the number of elements in static array. */
-#define PJ_ARRAY_SIZE(a)    (sizeof(a)/sizeof(a[0]))
-
-/** Maximum value for signed 32-bit integer. */
-#define PJ_MAXINT32  0x7FFFFFFFL
-
-/**
- * Length of object names.
- */
-#define PJ_MAX_OBJ_NAME	16
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * General.
- */
-/**
- * Initialize the PJ Library.
- * This function must be called before using the library. The purpose of this
- * function is to initialize static library data, such as character table used
- * in random string generation, and to initialize operating system dependent
- * functionality (such as WSAStartup() in Windows).
- */
-PJ_DECL(pj_status_t) pj_init(void);
-
-
-/**
- * @}
- */
-/**
- * @addtogroup PJ_TIME Time Data Type and Manipulation.
- * @ingroup PJ_MISC
- * @{
- */
-
-/**
- * Representation of time value in this library.
- * This type can be used to represent either an interval or a specific time
- * or date. 
- */
-typedef struct pj_time_val
-{
-    /** The seconds part of the time. */
-    long    sec;
-
-    /** The miliseconds fraction of the time. */
-    long    msec;
-
-} pj_time_val;
-
-/**
- * Normalize the value in time value.
- * @param t     Time value to be normalized.
- */
-PJ_DECL(void) pj_time_val_normalize(pj_time_val *t);
-
-/**
- * Get the total time value in miliseconds. This is the same as
- * multiplying the second part with 1000 and then add the miliseconds
- * part to the result.
- *
- * @param t     The time value.
- * @return      Total time in miliseconds.
- * @hideinitializer
- */
-#define PJ_TIME_VAL_MSEC(t)	((t).sec * 1000 + (t).msec)
-
-/**
- * This macro will check if \a t1 is equal to \a t2.
- *
- * @param t1    The first time value to compare.
- * @param t2    The second time value to compare.
- * @return      Non-zero if both time values are equal.
- * @hideinitializer
- */
-#define PJ_TIME_VAL_EQ(t1, t2)	((t1).sec==(t2).sec && (t1).msec==(t2).msec)
-
-/**
- * This macro will check if \a t1 is greater than \a t2
- *
- * @param t1    The first time value to compare.
- * @param t2    The second time value to compare.
- * @return      Non-zero if t1 is greater than t2.
- * @hideinitializer
- */
-#define PJ_TIME_VAL_GT(t1, t2)	((t1).sec>(t2).sec || \
-                                ((t1).sec==(t2).sec && (t1).msec>(t2).msec))
-
-/**
- * This macro will check if \a t1 is greater than or equal to \a t2
- *
- * @param t1    The first time value to compare.
- * @param t2    The second time value to compare.
- * @return      Non-zero if t1 is greater than or equal to t2.
- * @hideinitializer
- */
-#define PJ_TIME_VAL_GTE(t1, t2)	(PJ_TIME_VAL_GT(t1,t2) || \
-                                 PJ_TIME_VAL_EQ(t1,t2))
-
-/**
- * This macro will check if \a t1 is less than \a t2
- *
- * @param t1    The first time value to compare.
- * @param t2    The second time value to compare.
- * @return      Non-zero if t1 is less than t2.
- * @hideinitializer
- */
-#define PJ_TIME_VAL_LT(t1, t2)	(!(PJ_TIME_VAL_GTE(t1,t2)))
-
-/**
- * This macro will check if \a t1 is less than or equal to \a t2.
- *
- * @param t1    The first time value to compare.
- * @param t2    The second time value to compare.
- * @return      Non-zero if t1 is less than or equal to t2.
- * @hideinitializer
- */
-#define PJ_TIME_VAL_LTE(t1, t2)	(!PJ_TIME_VAL_GT(t1, t2))
-
-/**
- * Add \a t2 to \a t1 and store the result in \a t1. Effectively
- *
- * this macro will expand as: (\a t1 += \a t2).
- * @param t1    The time value to add.
- * @param t2    The time value to be added to \a t1.
- * @hideinitializer
- */
-#define PJ_TIME_VAL_ADD(t1, t2)	    do {			    \
-					(t1).sec += (t2).sec;	    \
-					(t1).msec += (t2).msec;	    \
-					pj_time_val_normalize(&(t1)); \
-				    } while (0)
-
-
-/**
- * Substract \a t2 from \a t1 and store the result in \a t1. Effectively
- * this macro will expand as (\a t1 -= \a t2).
- *
- * @param t1    The time value to subsctract.
- * @param t2    The time value to be substracted from \a t1.
- * @hideinitializer
- */
-#define PJ_TIME_VAL_SUB(t1, t2)	    do {			    \
-					(t1).sec -= (t2).sec;	    \
-					(t1).msec -= (t2).msec;	    \
-					pj_time_val_normalize(&(t1)); \
-				    } while (0)
-
-
-/**
- * This structure represent the parsed representation of time.
- * It is acquired by calling #pj_time_decode().
- */
-typedef struct pj_parsed_time
-{
-    /** This represents day of week where value zero means Sunday */
-    int wday;
-
-    /** This represents day of the year, 0-365, where zero means
-     *  1st of January.
-     */
-    int yday;
-
-    /** This represents day of month: 1-31 */
-    int day;
-
-    /** This represents month, with the value is 0 - 11 (zero is January) */
-    int mon;
-
-    /** This represent the actual year (unlike in ANSI libc where
-     *  the value must be added by 1900).
-     */
-    int year;
-
-    /** This represents the second part, with the value is 0-59 */
-    int sec;
-
-    /** This represents the minute part, with the value is: 0-59 */
-    int min;
-
-    /** This represents the hour part, with the value is 0-23 */
-    int hour;
-
-    /** This represents the milisecond part, with the value is 0-999 */
-    int msec;
-
-} pj_parsed_time;
-
-
-/**
- * @}	// Time Management
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Terminal.
- */
-/**
- * Color code combination.
- */
-enum {
-    PJ_TERM_COLOR_R	= 2,    /**< Red            */
-    PJ_TERM_COLOR_G	= 4,    /**< Green          */
-    PJ_TERM_COLOR_B	= 1,    /**< Blue.          */
-    PJ_TERM_COLOR_BRIGHT = 8    /**< Bright mask.   */
-};
-
-
-
-
-PJ_END_DECL
-
-
-#endif /* __PJ_TYPES_H__ */
-
+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Data structure types.

+ */

+/**

+ * This type is used as replacement to legacy C string, and used throughout

+ * the library. By convention, the string is NOT null terminated.

+ */

+struct pj_str_t

+{

+    /** Buffer pointer, which is by convention NOT null terminated. */

+    char       *ptr;

+

+    /** The length of the string. */

+    pj_ssize_t  slen;

+};

+

+

+/**

+ * The opaque data type for linked list, which is used as arguments throughout

+ * the linked list operations.

+ */

+typedef void pj_list_type;

+

+/** 

+ * List.

+ */

+typedef struct pj_list pj_list;

+

+/**

+ * Opaque data type for hash tables.

+ */

+typedef struct pj_hash_table_t pj_hash_table_t;

+

+/**

+ * Opaque data type for hash entry (only used internally by hash table).

+ */

+typedef struct pj_hash_entry pj_hash_entry;

+

+/**

+ * Data type for hash search iterator.

+ * This structure should be opaque, however applications need to declare

+ * concrete variable of this type, that's why the declaration is visible here.

+ */

+typedef struct pj_hash_iterator_t

+{

+    pj_uint32_t	     index;     /**< Internal index.     */

+    pj_hash_entry   *entry;     /**< Internal entry.     */

+} pj_hash_iterator_t;

+

+

+/**

+ * Forward declaration for memory pool factory.

+ */

+typedef struct pj_pool_factory pj_pool_factory;

+

+/**

+ * Opaque data type for memory pool.

+ */

+typedef struct pj_pool_t pj_pool_t;

+

+/**

+ * Forward declaration for caching pool, a pool factory implementation.

+ */

+typedef struct pj_caching_pool pj_caching_pool;

+

+/**

+ * This type is used as replacement to legacy C string, and used throughout

+ * the library.

+ */

+typedef struct pj_str_t pj_str_t;

+

+/**

+ * Opaque data type for I/O Queue structure.

+ */

+typedef struct pj_ioqueue_t pj_ioqueue_t;

+

+/**

+ * Opaque data type for key that identifies a handle registered to the

+ * I/O queue framework.

+ */

+typedef struct pj_ioqueue_key_t pj_ioqueue_key_t;

+

+/**

+ * Opaque data to identify timer heap.

+ */

+typedef struct pj_timer_heap_t pj_timer_heap_t;

+

+/**

+ * Forward declaration for timer entry.

+ */

+typedef struct pj_timer_entry pj_timer_entry;

+

+/** 

+ * Opaque data type for atomic operations.

+ */

+typedef struct pj_atomic_t pj_atomic_t;

+

+/**

+ * Value type of an atomic variable.

+ */

+typedef PJ_ATOMIC_VALUE_TYPE pj_atomic_value_t;

+ 

+///////////////////////////////////////////////////////////////////////////////

+

+/** Thread handle. */

+typedef struct pj_thread_t pj_thread_t;

+

+/** Lock object. */

+typedef struct pj_lock_t pj_lock_t;

+

+/** Mutex handle. */

+typedef struct pj_mutex_t pj_mutex_t;

+

+/** Semaphore handle. */

+typedef struct pj_sem_t pj_sem_t;

+

+/** Event object. */

+typedef struct pj_event_t pj_event_t;

+

+/** Unidirectional stream pipe object. */

+typedef struct pj_pipe_t pj_pipe_t;

+

+/** Operating system handle. */

+typedef void *pj_oshandle_t;

+

+/** Socket handle. */

+typedef long pj_sock_t;

+

+/** Generic socket address. */

+typedef void pj_sockaddr_t;

+

+/** Color type. */

+typedef unsigned int pj_color_t;

+

+/** Exception id. */

+typedef int pj_exception_id_t;

+

+///////////////////////////////////////////////////////////////////////////////

+

+/** Utility macro to compute the number of elements in static array. */

+#define PJ_ARRAY_SIZE(a)    (sizeof(a)/sizeof(a[0]))

+

+/** Maximum value for signed 32-bit integer. */

+#define PJ_MAXINT32  0x7FFFFFFFL

+

+/**

+ * Length of object names.

+ */

+#define PJ_MAX_OBJ_NAME	16

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * General.

+ */

+/**

+ * Initialize the PJ Library.

+ * This function must be called before using the library. The purpose of this

+ * function is to initialize static library data, such as character table used

+ * in random string generation, and to initialize operating system dependent

+ * functionality (such as WSAStartup() in Windows).

+ */

+PJ_DECL(pj_status_t) pj_init(void);

+

+

+/**

+ * @}

+ */

+/**

+ * @addtogroup PJ_TIME Time Data Type and Manipulation.

+ * @ingroup PJ_MISC

+ * @{

+ */

+

+/**

+ * Representation of time value in this library.

+ * This type can be used to represent either an interval or a specific time

+ * or date. 

+ */

+typedef struct pj_time_val

+{

+    /** The seconds part of the time. */

+    long    sec;

+

+    /** The miliseconds fraction of the time. */

+    long    msec;

+

+} pj_time_val;

+

+/**

+ * Normalize the value in time value.

+ * @param t     Time value to be normalized.

+ */

+PJ_DECL(void) pj_time_val_normalize(pj_time_val *t);

+

+/**

+ * Get the total time value in miliseconds. This is the same as

+ * multiplying the second part with 1000 and then add the miliseconds

+ * part to the result.

+ *

+ * @param t     The time value.

+ * @return      Total time in miliseconds.

+ * @hideinitializer

+ */

+#define PJ_TIME_VAL_MSEC(t)	((t).sec * 1000 + (t).msec)

+

+/**

+ * This macro will check if \a t1 is equal to \a t2.

+ *

+ * @param t1    The first time value to compare.

+ * @param t2    The second time value to compare.

+ * @return      Non-zero if both time values are equal.

+ * @hideinitializer

+ */

+#define PJ_TIME_VAL_EQ(t1, t2)	((t1).sec==(t2).sec && (t1).msec==(t2).msec)

+

+/**

+ * This macro will check if \a t1 is greater than \a t2

+ *

+ * @param t1    The first time value to compare.

+ * @param t2    The second time value to compare.

+ * @return      Non-zero if t1 is greater than t2.

+ * @hideinitializer

+ */

+#define PJ_TIME_VAL_GT(t1, t2)	((t1).sec>(t2).sec || \

+                                ((t1).sec==(t2).sec && (t1).msec>(t2).msec))

+

+/**

+ * This macro will check if \a t1 is greater than or equal to \a t2

+ *

+ * @param t1    The first time value to compare.

+ * @param t2    The second time value to compare.

+ * @return      Non-zero if t1 is greater than or equal to t2.

+ * @hideinitializer

+ */

+#define PJ_TIME_VAL_GTE(t1, t2)	(PJ_TIME_VAL_GT(t1,t2) || \

+                                 PJ_TIME_VAL_EQ(t1,t2))

+

+/**

+ * This macro will check if \a t1 is less than \a t2

+ *

+ * @param t1    The first time value to compare.

+ * @param t2    The second time value to compare.

+ * @return      Non-zero if t1 is less than t2.

+ * @hideinitializer

+ */

+#define PJ_TIME_VAL_LT(t1, t2)	(!(PJ_TIME_VAL_GTE(t1,t2)))

+

+/**

+ * This macro will check if \a t1 is less than or equal to \a t2.

+ *

+ * @param t1    The first time value to compare.

+ * @param t2    The second time value to compare.

+ * @return      Non-zero if t1 is less than or equal to t2.

+ * @hideinitializer

+ */

+#define PJ_TIME_VAL_LTE(t1, t2)	(!PJ_TIME_VAL_GT(t1, t2))

+

+/**

+ * Add \a t2 to \a t1 and store the result in \a t1. Effectively

+ *

+ * this macro will expand as: (\a t1 += \a t2).

+ * @param t1    The time value to add.

+ * @param t2    The time value to be added to \a t1.

+ * @hideinitializer

+ */

+#define PJ_TIME_VAL_ADD(t1, t2)	    do {			    \

+					(t1).sec += (t2).sec;	    \

+					(t1).msec += (t2).msec;	    \

+					pj_time_val_normalize(&(t1)); \

+				    } while (0)

+

+

+/**

+ * Substract \a t2 from \a t1 and store the result in \a t1. Effectively

+ * this macro will expand as (\a t1 -= \a t2).

+ *

+ * @param t1    The time value to subsctract.

+ * @param t2    The time value to be substracted from \a t1.

+ * @hideinitializer

+ */

+#define PJ_TIME_VAL_SUB(t1, t2)	    do {			    \

+					(t1).sec -= (t2).sec;	    \

+					(t1).msec -= (t2).msec;	    \

+					pj_time_val_normalize(&(t1)); \

+				    } while (0)

+

+

+/**

+ * This structure represent the parsed representation of time.

+ * It is acquired by calling #pj_time_decode().

+ */

+typedef struct pj_parsed_time

+{

+    /** This represents day of week where value zero means Sunday */

+    int wday;

+

+    /** This represents day of the year, 0-365, where zero means

+     *  1st of January.

+     */

+    int yday;

+

+    /** This represents day of month: 1-31 */

+    int day;

+

+    /** This represents month, with the value is 0 - 11 (zero is January) */

+    int mon;

+

+    /** This represent the actual year (unlike in ANSI libc where

+     *  the value must be added by 1900).

+     */

+    int year;

+

+    /** This represents the second part, with the value is 0-59 */

+    int sec;

+

+    /** This represents the minute part, with the value is: 0-59 */

+    int min;

+

+    /** This represents the hour part, with the value is 0-23 */

+    int hour;

+

+    /** This represents the milisecond part, with the value is 0-999 */

+    int msec;

+

+} pj_parsed_time;

+

+

+/**

+ * @}	// Time Management

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Terminal.

+ */

+/**

+ * Color code combination.

+ */

+enum {

+    PJ_TERM_COLOR_R	= 2,    /**< Red            */

+    PJ_TERM_COLOR_G	= 4,    /**< Green          */

+    PJ_TERM_COLOR_B	= 1,    /**< Blue.          */

+    PJ_TERM_COLOR_BRIGHT = 8    /**< Bright mask.   */

+};

+

+

+

+

+PJ_END_DECL

+

+

+#endif /* __PJ_TYPES_H__ */

+

diff --git a/pjlib/include/pjlib++.hpp b/pjlib/include/pjlib++.hpp
index fefd3d0..81db220 100644
--- a/pjlib/include/pjlib++.hpp
+++ b/pjlib/include/pjlib++.hpp
@@ -1,5 +1,26 @@
-/* $Id$
- *
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  */

 #ifndef __PJLIBPP_H__

 #define __PJLIBPP_H__

diff --git a/pjlib/include/pjlib.h b/pjlib/include/pjlib.h
index 7e4bf36..63af44b 100644
--- a/pjlib/include/pjlib.h
+++ b/pjlib/include/pjlib.h
@@ -1,39 +1,60 @@
-/* $Id$
- *
- */
-#ifndef __PJLIB_H__
-#define __PJLIB_H__
-
-/**
- * @file pjlib.h
- * @brief Include all PJLIB header files.
- */
-
-#include <pj/addr_resolv.h>
-#include <pj/array.h>
-#include <pj/assert.h>
-#include <pj/ctype.h>
-#include <pj/errno.h>
-#include <pj/except.h>
-#include <pj/fifobuf.h>
-#include <pj/file_access.h>
-#include <pj/file_io.h>
-#include <pj/guid.h>
-#include <pj/hash.h>
-#include <pj/ioqueue.h>
-#include <pj/list.h>
-#include <pj/lock.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/rand.h>
-#include <pj/rbtree.h>
-#include <pj/sock.h>
-#include <pj/sock_select.h>
-#include <pj/string.h>
-#include <pj/timer.h>
-
-#include <pj/compat/high_precision.h>
-
-#endif  /* __PJLIB_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJLIB_H__

+#define __PJLIB_H__

+

+/**

+ * @file pjlib.h

+ * @brief Include all PJLIB header files.

+ */

+

+#include <pj/addr_resolv.h>

+#include <pj/array.h>

+#include <pj/assert.h>

+#include <pj/ctype.h>

+#include <pj/errno.h>

+#include <pj/except.h>

+#include <pj/fifobuf.h>

+#include <pj/file_access.h>

+#include <pj/file_io.h>

+#include <pj/guid.h>

+#include <pj/hash.h>

+#include <pj/ioqueue.h>

+#include <pj/list.h>

+#include <pj/lock.h>

+#include <pj/log.h>

+#include <pj/os.h>

+#include <pj/pool.h>

+#include <pj/rand.h>

+#include <pj/rbtree.h>

+#include <pj/sock.h>

+#include <pj/sock_select.h>

+#include <pj/string.h>

+#include <pj/timer.h>

+

+#include <pj/compat/high_precision.h>

+

+#endif  /* __PJLIB_H__ */

+

diff --git a/pjlib/src/pj/addr_resolv_linux_kernel.c b/pjlib/src/pj/addr_resolv_linux_kernel.c
index 996c631..4d587ac 100644
--- a/pjlib/src/pj/addr_resolv_linux_kernel.c
+++ b/pjlib/src/pj/addr_resolv_linux_kernel.c
@@ -1,10 +1,31 @@
-/* $Id$
- *
- */
-#include <pj/addr_resolv.h>
-
-PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
-{
-    return -1;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/addr_resolv.h>

+

+PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)

+{

+    return -1;

+}

+

diff --git a/pjlib/src/pj/addr_resolv_sock.c b/pjlib/src/pj/addr_resolv_sock.c
index ee49db2..5e2676d 100644
--- a/pjlib/src/pj/addr_resolv_sock.c
+++ b/pjlib/src/pj/addr_resolv_sock.c
@@ -1,35 +1,56 @@
-/* $Id$
- */
-#include <pj/addr_resolv.h>
-#include <pj/assert.h>
-#include <pj/string.h>
-#include <pj/compat/socket.h>
-#include <pj/errno.h>
-
-
-PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)
-{
-    struct hostent *he;
-    char copy[PJ_MAX_HOSTNAME];
-
-    pj_assert(hostname && hostname ->slen < PJ_MAX_HOSTNAME);
-    
-    if (hostname->slen >= PJ_MAX_HOSTNAME)
-	return PJ_ENAMETOOLONG;
-
-    pj_memcpy(copy, hostname->ptr, hostname->slen);
-    copy[ hostname->slen ] = '\0';
-
-    he = gethostbyname(copy);
-    if (!he)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-
-    phe->h_name = he->h_name;
-    phe->h_aliases = he->h_aliases;
-    phe->h_addrtype = he->h_addrtype;
-    phe->h_length = he->h_length;
-    phe->h_addr_list = he->h_addr_list;
-
-    return PJ_SUCCESS;
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/addr_resolv.h>

+#include <pj/assert.h>

+#include <pj/string.h>

+#include <pj/compat/socket.h>

+#include <pj/errno.h>

+

+

+PJ_DEF(pj_status_t) pj_gethostbyname(const pj_str_t *hostname, pj_hostent *phe)

+{

+    struct hostent *he;

+    char copy[PJ_MAX_HOSTNAME];

+

+    pj_assert(hostname && hostname ->slen < PJ_MAX_HOSTNAME);

+    

+    if (hostname->slen >= PJ_MAX_HOSTNAME)

+	return PJ_ENAMETOOLONG;

+

+    pj_memcpy(copy, hostname->ptr, hostname->slen);

+    copy[ hostname->slen ] = '\0';

+

+    he = gethostbyname(copy);

+    if (!he)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+

+    phe->h_name = he->h_name;

+    phe->h_aliases = he->h_aliases;

+    phe->h_addrtype = he->h_addrtype;

+    phe->h_length = he->h_length;

+    phe->h_addr_list = he->h_addr_list;

+

+    return PJ_SUCCESS;

+}

+

diff --git a/pjlib/src/pj/array.c b/pjlib/src/pj/array.c
index 563b7bf..76fea95 100644
--- a/pjlib/src/pj/array.c
+++ b/pjlib/src/pj/array.c
@@ -1,54 +1,74 @@
-/* $Id$
- */
-#include <pj/array.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-
-PJ_DEF(void) pj_array_insert( void *array,
-			      unsigned elem_size,
-			      unsigned count,
-			      unsigned pos,
-			      const void *value)
-{
-    if (count && pos < count-1) {
-	pj_memmove( (char*)array + (pos+1)*elem_size,
-		    (char*)array + pos*elem_size,
-		    (count-pos)*elem_size);
-    }
-    pj_memmove((char*)array + pos*elem_size, value, elem_size);
-}
-
-PJ_DEF(void) pj_array_erase( void *array,
-			     unsigned elem_size,
-			     unsigned count,
-			     unsigned pos)
-{
-    pj_assert(count != 0);
-    if (pos < count-1) {
-	pj_memmove( (char*)array + pos*elem_size,
-		    (char*)array + (pos+1)*elem_size,
-		    (count-pos-1)*elem_size);
-    }
-}
-
-PJ_DEF(pj_status_t) pj_array_find( const void *array, 
-				   unsigned elem_size, 
-				   unsigned count, 
-				   pj_status_t (*matching)(const void *value),
-				   void **result)
-{
-    unsigned i;
-    const char *char_array = array;
-    for (i=0; i<count; ++i) {
-	if ( (*matching)(char_array) == PJ_SUCCESS) {
-	    if (result) {
-		*result = (void*)char_array;
-	    }
-	    return PJ_SUCCESS;
-	}
-	char_array += elem_size;
-    }
-    return PJ_ENOTFOUND;
-}
-
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/array.h>

+#include <pj/string.h>

+#include <pj/assert.h>

+#include <pj/errno.h>

+

+PJ_DEF(void) pj_array_insert( void *array,

+			      unsigned elem_size,

+			      unsigned count,

+			      unsigned pos,

+			      const void *value)

+{

+    if (count && pos < count-1) {

+	pj_memmove( (char*)array + (pos+1)*elem_size,

+		    (char*)array + pos*elem_size,

+		    (count-pos)*elem_size);

+    }

+    pj_memmove((char*)array + pos*elem_size, value, elem_size);

+}

+

+PJ_DEF(void) pj_array_erase( void *array,

+			     unsigned elem_size,

+			     unsigned count,

+			     unsigned pos)

+{

+    pj_assert(count != 0);

+    if (pos < count-1) {

+	pj_memmove( (char*)array + pos*elem_size,

+		    (char*)array + (pos+1)*elem_size,

+		    (count-pos-1)*elem_size);

+    }

+}

+

+PJ_DEF(pj_status_t) pj_array_find( const void *array, 

+				   unsigned elem_size, 

+				   unsigned count, 

+				   pj_status_t (*matching)(const void *value),

+				   void **result)

+{

+    unsigned i;

+    const char *char_array = array;

+    for (i=0; i<count; ++i) {

+	if ( (*matching)(char_array) == PJ_SUCCESS) {

+	    if (result) {

+		*result = (void*)char_array;

+	    }

+	    return PJ_SUCCESS;

+	}

+	char_array += elem_size;

+    }

+    return PJ_ENOTFOUND;

+}

+

diff --git a/pjlib/src/pj/compat/sigjmp.c b/pjlib/src/pj/compat/sigjmp.c
index d3fb0d7..ccdec59 100644
--- a/pjlib/src/pj/compat/sigjmp.c
+++ b/pjlib/src/pj/compat/sigjmp.c
@@ -1,24 +1,43 @@
-/* $Id$
- *
- */
-#include <pj/config.h>
-#include <pj/compat/setjmp.h>
-
-int __sigjmp_save(sigjmp_buf env, int savemask)
-{
-    return 0;
-}
-
-extern int __sigsetjmp(pj_jmp_buf env, int savemask);
-extern void __longjmp(pj_jmp_buf env, int val) __attribute__((noreturn));
-
-PJ_DEF(int) pj_setjmp(pj_jmp_buf env)
-{
-    return __sigsetjmp(env, 0);
-}
-
-PJ_DEF(void) pj_longjmp(pj_jmp_buf env, int val)
-{
-    __longjmp(env, val);
-}
-
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/config.h>

+#include <pj/compat/setjmp.h>

+

+int __sigjmp_save(sigjmp_buf env, int savemask)

+{

+    return 0;

+}

+

+extern int __sigsetjmp(pj_jmp_buf env, int savemask);

+extern void __longjmp(pj_jmp_buf env, int val) __attribute__((noreturn));

+

+PJ_DEF(int) pj_setjmp(pj_jmp_buf env)

+{

+    return __sigsetjmp(env, 0);

+}

+

+PJ_DEF(void) pj_longjmp(pj_jmp_buf env, int val)

+{

+    __longjmp(env, val);

+}

+

diff --git a/pjlib/src/pj/compat/string.c b/pjlib/src/pj/compat/string.c
index 766857e..a1cab0b 100644
--- a/pjlib/src/pj/compat/string.c
+++ b/pjlib/src/pj/compat/string.c
@@ -1,29 +1,48 @@
-/* $Id$
- *
- */
-#include <pj/types.h>
-#include <pj/compat/string.h>
-#include <pj/ctype.h>
-
-PJ_DEF(int) strcasecmp(const char *s1, const char *s2)
-{
-    while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {
-	if (!*s1++)
-	    return 0;
-	++s2;
-    }
-    return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;
-}
-
-PJ_DEF(int) strncasecmp(const char *s1, const char *s2, int len)
-{
-    if (!len) return 0;
-
-    while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {
-	if (!*s1++ || --len <= 0)
-	    return 0;
-	++s2;
-    }
-    return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;
-}
-
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/types.h>

+#include <pj/compat/string.h>

+#include <pj/ctype.h>

+

+PJ_DEF(int) strcasecmp(const char *s1, const char *s2)

+{

+    while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {

+	if (!*s1++)

+	    return 0;

+	++s2;

+    }

+    return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;

+}

+

+PJ_DEF(int) strncasecmp(const char *s1, const char *s2, int len)

+{

+    if (!len) return 0;

+

+    while ((*s1==*s2) || (pj_tolower(*s1)==pj_tolower(*s2))) {

+	if (!*s1++ || --len <= 0)

+	    return 0;

+	++s2;

+    }

+    return (pj_tolower(*s1) < pj_tolower(*s2)) ? -1 : 1;

+}

+

diff --git a/pjlib/src/pj/config.c b/pjlib/src/pj/config.c
index 7923088..329fd98 100644
--- a/pjlib/src/pj/config.c
+++ b/pjlib/src/pj/config.c
@@ -1,32 +1,53 @@
-/* $Id$
- */
-#include <pj/config.h>
-#include <pj/log.h>
-#include <pj/ioqueue.h>
-
-static const char *id = "config.c";
-const char *PJ_VERSION = "0.3.0-pre4";
-
-PJ_DEF(void) pj_dump_config(void)
-{
-    PJ_LOG(3, (id, "PJLIB (c)2005 Benny Prijono"));
-    PJ_LOG(3, (id, "Dumping configurations:"));
-    PJ_LOG(3, (id, " PJ_VERSION               : %s", PJ_VERSION));
-    PJ_LOG(3, (id, " PJ_DEBUG                 : %d", PJ_DEBUG));
-    PJ_LOG(3, (id, " PJ_FUNCTIONS_ARE_INLINED : %d", PJ_FUNCTIONS_ARE_INLINED));
-    PJ_LOG(3, (id, " PJ_POOL_DEBUG            : %d", PJ_POOL_DEBUG));
-    PJ_LOG(3, (id, " PJ_HAS_THREADS           : %d", PJ_HAS_THREADS));
-    PJ_LOG(3, (id, " PJ_LOG_MAX_LEVEL         : %d", PJ_LOG_MAX_LEVEL));
-    PJ_LOG(3, (id, " PJ_LOG_MAX_SIZE          : %d", PJ_LOG_MAX_SIZE));
-    PJ_LOG(3, (id, " PJ_LOG_USE_STACK_BUFFER  : %d", PJ_LOG_USE_STACK_BUFFER));
-    PJ_LOG(3, (id, " PJ_HAS_TCP               : %d", PJ_HAS_TCP));
-    PJ_LOG(3, (id, " PJ_MAX_HOSTNAME          : %d", PJ_MAX_HOSTNAME));
-    PJ_LOG(3, (id, " PJ_HAS_SEMAPHORE         : %d", PJ_HAS_SEMAPHORE));
-    PJ_LOG(3, (id, " PJ_HAS_EVENT_OBJ         : %d", PJ_HAS_EVENT_OBJ));
-    PJ_LOG(3, (id, " PJ_HAS_HIGH_RES_TIMER    : %d", PJ_HAS_HIGH_RES_TIMER));
-    PJ_LOG(3, (id, " PJ_(endianness)          : %s", 
-	       (PJ_IS_BIG_ENDIAN?"big-endian":"little-endian")));
-    PJ_LOG(3, (id, " ioqueue type             : %s", pj_ioqueue_name()));
-    PJ_LOG(3, (id, " PJ_IOQUEUE_MAX_HANDLES   : %d", PJ_IOQUEUE_MAX_HANDLES));
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/config.h>

+#include <pj/log.h>

+#include <pj/ioqueue.h>

+

+static const char *id = "config.c";

+const char *PJ_VERSION = "0.3.0-pre4";

+

+PJ_DEF(void) pj_dump_config(void)

+{

+    PJ_LOG(3, (id, "PJLIB (c)2005 Benny Prijono"));

+    PJ_LOG(3, (id, "Dumping configurations:"));

+    PJ_LOG(3, (id, " PJ_VERSION               : %s", PJ_VERSION));

+    PJ_LOG(3, (id, " PJ_DEBUG                 : %d", PJ_DEBUG));

+    PJ_LOG(3, (id, " PJ_FUNCTIONS_ARE_INLINED : %d", PJ_FUNCTIONS_ARE_INLINED));

+    PJ_LOG(3, (id, " PJ_POOL_DEBUG            : %d", PJ_POOL_DEBUG));

+    PJ_LOG(3, (id, " PJ_HAS_THREADS           : %d", PJ_HAS_THREADS));

+    PJ_LOG(3, (id, " PJ_LOG_MAX_LEVEL         : %d", PJ_LOG_MAX_LEVEL));

+    PJ_LOG(3, (id, " PJ_LOG_MAX_SIZE          : %d", PJ_LOG_MAX_SIZE));

+    PJ_LOG(3, (id, " PJ_LOG_USE_STACK_BUFFER  : %d", PJ_LOG_USE_STACK_BUFFER));

+    PJ_LOG(3, (id, " PJ_HAS_TCP               : %d", PJ_HAS_TCP));

+    PJ_LOG(3, (id, " PJ_MAX_HOSTNAME          : %d", PJ_MAX_HOSTNAME));

+    PJ_LOG(3, (id, " PJ_HAS_SEMAPHORE         : %d", PJ_HAS_SEMAPHORE));

+    PJ_LOG(3, (id, " PJ_HAS_EVENT_OBJ         : %d", PJ_HAS_EVENT_OBJ));

+    PJ_LOG(3, (id, " PJ_HAS_HIGH_RES_TIMER    : %d", PJ_HAS_HIGH_RES_TIMER));

+    PJ_LOG(3, (id, " PJ_(endianness)          : %s", 

+	       (PJ_IS_BIG_ENDIAN?"big-endian":"little-endian")));

+    PJ_LOG(3, (id, " ioqueue type             : %s", pj_ioqueue_name()));

+    PJ_LOG(3, (id, " PJ_IOQUEUE_MAX_HANDLES   : %d", PJ_IOQUEUE_MAX_HANDLES));

+}

+

diff --git a/pjlib/src/pj/equeue_winnt.c b/pjlib/src/pj/equeue_winnt.c
index 8357dce..1565b9a 100644
--- a/pjlib/src/pj/equeue_winnt.c
+++ b/pjlib/src/pj/equeue_winnt.c
@@ -1,3 +1,24 @@
-/* $Id$
- */
-#include <pj/equeue.h>
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/equeue.h>

diff --git a/pjlib/src/pj/errno.c b/pjlib/src/pj/errno.c
index 5a98651..6d05576 100644
--- a/pjlib/src/pj/errno.c
+++ b/pjlib/src/pj/errno.c
@@ -1,99 +1,120 @@
-/* $Id$
- */
-#include <pj/errno.h>
-#include <pj/string.h>
-#include <pj/compat/sprintf.h>
-
-/* Prototype for platform specific error message, which will be defined 
- * in separate file.
- */
-extern int platform_strerror( pj_os_err_type code, 
-                              char *buf, pj_size_t bufsize );
-
-/* PJLIB's own error codes/messages */
-static const struct 
-{
-    int code;
-    const char *msg;
-} err_str[] = 
-{
-    { PJ_EUNKNOWN,      "Unknown Error" },
-    { PJ_EPENDING,      "Pending operation" },
-    { PJ_ETOOMANYCONN,  "Too many connecting sockets" },
-    { PJ_EINVAL,        "Invalid value or argument" },
-    { PJ_ENAMETOOLONG,  "Name too long" },
-    { PJ_ENOTFOUND,     "Not found" },
-    { PJ_ENOMEM,        "Not enough memory" },
-    { PJ_EBUG,          "BUG DETECTED!" },
-    { PJ_ETIMEDOUT,     "Operation timed out" },
-    { PJ_ETOOMANY,      "Too many objects of the specified type"},
-    { PJ_EBUSY,         "Object is busy"},
-    { PJ_ENOTSUP,	"Option/operation is not supported"},
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/errno.h>

+#include <pj/string.h>

+#include <pj/compat/sprintf.h>

+

+/* Prototype for platform specific error message, which will be defined 

+ * in separate file.

+ */

+extern int platform_strerror( pj_os_err_type code, 

+                              char *buf, pj_size_t bufsize );

+

+/* PJLIB's own error codes/messages */

+static const struct 

+{

+    int code;

+    const char *msg;

+} err_str[] = 

+{

+    { PJ_EUNKNOWN,      "Unknown Error" },

+    { PJ_EPENDING,      "Pending operation" },

+    { PJ_ETOOMANYCONN,  "Too many connecting sockets" },

+    { PJ_EINVAL,        "Invalid value or argument" },

+    { PJ_ENAMETOOLONG,  "Name too long" },

+    { PJ_ENOTFOUND,     "Not found" },

+    { PJ_ENOMEM,        "Not enough memory" },

+    { PJ_EBUG,          "BUG DETECTED!" },

+    { PJ_ETIMEDOUT,     "Operation timed out" },

+    { PJ_ETOOMANY,      "Too many objects of the specified type"},

+    { PJ_EBUSY,         "Object is busy"},

+    { PJ_ENOTSUP,	"Option/operation is not supported"},

     { PJ_EINVALIDOP,	"Invalid operation"},

     { PJ_ECANCELLED,    "Operation cancelled"},

-    { PJ_EEXISTS,       "Object already exists" }
-};
-
-/*
- * pjlib_error()
- *
- * Retrieve message string for PJLIB's own error code.
- */
-static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)
-{
-    unsigned i;
-
-    for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {
-        if (err_str[i].code == code) {
-            pj_size_t len = strlen(err_str[i].msg);
-            if (len >= size) len = size-1;
-            pj_memcpy(buf, err_str[i].msg, len);
-            buf[len] = '\0';
-            return len;
-        }
-    }
-
-    *buf++ = '?';
-    *buf++ = '?';
-    *buf++ = '?';
-    *buf++ = '\0';
-    return 3;
-}
-
-/*
- * pj_strerror()
- */
-PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode, 
-			      char *buf, pj_size_t bufsize )
-{
-    int len = -1;
-    pj_str_t errstr;
-
-    if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
-        len = pj_snprintf( buf, bufsize, "Unknown error %d", statcode);
-
-    } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {
-        len = pjlib_error(statcode, buf, bufsize);
-
-    } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {
-        len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);
-
-    } else if (statcode < PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) {
-        len = pj_snprintf( buf, bufsize, "User error %d", statcode);
-
-    } else {
-        len = pj_snprintf( buf, bufsize, "Invalid error %d", statcode);
-
-    }
-
-    if (len < 1) {
-        *buf = '\0';
-        len = 0;
-    }
-
-    errstr.ptr = buf;
-    errstr.slen = len;
-
-    return errstr;
-}
-
+    { PJ_EEXISTS,       "Object already exists" }

+};

+

+/*

+ * pjlib_error()

+ *

+ * Retrieve message string for PJLIB's own error code.

+ */

+static int pjlib_error(pj_status_t code, char *buf, pj_size_t size)

+{

+    unsigned i;

+

+    for (i=0; i<sizeof(err_str)/sizeof(err_str[0]); ++i) {

+        if (err_str[i].code == code) {

+            pj_size_t len = strlen(err_str[i].msg);

+            if (len >= size) len = size-1;

+            pj_memcpy(buf, err_str[i].msg, len);

+            buf[len] = '\0';

+            return len;

+        }

+    }

+

+    *buf++ = '?';

+    *buf++ = '?';

+    *buf++ = '?';

+    *buf++ = '\0';

+    return 3;

+}

+

+/*

+ * pj_strerror()

+ */

+PJ_DEF(pj_str_t) pj_strerror( pj_status_t statcode, 

+			      char *buf, pj_size_t bufsize )

+{

+    int len = -1;

+    pj_str_t errstr;

+

+    if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {

+        len = pj_snprintf( buf, bufsize, "Unknown error %d", statcode);

+

+    } else if (statcode < PJ_ERRNO_START_STATUS + PJ_ERRNO_SPACE_SIZE) {

+        len = pjlib_error(statcode, buf, bufsize);

+

+    } else if (statcode < PJ_ERRNO_START_SYS + PJ_ERRNO_SPACE_SIZE) {

+        len = platform_strerror(PJ_STATUS_TO_OS(statcode), buf, bufsize);

+

+    } else if (statcode < PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE) {

+        len = pj_snprintf( buf, bufsize, "User error %d", statcode);

+

+    } else {

+        len = pj_snprintf( buf, bufsize, "Invalid error %d", statcode);

+

+    }

+

+    if (len < 1) {

+        *buf = '\0';

+        len = 0;

+    }

+

+    errstr.ptr = buf;

+    errstr.slen = len;

+

+    return errstr;

+}

+

diff --git a/pjlib/src/pj/except.c b/pjlib/src/pj/except.c
index 84fb93c..024a417 100644
--- a/pjlib/src/pj/except.c
+++ b/pjlib/src/pj/except.c
@@ -1,135 +1,156 @@
-/* $Id$
- */
-#include <pj/except.h>
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/log.h>
-#include <pj/errno.h>
-
-static long thread_local_id = -1;
-
-#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
-    static const char *exception_id_names[PJ_MAX_EXCEPTION_ID];
-#else
-    /*
-     * Start from 1 (not 0)!!!
-     * Exception 0 is reserved for normal path of setjmp()!!!
-     */
-    static int last_exception_id = 1;
-#endif  /* PJ_HAS_EXCEPTION_NAMES */
-
-
-PJ_DEF(void) pj_throw_exception_(int exception_id)
-{
-    struct pj_exception_state_t *handler;
-
-    handler = pj_thread_local_get(thread_local_id);
-    if (handler == NULL) {
-        PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %d!\n", exception_id));
-        pj_assert(handler != NULL);
-        /* This will crash the system! */
-    }
-    pj_longjmp(handler->state, exception_id);
-}
-
-PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec)
-{
-    struct pj_exception_state_t *parent_handler = NULL;
-
-    if (thread_local_id == -1) {
-	pj_thread_local_alloc(&thread_local_id);
-	pj_assert(thread_local_id != -1);
-    }
-    parent_handler = pj_thread_local_get(thread_local_id);
-    rec->prev = parent_handler;
-    pj_thread_local_set(thread_local_id, rec);
-}
-
-PJ_DEF(void) pj_pop_exception_handler_(void)
-{
-    struct pj_exception_state_t *handler;
-
-    handler = pj_thread_local_get(thread_local_id);
-    pj_assert(handler != NULL);
-    pj_thread_local_set(thread_local_id, handler->prev);
-}
-
-#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
-PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
-                                           pj_exception_id_t *id)
-{
-    unsigned i;
-
-    pj_enter_critical_section();
-
-    /*
-     * Start from 1 (not 0)!!!
-     * Exception 0 is reserved for normal path of setjmp()!!!
-     */
-    for (i=1; i<PJ_MAX_EXCEPTION_ID; ++i) {
-        if (exception_id_names[i] == NULL) {
-            exception_id_names[i] = name;
-            *id = i;
-            pj_leave_critical_section();
-            return PJ_SUCCESS;
-        }
-    }
-
-    pj_leave_critical_section();
-    return PJ_ETOOMANY;
-}
-
-PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
-{
-    /*
-     * Start from 1 (not 0)!!!
-     * Exception 0 is reserved for normal path of setjmp()!!!
-     */
-    PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, PJ_EINVAL);
-    
-    pj_enter_critical_section();
-    exception_id_names[id] = NULL;
-    pj_leave_critical_section();
-
-    return PJ_SUCCESS;
-
-}
-
-PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
-{
-    /*
-     * Start from 1 (not 0)!!!
-     * Exception 0 is reserved for normal path of setjmp()!!!
-     */
-    PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, "<Invalid ID>");
-
-    if (exception_id_names[id] == NULL)
-        return "<Unallocated ID>";
-
-    return exception_id_names[id];
-}
-
-#else   /* PJ_HAS_EXCEPTION_NAMES */
-PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
-                                           pj_exception_id_t *id)
-{
-    PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY);
-
-    *id = last_exception_id++
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
-{
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
-{
-    return "";
-}
-
-#endif  /* PJ_HAS_EXCEPTION_NAMES */
-
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/except.h>

+#include <pj/os.h>

+#include <pj/assert.h>

+#include <pj/log.h>

+#include <pj/errno.h>

+

+static long thread_local_id = -1;

+

+#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0

+    static const char *exception_id_names[PJ_MAX_EXCEPTION_ID];

+#else

+    /*

+     * Start from 1 (not 0)!!!

+     * Exception 0 is reserved for normal path of setjmp()!!!

+     */

+    static int last_exception_id = 1;

+#endif  /* PJ_HAS_EXCEPTION_NAMES */

+

+

+PJ_DEF(void) pj_throw_exception_(int exception_id)

+{

+    struct pj_exception_state_t *handler;

+

+    handler = pj_thread_local_get(thread_local_id);

+    if (handler == NULL) {

+        PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %d!\n", exception_id));

+        pj_assert(handler != NULL);

+        /* This will crash the system! */

+    }

+    pj_longjmp(handler->state, exception_id);

+}

+

+PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec)

+{

+    struct pj_exception_state_t *parent_handler = NULL;

+

+    if (thread_local_id == -1) {

+	pj_thread_local_alloc(&thread_local_id);

+	pj_assert(thread_local_id != -1);

+    }

+    parent_handler = pj_thread_local_get(thread_local_id);

+    rec->prev = parent_handler;

+    pj_thread_local_set(thread_local_id, rec);

+}

+

+PJ_DEF(void) pj_pop_exception_handler_(void)

+{

+    struct pj_exception_state_t *handler;

+

+    handler = pj_thread_local_get(thread_local_id);

+    pj_assert(handler != NULL);

+    pj_thread_local_set(thread_local_id, handler->prev);

+}

+

+#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0

+PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,

+                                           pj_exception_id_t *id)

+{

+    unsigned i;

+

+    pj_enter_critical_section();

+

+    /*

+     * Start from 1 (not 0)!!!

+     * Exception 0 is reserved for normal path of setjmp()!!!

+     */

+    for (i=1; i<PJ_MAX_EXCEPTION_ID; ++i) {

+        if (exception_id_names[i] == NULL) {

+            exception_id_names[i] = name;

+            *id = i;

+            pj_leave_critical_section();

+            return PJ_SUCCESS;

+        }

+    }

+

+    pj_leave_critical_section();

+    return PJ_ETOOMANY;

+}

+

+PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )

+{

+    /*

+     * Start from 1 (not 0)!!!

+     * Exception 0 is reserved for normal path of setjmp()!!!

+     */

+    PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, PJ_EINVAL);

+    

+    pj_enter_critical_section();

+    exception_id_names[id] = NULL;

+    pj_leave_critical_section();

+

+    return PJ_SUCCESS;

+

+}

+

+PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)

+{

+    /*

+     * Start from 1 (not 0)!!!

+     * Exception 0 is reserved for normal path of setjmp()!!!

+     */

+    PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, "<Invalid ID>");

+

+    if (exception_id_names[id] == NULL)

+        return "<Unallocated ID>";

+

+    return exception_id_names[id];

+}

+

+#else   /* PJ_HAS_EXCEPTION_NAMES */

+PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,

+                                           pj_exception_id_t *id)

+{

+    PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY);

+

+    *id = last_exception_id++

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )

+{

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)

+{

+    return "";

+}

+

+#endif  /* PJ_HAS_EXCEPTION_NAMES */

+

+

+

diff --git a/pjlib/src/pj/extra-exports.c b/pjlib/src/pj/extra-exports.c
index 29e1921..af7276c 100644
--- a/pjlib/src/pj/extra-exports.c
+++ b/pjlib/src/pj/extra-exports.c
@@ -1,32 +1,53 @@
-/* $Id$
- *
- */
-/*
- * This file contains code to export extra symbols from Linux kernel.
- * It should be copied to Linux kernel source tree and added to
- * Linux kernel combilation.
- *
- * This file is part of PJLIB project.
- */
-#include <linux/module.h>
-#include <linux/syscalls.h>
-
-EXPORT_SYMBOL(sys_select);
-
-EXPORT_SYMBOL(sys_epoll_create);
-EXPORT_SYMBOL(sys_epoll_ctl);
-EXPORT_SYMBOL(sys_epoll_wait);
-
-EXPORT_SYMBOL(sys_socket);
-EXPORT_SYMBOL(sys_bind);
-EXPORT_SYMBOL(sys_getpeername);
-EXPORT_SYMBOL(sys_getsockname);
-EXPORT_SYMBOL(sys_sendto);
-EXPORT_SYMBOL(sys_recvfrom);
-EXPORT_SYMBOL(sys_getsockopt);
-EXPORT_SYMBOL(sys_setsockopt);
-EXPORT_SYMBOL(sys_listen);
-EXPORT_SYMBOL(sys_shutdown);
-EXPORT_SYMBOL(sys_connect);
-EXPORT_SYMBOL(sys_accept);
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/*

+ * This file contains code to export extra symbols from Linux kernel.

+ * It should be copied to Linux kernel source tree and added to

+ * Linux kernel combilation.

+ *

+ * This file is part of PJLIB project.

+ */

+#include <linux/module.h>

+#include <linux/syscalls.h>

+

+EXPORT_SYMBOL(sys_select);

+

+EXPORT_SYMBOL(sys_epoll_create);

+EXPORT_SYMBOL(sys_epoll_ctl);

+EXPORT_SYMBOL(sys_epoll_wait);

+

+EXPORT_SYMBOL(sys_socket);

+EXPORT_SYMBOL(sys_bind);

+EXPORT_SYMBOL(sys_getpeername);

+EXPORT_SYMBOL(sys_getsockname);

+EXPORT_SYMBOL(sys_sendto);

+EXPORT_SYMBOL(sys_recvfrom);

+EXPORT_SYMBOL(sys_getsockopt);

+EXPORT_SYMBOL(sys_setsockopt);

+EXPORT_SYMBOL(sys_listen);

+EXPORT_SYMBOL(sys_shutdown);

+EXPORT_SYMBOL(sys_connect);

+EXPORT_SYMBOL(sys_accept);

+

diff --git a/pjlib/src/pj/fifobuf.c b/pjlib/src/pj/fifobuf.c
index 0368ef3..2902363 100644
--- a/pjlib/src/pj/fifobuf.c
+++ b/pjlib/src/pj/fifobuf.c
@@ -1,177 +1,198 @@
-/* $Id$
- */
-#include <pj/fifobuf.h>
-#include <pj/log.h>
-#include <pj/assert.h>
-#include <pj/os.h>
-
-#define THIS_FILE   "fifobuf"
-
-#define SZ  sizeof(unsigned)
-
-PJ_DEF(void)
-pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size)
-{
-    PJ_CHECK_STACK();
-
-    PJ_LOG(6, (THIS_FILE, 
-	       "fifobuf_init fifobuf=%p buffer=%p, size=%d", 
-	       fifobuf, buffer, size));
-
-    fifobuf->first = buffer;
-    fifobuf->last = fifobuf->first + size;
-    fifobuf->ubegin = fifobuf->uend = fifobuf->first;
-    fifobuf->full = 0;
-}
-
-PJ_DEF(unsigned)
-pj_fifobuf_max_size (pj_fifobuf_t *fifobuf)
-{
-    unsigned s1, s2;
-
-    PJ_CHECK_STACK();
-
-    if (fifobuf->uend >= fifobuf->ubegin) {
-	s1 = fifobuf->last - fifobuf->uend;
-	s2 = fifobuf->ubegin - fifobuf->first;
-    } else {
-	s1 = s2 = fifobuf->ubegin - fifobuf->uend;
-    }
-    
-    return s1<s2 ? s2 : s1;
-}
-
-PJ_DEF(void*)
-pj_fifobuf_alloc (pj_fifobuf_t *fifobuf, unsigned size)
-{
-    unsigned available;
-    char *start;
-
-    PJ_CHECK_STACK();
-
-    if (fifobuf->full) {
-	PJ_LOG(6, (THIS_FILE, 
-		   "fifobuf_alloc fifobuf=%p, size=%d: full!", 
-		   fifobuf, size));
-	return NULL;
-    }
-
-    /* try to allocate from the end part of the fifo */
-    if (fifobuf->uend >= fifobuf->ubegin) {
-	available = fifobuf->last - fifobuf->uend;
-	if (available >= size+SZ) {
-	    char *ptr = fifobuf->uend;
-	    fifobuf->uend += (size+SZ);
-	    if (fifobuf->uend == fifobuf->last)
-		fifobuf->uend = fifobuf->first;
-	    if (fifobuf->uend == fifobuf->ubegin)
-		fifobuf->full = 1;
-	    *(unsigned*)ptr = size+SZ;
-	    ptr += SZ;
-
-	    PJ_LOG(6, (THIS_FILE, 
-		       "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", 
-		       fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
-	    return ptr;
-	}
-    }
-
-    /* try to allocate from the start part of the fifo */
-    start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first;
-    available = fifobuf->ubegin - start;
-    if (available >= size+SZ) {
-	char *ptr = start;
-	fifobuf->uend = start + size + SZ;
-	if (fifobuf->uend == fifobuf->ubegin)
-	    fifobuf->full = 1;
-	*(unsigned*)ptr = size+SZ;
-	ptr += SZ;
-
-	PJ_LOG(6, (THIS_FILE, 
-		   "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", 
-		   fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));
-	return ptr;
-    }
-
-    PJ_LOG(6, (THIS_FILE, 
-	       "fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p", 
-	       fifobuf, size, fifobuf->ubegin, fifobuf->uend));
-    return NULL;
-}
-
-PJ_DEF(pj_status_t)
-pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf)
-{
-    char *ptr = buf;
-    char *endptr;
-    unsigned sz;
-
-    PJ_CHECK_STACK();
-
-    ptr -= SZ;
-    sz = *(unsigned*)ptr;
-
-    endptr = fifobuf->uend;
-    if (endptr == fifobuf->first)
-	endptr = fifobuf->last;
-
-    if (ptr+sz != endptr) {
-	pj_assert(!"Invalid pointer to undo alloc");
-	return -1;
-    }
-
-    fifobuf->uend = ptr;
-    fifobuf->full = 0;
-
-    PJ_LOG(6, (THIS_FILE, 
-	       "fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", 
-	       fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
-
-    return 0;
-}
-
-PJ_DEF(pj_status_t)
-pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf)
-{
-    char *ptr = buf;
-    char *end;
-    unsigned sz;
-
-    PJ_CHECK_STACK();
-
-    ptr -= SZ;
-    if (ptr < fifobuf->first || ptr >= fifobuf->last) {
-	pj_assert(!"Invalid pointer to free");
-	return -1;
-    }
-
-    if (ptr != fifobuf->ubegin && ptr != fifobuf->first) {
-	pj_assert(!"Invalid free() sequence!");
-	return -1;
-    }
-
-    end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last;
-    sz = *(unsigned*)ptr;
-    if (ptr+sz > end) {
-	pj_assert(!"Invalid size!");
-	return -1;
-    }
-
-    fifobuf->ubegin = ptr + sz;
-
-    /* Rollover */
-    if (fifobuf->ubegin == fifobuf->last)
-	fifobuf->ubegin = fifobuf->first;
-
-    /* Reset if fifobuf is empty */
-    if (fifobuf->ubegin == fifobuf->uend)
-	fifobuf->ubegin = fifobuf->uend = fifobuf->first;
-
-    fifobuf->full = 0;
-
-    PJ_LOG(6, (THIS_FILE, 
-	       "fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", 
-	       fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));
-
-    return 0;
-}
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/fifobuf.h>

+#include <pj/log.h>

+#include <pj/assert.h>

+#include <pj/os.h>

+

+#define THIS_FILE   "fifobuf"

+

+#define SZ  sizeof(unsigned)

+

+PJ_DEF(void)

+pj_fifobuf_init (pj_fifobuf_t *fifobuf, void *buffer, unsigned size)

+{

+    PJ_CHECK_STACK();

+

+    PJ_LOG(6, (THIS_FILE, 

+	       "fifobuf_init fifobuf=%p buffer=%p, size=%d", 

+	       fifobuf, buffer, size));

+

+    fifobuf->first = buffer;

+    fifobuf->last = fifobuf->first + size;

+    fifobuf->ubegin = fifobuf->uend = fifobuf->first;

+    fifobuf->full = 0;

+}

+

+PJ_DEF(unsigned)

+pj_fifobuf_max_size (pj_fifobuf_t *fifobuf)

+{

+    unsigned s1, s2;

+

+    PJ_CHECK_STACK();

+

+    if (fifobuf->uend >= fifobuf->ubegin) {

+	s1 = fifobuf->last - fifobuf->uend;

+	s2 = fifobuf->ubegin - fifobuf->first;

+    } else {

+	s1 = s2 = fifobuf->ubegin - fifobuf->uend;

+    }

+    

+    return s1<s2 ? s2 : s1;

+}

+

+PJ_DEF(void*)

+pj_fifobuf_alloc (pj_fifobuf_t *fifobuf, unsigned size)

+{

+    unsigned available;

+    char *start;

+

+    PJ_CHECK_STACK();

+

+    if (fifobuf->full) {

+	PJ_LOG(6, (THIS_FILE, 

+		   "fifobuf_alloc fifobuf=%p, size=%d: full!", 

+		   fifobuf, size));

+	return NULL;

+    }

+

+    /* try to allocate from the end part of the fifo */

+    if (fifobuf->uend >= fifobuf->ubegin) {

+	available = fifobuf->last - fifobuf->uend;

+	if (available >= size+SZ) {

+	    char *ptr = fifobuf->uend;

+	    fifobuf->uend += (size+SZ);

+	    if (fifobuf->uend == fifobuf->last)

+		fifobuf->uend = fifobuf->first;

+	    if (fifobuf->uend == fifobuf->ubegin)

+		fifobuf->full = 1;

+	    *(unsigned*)ptr = size+SZ;

+	    ptr += SZ;

+

+	    PJ_LOG(6, (THIS_FILE, 

+		       "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", 

+		       fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));

+	    return ptr;

+	}

+    }

+

+    /* try to allocate from the start part of the fifo */

+    start = (fifobuf->uend <= fifobuf->ubegin) ? fifobuf->uend : fifobuf->first;

+    available = fifobuf->ubegin - start;

+    if (available >= size+SZ) {

+	char *ptr = start;

+	fifobuf->uend = start + size + SZ;

+	if (fifobuf->uend == fifobuf->ubegin)

+	    fifobuf->full = 1;

+	*(unsigned*)ptr = size+SZ;

+	ptr += SZ;

+

+	PJ_LOG(6, (THIS_FILE, 

+		   "fifobuf_alloc fifobuf=%p, size=%d: returning %p, p1=%p, p2=%p", 

+		   fifobuf, size, ptr, fifobuf->ubegin, fifobuf->uend));

+	return ptr;

+    }

+

+    PJ_LOG(6, (THIS_FILE, 

+	       "fifobuf_alloc fifobuf=%p, size=%d: no space left! p1=%p, p2=%p", 

+	       fifobuf, size, fifobuf->ubegin, fifobuf->uend));

+    return NULL;

+}

+

+PJ_DEF(pj_status_t)

+pj_fifobuf_unalloc (pj_fifobuf_t *fifobuf, void *buf)

+{

+    char *ptr = buf;

+    char *endptr;

+    unsigned sz;

+

+    PJ_CHECK_STACK();

+

+    ptr -= SZ;

+    sz = *(unsigned*)ptr;

+

+    endptr = fifobuf->uend;

+    if (endptr == fifobuf->first)

+	endptr = fifobuf->last;

+

+    if (ptr+sz != endptr) {

+	pj_assert(!"Invalid pointer to undo alloc");

+	return -1;

+    }

+

+    fifobuf->uend = ptr;

+    fifobuf->full = 0;

+

+    PJ_LOG(6, (THIS_FILE, 

+	       "fifobuf_unalloc fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", 

+	       fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));

+

+    return 0;

+}

+

+PJ_DEF(pj_status_t)

+pj_fifobuf_free (pj_fifobuf_t *fifobuf, void *buf)

+{

+    char *ptr = buf;

+    char *end;

+    unsigned sz;

+

+    PJ_CHECK_STACK();

+

+    ptr -= SZ;

+    if (ptr < fifobuf->first || ptr >= fifobuf->last) {

+	pj_assert(!"Invalid pointer to free");

+	return -1;

+    }

+

+    if (ptr != fifobuf->ubegin && ptr != fifobuf->first) {

+	pj_assert(!"Invalid free() sequence!");

+	return -1;

+    }

+

+    end = (fifobuf->uend > fifobuf->ubegin) ? fifobuf->uend : fifobuf->last;

+    sz = *(unsigned*)ptr;

+    if (ptr+sz > end) {

+	pj_assert(!"Invalid size!");

+	return -1;

+    }

+

+    fifobuf->ubegin = ptr + sz;

+

+    /* Rollover */

+    if (fifobuf->ubegin == fifobuf->last)

+	fifobuf->ubegin = fifobuf->first;

+

+    /* Reset if fifobuf is empty */

+    if (fifobuf->ubegin == fifobuf->uend)

+	fifobuf->ubegin = fifobuf->uend = fifobuf->first;

+

+    fifobuf->full = 0;

+

+    PJ_LOG(6, (THIS_FILE, 

+	       "fifobuf_free fifobuf=%p, ptr=%p, size=%d, p1=%p, p2=%p", 

+	       fifobuf, buf, sz, fifobuf->ubegin, fifobuf->uend));

+

+    return 0;

+}

diff --git a/pjlib/src/pj/file_access_unistd.c b/pjlib/src/pj/file_access_unistd.c
index 8e46e0e..b4e0ab4 100644
--- a/pjlib/src/pj/file_access_unistd.c
+++ b/pjlib/src/pj/file_access_unistd.c
@@ -1,96 +1,117 @@
-/* $Id$ */
-#include <pj/file_access.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>	/* rename() */
-#include <errno.h>
-
-/*
- * pj_file_exists()
- */
-PJ_DEF(pj_bool_t) pj_file_exists(const char *filename)
-{
-    struct stat buf;
-
-    PJ_ASSERT_RETURN(filename, 0);
-
-    if (stat(filename, &buf) != 0)
-	return 0;
-
-    return PJ_TRUE;
-}
-
-
-/*
- * pj_file_size()
- */
-PJ_DEF(pj_off_t) pj_file_size(const char *filename)
-{
-    struct stat buf;
-
-    PJ_ASSERT_RETURN(filename, -1);
-
-    if (stat(filename, &buf) != 0)
-	return -1;
-
-    return buf.st_size;
-}
-
-
-/*
- * pj_file_delete()
- */
-PJ_DEF(pj_status_t) pj_file_delete(const char *filename)
-{
-    PJ_ASSERT_RETURN(filename, PJ_EINVAL);
-
-    if (unlink(filename)!=0) {
-	return PJ_RETURN_OS_ERROR(errno);
-    }
-    return PJ_SUCCESS;
-}
-
-
-/*
- * pj_file_move()
- */
-PJ_DEF(pj_status_t) pj_file_move( const char *oldname, const char *newname)
-{
-    PJ_ASSERT_RETURN(oldname && newname, PJ_EINVAL);
-
-    if (rename(oldname, newname) != 0) {
-	return PJ_RETURN_OS_ERROR(errno);
-    }
-    return PJ_SUCCESS;
-}
-
-
-/*
- * pj_file_getstat()
- */
-PJ_DEF(pj_status_t) pj_file_getstat(const char *filename, 
-				    pj_file_stat *statbuf)
-{
-    struct stat buf;
-
-    PJ_ASSERT_RETURN(filename && statbuf, PJ_EINVAL);
-
-    if (stat(filename, &buf) != 0) {
-	return PJ_RETURN_OS_ERROR(errno);
-    }
-
-    statbuf->size = buf.st_size;
-    statbuf->ctime.sec = buf.st_ctime;
-    statbuf->ctime.msec = 0;
-    statbuf->mtime.sec = buf.st_mtime;
-    statbuf->mtime.msec = 0;
-    statbuf->atime.sec = buf.st_atime;
-    statbuf->atime.msec = 0;
-
-    return PJ_SUCCESS;
-}
-
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/file_access.h>

+#include <pj/assert.h>

+#include <pj/errno.h>

+

+#include <sys/types.h>

+#include <sys/stat.h>

+#include <unistd.h>

+#include <stdio.h>	/* rename() */

+#include <errno.h>

+

+/*

+ * pj_file_exists()

+ */

+PJ_DEF(pj_bool_t) pj_file_exists(const char *filename)

+{

+    struct stat buf;

+

+    PJ_ASSERT_RETURN(filename, 0);

+

+    if (stat(filename, &buf) != 0)

+	return 0;

+

+    return PJ_TRUE;

+}

+

+

+/*

+ * pj_file_size()

+ */

+PJ_DEF(pj_off_t) pj_file_size(const char *filename)

+{

+    struct stat buf;

+

+    PJ_ASSERT_RETURN(filename, -1);

+

+    if (stat(filename, &buf) != 0)

+	return -1;

+

+    return buf.st_size;

+}

+

+

+/*

+ * pj_file_delete()

+ */

+PJ_DEF(pj_status_t) pj_file_delete(const char *filename)

+{

+    PJ_ASSERT_RETURN(filename, PJ_EINVAL);

+

+    if (unlink(filename)!=0) {

+	return PJ_RETURN_OS_ERROR(errno);

+    }

+    return PJ_SUCCESS;

+}

+

+

+/*

+ * pj_file_move()

+ */

+PJ_DEF(pj_status_t) pj_file_move( const char *oldname, const char *newname)

+{

+    PJ_ASSERT_RETURN(oldname && newname, PJ_EINVAL);

+

+    if (rename(oldname, newname) != 0) {

+	return PJ_RETURN_OS_ERROR(errno);

+    }

+    return PJ_SUCCESS;

+}

+

+

+/*

+ * pj_file_getstat()

+ */

+PJ_DEF(pj_status_t) pj_file_getstat(const char *filename, 

+				    pj_file_stat *statbuf)

+{

+    struct stat buf;

+

+    PJ_ASSERT_RETURN(filename && statbuf, PJ_EINVAL);

+

+    if (stat(filename, &buf) != 0) {

+	return PJ_RETURN_OS_ERROR(errno);

+    }

+

+    statbuf->size = buf.st_size;

+    statbuf->ctime.sec = buf.st_ctime;

+    statbuf->ctime.msec = 0;

+    statbuf->mtime.sec = buf.st_mtime;

+    statbuf->mtime.msec = 0;

+    statbuf->atime.sec = buf.st_atime;

+    statbuf->atime.msec = 0;

+

+    return PJ_SUCCESS;

+}

+

diff --git a/pjlib/src/pj/file_access_win32.c b/pjlib/src/pj/file_access_win32.c
index 3640565..7aeceb8 100644
--- a/pjlib/src/pj/file_access_win32.c
+++ b/pjlib/src/pj/file_access_win32.c
@@ -1,4 +1,25 @@
 /* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #include <pj/file_access.h>

 #include <pj/assert.h>

 #include <pj/errno.h>

diff --git a/pjlib/src/pj/file_io_ansi.c b/pjlib/src/pj/file_io_ansi.c
index 0946edd..3acb91e 100644
--- a/pjlib/src/pj/file_io_ansi.c
+++ b/pjlib/src/pj/file_io_ansi.c
@@ -1,140 +1,161 @@
-/* $Id$ */
-#include <pj/file_io.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-#include <stdio.h>
-#include <errno.h>
-
-PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,
-                                  const char *pathname, 
-                                  unsigned flags,
-                                  pj_oshandle_t *fd)
-{
-    char mode[8];
-    char *p = mode;
-
-    PJ_ASSERT_RETURN(pathname && fd, PJ_EINVAL);
-    PJ_UNUSED_ARG(pool);
-
-    if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {
-        if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {
-            *p++ = 'a';
-            if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY)
-                *p++ = '+';
-        } else {
-            /* This is invalid.
-             * Can not specify PJ_O_RDONLY with PJ_O_APPEND! 
-             */
-        }
-    } else {
-        if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {
-            *p++ = 'r';
-            if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY)
-                *p++ = '+';
-        } else {
-            *p++ = 'w';
-        }
-    }
-
-    if (p==mode)
-        return PJ_EINVAL;
-
-    *p++ = 'b';
-    *p++ = '\0';
-
-    *fd = fopen(pathname, mode);
-    if (*fd == NULL)
-        return PJ_RETURN_OS_ERROR(errno);
-    
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)
-{
-    PJ_ASSERT_RETURN(fd, PJ_EINVAL);
-    if (fclose((FILE*)fd) != 0)
-        return PJ_RETURN_OS_ERROR(errno);
-
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,
-                                   const void *data,
-                                   pj_ssize_t *size)
-{
-    size_t written;
-
-    clearerr((FILE*)fd);
-    written = fwrite(data, 1, *size, (FILE*)fd);
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/file_io.h>

+#include <pj/assert.h>

+#include <pj/errno.h>

+#include <stdio.h>

+#include <errno.h>

+

+PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,

+                                  const char *pathname, 

+                                  unsigned flags,

+                                  pj_oshandle_t *fd)

+{

+    char mode[8];

+    char *p = mode;

+

+    PJ_ASSERT_RETURN(pathname && fd, PJ_EINVAL);

+    PJ_UNUSED_ARG(pool);

+

+    if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {

+        if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {

+            *p++ = 'a';

+            if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY)

+                *p++ = '+';

+        } else {

+            /* This is invalid.

+             * Can not specify PJ_O_RDONLY with PJ_O_APPEND! 

+             */

+        }

+    } else {

+        if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {

+            *p++ = 'r';

+            if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY)

+                *p++ = '+';

+        } else {

+            *p++ = 'w';

+        }

+    }

+

+    if (p==mode)

+        return PJ_EINVAL;

+

+    *p++ = 'b';

+    *p++ = '\0';

+

+    *fd = fopen(pathname, mode);

+    if (*fd == NULL)

+        return PJ_RETURN_OS_ERROR(errno);

+    

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)

+{

+    PJ_ASSERT_RETURN(fd, PJ_EINVAL);

+    if (fclose((FILE*)fd) != 0)

+        return PJ_RETURN_OS_ERROR(errno);

+

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,

+                                   const void *data,

+                                   pj_ssize_t *size)

+{

+    size_t written;

+

+    clearerr((FILE*)fd);

+    written = fwrite(data, 1, *size, (FILE*)fd);

     if (ferror((FILE*)fd)) {

-        *size = -1;
-        return PJ_RETURN_OS_ERROR(errno);
-    }
-
-    *size = written;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,
-                                  void *data,
-                                  pj_ssize_t *size)
-{
-    size_t bytes;
-
-    clearerr((FILE*)fd);
-    bytes = fread(data, 1, *size, (FILE*)fd);
+        *size = -1;

+        return PJ_RETURN_OS_ERROR(errno);

+    }

+

+    *size = written;

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,

+                                  void *data,

+                                  pj_ssize_t *size)

+{

+    size_t bytes;

+

+    clearerr((FILE*)fd);

+    bytes = fread(data, 1, *size, (FILE*)fd);

     if (ferror((FILE*)fd)) {

-        *size = -1;
-        return PJ_RETURN_OS_ERROR(errno);
-    }
-
-    *size = bytes;
-    return PJ_SUCCESS;
-}
+        *size = -1;

+        return PJ_RETURN_OS_ERROR(errno);

+    }

+

+    *size = bytes;

+    return PJ_SUCCESS;

+}

 

 PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access)

 {

     PJ_UNUSED_ARG(access);

     return feof((FILE*)fd) ? PJ_TRUE : 0;

 }

-
-PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,
-                                    pj_off_t offset,
-                                    enum pj_file_seek_type whence)
-{
-    int mode;
-
-    switch (whence) {
-    case PJ_SEEK_SET:
-        mode = SEEK_SET; break;
-    case PJ_SEEK_CUR:
-        mode = SEEK_CUR; break;
-    case PJ_SEEK_END:
-        mode = SEEK_END; break;
-    default:
-        pj_assert(!"Invalid whence in file_setpos");
-        return PJ_EINVAL;
-    }
-
-    if (fseek((FILE*)fd, (long)offset, mode) != 0)
-        return PJ_RETURN_OS_ERROR(errno);
-
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,
-                                    pj_off_t *pos)
-{
-    long offset;
-
-    offset = ftell((FILE*)fd);
-    if (offset == -1) {
-        *pos = -1;
-        return PJ_RETURN_OS_ERROR(errno);
-    }
-
-    *pos = offset;
-    return PJ_SUCCESS;
-}
-
-
+

+PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,

+                                    pj_off_t offset,

+                                    enum pj_file_seek_type whence)

+{

+    int mode;

+

+    switch (whence) {

+    case PJ_SEEK_SET:

+        mode = SEEK_SET; break;

+    case PJ_SEEK_CUR:

+        mode = SEEK_CUR; break;

+    case PJ_SEEK_END:

+        mode = SEEK_END; break;

+    default:

+        pj_assert(!"Invalid whence in file_setpos");

+        return PJ_EINVAL;

+    }

+

+    if (fseek((FILE*)fd, (long)offset, mode) != 0)

+        return PJ_RETURN_OS_ERROR(errno);

+

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,

+                                    pj_off_t *pos)

+{

+    long offset;

+

+    offset = ftell((FILE*)fd);

+    if (offset == -1) {

+        *pos = -1;

+        return PJ_RETURN_OS_ERROR(errno);

+    }

+

+    *pos = offset;

+    return PJ_SUCCESS;

+}

+

+

diff --git a/pjlib/src/pj/file_io_win32.c b/pjlib/src/pj/file_io_win32.c
index d990841..d90f5f4 100644
--- a/pjlib/src/pj/file_io_win32.c
+++ b/pjlib/src/pj/file_io_win32.c
@@ -1,13 +1,34 @@
-/* $Id$ */
-#include <pj/file_io.h>
-#include <pj/errno.h>
-#include <pj/assert.h>
-
-#include <windows.h>
-
-#ifndef INVALID_SET_FILE_POINTER
-#   define INVALID_SET_FILE_POINTER     ((DWORD)-1)
-#endif
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/file_io.h>

+#include <pj/errno.h>

+#include <pj/assert.h>

+

+#include <windows.h>

+

+#ifndef INVALID_SET_FILE_POINTER

+#   define INVALID_SET_FILE_POINTER     ((DWORD)-1)

+#endif

 

 /**

  * Check for end-of-file condition on the specified descriptor.

@@ -19,97 +40,97 @@
  */

 PJ_DECL(pj_bool_t) pj_file_eof(pj_oshandle_t fd, 

                                enum pj_file_access access);

-
-
-PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,
-                                  const char *pathname, 
-                                  unsigned flags,
-                                  pj_oshandle_t *fd)
-{
-    HANDLE hFile;
-    DWORD dwDesiredAccess = 0;
-    DWORD dwShareMode = 0;
-    DWORD dwCreationDisposition = 0;
-    DWORD dwFlagsAndAttributes = 0;
-
-    PJ_UNUSED_ARG(pool);
-
-    PJ_ASSERT_RETURN(pathname!=NULL, PJ_EINVAL);
-
-    if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {
-        dwDesiredAccess |= GENERIC_WRITE;
-        if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {
-            dwDesiredAccess |= FILE_APPEND_DATA;
-        } else {
+

+

+PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool,

+                                  const char *pathname, 

+                                  unsigned flags,

+                                  pj_oshandle_t *fd)

+{

+    HANDLE hFile;

+    DWORD dwDesiredAccess = 0;

+    DWORD dwShareMode = 0;

+    DWORD dwCreationDisposition = 0;

+    DWORD dwFlagsAndAttributes = 0;

+

+    PJ_UNUSED_ARG(pool);

+

+    PJ_ASSERT_RETURN(pathname!=NULL, PJ_EINVAL);

+

+    if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) {

+        dwDesiredAccess |= GENERIC_WRITE;

+        if ((flags & PJ_O_APPEND) == PJ_O_APPEND) {

+            dwDesiredAccess |= FILE_APPEND_DATA;

+        } else {

             dwDesiredAccess &= ~(FILE_APPEND_DATA);

             dwCreationDisposition |= CREATE_ALWAYS;

-        }
-    }
+        }

+    }

     if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) {

         dwDesiredAccess |= GENERIC_READ;

         if (flags == PJ_O_RDONLY)

             dwCreationDisposition |= OPEN_EXISTING;

     }

-
-    if (dwDesiredAccess == 0) {
-        pj_assert(!"Invalid file open flags");
-        return PJ_EINVAL;
-    }
-
-    dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
-    dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
 

-    hFile = CreateFile(pathname, dwDesiredAccess, dwShareMode, NULL,
-                       dwCreationDisposition, dwFlagsAndAttributes, NULL);
-    if (hFile == INVALID_HANDLE_VALUE) {
-        *fd = 0;
-        return PJ_RETURN_OS_ERROR(GetLastError());
-    }
-
-    *fd = hFile;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)
-{
-    if (CloseHandle(fd)==0)
-        return PJ_RETURN_OS_ERROR(GetLastError());
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,
-                                   const void *data,
-                                   pj_ssize_t *size)
-{
-    BOOL rc;
-    DWORD bytesWritten;
-
-    rc = WriteFile(fd, data, *size, &bytesWritten, NULL);
-    if (!rc) {
-        *size = -1;
-        return PJ_RETURN_OS_ERROR(GetLastError());
-    }
-
-    *size = bytesWritten;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,
-                                  void *data,
-                                  pj_ssize_t *size)
-{
-    BOOL rc;
-    DWORD bytesRead;
-
-    rc = ReadFile(fd, data, *size, &bytesRead, NULL);
-    if (!rc) {
-        *size = -1;
-        return PJ_RETURN_OS_ERROR(GetLastError());
-    }
-
-    *size = bytesRead;
-    return PJ_SUCCESS;
-}
+    if (dwDesiredAccess == 0) {

+        pj_assert(!"Invalid file open flags");

+        return PJ_EINVAL;

+    }

+

+    dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;

+    dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;

+

+    hFile = CreateFile(pathname, dwDesiredAccess, dwShareMode, NULL,

+                       dwCreationDisposition, dwFlagsAndAttributes, NULL);

+    if (hFile == INVALID_HANDLE_VALUE) {

+        *fd = 0;

+        return PJ_RETURN_OS_ERROR(GetLastError());

+    }

+

+    *fd = hFile;

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd)

+{

+    if (CloseHandle(fd)==0)

+        return PJ_RETURN_OS_ERROR(GetLastError());

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd,

+                                   const void *data,

+                                   pj_ssize_t *size)

+{

+    BOOL rc;

+    DWORD bytesWritten;

+

+    rc = WriteFile(fd, data, *size, &bytesWritten, NULL);

+    if (!rc) {

+        *size = -1;

+        return PJ_RETURN_OS_ERROR(GetLastError());

+    }

+

+    *size = bytesWritten;

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd,

+                                  void *data,

+                                  pj_ssize_t *size)

+{

+    BOOL rc;

+    DWORD bytesRead;

+

+    rc = ReadFile(fd, data, *size, &bytesRead, NULL);

+    if (!rc) {

+        *size = -1;

+        return PJ_RETURN_OS_ERROR(GetLastError());

+    }

+

+    *size = bytesRead;

+    return PJ_SUCCESS;

+}

 

 /*

 PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access)

@@ -134,53 +155,53 @@
     return 0;

 }

 */

-
-PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,
-                                    pj_off_t offset,
-                                    enum pj_file_seek_type whence)
-{
-    DWORD dwMoveMethod;
-    DWORD dwNewPos;
-    LONG  hi32;
-
-    if (whence == PJ_SEEK_SET)
-        dwMoveMethod = FILE_BEGIN;
-    else if (whence == PJ_SEEK_CUR)
-        dwMoveMethod = FILE_CURRENT;
-    else if (whence == PJ_SEEK_END)
-        dwMoveMethod = FILE_END;
-    else {
-        pj_assert(!"Invalid whence in file_setpos");
-        return PJ_EINVAL;
-    }
-
-    hi32 = (LONG)(offset >> 32);
-    dwNewPos = SetFilePointer(fd, (long)offset, &hi32, dwMoveMethod);
-    if (dwNewPos == (DWORD)INVALID_SET_FILE_POINTER) {
-        DWORD dwStatus = GetLastError();
-        if (dwStatus != 0)
-            return PJ_RETURN_OS_ERROR(dwStatus);
-        /* dwNewPos actually is not an error. */
-    }
-
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,
-                                    pj_off_t *pos)
-{
-    LONG hi32 = 0;
-    DWORD lo32;
-
-    lo32 = SetFilePointer(fd, 0, &hi32, FILE_CURRENT);
-    if (lo32 == (DWORD)INVALID_SET_FILE_POINTER) {
-        DWORD dwStatus = GetLastError();
-        if (dwStatus != 0)
-            return PJ_RETURN_OS_ERROR(dwStatus);
-    }
-
-    *pos = hi32;
-    *pos = (*pos << 32) + lo32;
-    return PJ_SUCCESS;
-}
-
+

+PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd,

+                                    pj_off_t offset,

+                                    enum pj_file_seek_type whence)

+{

+    DWORD dwMoveMethod;

+    DWORD dwNewPos;

+    LONG  hi32;

+

+    if (whence == PJ_SEEK_SET)

+        dwMoveMethod = FILE_BEGIN;

+    else if (whence == PJ_SEEK_CUR)

+        dwMoveMethod = FILE_CURRENT;

+    else if (whence == PJ_SEEK_END)

+        dwMoveMethod = FILE_END;

+    else {

+        pj_assert(!"Invalid whence in file_setpos");

+        return PJ_EINVAL;

+    }

+

+    hi32 = (LONG)(offset >> 32);

+    dwNewPos = SetFilePointer(fd, (long)offset, &hi32, dwMoveMethod);

+    if (dwNewPos == (DWORD)INVALID_SET_FILE_POINTER) {

+        DWORD dwStatus = GetLastError();

+        if (dwStatus != 0)

+            return PJ_RETURN_OS_ERROR(dwStatus);

+        /* dwNewPos actually is not an error. */

+    }

+

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd,

+                                    pj_off_t *pos)

+{

+    LONG hi32 = 0;

+    DWORD lo32;

+

+    lo32 = SetFilePointer(fd, 0, &hi32, FILE_CURRENT);

+    if (lo32 == (DWORD)INVALID_SET_FILE_POINTER) {

+        DWORD dwStatus = GetLastError();

+        if (dwStatus != 0)

+            return PJ_RETURN_OS_ERROR(dwStatus);

+    }

+

+    *pos = hi32;

+    *pos = (*pos << 32) + lo32;

+    return PJ_SUCCESS;

+}

+

diff --git a/pjlib/src/pj/guid.c b/pjlib/src/pj/guid.c
index a99b3a8..735ea88 100644
--- a/pjlib/src/pj/guid.c
+++ b/pjlib/src/pj/guid.c
@@ -1,10 +1,31 @@
-/* $Id$
- */
-#include <pj/guid.h>
-#include <pj/pool.h>
-
-PJ_DEF(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str)
-{
-    str->ptr = pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH);
-    pj_generate_unique_string(str);
-}
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/guid.h>

+#include <pj/pool.h>

+

+PJ_DEF(void) pj_create_unique_string(pj_pool_t *pool, pj_str_t *str)

+{

+    str->ptr = pj_pool_alloc(pool, PJ_GUID_STRING_LENGTH);

+    pj_generate_unique_string(str);

+}

diff --git a/pjlib/src/pj/guid_simple.c b/pjlib/src/pj/guid_simple.c
index 6e41672..4fb0a67 100644
--- a/pjlib/src/pj/guid_simple.c
+++ b/pjlib/src/pj/guid_simple.c
@@ -1,52 +1,73 @@
-/* $Id$
- *
- */
-#include <pj/guid.h>
-#include <pj/os.h>
-#include <pj/rand.h>
-#include <pj/string.h>
-#include <pj/compat/sprintf.h>
-
-const unsigned PJ_GUID_STRING_LENGTH=20;
-
-static void init_mac_address(unsigned char mac_addr[16])
-{
-    unsigned long *ulval1 = (unsigned long*) &mac_addr[0];
-    unsigned short *usval1 = (unsigned short*) &mac_addr[4];
-
-    *ulval1 = pj_rand();
-    *usval1 = (unsigned short) pj_rand();
-}
-
-PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
-{
-    static int guid_initialized;
-    static unsigned pid;
-    static char str_pid[5];
-    static unsigned char mac_addr[6];
-    static char str_mac_addr[16];
-    static unsigned clock_seq;
-
-    PJ_CHECK_STACK();
-
-    if (guid_initialized == 0) {
-	pid = pj_getpid();
-	init_mac_address(mac_addr);
-	clock_seq = 0;
-
-	sprintf(str_pid, "%04x", pid);
-	sprintf(str_mac_addr, "%02x%02x%02x%02x%02x%02x",
-	    mac_addr[0], mac_addr[1], mac_addr[2],
-	    mac_addr[3], mac_addr[4], mac_addr[5]);
-
-	guid_initialized = 1;
-    }
-
-    strcpy(str->ptr, str_pid);
-    sprintf(str->ptr+4, "%04x", clock_seq++);
-    pj_memcpy(str->ptr+8, str_mac_addr, 12);
-    str->slen = 20;
-
-    return str;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/guid.h>

+#include <pj/os.h>

+#include <pj/rand.h>

+#include <pj/string.h>

+#include <pj/compat/sprintf.h>

+

+const unsigned PJ_GUID_STRING_LENGTH=20;

+

+static void init_mac_address(unsigned char mac_addr[16])

+{

+    unsigned long *ulval1 = (unsigned long*) &mac_addr[0];

+    unsigned short *usval1 = (unsigned short*) &mac_addr[4];

+

+    *ulval1 = pj_rand();

+    *usval1 = (unsigned short) pj_rand();

+}

+

+PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)

+{

+    static int guid_initialized;

+    static unsigned pid;

+    static char str_pid[5];

+    static unsigned char mac_addr[6];

+    static char str_mac_addr[16];

+    static unsigned clock_seq;

+

+    PJ_CHECK_STACK();

+

+    if (guid_initialized == 0) {

+	pid = pj_getpid();

+	init_mac_address(mac_addr);

+	clock_seq = 0;

+

+	sprintf(str_pid, "%04x", pid);

+	sprintf(str_mac_addr, "%02x%02x%02x%02x%02x%02x",

+	    mac_addr[0], mac_addr[1], mac_addr[2],

+	    mac_addr[3], mac_addr[4], mac_addr[5]);

+

+	guid_initialized = 1;

+    }

+

+    strcpy(str->ptr, str_pid);

+    sprintf(str->ptr+4, "%04x", clock_seq++);

+    pj_memcpy(str->ptr+8, str_mac_addr, 12);

+    str->slen = 20;

+

+    return str;

+}

+

diff --git a/pjlib/src/pj/guid_win32.c b/pjlib/src/pj/guid_win32.c
index 0832b8c..b34b6e1 100644
--- a/pjlib/src/pj/guid_win32.c
+++ b/pjlib/src/pj/guid_win32.c
@@ -1,52 +1,73 @@
-/* $Id$
- */
-#include <pj/guid.h>
-#include <pj/string.h>
-#include <pj/sock.h>
-#include <windows.h>
-#include <objbase.h>
-#include <pj/os.h>
-
-
-const unsigned PJ_GUID_STRING_LENGTH=32;
-
-PJ_INLINE(void) hex2digit(unsigned value, char *p)
-{
-    static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
-			 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-    *p++ = hex[ (value & 0xF0) >> 4 ];
-    *p++ = hex[ (value & 0x0F) ];
-}
-
-static void guid_to_str( const GUID *guid, pj_str_t *str )
-{
-    unsigned i;
-    GUID guid_copy;
-    const unsigned char *src = (const unsigned char*)&guid_copy;
-    char *dst = str->ptr;
-
-    pj_memcpy(&guid_copy, guid, sizeof(*guid));
-    guid_copy.Data1 = pj_ntohl(guid_copy.Data1);
-    guid_copy.Data2 = pj_ntohs(guid_copy.Data2);
-    guid_copy.Data3 = pj_ntohs(guid_copy.Data3);
-
-    for (i=0; i<16; ++i) {
-	hex2digit( *src, dst );
-	dst += 2;
-	++src;
-    }
-    str->slen = 32;
-}
-
-
-PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)
-{
-    GUID guid;
-
-    PJ_CHECK_STACK();
-
-    CoCreateGuid(&guid);
-    guid_to_str( &guid, str );
-    return str;
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/guid.h>

+#include <pj/string.h>

+#include <pj/sock.h>

+#include <windows.h>

+#include <objbase.h>

+#include <pj/os.h>

+

+

+const unsigned PJ_GUID_STRING_LENGTH=32;

+

+PJ_INLINE(void) hex2digit(unsigned value, char *p)

+{

+    static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',

+			 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

+    *p++ = hex[ (value & 0xF0) >> 4 ];

+    *p++ = hex[ (value & 0x0F) ];

+}

+

+static void guid_to_str( const GUID *guid, pj_str_t *str )

+{

+    unsigned i;

+    GUID guid_copy;

+    const unsigned char *src = (const unsigned char*)&guid_copy;

+    char *dst = str->ptr;

+

+    pj_memcpy(&guid_copy, guid, sizeof(*guid));

+    guid_copy.Data1 = pj_ntohl(guid_copy.Data1);

+    guid_copy.Data2 = pj_ntohs(guid_copy.Data2);

+    guid_copy.Data3 = pj_ntohs(guid_copy.Data3);

+

+    for (i=0; i<16; ++i) {

+	hex2digit( *src, dst );

+	dst += 2;

+	++src;

+    }

+    str->slen = 32;

+}

+

+

+PJ_DEF(pj_str_t*) pj_generate_unique_string(pj_str_t *str)

+{

+    GUID guid;

+

+    PJ_CHECK_STACK();

+

+    CoCreateGuid(&guid);

+    guid_to_str( &guid, str );

+    return str;

+}

+

diff --git a/pjlib/src/pj/hash.c b/pjlib/src/pj/hash.c
index 195c881..499032c 100644
--- a/pjlib/src/pj/hash.c
+++ b/pjlib/src/pj/hash.c
@@ -1,55 +1,77 @@
-/* $Id$
- */
-#include <pj/hash.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/pool.h>
-#include <pj/os.h>
-
-/**
- * The hash multiplier used to calculate hash value.
- */
-#define PJ_HASH_MULTIPLIER	33
-
-
-struct pj_hash_entry
-{
-    struct pj_hash_entry *next;
-    const void *key;
-    pj_uint32_t hash;
-    pj_uint32_t keylen;
-    void *value;
-};
-
-
-struct pj_hash_table_t
-{
-    pj_hash_entry     **table;
-    unsigned		count, rows;
-    pj_hash_iterator_t	iterator;
-};
-
-
-
-PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned keylen)
-{
-    PJ_CHECK_STACK();
-
-    if (keylen==PJ_HASH_KEY_STRING) {
-	const unsigned char *p = key;
-	for ( ; *p; ++p ) {
-	    hash = hash * PJ_HASH_MULTIPLIER + *p;
-	}
-	keylen = p - (const unsigned char*)key;
-    } else {
-	const unsigned char *p = key,
-			    *end = p + keylen;
-	for ( ; p!=end; ++p) {
-	    hash = hash * PJ_HASH_MULTIPLIER + *p;
-	}
-    }
-    return hash;
-}
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/hash.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/pool.h>

+#include <pj/os.h>

+#include <pj/ctype.h>

+

+/**

+ * The hash multiplier used to calculate hash value.

+ */

+#define PJ_HASH_MULTIPLIER	33

+

+

+struct pj_hash_entry

+{

+    struct pj_hash_entry *next;

+    const void *key;

+    pj_uint32_t hash;

+    pj_uint32_t keylen;

+    void *value;

+};

+

+

+struct pj_hash_table_t

+{

+    pj_hash_entry     **table;

+    unsigned		count, rows;

+    pj_hash_iterator_t	iterator;

+};

+

+

+

+PJ_DEF(pj_uint32_t) pj_hash_calc(pj_uint32_t hash, const void *key, unsigned keylen)

+{

+    PJ_CHECK_STACK();

+

+    if (keylen==PJ_HASH_KEY_STRING) {

+	const unsigned char *p = key;

+	for ( ; *p; ++p ) {

+	    hash = hash * PJ_HASH_MULTIPLIER + *p;

+	}

+	keylen = p - (const unsigned char*)key;

+    } else {

+	const unsigned char *p = key,

+			    *end = p + keylen;

+	for ( ; p!=end; ++p) {

+	    hash = hash * PJ_HASH_MULTIPLIER + *p;

+	}

+    }

+    return hash;

+}

 

 PJ_DEF(pj_uint32_t) pj_hash_calc_tolower( pj_uint32_t hval,

                                           char *result,

@@ -64,194 +86,194 @@
 

     return hval;

 }

-
-
-PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size)
-{
-    pj_hash_table_t *h;
-    unsigned table_size;
-    
-    h = pj_pool_alloc(pool, sizeof(pj_hash_table_t));
-    h->count = 0;
-
-    PJ_LOG( 5, ("hashtbl", "hash table %p created from pool %s", h, pj_pool_getobjname(pool)));
-
-    /* size must be 2^n - 1.
-       round-up the size to this rule, except when size is 2^n, then size
-       will be round-down to 2^n-1.
-     */
-    table_size = 8;
-    do {
-	table_size <<= 1;    
-    } while (table_size <= size);
-    table_size -= 1;
-    
-    h->rows = table_size;
-    h->table = pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*));
-    return h;
-}
-
-static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, 
-				   const void *key, unsigned keylen,
-				   void *val)
-{
-    pj_uint32_t hash;
-    pj_hash_entry **p_entry, *entry;
-
-    hash=0;
-    if (keylen==PJ_HASH_KEY_STRING) {
-	const unsigned char *p = key;
-	for ( ; *p; ++p ) {
-	    hash = hash * PJ_HASH_MULTIPLIER + *p;
-	}
-	keylen = p - (const unsigned char*)key;
-    } else {
-	const unsigned char *p = key,
-			    *end = p + keylen;
-	for ( ; p!=end; ++p) {
-	    hash = hash * PJ_HASH_MULTIPLIER + *p;
-	}
-    }
-
-    /* scan the linked list */
-    for (p_entry = &ht->table[hash & ht->rows], entry=*p_entry; 
-	 entry; 
-	 p_entry = &entry->next, entry = *p_entry)
-    {
-	if (entry->hash==hash && entry->keylen==keylen &&
-	    memcmp(entry->key, key, keylen)==0) 
-	{
-	    break;	
-	}
-    }
-
-    if (entry || val==NULL)
-	return p_entry;
-
-    /* create a new entry */
-    entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));
-    PJ_LOG(5, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry, 
-			  pj_pool_get_used_size(pool), pj_pool_get_capacity(pool)));
-    entry->next = NULL;
-    entry->hash = hash;
-    entry->key = key;
-    entry->keylen = keylen;
-    entry->value = val;
-    *p_entry = entry;
-    
-    ++ht->count;
-    
-    return p_entry;
-}
-
-PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht,
-			    const void *key, unsigned keylen )
-{
-    pj_hash_entry *entry;
-    entry = *find_entry( NULL, ht, key, keylen, NULL);
-    return entry ? entry->value : NULL;
-}
-
-PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,
-			  const void *key, unsigned keylen,
-			  void *value )
-{
-    pj_hash_entry **p_entry;
-
-    p_entry = find_entry( pool, ht, key, keylen, value );
-    if (*p_entry) {
-	if (value == NULL) {
-	    /* delete entry */
-	    PJ_LOG(5, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry));
-	    *p_entry = (*p_entry)->next;
-	    --ht->count;
-	    
-	} else {
-	    /* overwrite */
-	    (*p_entry)->value = value;
-	    PJ_LOG(5, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value));
-	}
-    }
-}
-
-PJ_DEF(unsigned) pj_hash_count( pj_hash_table_t *ht )
-{
-    return ht->count;
-}
-
-PJ_DEF(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,
-					   pj_hash_iterator_t *it )
-{
-    it->index = 0;
-    it->entry = NULL;
-
-    for (; it->index < ht->rows; ++it->index) {
-	it->entry = ht->table[it->index];
-	if (it->entry) {
-	    break;
-	}
-    }
-
-    return it->entry ? it : NULL;
-}
-
-PJ_DEF(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, 
-					  pj_hash_iterator_t *it )
-{
-    it->entry = it->entry->next;
-    if (it->entry) {
-	return it;
-    }
-
-    for (++it->index; it->index < ht->rows; ++it->index) {
-	it->entry = ht->table[it->index];
-	if (it->entry) {
-	    break;
-	}
-    }
-
-    return it->entry ? it : NULL;
-}
-
-PJ_DEF(void*) pj_hash_this( pj_hash_table_t *ht, pj_hash_iterator_t *it )
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(ht);
-    return it->entry->value;
-}
-
-#if 0
-void pj_hash_dump_collision( pj_hash_table_t *ht )
-{
-    unsigned min=0xFFFFFFFF, max=0;
-    unsigned i;
-    char line[120];
-    int len, totlen = 0;
-
-    for (i=0; i<ht->rows; ++i) {
-	unsigned count = 0;    
-	pj_hash_entry *entry = ht->table[i];
-	while (entry) {
-	    ++count;
-	    entry = entry->next;
-	}
-	if (count < min)
-	    min = count;
-	if (count > max)
-	    max = count;
-	len = pj_snprintf( line+totlen, sizeof(line)-totlen, "%3d:%3d ", i, count);
-	if (len < 1)
-	    break;
-	totlen += len;
-
-	if ((i+1) % 10 == 0) {
-	    line[totlen] = '\0';
-	    PJ_LOG(4,(__FILE__, line));
-	}
-    }
-
-    PJ_LOG(4,(__FILE__,"Count: %d, min: %d, max: %d\n", ht->count, min, max));
-}
-#endif
-
-
+

+

+PJ_DEF(pj_hash_table_t*) pj_hash_create(pj_pool_t *pool, unsigned size)

+{

+    pj_hash_table_t *h;

+    unsigned table_size;

+    

+    h = pj_pool_alloc(pool, sizeof(pj_hash_table_t));

+    h->count = 0;

+

+    PJ_LOG( 5, ("hashtbl", "hash table %p created from pool %s", h, pj_pool_getobjname(pool)));

+

+    /* size must be 2^n - 1.

+       round-up the size to this rule, except when size is 2^n, then size

+       will be round-down to 2^n-1.

+     */

+    table_size = 8;

+    do {

+	table_size <<= 1;    

+    } while (table_size <= size);

+    table_size -= 1;

+    

+    h->rows = table_size;

+    h->table = pj_pool_calloc(pool, table_size+1, sizeof(pj_hash_entry*));

+    return h;

+}

+

+static pj_hash_entry **find_entry( pj_pool_t *pool, pj_hash_table_t *ht, 

+				   const void *key, unsigned keylen,

+				   void *val)

+{

+    pj_uint32_t hash;

+    pj_hash_entry **p_entry, *entry;

+

+    hash=0;

+    if (keylen==PJ_HASH_KEY_STRING) {

+	const unsigned char *p = key;

+	for ( ; *p; ++p ) {

+	    hash = hash * PJ_HASH_MULTIPLIER + *p;

+	}

+	keylen = p - (const unsigned char*)key;

+    } else {

+	const unsigned char *p = key,

+			    *end = p + keylen;

+	for ( ; p!=end; ++p) {

+	    hash = hash * PJ_HASH_MULTIPLIER + *p;

+	}

+    }

+

+    /* scan the linked list */

+    for (p_entry = &ht->table[hash & ht->rows], entry=*p_entry; 

+	 entry; 

+	 p_entry = &entry->next, entry = *p_entry)

+    {

+	if (entry->hash==hash && entry->keylen==keylen &&

+	    memcmp(entry->key, key, keylen)==0) 

+	{

+	    break;	

+	}

+    }

+

+    if (entry || val==NULL)

+	return p_entry;

+

+    /* create a new entry */

+    entry = pj_pool_alloc(pool, sizeof(pj_hash_entry));

+    PJ_LOG(5, ("hashtbl", "%p: New p_entry %p created, pool used=%u, cap=%u", ht, entry, 

+			  pj_pool_get_used_size(pool), pj_pool_get_capacity(pool)));

+    entry->next = NULL;

+    entry->hash = hash;

+    entry->key = key;

+    entry->keylen = keylen;

+    entry->value = val;

+    *p_entry = entry;

+    

+    ++ht->count;

+    

+    return p_entry;

+}

+

+PJ_DEF(void *) pj_hash_get( pj_hash_table_t *ht,

+			    const void *key, unsigned keylen )

+{

+    pj_hash_entry *entry;

+    entry = *find_entry( NULL, ht, key, keylen, NULL);

+    return entry ? entry->value : NULL;

+}

+

+PJ_DEF(void) pj_hash_set( pj_pool_t *pool, pj_hash_table_t *ht,

+			  const void *key, unsigned keylen,

+			  void *value )

+{

+    pj_hash_entry **p_entry;

+

+    p_entry = find_entry( pool, ht, key, keylen, value );

+    if (*p_entry) {

+	if (value == NULL) {

+	    /* delete entry */

+	    PJ_LOG(5, ("hashtbl", "%p: p_entry %p deleted", ht, *p_entry));

+	    *p_entry = (*p_entry)->next;

+	    --ht->count;

+	    

+	} else {

+	    /* overwrite */

+	    (*p_entry)->value = value;

+	    PJ_LOG(5, ("hashtbl", "%p: p_entry %p value set to %p", ht, *p_entry, value));

+	}

+    }

+}

+

+PJ_DEF(unsigned) pj_hash_count( pj_hash_table_t *ht )

+{

+    return ht->count;

+}

+

+PJ_DEF(pj_hash_iterator_t*) pj_hash_first( pj_hash_table_t *ht,

+					   pj_hash_iterator_t *it )

+{

+    it->index = 0;

+    it->entry = NULL;

+

+    for (; it->index < ht->rows; ++it->index) {

+	it->entry = ht->table[it->index];

+	if (it->entry) {

+	    break;

+	}

+    }

+

+    return it->entry ? it : NULL;

+}

+

+PJ_DEF(pj_hash_iterator_t*) pj_hash_next( pj_hash_table_t *ht, 

+					  pj_hash_iterator_t *it )

+{

+    it->entry = it->entry->next;

+    if (it->entry) {

+	return it;

+    }

+

+    for (++it->index; it->index < ht->rows; ++it->index) {

+	it->entry = ht->table[it->index];

+	if (it->entry) {

+	    break;

+	}

+    }

+

+    return it->entry ? it : NULL;

+}

+

+PJ_DEF(void*) pj_hash_this( pj_hash_table_t *ht, pj_hash_iterator_t *it )

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(ht);

+    return it->entry->value;

+}

+

+#if 0

+void pj_hash_dump_collision( pj_hash_table_t *ht )

+{

+    unsigned min=0xFFFFFFFF, max=0;

+    unsigned i;

+    char line[120];

+    int len, totlen = 0;

+

+    for (i=0; i<ht->rows; ++i) {

+	unsigned count = 0;    

+	pj_hash_entry *entry = ht->table[i];

+	while (entry) {

+	    ++count;

+	    entry = entry->next;

+	}

+	if (count < min)

+	    min = count;

+	if (count > max)

+	    max = count;

+	len = pj_snprintf( line+totlen, sizeof(line)-totlen, "%3d:%3d ", i, count);

+	if (len < 1)

+	    break;

+	totlen += len;

+

+	if ((i+1) % 10 == 0) {

+	    line[totlen] = '\0';

+	    PJ_LOG(4,(__FILE__, line));

+	}

+    }

+

+    PJ_LOG(4,(__FILE__,"Count: %d, min: %d, max: %d\n", ht->count, min, max));

+}

+#endif

+

+

diff --git a/pjlib/src/pj/ioqueue_common_abs.c b/pjlib/src/pj/ioqueue_common_abs.c
index c2e1121..ed71772 100644
--- a/pjlib/src/pj/ioqueue_common_abs.c
+++ b/pjlib/src/pj/ioqueue_common_abs.c
@@ -1,837 +1,858 @@
-/* $Id$ */
-
-/*
- * ioqueue_common_abs.c
- *
- * This contains common functionalities to emulate proactor pattern with
- * various event dispatching mechanisms (e.g. select, epoll).
- *
- * This file will be included by the appropriate ioqueue implementation.
- * This file is NOT supposed to be compiled as stand-alone source.
- */
-
-static void ioqueue_init( pj_ioqueue_t *ioqueue )
-{
-    ioqueue->lock = NULL;
-    ioqueue->auto_delete_lock = 0;
-}
-
-static pj_status_t ioqueue_destroy(pj_ioqueue_t *ioqueue)
-{
-    if (ioqueue->auto_delete_lock && ioqueue->lock ) {
-	pj_lock_release(ioqueue->lock);
-        return pj_lock_destroy(ioqueue->lock);
-    } else
-        return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_set_lock()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue, 
-					 pj_lock_t *lock,
-					 pj_bool_t auto_delete )
-{
-    PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);
-
-    if (ioqueue->auto_delete_lock && ioqueue->lock) {
-        pj_lock_destroy(ioqueue->lock);
-    }
-
-    ioqueue->lock = lock;
-    ioqueue->auto_delete_lock = auto_delete;
-
-    return PJ_SUCCESS;
-}
-
-static pj_status_t ioqueue_init_key( pj_pool_t *pool,
-                                     pj_ioqueue_t *ioqueue,
-                                     pj_ioqueue_key_t *key,
-                                     pj_sock_t sock,
-                                     void *user_data,
-                                     const pj_ioqueue_callback *cb)
-{
-    pj_status_t rc;
-    int optlen;
-
-    key->ioqueue = ioqueue;
-    key->fd = sock;
-    key->user_data = user_data;
-    pj_list_init(&key->read_list);
-    pj_list_init(&key->write_list);
-#if PJ_HAS_TCP
-    pj_list_init(&key->accept_list);
-#endif
-
-    /* Save callback. */
-    pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback));
-
-    /* Get socket type. When socket type is datagram, some optimization
-     * will be performed during send to allow parallel send operations.
-     */
-    optlen = sizeof(key->fd_type);
-    rc = pj_sock_getsockopt(sock, PJ_SOL_SOCKET, PJ_SO_TYPE,
-                            &key->fd_type, &optlen);
-    if (rc != PJ_SUCCESS)
-        key->fd_type = PJ_SOCK_STREAM;
-
-    /* Create mutex for the key. */
-    rc = pj_mutex_create_simple(pool, NULL, &key->mutex);
-    
-    return rc;
-}
-
-static void ioqueue_destroy_key( pj_ioqueue_key_t *key )
-{
-    pj_mutex_destroy(key->mutex);
-}
-
-/*
- * pj_ioqueue_get_user_data()
- *
- * Obtain value associated with a key.
- */
-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
-{
-    PJ_ASSERT_RETURN(key != NULL, NULL);
-    return key->user_data;
-}
-
-/*
- * pj_ioqueue_set_user_data()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
-                                              void *user_data,
-                                              void **old_data)
-{
-    PJ_ASSERT_RETURN(key, PJ_EINVAL);
-
-    if (old_data)
-        *old_data = key->user_data;
-    key->user_data = user_data;
-
-    return PJ_SUCCESS;
-}
-
-PJ_INLINE(int) key_has_pending_write(pj_ioqueue_key_t *key)
-{
-    return !pj_list_empty(&key->write_list);
-}
-
-PJ_INLINE(int) key_has_pending_read(pj_ioqueue_key_t *key)
-{
-    return !pj_list_empty(&key->read_list);
-}
-
-PJ_INLINE(int) key_has_pending_accept(pj_ioqueue_key_t *key)
-{
-#if PJ_HAS_TCP
-    return !pj_list_empty(&key->accept_list);
-#else
-    return 0;
-#endif
-}
-
-PJ_INLINE(int) key_has_pending_connect(pj_ioqueue_key_t *key)
-{
-    return key->connecting;
-}
-
-
-/*
- * ioqueue_dispatch_event()
- *
- * Report occurence of an event in the key to be processed by the
- * framework.
- */
-void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)
-{
-    /* Lock the key. */
-    pj_mutex_lock(h->mutex);
-
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
-    if (h->connecting) {
-	/* Completion of connect() operation */
-	pj_ssize_t bytes_transfered;
-
-	/* Clear operation. */
-	h->connecting = 0;
-
-        ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
-        ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);
-
-        /* Unlock; from this point we don't need to hold key's mutex. */
-        pj_mutex_unlock(h->mutex);
-
-#if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0)
-	/* from connect(2): 
-	 * On Linux, use getsockopt to read the SO_ERROR option at
-	 * level SOL_SOCKET to determine whether connect() completed
-	 * successfully (if SO_ERROR is zero).
-	 */
-	{
-	  int value;
-	  socklen_t vallen = sizeof(value);
-	  int gs_rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, 
-                               &value, &vallen);
-	  if (gs_rc != 0) {
-	    /* Argh!! What to do now??? 
-	     * Just indicate that the socket is connected. The
-	     * application will get error as soon as it tries to use
-	     * the socket to send/receive.
-	     */
-	    bytes_transfered = 0;
-	  } else {
-            bytes_transfered = value;
-	  }
- 	}
-#elif defined(PJ_WIN32) && PJ_WIN32!=0
-	bytes_transfered = 0; /* success */
-#else
-	/* Excellent information in D.J. Bernstein page:
-	 * http://cr.yp.to/docs/connect.html
-	 *
-	 * Seems like the most portable way of detecting connect()
-	 * failure is to call getpeername(). If socket is connected,
-	 * getpeername() will return 0. If the socket is not connected,
-	 * it will return ENOTCONN, and read(fd, &ch, 1) will produce
-	 * the right errno through error slippage. This is a combination
-	 * of suggestions from Douglas C. Schmidt and Ken Keys.
-	 */
-	int gp_rc;
-	struct sockaddr_in addr;
-	socklen_t addrlen = sizeof(addr);
-
-	gp_rc = getpeername(h->fd, (struct sockaddr*)&addr, &addrlen);
-	bytes_transfered = gp_rc;
-#endif
-
-	/* Call callback. */
-        if (h->cb.on_connect_complete)
-	    (*h->cb.on_connect_complete)(h, bytes_transfered);
-
-        /* Done. */
-
-    } else 
-#endif /* PJ_HAS_TCP */
-    if (key_has_pending_write(h)) {
-	/* Socket is writable. */
-        struct write_operation *write_op;
-        pj_ssize_t sent;
-        pj_status_t send_rc;
-
-        /* Get the first in the queue. */
-        write_op = h->write_list.next;
-
-        /* For datagrams, we can remove the write_op from the list
-         * so that send() can work in parallel.
-         */
-        if (h->fd_type == PJ_SOCK_DGRAM) {
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/*

+ * ioqueue_common_abs.c

+ *

+ * This contains common functionalities to emulate proactor pattern with

+ * various event dispatching mechanisms (e.g. select, epoll).

+ *

+ * This file will be included by the appropriate ioqueue implementation.

+ * This file is NOT supposed to be compiled as stand-alone source.

+ */

+

+static void ioqueue_init( pj_ioqueue_t *ioqueue )

+{

+    ioqueue->lock = NULL;

+    ioqueue->auto_delete_lock = 0;

+}

+

+static pj_status_t ioqueue_destroy(pj_ioqueue_t *ioqueue)

+{

+    if (ioqueue->auto_delete_lock && ioqueue->lock ) {

+	pj_lock_release(ioqueue->lock);

+        return pj_lock_destroy(ioqueue->lock);

+    } else

+        return PJ_SUCCESS;

+}

+

+/*

+ * pj_ioqueue_set_lock()

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue, 

+					 pj_lock_t *lock,

+					 pj_bool_t auto_delete )

+{

+    PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);

+

+    if (ioqueue->auto_delete_lock && ioqueue->lock) {

+        pj_lock_destroy(ioqueue->lock);

+    }

+

+    ioqueue->lock = lock;

+    ioqueue->auto_delete_lock = auto_delete;

+

+    return PJ_SUCCESS;

+}

+

+static pj_status_t ioqueue_init_key( pj_pool_t *pool,

+                                     pj_ioqueue_t *ioqueue,

+                                     pj_ioqueue_key_t *key,

+                                     pj_sock_t sock,

+                                     void *user_data,

+                                     const pj_ioqueue_callback *cb)

+{

+    pj_status_t rc;

+    int optlen;

+

+    key->ioqueue = ioqueue;

+    key->fd = sock;

+    key->user_data = user_data;

+    pj_list_init(&key->read_list);

+    pj_list_init(&key->write_list);

+#if PJ_HAS_TCP

+    pj_list_init(&key->accept_list);

+#endif

+

+    /* Save callback. */

+    pj_memcpy(&key->cb, cb, sizeof(pj_ioqueue_callback));

+

+    /* Get socket type. When socket type is datagram, some optimization

+     * will be performed during send to allow parallel send operations.

+     */

+    optlen = sizeof(key->fd_type);

+    rc = pj_sock_getsockopt(sock, PJ_SOL_SOCKET, PJ_SO_TYPE,

+                            &key->fd_type, &optlen);

+    if (rc != PJ_SUCCESS)

+        key->fd_type = PJ_SOCK_STREAM;

+

+    /* Create mutex for the key. */

+    rc = pj_mutex_create_simple(pool, NULL, &key->mutex);

+    

+    return rc;

+}

+

+static void ioqueue_destroy_key( pj_ioqueue_key_t *key )

+{

+    pj_mutex_destroy(key->mutex);

+}

+

+/*

+ * pj_ioqueue_get_user_data()

+ *

+ * Obtain value associated with a key.

+ */

+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )

+{

+    PJ_ASSERT_RETURN(key != NULL, NULL);

+    return key->user_data;

+}

+

+/*

+ * pj_ioqueue_set_user_data()

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,

+                                              void *user_data,

+                                              void **old_data)

+{

+    PJ_ASSERT_RETURN(key, PJ_EINVAL);

+

+    if (old_data)

+        *old_data = key->user_data;

+    key->user_data = user_data;

+

+    return PJ_SUCCESS;

+}

+

+PJ_INLINE(int) key_has_pending_write(pj_ioqueue_key_t *key)

+{

+    return !pj_list_empty(&key->write_list);

+}

+

+PJ_INLINE(int) key_has_pending_read(pj_ioqueue_key_t *key)

+{

+    return !pj_list_empty(&key->read_list);

+}

+

+PJ_INLINE(int) key_has_pending_accept(pj_ioqueue_key_t *key)

+{

+#if PJ_HAS_TCP

+    return !pj_list_empty(&key->accept_list);

+#else

+    return 0;

+#endif

+}

+

+PJ_INLINE(int) key_has_pending_connect(pj_ioqueue_key_t *key)

+{

+    return key->connecting;

+}

+

+

+/*

+ * ioqueue_dispatch_event()

+ *

+ * Report occurence of an event in the key to be processed by the

+ * framework.

+ */

+void ioqueue_dispatch_write_event(pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h)

+{

+    /* Lock the key. */

+    pj_mutex_lock(h->mutex);

+

+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0

+    if (h->connecting) {

+	/* Completion of connect() operation */

+	pj_ssize_t bytes_transfered;

+

+	/* Clear operation. */

+	h->connecting = 0;

+

+        ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);

+        ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);

+

+        /* Unlock; from this point we don't need to hold key's mutex. */

+        pj_mutex_unlock(h->mutex);

+

+#if (defined(PJ_HAS_SO_ERROR) && PJ_HAS_SO_ERROR!=0)

+	/* from connect(2): 

+	 * On Linux, use getsockopt to read the SO_ERROR option at

+	 * level SOL_SOCKET to determine whether connect() completed

+	 * successfully (if SO_ERROR is zero).

+	 */

+	{

+	  int value;

+	  socklen_t vallen = sizeof(value);

+	  int gs_rc = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, 

+                               &value, &vallen);

+	  if (gs_rc != 0) {

+	    /* Argh!! What to do now??? 

+	     * Just indicate that the socket is connected. The

+	     * application will get error as soon as it tries to use

+	     * the socket to send/receive.

+	     */

+	    bytes_transfered = 0;

+	  } else {

+            bytes_transfered = value;

+	  }

+ 	}

+#elif defined(PJ_WIN32) && PJ_WIN32!=0

+	bytes_transfered = 0; /* success */

+#else

+	/* Excellent information in D.J. Bernstein page:

+	 * http://cr.yp.to/docs/connect.html

+	 *

+	 * Seems like the most portable way of detecting connect()

+	 * failure is to call getpeername(). If socket is connected,

+	 * getpeername() will return 0. If the socket is not connected,

+	 * it will return ENOTCONN, and read(fd, &ch, 1) will produce

+	 * the right errno through error slippage. This is a combination

+	 * of suggestions from Douglas C. Schmidt and Ken Keys.

+	 */

+	int gp_rc;

+	struct sockaddr_in addr;

+	socklen_t addrlen = sizeof(addr);

+

+	gp_rc = getpeername(h->fd, (struct sockaddr*)&addr, &addrlen);

+	bytes_transfered = gp_rc;

+#endif

+

+	/* Call callback. */

+        if (h->cb.on_connect_complete)

+	    (*h->cb.on_connect_complete)(h, bytes_transfered);

+

+        /* Done. */

+

+    } else 

+#endif /* PJ_HAS_TCP */

+    if (key_has_pending_write(h)) {

+	/* Socket is writable. */

+        struct write_operation *write_op;

+        pj_ssize_t sent;

+        pj_status_t send_rc;

+

+        /* Get the first in the queue. */

+        write_op = h->write_list.next;

+

+        /* For datagrams, we can remove the write_op from the list

+         * so that send() can work in parallel.

+         */

+        if (h->fd_type == PJ_SOCK_DGRAM) {

             pj_list_erase(write_op);

             write_op->op = 0;

-
-            if (pj_list_empty(&h->write_list))
-                ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
-
-            pj_mutex_unlock(h->mutex);
-        }
-
-        /* Send the data. 
-         * Unfortunately we must do this while holding key's mutex, thus
-         * preventing parallel write on a single key.. :-((
-         */
-        sent = write_op->size - write_op->written;
-        if (write_op->op == PJ_IOQUEUE_OP_SEND) {
-            send_rc = pj_sock_send(h->fd, write_op->buf+write_op->written,
-                                   &sent, write_op->flags);
-        } else if (write_op->op == PJ_IOQUEUE_OP_SEND_TO) {
-            send_rc = pj_sock_sendto(h->fd, 
-                                     write_op->buf+write_op->written,
-                                     &sent, write_op->flags,
-                                     &write_op->rmt_addr, 
-                                     write_op->rmt_addrlen);
-        } else {
-            pj_assert(!"Invalid operation type!");
-            send_rc = PJ_EBUG;
-        }
-
-        if (send_rc == PJ_SUCCESS) {
-            write_op->written += sent;
-        } else {
-            pj_assert(send_rc > 0);
-            write_op->written = -send_rc;
-        }
-
-        /* Are we finished with this buffer? */
-        if (send_rc!=PJ_SUCCESS || 
-            write_op->written == (pj_ssize_t)write_op->size ||
-            h->fd_type == PJ_SOCK_DGRAM) 
-        {
-            if (h->fd_type != PJ_SOCK_DGRAM) {
-                /* Write completion of the whole stream. */
+

+            if (pj_list_empty(&h->write_list))

+                ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);

+

+            pj_mutex_unlock(h->mutex);

+        }

+

+        /* Send the data. 

+         * Unfortunately we must do this while holding key's mutex, thus

+         * preventing parallel write on a single key.. :-((

+         */

+        sent = write_op->size - write_op->written;

+        if (write_op->op == PJ_IOQUEUE_OP_SEND) {

+            send_rc = pj_sock_send(h->fd, write_op->buf+write_op->written,

+                                   &sent, write_op->flags);

+        } else if (write_op->op == PJ_IOQUEUE_OP_SEND_TO) {

+            send_rc = pj_sock_sendto(h->fd, 

+                                     write_op->buf+write_op->written,

+                                     &sent, write_op->flags,

+                                     &write_op->rmt_addr, 

+                                     write_op->rmt_addrlen);

+        } else {

+            pj_assert(!"Invalid operation type!");

+            send_rc = PJ_EBUG;

+        }

+

+        if (send_rc == PJ_SUCCESS) {

+            write_op->written += sent;

+        } else {

+            pj_assert(send_rc > 0);

+            write_op->written = -send_rc;

+        }

+

+        /* Are we finished with this buffer? */

+        if (send_rc!=PJ_SUCCESS || 

+            write_op->written == (pj_ssize_t)write_op->size ||

+            h->fd_type == PJ_SOCK_DGRAM) 

+        {

+            if (h->fd_type != PJ_SOCK_DGRAM) {

+                /* Write completion of the whole stream. */

                 pj_list_erase(write_op);

-                write_op->op = 0;
-
-                /* Clear operation if there's no more data to send. */
-                if (pj_list_empty(&h->write_list))
-                    ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
-
-                /* No need to hold mutex anymore */
-                pj_mutex_unlock(h->mutex);
-            }
-
-	    /* Call callback. */
-            if (h->cb.on_write_complete) {
-	        (*h->cb.on_write_complete)(h, 
-                                           (pj_ioqueue_op_key_t*)write_op,
-                                           write_op->written);
-            }
-
-        } else {
-            pj_mutex_unlock(h->mutex);
-        }
-
-        /* Done. */
-    } else {
-        /*
-         * This is normal; execution may fall here when multiple threads

-         * are signalled for the same event, but only one thread eventually

-         * able to process the event.

-         */
-        pj_mutex_unlock(h->mutex);
-    }
-}
-
-void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )
-{
-    pj_status_t rc;
-
-    /* Lock the key. */
-    pj_mutex_lock(h->mutex);
-
-#   if PJ_HAS_TCP
-    if (!pj_list_empty(&h->accept_list)) {
-
-        struct accept_operation *accept_op;
-	
-        /* Get one accept operation from the list. */
-	accept_op = h->accept_list.next;
-        pj_list_erase(accept_op);

-        accept_op->op = 0;
-
-	/* Clear bit in fdset if there is no more pending accept */
-        if (pj_list_empty(&h->accept_list))
-            ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);
-
-        /* Unlock; from this point we don't need to hold key's mutex. */
-        pj_mutex_unlock(h->mutex);
-
-	rc=pj_sock_accept(h->fd, accept_op->accept_fd, 
-                          accept_op->rmt_addr, accept_op->addrlen);
-	if (rc==PJ_SUCCESS && accept_op->local_addr) {
-	    rc = pj_sock_getsockname(*accept_op->accept_fd, 
-                                     accept_op->local_addr,
-				     accept_op->addrlen);
-	}
-
-	/* Call callback. */
-        if (h->cb.on_accept_complete) {
-	    (*h->cb.on_accept_complete)(h, 
-                                        (pj_ioqueue_op_key_t*)accept_op,
-                                        *accept_op->accept_fd, rc);
-	}
-
-    }
-    else
-#   endif
-    if (key_has_pending_read(h)) {
-        struct read_operation *read_op;
-        pj_ssize_t bytes_read;
-
-        /* Get one pending read operation from the list. */
-        read_op = h->read_list.next;
-        pj_list_erase(read_op);

-        read_op->op = 0;
-
-        /* Clear fdset if there is no pending read. */
-        if (pj_list_empty(&h->read_list))
-            ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);
-
-        /* Unlock; from this point we don't need to hold key's mutex. */
-        pj_mutex_unlock(h->mutex);
-
-        bytes_read = read_op->size;
-
-	if ((read_op->op == PJ_IOQUEUE_OP_RECV_FROM)) {
-	    rc = pj_sock_recvfrom(h->fd, read_op->buf, &bytes_read, 0,
-				  read_op->rmt_addr, 
-                                  read_op->rmt_addrlen);
-	} else if ((read_op->op == PJ_IOQUEUE_OP_RECV)) {
-	    rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);
-        } else {
-            pj_assert(read_op->op == PJ_IOQUEUE_OP_READ);
-            /*
-             * User has specified pj_ioqueue_read().
-             * On Win32, we should do ReadFile(). But because we got
-             * here because of select() anyway, user must have put a
-             * socket descriptor on h->fd, which in this case we can
-             * just call pj_sock_recv() instead of ReadFile().
-             * On Unix, user may put a file in h->fd, so we'll have
-             * to call read() here.
-             * This may not compile on systems which doesn't have 
-             * read(). That's why we only specify PJ_LINUX here so
-             * that error is easier to catch.
-             */
-#	    if defined(PJ_WIN32) && PJ_WIN32 != 0
-                rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);
-                //rc = ReadFile((HANDLE)h->fd, read_op->buf, read_op->size,
-                //              &bytes_read, NULL);
-#           elif (defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0)
-                bytes_read = read(h->fd, read_op->buf, bytes_read);
-                rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error();
-#	    elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0
-                bytes_read = sys_read(h->fd, read_op->buf, bytes_read);
-                rc = (bytes_read >= 0) ? PJ_SUCCESS : -bytes_read;
-#           else
-#               error "Implement read() for this platform!"
-#           endif
-        }
-	
-	if (rc != PJ_SUCCESS) {
-#	    if defined(PJ_WIN32) && PJ_WIN32 != 0
-	    /* On Win32, for UDP, WSAECONNRESET on the receive side 
-	     * indicates that previous sending has triggered ICMP Port 
-	     * Unreachable message.
-	     * But we wouldn't know at this point which one of previous 
-	     * key that has triggered the error, since UDP socket can
-	     * be shared!
-	     * So we'll just ignore it!
-	     */
-
-	    if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) {
-		//PJ_LOG(4,(THIS_FILE, 
-                //          "Ignored ICMP port unreach. on key=%p", h));
-	    }
-#	    endif
-
-            /* In any case we would report this to caller. */
-            bytes_read = -rc;
-	}
-
-	/* Call callback. */
-        if (h->cb.on_read_complete) {
-	    (*h->cb.on_read_complete)(h, 
-                                      (pj_ioqueue_op_key_t*)read_op,
-                                      bytes_read);
-        }
-
-    } else {
+                write_op->op = 0;

+

+                /* Clear operation if there's no more data to send. */

+                if (pj_list_empty(&h->write_list))

+                    ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);

+

+                /* No need to hold mutex anymore */

+                pj_mutex_unlock(h->mutex);

+            }

+

+	    /* Call callback. */

+            if (h->cb.on_write_complete) {

+	        (*h->cb.on_write_complete)(h, 

+                                           (pj_ioqueue_op_key_t*)write_op,

+                                           write_op->written);

+            }

+

+        } else {

+            pj_mutex_unlock(h->mutex);

+        }

+

+        /* Done. */

+    } else {

         /*

          * This is normal; execution may fall here when multiple threads

          * are signalled for the same event, but only one thread eventually

          * able to process the event.

          */

-        pj_mutex_unlock(h->mutex);
-    }
-}
-
-
-void ioqueue_dispatch_exception_event( pj_ioqueue_t *ioqueue, 
-                                       pj_ioqueue_key_t *h )
-{
-    pj_mutex_lock(h->mutex);
-
-    if (!h->connecting) {
-        /* It is possible that more than one thread was woken up, thus
-         * the remaining thread will see h->connecting as zero because
-         * it has been processed by other thread.
-         */
-        pj_mutex_unlock(h->mutex);
-        return;
-    }
-
-    /* Clear operation. */
-    h->connecting = 0;
-
-    pj_mutex_unlock(h->mutex);
-
-    ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);
-    ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);
-
-    /* Call callback. */
-    if (h->cb.on_connect_complete)
-	(*h->cb.on_connect_complete)(h, -1);
-}
-
-/*
- * pj_ioqueue_recv()
- *
- * Start asynchronous recv() from the socket.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_recv(  pj_ioqueue_key_t *key,
-                                      pj_ioqueue_op_key_t *op_key,
-				      void *buffer,
-				      pj_ssize_t *length,
-				      unsigned flags )
-{
-    pj_status_t status;
-    pj_ssize_t size;
-    struct read_operation *read_op;
-
-    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
-    PJ_CHECK_STACK();
+        pj_mutex_unlock(h->mutex);

+    }

+}

+

+void ioqueue_dispatch_read_event( pj_ioqueue_t *ioqueue, pj_ioqueue_key_t *h )

+{

+    pj_status_t rc;

+

+    /* Lock the key. */

+    pj_mutex_lock(h->mutex);

+

+#   if PJ_HAS_TCP

+    if (!pj_list_empty(&h->accept_list)) {

+

+        struct accept_operation *accept_op;

+	

+        /* Get one accept operation from the list. */

+	accept_op = h->accept_list.next;

+        pj_list_erase(accept_op);

+        accept_op->op = 0;

+

+	/* Clear bit in fdset if there is no more pending accept */

+        if (pj_list_empty(&h->accept_list))

+            ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);

+

+        /* Unlock; from this point we don't need to hold key's mutex. */

+        pj_mutex_unlock(h->mutex);

+

+	rc=pj_sock_accept(h->fd, accept_op->accept_fd, 

+                          accept_op->rmt_addr, accept_op->addrlen);

+	if (rc==PJ_SUCCESS && accept_op->local_addr) {

+	    rc = pj_sock_getsockname(*accept_op->accept_fd, 

+                                     accept_op->local_addr,

+				     accept_op->addrlen);

+	}

+

+	/* Call callback. */

+        if (h->cb.on_accept_complete) {

+	    (*h->cb.on_accept_complete)(h, 

+                                        (pj_ioqueue_op_key_t*)accept_op,

+                                        *accept_op->accept_fd, rc);

+	}

+

+    }

+    else

+#   endif

+    if (key_has_pending_read(h)) {

+        struct read_operation *read_op;

+        pj_ssize_t bytes_read;

+

+        /* Get one pending read operation from the list. */

+        read_op = h->read_list.next;

+        pj_list_erase(read_op);

+        read_op->op = 0;

+

+        /* Clear fdset if there is no pending read. */

+        if (pj_list_empty(&h->read_list))

+            ioqueue_remove_from_set(ioqueue, h->fd, READABLE_EVENT);

+

+        /* Unlock; from this point we don't need to hold key's mutex. */

+        pj_mutex_unlock(h->mutex);

+

+        bytes_read = read_op->size;

+

+	if ((read_op->op == PJ_IOQUEUE_OP_RECV_FROM)) {

+	    rc = pj_sock_recvfrom(h->fd, read_op->buf, &bytes_read, 0,

+				  read_op->rmt_addr, 

+                                  read_op->rmt_addrlen);

+	} else if ((read_op->op == PJ_IOQUEUE_OP_RECV)) {

+	    rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);

+        } else {

+            pj_assert(read_op->op == PJ_IOQUEUE_OP_READ);

+            /*

+             * User has specified pj_ioqueue_read().

+             * On Win32, we should do ReadFile(). But because we got

+             * here because of select() anyway, user must have put a

+             * socket descriptor on h->fd, which in this case we can

+             * just call pj_sock_recv() instead of ReadFile().

+             * On Unix, user may put a file in h->fd, so we'll have

+             * to call read() here.

+             * This may not compile on systems which doesn't have 

+             * read(). That's why we only specify PJ_LINUX here so

+             * that error is easier to catch.

+             */

+#	    if defined(PJ_WIN32) && PJ_WIN32 != 0

+                rc = pj_sock_recv(h->fd, read_op->buf, &bytes_read, 0);

+                //rc = ReadFile((HANDLE)h->fd, read_op->buf, read_op->size,

+                //              &bytes_read, NULL);

+#           elif (defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0)

+                bytes_read = read(h->fd, read_op->buf, bytes_read);

+                rc = (bytes_read >= 0) ? PJ_SUCCESS : pj_get_os_error();

+#	    elif defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL != 0

+                bytes_read = sys_read(h->fd, read_op->buf, bytes_read);

+                rc = (bytes_read >= 0) ? PJ_SUCCESS : -bytes_read;

+#           else

+#               error "Implement read() for this platform!"

+#           endif

+        }

+	

+	if (rc != PJ_SUCCESS) {

+#	    if defined(PJ_WIN32) && PJ_WIN32 != 0

+	    /* On Win32, for UDP, WSAECONNRESET on the receive side 

+	     * indicates that previous sending has triggered ICMP Port 

+	     * Unreachable message.

+	     * But we wouldn't know at this point which one of previous 

+	     * key that has triggered the error, since UDP socket can

+	     * be shared!

+	     * So we'll just ignore it!

+	     */

+

+	    if (rc == PJ_STATUS_FROM_OS(WSAECONNRESET)) {

+		//PJ_LOG(4,(THIS_FILE, 

+                //          "Ignored ICMP port unreach. on key=%p", h));

+	    }

+#	    endif

+

+            /* In any case we would report this to caller. */

+            bytes_read = -rc;

+	}

+

+	/* Call callback. */

+        if (h->cb.on_read_complete) {

+	    (*h->cb.on_read_complete)(h, 

+                                      (pj_ioqueue_op_key_t*)read_op,

+                                      bytes_read);

+        }

+

+    } else {

+        /*

+         * This is normal; execution may fall here when multiple threads

+         * are signalled for the same event, but only one thread eventually

+         * able to process the event.

+         */

+        pj_mutex_unlock(h->mutex);

+    }

+}

+

+

+void ioqueue_dispatch_exception_event( pj_ioqueue_t *ioqueue, 

+                                       pj_ioqueue_key_t *h )

+{

+    pj_mutex_lock(h->mutex);

+

+    if (!h->connecting) {

+        /* It is possible that more than one thread was woken up, thus

+         * the remaining thread will see h->connecting as zero because

+         * it has been processed by other thread.

+         */

+        pj_mutex_unlock(h->mutex);

+        return;

+    }

+

+    /* Clear operation. */

+    h->connecting = 0;

+

+    pj_mutex_unlock(h->mutex);

+

+    ioqueue_remove_from_set(ioqueue, h->fd, WRITEABLE_EVENT);

+    ioqueue_remove_from_set(ioqueue, h->fd, EXCEPTION_EVENT);

+

+    /* Call callback. */

+    if (h->cb.on_connect_complete)

+	(*h->cb.on_connect_complete)(h, -1);

+}

+

+/*

+ * pj_ioqueue_recv()

+ *

+ * Start asynchronous recv() from the socket.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_recv(  pj_ioqueue_key_t *key,

+                                      pj_ioqueue_op_key_t *op_key,

+				      void *buffer,

+				      pj_ssize_t *length,

+				      unsigned flags )

+{

+    pj_status_t status;

+    pj_ssize_t size;

+    struct read_operation *read_op;

+

+    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);

+    PJ_CHECK_STACK();

 

     read_op = (struct read_operation*)op_key;

     read_op->op = 0;

-
-    /* Try to see if there's data immediately available. 
-     */
-    size = *length;
-    status = pj_sock_recv(key->fd, buffer, &size, flags);
-    if (status == PJ_SUCCESS) {
-        /* Yes! Data is available! */
-        *length = size;
-        return PJ_SUCCESS;
-    } else {
-        /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
-         * the error to caller.
-         */
-        if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
-            return status;
-    }
-
-    /*
-     * No data is immediately available.
-     * Must schedule asynchronous operation to the ioqueue.
-     */
-    read_op->op = PJ_IOQUEUE_OP_RECV;
-    read_op->buf = buffer;
-    read_op->size = *length;
-    read_op->flags = flags;
-
-    pj_mutex_lock(key->mutex);
-    pj_list_insert_before(&key->read_list, read_op);
-    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
-    pj_mutex_unlock(key->mutex);
-
-    return PJ_EPENDING;
-}
-
-/*
- * pj_ioqueue_recvfrom()
- *
- * Start asynchronous recvfrom() from the socket.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
-                                         pj_ioqueue_op_key_t *op_key,
-				         void *buffer,
-				         pj_ssize_t *length,
-                                         unsigned flags,
-				         pj_sockaddr_t *addr,
-				         int *addrlen)
-{
-    pj_status_t status;
-    pj_ssize_t size;
-    struct read_operation *read_op;
-
-    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
-    PJ_CHECK_STACK();
+

+    /* Try to see if there's data immediately available. 

+     */

+    size = *length;

+    status = pj_sock_recv(key->fd, buffer, &size, flags);

+    if (status == PJ_SUCCESS) {

+        /* Yes! Data is available! */

+        *length = size;

+        return PJ_SUCCESS;

+    } else {

+        /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

+         * the error to caller.

+         */

+        if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))

+            return status;

+    }

+

+    /*

+     * No data is immediately available.

+     * Must schedule asynchronous operation to the ioqueue.

+     */

+    read_op->op = PJ_IOQUEUE_OP_RECV;

+    read_op->buf = buffer;

+    read_op->size = *length;

+    read_op->flags = flags;

+

+    pj_mutex_lock(key->mutex);

+    pj_list_insert_before(&key->read_list, read_op);

+    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);

+    pj_mutex_unlock(key->mutex);

+

+    return PJ_EPENDING;

+}

+

+/*

+ * pj_ioqueue_recvfrom()

+ *

+ * Start asynchronous recvfrom() from the socket.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,

+                                         pj_ioqueue_op_key_t *op_key,

+				         void *buffer,

+				         pj_ssize_t *length,

+                                         unsigned flags,

+				         pj_sockaddr_t *addr,

+				         int *addrlen)

+{

+    pj_status_t status;

+    pj_ssize_t size;

+    struct read_operation *read_op;

+

+    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);

+    PJ_CHECK_STACK();

 

     read_op = (struct read_operation*)op_key;

     read_op->op = 0;

-
-    /* Try to see if there's data immediately available. 
-     */
-    size = *length;
-    status = pj_sock_recvfrom(key->fd, buffer, &size, flags,
-                              addr, addrlen);
-    if (status == PJ_SUCCESS) {
-        /* Yes! Data is available! */
-        *length = size;
-        return PJ_SUCCESS;
-    } else {
-        /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
-         * the error to caller.
-         */
-        if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
-            return status;
-    }
-
-    /*
-     * No data is immediately available.
-     * Must schedule asynchronous operation to the ioqueue.
-     */
-    read_op->op = PJ_IOQUEUE_OP_RECV_FROM;
-    read_op->buf = buffer;
-    read_op->size = *length;
-    read_op->flags = flags;
-    read_op->rmt_addr = addr;
-    read_op->rmt_addrlen = addrlen;
-
-    pj_mutex_lock(key->mutex);
-    pj_list_insert_before(&key->read_list, read_op);
-    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
-    pj_mutex_unlock(key->mutex);
-
-    return PJ_EPENDING;
-}
-
-/*
- * pj_ioqueue_send()
- *
- * Start asynchronous send() to the descriptor.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,
-                                     pj_ioqueue_op_key_t *op_key,
-			             const void *data,
-			             pj_ssize_t *length,
-                                     unsigned flags)
-{
-    struct write_operation *write_op;
-    pj_status_t status;
-    pj_ssize_t sent;
-
-    PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
-    PJ_CHECK_STACK();
+

+    /* Try to see if there's data immediately available. 

+     */

+    size = *length;

+    status = pj_sock_recvfrom(key->fd, buffer, &size, flags,

+                              addr, addrlen);

+    if (status == PJ_SUCCESS) {

+        /* Yes! Data is available! */

+        *length = size;

+        return PJ_SUCCESS;

+    } else {

+        /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

+         * the error to caller.

+         */

+        if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))

+            return status;

+    }

+

+    /*

+     * No data is immediately available.

+     * Must schedule asynchronous operation to the ioqueue.

+     */

+    read_op->op = PJ_IOQUEUE_OP_RECV_FROM;

+    read_op->buf = buffer;

+    read_op->size = *length;

+    read_op->flags = flags;

+    read_op->rmt_addr = addr;

+    read_op->rmt_addrlen = addrlen;

+

+    pj_mutex_lock(key->mutex);

+    pj_list_insert_before(&key->read_list, read_op);

+    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);

+    pj_mutex_unlock(key->mutex);

+

+    return PJ_EPENDING;

+}

+

+/*

+ * pj_ioqueue_send()

+ *

+ * Start asynchronous send() to the descriptor.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_key_t *key,

+                                     pj_ioqueue_op_key_t *op_key,

+			             const void *data,

+			             pj_ssize_t *length,

+                                     unsigned flags)

+{

+    struct write_operation *write_op;

+    pj_status_t status;

+    pj_ssize_t sent;

+

+    PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);

+    PJ_CHECK_STACK();

 

     write_op = (struct write_operation*)op_key;

     write_op->op = 0;

-
-    /* Fast track:
-     *   Try to send data immediately, only if there's no pending write!
-     * Note:
-     *  We are speculating that the list is empty here without properly
-     *  acquiring ioqueue's mutex first. This is intentional, to maximize
-     *  performance via parallelism.
-     *
-     *  This should be safe, because:
-     *      - by convention, we require caller to make sure that the
-     *        key is not unregistered while other threads are invoking
-     *        an operation on the same key.
-     *      - pj_list_empty() is safe to be invoked by multiple threads,
-     *        even when other threads are modifying the list.
-     */
-    if (pj_list_empty(&key->write_list)) {
-        /*
-         * See if data can be sent immediately.
-         */
-        sent = *length;
-        status = pj_sock_send(key->fd, data, &sent, flags);
-        if (status == PJ_SUCCESS) {
-            /* Success! */
-            *length = sent;
-            return PJ_SUCCESS;
-        } else {
-            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
-             * the error to caller.
-             */
-            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
-                return status;
-            }
-        }
-    }
-
-    /*
-     * Schedule asynchronous send.
-     */
-    write_op->op = PJ_IOQUEUE_OP_SEND;
-    write_op->buf = (void*)data;
-    write_op->size = *length;
-    write_op->written = 0;
-    write_op->flags = flags;
-    
-    pj_mutex_lock(key->mutex);
-    pj_list_insert_before(&key->write_list, write_op);
-    ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
-    pj_mutex_unlock(key->mutex);
-
-    return PJ_EPENDING;
-}
-
-
-/*
- * pj_ioqueue_sendto()
- *
- * Start asynchronous write() to the descriptor.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
-                                       pj_ioqueue_op_key_t *op_key,
-			               const void *data,
-			               pj_ssize_t *length,
-                                       unsigned flags,
-			               const pj_sockaddr_t *addr,
-			               int addrlen)
-{
-    struct write_operation *write_op;
-    pj_status_t status;
-    pj_ssize_t sent;
-
-    PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);
-    PJ_CHECK_STACK();
+

+    /* Fast track:

+     *   Try to send data immediately, only if there's no pending write!

+     * Note:

+     *  We are speculating that the list is empty here without properly

+     *  acquiring ioqueue's mutex first. This is intentional, to maximize

+     *  performance via parallelism.

+     *

+     *  This should be safe, because:

+     *      - by convention, we require caller to make sure that the

+     *        key is not unregistered while other threads are invoking

+     *        an operation on the same key.

+     *      - pj_list_empty() is safe to be invoked by multiple threads,

+     *        even when other threads are modifying the list.

+     */

+    if (pj_list_empty(&key->write_list)) {

+        /*

+         * See if data can be sent immediately.

+         */

+        sent = *length;

+        status = pj_sock_send(key->fd, data, &sent, flags);

+        if (status == PJ_SUCCESS) {

+            /* Success! */

+            *length = sent;

+            return PJ_SUCCESS;

+        } else {

+            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

+             * the error to caller.

+             */

+            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {

+                return status;

+            }

+        }

+    }

+

+    /*

+     * Schedule asynchronous send.

+     */

+    write_op->op = PJ_IOQUEUE_OP_SEND;

+    write_op->buf = (void*)data;

+    write_op->size = *length;

+    write_op->written = 0;

+    write_op->flags = flags;

+    

+    pj_mutex_lock(key->mutex);

+    pj_list_insert_before(&key->write_list, write_op);

+    ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);

+    pj_mutex_unlock(key->mutex);

+

+    return PJ_EPENDING;

+}

+

+

+/*

+ * pj_ioqueue_sendto()

+ *

+ * Start asynchronous write() to the descriptor.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,

+                                       pj_ioqueue_op_key_t *op_key,

+			               const void *data,

+			               pj_ssize_t *length,

+                                       unsigned flags,

+			               const pj_sockaddr_t *addr,

+			               int addrlen)

+{

+    struct write_operation *write_op;

+    pj_status_t status;

+    pj_ssize_t sent;

+

+    PJ_ASSERT_RETURN(key && op_key && data && length, PJ_EINVAL);

+    PJ_CHECK_STACK();

 

     write_op = (struct write_operation*)op_key;

     write_op->op = 0;

-
-    /* Fast track:
-     *   Try to send data immediately, only if there's no pending write!
-     * Note:
-     *  We are speculating that the list is empty here without properly
-     *  acquiring ioqueue's mutex first. This is intentional, to maximize
-     *  performance via parallelism.
-     *
-     *  This should be safe, because:
-     *      - by convention, we require caller to make sure that the
-     *        key is not unregistered while other threads are invoking
-     *        an operation on the same key.
-     *      - pj_list_empty() is safe to be invoked by multiple threads,
-     *        even when other threads are modifying the list.
-     */
-    if (pj_list_empty(&key->write_list)) {
-        /*
-         * See if data can be sent immediately.
-         */
-        sent = *length;
-        status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen);
-        if (status == PJ_SUCCESS) {
-            /* Success! */
-            *length = sent;
-            return PJ_SUCCESS;
-        } else {
-            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
-             * the error to caller.
-             */
-            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
-                return status;
-            }
-        }
-    }
-
-    /*
-     * Check that address storage can hold the address parameter.
-     */
-    PJ_ASSERT_RETURN(addrlen <= sizeof(pj_sockaddr_in), PJ_EBUG);
-
-    /*
-     * Schedule asynchronous send.
-     */
-    write_op->op = PJ_IOQUEUE_OP_SEND_TO;
-    write_op->buf = (void*)data;
-    write_op->size = *length;
-    write_op->written = 0;
-    write_op->flags = flags;
-    pj_memcpy(&write_op->rmt_addr, addr, addrlen);
-    write_op->rmt_addrlen = addrlen;
-    
-    pj_mutex_lock(key->mutex);
-    pj_list_insert_before(&key->write_list, write_op);
-    ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
-    pj_mutex_unlock(key->mutex);
-
-    return PJ_EPENDING;
-}
-
-#if PJ_HAS_TCP
-/*
- * Initiate overlapped accept() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
-                                       pj_ioqueue_op_key_t *op_key,
-			               pj_sock_t *new_sock,
-			               pj_sockaddr_t *local,
-			               pj_sockaddr_t *remote,
-			               int *addrlen)
-{
-    struct accept_operation *accept_op;
-    pj_status_t status;
-
-    /* check parameters. All must be specified! */
-    PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
+

+    /* Fast track:

+     *   Try to send data immediately, only if there's no pending write!

+     * Note:

+     *  We are speculating that the list is empty here without properly

+     *  acquiring ioqueue's mutex first. This is intentional, to maximize

+     *  performance via parallelism.

+     *

+     *  This should be safe, because:

+     *      - by convention, we require caller to make sure that the

+     *        key is not unregistered while other threads are invoking

+     *        an operation on the same key.

+     *      - pj_list_empty() is safe to be invoked by multiple threads,

+     *        even when other threads are modifying the list.

+     */

+    if (pj_list_empty(&key->write_list)) {

+        /*

+         * See if data can be sent immediately.

+         */

+        sent = *length;

+        status = pj_sock_sendto(key->fd, data, &sent, flags, addr, addrlen);

+        if (status == PJ_SUCCESS) {

+            /* Success! */

+            *length = sent;

+            return PJ_SUCCESS;

+        } else {

+            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

+             * the error to caller.

+             */

+            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {

+                return status;

+            }

+        }

+    }

+

+    /*

+     * Check that address storage can hold the address parameter.

+     */

+    PJ_ASSERT_RETURN(addrlen <= sizeof(pj_sockaddr_in), PJ_EBUG);

+

+    /*

+     * Schedule asynchronous send.

+     */

+    write_op->op = PJ_IOQUEUE_OP_SEND_TO;

+    write_op->buf = (void*)data;

+    write_op->size = *length;

+    write_op->written = 0;

+    write_op->flags = flags;

+    pj_memcpy(&write_op->rmt_addr, addr, addrlen);

+    write_op->rmt_addrlen = addrlen;

+    

+    pj_mutex_lock(key->mutex);

+    pj_list_insert_before(&key->write_list, write_op);

+    ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);

+    pj_mutex_unlock(key->mutex);

+

+    return PJ_EPENDING;

+}

+

+#if PJ_HAS_TCP

+/*

+ * Initiate overlapped accept() operation.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,

+                                       pj_ioqueue_op_key_t *op_key,

+			               pj_sock_t *new_sock,

+			               pj_sockaddr_t *local,

+			               pj_sockaddr_t *remote,

+			               int *addrlen)

+{

+    struct accept_operation *accept_op;

+    pj_status_t status;

+

+    /* check parameters. All must be specified! */

+    PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);

 

     accept_op = (struct accept_operation*)op_key;

     accept_op->op = 0;

-
-    /* Fast track:
-     *  See if there's new connection available immediately.
-     */
-    if (pj_list_empty(&key->accept_list)) {
-        status = pj_sock_accept(key->fd, new_sock, remote, addrlen);
-        if (status == PJ_SUCCESS) {
-            /* Yes! New connection is available! */
-            if (local && addrlen) {
-                status = pj_sock_getsockname(*new_sock, local, addrlen);
-                if (status != PJ_SUCCESS) {
-                    pj_sock_close(*new_sock);
-                    *new_sock = PJ_INVALID_SOCKET;
-                    return status;
-                }
-            }
-            return PJ_SUCCESS;
-        } else {
-            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report
-             * the error to caller.
-             */
-            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {
-                return status;
-            }
-        }
-    }
-
-    /*
-     * No connection is available immediately.
-     * Schedule accept() operation to be completed when there is incoming
-     * connection available.
-     */
-    accept_op->op = PJ_IOQUEUE_OP_ACCEPT;
-    accept_op->accept_fd = new_sock;
-    accept_op->rmt_addr = remote;
-    accept_op->addrlen= addrlen;
-    accept_op->local_addr = local;
-
-    pj_mutex_lock(key->mutex);
-    pj_list_insert_before(&key->accept_list, accept_op);
-    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);
-    pj_mutex_unlock(key->mutex);
-
-    return PJ_EPENDING;
-}
-
-/*
- * Initiate overlapped connect() operation (well, it's non-blocking actually,
- * since there's no overlapped version of connect()).
- */
-PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
-					const pj_sockaddr_t *addr,
-					int addrlen )
-{
-    pj_status_t status;
-    
-    /* check parameters. All must be specified! */
-    PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);
-
-    /* Check if socket has not been marked for connecting */
-    if (key->connecting != 0)
-        return PJ_EPENDING;
-    
-    status = pj_sock_connect(key->fd, addr, addrlen);
-    if (status == PJ_SUCCESS) {
-	/* Connected! */
-	return PJ_SUCCESS;
-    } else {
-	if (status == PJ_STATUS_FROM_OS(PJ_BLOCKING_CONNECT_ERROR_VAL)) {
-	    /* Pending! */
-            pj_mutex_lock(key->mutex);
-	    key->connecting = PJ_TRUE;
-            ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);
-            ioqueue_add_to_set(key->ioqueue, key->fd, EXCEPTION_EVENT);
-            pj_mutex_unlock(key->mutex);
-	    return PJ_EPENDING;
-	} else {
-	    /* Error! */
-	    return status;
-	}
-    }
-}
-#endif	/* PJ_HAS_TCP */
+

+    /* Fast track:

+     *  See if there's new connection available immediately.

+     */

+    if (pj_list_empty(&key->accept_list)) {

+        status = pj_sock_accept(key->fd, new_sock, remote, addrlen);

+        if (status == PJ_SUCCESS) {

+            /* Yes! New connection is available! */

+            if (local && addrlen) {

+                status = pj_sock_getsockname(*new_sock, local, addrlen);

+                if (status != PJ_SUCCESS) {

+                    pj_sock_close(*new_sock);

+                    *new_sock = PJ_INVALID_SOCKET;

+                    return status;

+                }

+            }

+            return PJ_SUCCESS;

+        } else {

+            /* If error is not EWOULDBLOCK (or EAGAIN on Linux), report

+             * the error to caller.

+             */

+            if (status != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL)) {

+                return status;

+            }

+        }

+    }

+

+    /*

+     * No connection is available immediately.

+     * Schedule accept() operation to be completed when there is incoming

+     * connection available.

+     */

+    accept_op->op = PJ_IOQUEUE_OP_ACCEPT;

+    accept_op->accept_fd = new_sock;

+    accept_op->rmt_addr = remote;

+    accept_op->addrlen= addrlen;

+    accept_op->local_addr = local;

+

+    pj_mutex_lock(key->mutex);

+    pj_list_insert_before(&key->accept_list, accept_op);

+    ioqueue_add_to_set(key->ioqueue, key->fd, READABLE_EVENT);

+    pj_mutex_unlock(key->mutex);

+

+    return PJ_EPENDING;

+}

+

+/*

+ * Initiate overlapped connect() operation (well, it's non-blocking actually,

+ * since there's no overlapped version of connect()).

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,

+					const pj_sockaddr_t *addr,

+					int addrlen )

+{

+    pj_status_t status;

+    

+    /* check parameters. All must be specified! */

+    PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);

+

+    /* Check if socket has not been marked for connecting */

+    if (key->connecting != 0)

+        return PJ_EPENDING;

+    

+    status = pj_sock_connect(key->fd, addr, addrlen);

+    if (status == PJ_SUCCESS) {

+	/* Connected! */

+	return PJ_SUCCESS;

+    } else {

+	if (status == PJ_STATUS_FROM_OS(PJ_BLOCKING_CONNECT_ERROR_VAL)) {

+	    /* Pending! */

+            pj_mutex_lock(key->mutex);

+	    key->connecting = PJ_TRUE;

+            ioqueue_add_to_set(key->ioqueue, key->fd, WRITEABLE_EVENT);

+            ioqueue_add_to_set(key->ioqueue, key->fd, EXCEPTION_EVENT);

+            pj_mutex_unlock(key->mutex);

+	    return PJ_EPENDING;

+	} else {

+	    /* Error! */

+	    return status;

+	}

+    }

+}

+#endif	/* PJ_HAS_TCP */

 

 

 PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,

@@ -840,7 +861,7 @@
     pj_memset(op_key, 0, size);

 }

 

-
+

 /*

  * pj_ioqueue_is_pending()

  */

diff --git a/pjlib/src/pj/ioqueue_common_abs.h b/pjlib/src/pj/ioqueue_common_abs.h
index 1902ff4..85f6f37 100644
--- a/pjlib/src/pj/ioqueue_common_abs.h
+++ b/pjlib/src/pj/ioqueue_common_abs.h
@@ -1,108 +1,129 @@
-/* $Id */
-
-/* ioqueue_common_abs.h
- *
- * This file contains private declarations for abstracting various 
- * event polling/dispatching mechanisms (e.g. select, poll, epoll) 
- * to the ioqueue. 
- */
-
-#include <pj/list.h>
-
-/*
- * The select ioqueue relies on socket functions (pj_sock_xxx()) to return
- * the correct error code.
- */
-#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)
-#   error "Proper error reporting must be enabled for ioqueue to work!"
-#endif
-
-
-struct generic_operation
-{
-    PJ_DECL_LIST_MEMBER(struct generic_operation);
-    pj_ioqueue_operation_e  op;
-};
-
-struct read_operation
-{
-    PJ_DECL_LIST_MEMBER(struct read_operation);
-    pj_ioqueue_operation_e  op;
-
-    void		   *buf;
-    pj_size_t		    size;
-    unsigned                flags;
-    pj_sockaddr_t	   *rmt_addr;
-    int			   *rmt_addrlen;
-};
-
-struct write_operation
-{
-    PJ_DECL_LIST_MEMBER(struct write_operation);
-    pj_ioqueue_operation_e  op;
-
-    char		   *buf;
-    pj_size_t		    size;
-    pj_ssize_t              written;
-    unsigned                flags;
-    pj_sockaddr_in	    rmt_addr;
-    int			    rmt_addrlen;
-};
-
-#if PJ_HAS_TCP
-struct accept_operation
-{
-    PJ_DECL_LIST_MEMBER(struct accept_operation);
-    pj_ioqueue_operation_e  op;
-
-    pj_sock_t              *accept_fd;
-    pj_sockaddr_t	   *local_addr;
-    pj_sockaddr_t	   *rmt_addr;
-    int			   *addrlen;
-};
-#endif
-
-union operation_key
-{
-    struct generic_operation generic;
-    struct read_operation    read;
-    struct write_operation   write;
-#if PJ_HAS_TCP
-    struct accept_operation  accept;
-#endif
-};
-
-#define DECLARE_COMMON_KEY                          \
-    PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t);   \
-    pj_ioqueue_t           *ioqueue;                \
-    pj_mutex_t             *mutex;                  \
-    pj_sock_t		    fd;                     \
-    int                     fd_type;                \
-    void		   *user_data;              \
-    pj_ioqueue_callback	    cb;                     \
-    int                     connecting;             \
-    struct read_operation   read_list;              \
-    struct write_operation  write_list;             \
-    struct accept_operation accept_list;
-
-
-#define DECLARE_COMMON_IOQUEUE                      \
-    pj_lock_t          *lock;                       \
-    pj_bool_t           auto_delete_lock;
-
-
-enum ioqueue_event_type
-{
-    NO_EVENT,
-    READABLE_EVENT,
-    WRITEABLE_EVENT,
-    EXCEPTION_EVENT,
-};
-
-static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
-                                pj_sock_t fd,
-                                enum ioqueue_event_type event_type );
-static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
-                                     pj_sock_t fd, 
-                                     enum ioqueue_event_type event_type);
-
+/* $Id */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/* ioqueue_common_abs.h

+ *

+ * This file contains private declarations for abstracting various 

+ * event polling/dispatching mechanisms (e.g. select, poll, epoll) 

+ * to the ioqueue. 

+ */

+

+#include <pj/list.h>

+

+/*

+ * The select ioqueue relies on socket functions (pj_sock_xxx()) to return

+ * the correct error code.

+ */

+#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)

+#   error "Proper error reporting must be enabled for ioqueue to work!"

+#endif

+

+

+struct generic_operation

+{

+    PJ_DECL_LIST_MEMBER(struct generic_operation);

+    pj_ioqueue_operation_e  op;

+};

+

+struct read_operation

+{

+    PJ_DECL_LIST_MEMBER(struct read_operation);

+    pj_ioqueue_operation_e  op;

+

+    void		   *buf;

+    pj_size_t		    size;

+    unsigned                flags;

+    pj_sockaddr_t	   *rmt_addr;

+    int			   *rmt_addrlen;

+};

+

+struct write_operation

+{

+    PJ_DECL_LIST_MEMBER(struct write_operation);

+    pj_ioqueue_operation_e  op;

+

+    char		   *buf;

+    pj_size_t		    size;

+    pj_ssize_t              written;

+    unsigned                flags;

+    pj_sockaddr_in	    rmt_addr;

+    int			    rmt_addrlen;

+};

+

+#if PJ_HAS_TCP

+struct accept_operation

+{

+    PJ_DECL_LIST_MEMBER(struct accept_operation);

+    pj_ioqueue_operation_e  op;

+

+    pj_sock_t              *accept_fd;

+    pj_sockaddr_t	   *local_addr;

+    pj_sockaddr_t	   *rmt_addr;

+    int			   *addrlen;

+};

+#endif

+

+union operation_key

+{

+    struct generic_operation generic;

+    struct read_operation    read;

+    struct write_operation   write;

+#if PJ_HAS_TCP

+    struct accept_operation  accept;

+#endif

+};

+

+#define DECLARE_COMMON_KEY                          \

+    PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t);   \

+    pj_ioqueue_t           *ioqueue;                \

+    pj_mutex_t             *mutex;                  \

+    pj_sock_t		    fd;                     \

+    int                     fd_type;                \

+    void		   *user_data;              \

+    pj_ioqueue_callback	    cb;                     \

+    int                     connecting;             \

+    struct read_operation   read_list;              \

+    struct write_operation  write_list;             \

+    struct accept_operation accept_list;

+

+

+#define DECLARE_COMMON_IOQUEUE                      \

+    pj_lock_t          *lock;                       \

+    pj_bool_t           auto_delete_lock;

+

+

+enum ioqueue_event_type

+{

+    NO_EVENT,

+    READABLE_EVENT,

+    WRITEABLE_EVENT,

+    EXCEPTION_EVENT,

+};

+

+static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,

+                                pj_sock_t fd,

+                                enum ioqueue_event_type event_type );

+static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,

+                                     pj_sock_t fd, 

+                                     enum ioqueue_event_type event_type);

+

diff --git a/pjlib/src/pj/ioqueue_dummy.c b/pjlib/src/pj/ioqueue_dummy.c
index 3a9927f..b09e5ed 100644
--- a/pjlib/src/pj/ioqueue_dummy.c
+++ b/pjlib/src/pj/ioqueue_dummy.c
@@ -1,178 +1,199 @@
-/* $Id$
- *
- */
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/log.h>
-#include <pj/list.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/sock.h>
-#include <pj/errno.h>
-
-#define THIS_FILE   "ioqueue"
-
-#define PJ_IOQUEUE_IS_READ_OP(op)   \
-	((op & PJ_IOQUEUE_OP_READ)  || (op & PJ_IOQUEUE_OP_RECV_FROM))
-#define PJ_IOQUEUE_IS_WRITE_OP(op)  \
-	((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))
-
-
-#if PJ_HAS_TCP
-#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	(op & PJ_IOQUEUE_OP_ACCEPT)
-#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	(op & PJ_IOQUEUE_OP_CONNECT)
-#else
-#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	0
-#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	0
-#endif
-
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-#  define VALIDATE_FD_SET		1
-#else
-#  define VALIDATE_FD_SET		0
-#endif
-
-struct pj_ioqueue_key_t
-{
-    PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)
-    pj_sock_t		    fd;
-    pj_ioqueue_operation_e  op;
-    void		   *user_data;
-    pj_ioqueue_callback	    cb;
-};
-
-struct pj_ioqueue_t
-{
-};
-
-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
-				       pj_size_t max_fd,
-				       int max_threads,
-				       pj_ioqueue_t **ptr_ioqueue)
-{
-    return PJ_ENOTSUP;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)
-{
-    return PJ_ENOTSUP;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 
-					 pj_lock_t *lock,
-					 pj_bool_t auto_delete )
-{
-    return PJ_ENOTSUP;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
-					      pj_ioqueue_t *ioque,
-					      pj_sock_t sock,
-					      void *user_data,
-					      const pj_ioqueue_callback *cb,
-					      pj_ioqueue_key_t **ptr_key)
-{
-    return PJ_ENOTSUP;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,
-					   pj_ioqueue_key_t *key)
-{
-    return PJ_ENOTSUP;
-}
-
-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
-{
-    return NULL;
-}
-
-
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)
-{
-    return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque,
-				     pj_ioqueue_key_t *key,
-				     void *buffer,
-				     pj_size_t buflen)
-{
-    return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque,
-				     pj_ioqueue_key_t *key,
-				     void *buffer,
-				     pj_size_t buflen,
-				     unsigned flags)
-{
-    return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
-					 pj_ioqueue_key_t *key,
-					 void *buffer,
-					 pj_size_t buflen,
-					 unsigned flags,
-					 pj_sockaddr_t *addr,
-					 int *addrlen)
-{
-    return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque,
-				      pj_ioqueue_key_t *key,
-				      const void *data,
-				      pj_size_t datalen)
-{
-    return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque,
-				     pj_ioqueue_key_t *key,
-				     const void *data,
-				     pj_size_t datalen,
-				     unsigned flags)
-{
-    return -1;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
-				       pj_ioqueue_key_t *key,
-				       const void *data,
-				       pj_size_t datalen,
-				       unsigned flags,
-				       const pj_sockaddr_t *addr,
-				       int addrlen)
-{
-    return -1;
-}
-
-#if PJ_HAS_TCP
-/*
- * Initiate overlapped accept() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,
-				       pj_ioqueue_key_t *key,
-				       pj_sock_t *new_sock,
-				       pj_sockaddr_t *local,
-				       pj_sockaddr_t *remote,
-				      int *addrlen)
-{
-    return -1;
-}
-
-/*
- * Initiate overlapped connect() operation (well, it's non-blocking actually,
- * since there's no overlapped version of connect()).
- */
-PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,
-					pj_ioqueue_key_t *key,
-					const pj_sockaddr_t *addr,
-					int addrlen )
-{
-    return -1;
-}
-#endif	/* PJ_HAS_TCP */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/ioqueue.h>

+#include <pj/os.h>

+#include <pj/log.h>

+#include <pj/list.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/assert.h>

+#include <pj/sock.h>

+#include <pj/errno.h>

+

+#define THIS_FILE   "ioqueue"

+

+#define PJ_IOQUEUE_IS_READ_OP(op)   \

+	((op & PJ_IOQUEUE_OP_READ)  || (op & PJ_IOQUEUE_OP_RECV_FROM))

+#define PJ_IOQUEUE_IS_WRITE_OP(op)  \

+	((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))

+

+

+#if PJ_HAS_TCP

+#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	(op & PJ_IOQUEUE_OP_ACCEPT)

+#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	(op & PJ_IOQUEUE_OP_CONNECT)

+#else

+#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	0

+#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	0

+#endif

+

+#if defined(PJ_DEBUG) && PJ_DEBUG != 0

+#  define VALIDATE_FD_SET		1

+#else

+#  define VALIDATE_FD_SET		0

+#endif

+

+struct pj_ioqueue_key_t

+{

+    PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)

+    pj_sock_t		    fd;

+    pj_ioqueue_operation_e  op;

+    void		   *user_data;

+    pj_ioqueue_callback	    cb;

+};

+

+struct pj_ioqueue_t

+{

+};

+

+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 

+				       pj_size_t max_fd,

+				       int max_threads,

+				       pj_ioqueue_t **ptr_ioqueue)

+{

+    return PJ_ENOTSUP;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)

+{

+    return PJ_ENOTSUP;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioque, 

+					 pj_lock_t *lock,

+					 pj_bool_t auto_delete )

+{

+    return PJ_ENOTSUP;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

+					      pj_ioqueue_t *ioque,

+					      pj_sock_t sock,

+					      void *user_data,

+					      const pj_ioqueue_callback *cb,

+					      pj_ioqueue_key_t **ptr_key)

+{

+    return PJ_ENOTSUP;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,

+					   pj_ioqueue_key_t *key)

+{

+    return PJ_ENOTSUP;

+}

+

+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )

+{

+    return NULL;

+}

+

+

+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)

+{

+    return -1;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_read( pj_ioqueue_t *ioque,

+				     pj_ioqueue_key_t *key,

+				     void *buffer,

+				     pj_size_t buflen)

+{

+    return -1;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_recv( pj_ioqueue_t *ioque,

+				     pj_ioqueue_key_t *key,

+				     void *buffer,

+				     pj_size_t buflen,

+				     unsigned flags)

+{

+    return -1;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,

+					 pj_ioqueue_key_t *key,

+					 void *buffer,

+					 pj_size_t buflen,

+					 unsigned flags,

+					 pj_sockaddr_t *addr,

+					 int *addrlen)

+{

+    return -1;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_write( pj_ioqueue_t *ioque,

+				      pj_ioqueue_key_t *key,

+				      const void *data,

+				      pj_size_t datalen)

+{

+    return -1;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_send( pj_ioqueue_t *ioque,

+				     pj_ioqueue_key_t *key,

+				     const void *data,

+				     pj_size_t datalen,

+				     unsigned flags)

+{

+    return -1;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_t *ioque,

+				       pj_ioqueue_key_t *key,

+				       const void *data,

+				       pj_size_t datalen,

+				       unsigned flags,

+				       const pj_sockaddr_t *addr,

+				       int addrlen)

+{

+    return -1;

+}

+

+#if PJ_HAS_TCP

+/*

+ * Initiate overlapped accept() operation.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,

+				       pj_ioqueue_key_t *key,

+				       pj_sock_t *new_sock,

+				       pj_sockaddr_t *local,

+				       pj_sockaddr_t *remote,

+				      int *addrlen)

+{

+    return -1;

+}

+

+/*

+ * Initiate overlapped connect() operation (well, it's non-blocking actually,

+ * since there's no overlapped version of connect()).

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,

+					pj_ioqueue_key_t *key,

+					const pj_sockaddr_t *addr,

+					int addrlen )

+{

+    return -1;

+}

+#endif	/* PJ_HAS_TCP */

+

diff --git a/pjlib/src/pj/ioqueue_epoll.c b/pjlib/src/pj/ioqueue_epoll.c
index 140bd13..8649042 100644
--- a/pjlib/src/pj/ioqueue_epoll.c
+++ b/pjlib/src/pj/ioqueue_epoll.c
@@ -1,458 +1,479 @@
-/* $Id$
- */
-/*
- * ioqueue_epoll.c
- *
- * This is the implementation of IOQueue framework using /dev/epoll
- * API in _both_ Linux user-mode and kernel-mode.
- */
-
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/lock.h>
-#include <pj/log.h>
-#include <pj/list.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-#include <pj/sock.h>
-#include <pj/compat/socket.h>
-
-#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0
-    /*
-     * Linux user mode
-     */
-#   include <sys/epoll.h>
-#   include <errno.h>
-#   include <unistd.h>
-
-#   define epoll_data		data.ptr
-#   define epoll_data_type	void*
-#   define ioctl_val_type	unsigned long
-#   define getsockopt_val_ptr	int*
-#   define os_getsockopt	getsockopt
-#   define os_ioctl		ioctl
-#   define os_read		read
-#   define os_close		close
-#   define os_epoll_create	epoll_create
-#   define os_epoll_ctl		epoll_ctl
-#   define os_epoll_wait	epoll_wait
-#else
-    /*
-     * Linux kernel mode.
-     */
-#   include <linux/config.h>
-#   include <linux/version.h>
-#   if defined(MODVERSIONS)
-#	include <linux/modversions.h>
-#   endif
-#   include <linux/kernel.h>
-#   include <linux/poll.h>
-#   include <linux/eventpoll.h>
-#   include <linux/syscalls.h>
-#   include <linux/errno.h>
-#   include <linux/unistd.h>
-#   include <asm/ioctls.h>
-    enum EPOLL_EVENTS
-    {
-	EPOLLIN = 0x001,
-	EPOLLOUT = 0x004,
-	EPOLLERR = 0x008,
-    };
-#   define os_epoll_create		sys_epoll_create
-    static int os_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
-    {
-	long rc;
-	mm_segment_t oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	rc = sys_epoll_ctl(epfd, op, fd, event);
-	set_fs(oldfs);
-	if (rc) {
-	    errno = -rc;
-	    return -1;
-	} else {
-	    return 0;
-	}
-    }
-    static int os_epoll_wait(int epfd, struct epoll_event *events,
-			  int maxevents, int timeout)
-    {
-	int count;
-	mm_segment_t oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	count = sys_epoll_wait(epfd, events, maxevents, timeout);
-	set_fs(oldfs);
-	return count;
-    }
-#   define os_close		sys_close
-#   define os_getsockopt	pj_sock_getsockopt
-    static int os_read(int fd, void *buf, size_t len)
-    {
-	long rc;
-	mm_segment_t oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	rc = sys_read(fd, buf, len);
-	set_fs(oldfs);
-	if (rc) {
-	    errno = -rc;
-	    return -1;
-	} else {
-	    return 0;
-	}
-    }
-#   define socklen_t		unsigned
-#   define ioctl_val_type	unsigned long
-    int ioctl(int fd, int opt, ioctl_val_type value);
-    static int os_ioctl(int fd, int opt, ioctl_val_type value)
-    {
-	int rc;
-        mm_segment_t oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	rc = ioctl(fd, opt, value);
-	set_fs(oldfs);
-	if (rc < 0) {
-	    errno = -rc;
-	    return rc;
-	} else
-	    return rc;
-    }
-#   define getsockopt_val_ptr	char*
-
-#   define epoll_data		data
-#   define epoll_data_type	__u32
-#endif
-
-#define THIS_FILE   "ioq_epoll"
-
-//#define TRACE_(expr) PJ_LOG(3,expr)
-#define TRACE_(expr)
-
-/*
- * Include common ioqueue abstraction.
- */
-#include "ioqueue_common_abs.h"
-
-/*
- * This describes each key.
- */
-struct pj_ioqueue_key_t
-{
-    DECLARE_COMMON_KEY
-};
-
-/*
- * This describes the I/O queue.
- */
-struct pj_ioqueue_t
-{
-    DECLARE_COMMON_IOQUEUE
-
-    unsigned		max, count;
-    pj_ioqueue_key_t	hlist;
-    int			epfd;
-};
-
-/* Include implementation for common abstraction after we declare
- * pj_ioqueue_key_t and pj_ioqueue_t.
- */
-#include "ioqueue_common_abs.c"
-
-/*
- * pj_ioqueue_name()
- */
-PJ_DEF(const char*) pj_ioqueue_name(void)
-{
-#if defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
-	return "epoll-kernel";
-#else
-	return "epoll";
-#endif
-}
-
-/*
- * pj_ioqueue_create()
- *
- * Create select ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
-                                       pj_size_t max_fd,
-                                       pj_ioqueue_t **p_ioqueue)
-{
-    pj_ioqueue_t *ioqueue;
-    pj_status_t rc;
-    pj_lock_t *lock;
-
-    /* Check that arguments are valid. */
-    PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && 
-                     max_fd > 0, PJ_EINVAL);
-
-    /* Check that size of pj_ioqueue_op_key_t is sufficient */
-    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
-                     sizeof(union operation_key), PJ_EBUG);
-
-    ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
-
-    ioqueue_init(ioqueue);
-
-    ioqueue->max = max_fd;
-    ioqueue->count = 0;
-    pj_list_init(&ioqueue->hlist);
-
-    rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
-    if (rc != PJ_SUCCESS)
-        return rc;
-
-    ioqueue->epfd = os_epoll_create(max_fd);
-    if (ioqueue->epfd < 0) {
-	ioqueue_destroy(ioqueue);
-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-    }
-    
-    PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue));
-
-    *p_ioqueue = ioqueue;
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_destroy()
- *
- * Destroy ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
-{
-    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
-    PJ_ASSERT_RETURN(ioqueue->epfd > 0, PJ_EINVALIDOP);
-
-    pj_lock_acquire(ioqueue->lock);
-    os_close(ioqueue->epfd);
-    ioqueue->epfd = 0;
-    return ioqueue_destroy(ioqueue);
-}
-
-/*
- * pj_ioqueue_register_sock()
- *
- * Register a socket to ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
-					      pj_ioqueue_t *ioqueue,
-					      pj_sock_t sock,
-					      void *user_data,
-					      const pj_ioqueue_callback *cb,
-                                              pj_ioqueue_key_t **p_key)
-{
-    pj_ioqueue_key_t *key = NULL;
-    pj_uint32_t value;
-    struct epoll_event ev;
-    int status;
-    pj_status_t rc = PJ_SUCCESS;
-    
-    PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
-                     cb && p_key, PJ_EINVAL);
-
-    pj_lock_acquire(ioqueue->lock);
-
-    if (ioqueue->count >= ioqueue->max) {
-        rc = PJ_ETOOMANY;
-	TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: too many files"));
-	goto on_return;
-    }
-
-    /* Set socket to nonblocking. */
-    value = 1;
-    if ((rc=os_ioctl(sock, FIONBIO, (ioctl_val_type)&value))) {
-	TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: ioctl rc=%d", 
-                rc));
-        rc = pj_get_netos_error();
-	goto on_return;
-    }
-
-    /* Create key. */
-    key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
-    rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
-    if (rc != PJ_SUCCESS) {
-	key = NULL;
-	goto on_return;
-    }
-
-    /* os_epoll_ctl. */
-    ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
-    ev.epoll_data = (epoll_data_type)key;
-    status = os_epoll_ctl(ioqueue->epfd, EPOLL_CTL_ADD, sock, &ev);
-    if (status < 0) {
-	rc = pj_get_os_error();
-	key = NULL;
-	TRACE_((THIS_FILE, 
-                "pj_ioqueue_register_sock error: os_epoll_ctl rc=%d", 
-                status));
-	goto on_return;
-    }
-    
-    /* Register */
-    pj_list_insert_before(&ioqueue->hlist, key);
-    ++ioqueue->count;
-
-on_return:
-    *p_key = key;
-    pj_lock_release(ioqueue->lock);
-    
-    return rc;
-}
-
-/*
- * pj_ioqueue_unregister()
- *
- * Unregister handle from ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
-{
-    pj_ioqueue_t *ioqueue;
-    struct epoll_event ev;
-    int status;
-    
-    PJ_ASSERT_RETURN(key != NULL, PJ_EINVAL);
-
-    ioqueue = key->ioqueue;
-    pj_lock_acquire(ioqueue->lock);
-
-    pj_assert(ioqueue->count > 0);
-    --ioqueue->count;
-    pj_list_erase(key);
-
-    ev.events = 0;
-    ev.epoll_data = (epoll_data_type)key;
-    status = os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_DEL, key->fd, &ev);
-    if (status != 0) {
-	pj_status_t rc = pj_get_os_error();
-	pj_lock_release(ioqueue->lock);
-	return rc;
-    }
-
-    pj_lock_release(ioqueue->lock);
-
-    /* Destroy the key. */
-    ioqueue_destroy_key(key);
-
-    return PJ_SUCCESS;
-}
-
-/* ioqueue_remove_from_set()
- * This function is called from ioqueue_dispatch_event() to instruct
- * the ioqueue to remove the specified descriptor from ioqueue's descriptor
- * set for the specified event.
- */
-static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
-                                     pj_sock_t fd, 
-                                     enum ioqueue_event_type event_type)
-{
-}
-
-/*
- * ioqueue_add_to_set()
- * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
- * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
- * set for the specified event.
- */
-static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
-                                pj_sock_t fd,
-                                enum ioqueue_event_type event_type )
-{
-}
-
-/*
- * pj_ioqueue_poll()
- *
- */
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
-{
-    int i, count, processed;
-    struct epoll_event events[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
-    int msec;
-    struct queue {
-	pj_ioqueue_key_t	*key;
-	enum ioqueue_event_type	 event_type;
-    } queue[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
-    
-    PJ_CHECK_STACK();
-
-    msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000;
-    
-    count = os_epoll_wait( ioqueue->epfd, events, PJ_ARRAY_SIZE(events), msec);
-    if (count <= 0)
-	return count;
-
-    /* Lock ioqueue. */
-    pj_lock_acquire(ioqueue->lock);
-
-    for (processed=0, i=0; i<count; ++i) {
-	pj_ioqueue_key_t *h = (pj_ioqueue_key_t*)(epoll_data_type)
-				events[i].epoll_data;
-
-	/*
-	 * Check readability.
-	 */
-	if ((events[i].events & EPOLLIN) && 
-	    (key_has_pending_read(h) || key_has_pending_accept(h))) {
-	    queue[processed].key = h;
-	    queue[processed].event_type = READABLE_EVENT;
-	    ++processed;
-	}
-
-	/*
-	 * Check for writeability.
-	 */
-	if ((events[i].events & EPOLLOUT) && key_has_pending_write(h)) {
-	    queue[processed].key = h;
-	    queue[processed].event_type = WRITEABLE_EVENT;
-	    ++processed;
-	}
-
-#if PJ_HAS_TCP
-	/*
-	 * Check for completion of connect() operation.
-	 */
-	if ((events[i].events & EPOLLOUT) && (h->connecting)) {
-	    queue[processed].key = h;
-	    queue[processed].event_type = WRITEABLE_EVENT;
-	    ++processed;
-	}
-#endif /* PJ_HAS_TCP */
-	
-	/*
-	 * Check for error condition.
-	 */
-	if (events[i].events & EPOLLERR && (h->connecting)) {
-	    queue[processed].key = h;
-	    queue[processed].event_type = EXCEPTION_EVENT;
-	    ++processed;
-	}
-    }
-    pj_lock_release(ioqueue->lock);
-
-    /* Now process the events. */
-    for (i=0; i<processed; ++i) {
-	switch (queue[i].event_type) {
-        case READABLE_EVENT:
-            ioqueue_dispatch_read_event(ioqueue, queue[i].key);
-            break;
-        case WRITEABLE_EVENT:
-            ioqueue_dispatch_write_event(ioqueue, queue[i].key);
-            break;
-        case EXCEPTION_EVENT:
-            ioqueue_dispatch_exception_event(ioqueue, queue[i].key);
-            break;
-        case NO_EVENT:
-            pj_assert(!"Invalid event!");
-            break;
-        }
-    }
-
-    return processed;
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/*

+ * ioqueue_epoll.c

+ *

+ * This is the implementation of IOQueue framework using /dev/epoll

+ * API in _both_ Linux user-mode and kernel-mode.

+ */

+

+#include <pj/ioqueue.h>

+#include <pj/os.h>

+#include <pj/lock.h>

+#include <pj/log.h>

+#include <pj/list.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/assert.h>

+#include <pj/errno.h>

+#include <pj/sock.h>

+#include <pj/compat/socket.h>

+

+#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0

+    /*

+     * Linux user mode

+     */

+#   include <sys/epoll.h>

+#   include <errno.h>

+#   include <unistd.h>

+

+#   define epoll_data		data.ptr

+#   define epoll_data_type	void*

+#   define ioctl_val_type	unsigned long

+#   define getsockopt_val_ptr	int*

+#   define os_getsockopt	getsockopt

+#   define os_ioctl		ioctl

+#   define os_read		read

+#   define os_close		close

+#   define os_epoll_create	epoll_create

+#   define os_epoll_ctl		epoll_ctl

+#   define os_epoll_wait	epoll_wait

+#else

+    /*

+     * Linux kernel mode.

+     */

+#   include <linux/config.h>

+#   include <linux/version.h>

+#   if defined(MODVERSIONS)

+#	include <linux/modversions.h>

+#   endif

+#   include <linux/kernel.h>

+#   include <linux/poll.h>

+#   include <linux/eventpoll.h>

+#   include <linux/syscalls.h>

+#   include <linux/errno.h>

+#   include <linux/unistd.h>

+#   include <asm/ioctls.h>

+    enum EPOLL_EVENTS

+    {

+	EPOLLIN = 0x001,

+	EPOLLOUT = 0x004,

+	EPOLLERR = 0x008,

+    };

+#   define os_epoll_create		sys_epoll_create

+    static int os_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

+    {

+	long rc;

+	mm_segment_t oldfs = get_fs();

+	set_fs(KERNEL_DS);

+	rc = sys_epoll_ctl(epfd, op, fd, event);

+	set_fs(oldfs);

+	if (rc) {

+	    errno = -rc;

+	    return -1;

+	} else {

+	    return 0;

+	}

+    }

+    static int os_epoll_wait(int epfd, struct epoll_event *events,

+			  int maxevents, int timeout)

+    {

+	int count;

+	mm_segment_t oldfs = get_fs();

+	set_fs(KERNEL_DS);

+	count = sys_epoll_wait(epfd, events, maxevents, timeout);

+	set_fs(oldfs);

+	return count;

+    }

+#   define os_close		sys_close

+#   define os_getsockopt	pj_sock_getsockopt

+    static int os_read(int fd, void *buf, size_t len)

+    {

+	long rc;

+	mm_segment_t oldfs = get_fs();

+	set_fs(KERNEL_DS);

+	rc = sys_read(fd, buf, len);

+	set_fs(oldfs);

+	if (rc) {

+	    errno = -rc;

+	    return -1;

+	} else {

+	    return 0;

+	}

+    }

+#   define socklen_t		unsigned

+#   define ioctl_val_type	unsigned long

+    int ioctl(int fd, int opt, ioctl_val_type value);

+    static int os_ioctl(int fd, int opt, ioctl_val_type value)

+    {

+	int rc;

+        mm_segment_t oldfs = get_fs();

+	set_fs(KERNEL_DS);

+	rc = ioctl(fd, opt, value);

+	set_fs(oldfs);

+	if (rc < 0) {

+	    errno = -rc;

+	    return rc;

+	} else

+	    return rc;

+    }

+#   define getsockopt_val_ptr	char*

+

+#   define epoll_data		data

+#   define epoll_data_type	__u32

+#endif

+

+#define THIS_FILE   "ioq_epoll"

+

+//#define TRACE_(expr) PJ_LOG(3,expr)

+#define TRACE_(expr)

+

+/*

+ * Include common ioqueue abstraction.

+ */

+#include "ioqueue_common_abs.h"

+

+/*

+ * This describes each key.

+ */

+struct pj_ioqueue_key_t

+{

+    DECLARE_COMMON_KEY

+};

+

+/*

+ * This describes the I/O queue.

+ */

+struct pj_ioqueue_t

+{

+    DECLARE_COMMON_IOQUEUE

+

+    unsigned		max, count;

+    pj_ioqueue_key_t	hlist;

+    int			epfd;

+};

+

+/* Include implementation for common abstraction after we declare

+ * pj_ioqueue_key_t and pj_ioqueue_t.

+ */

+#include "ioqueue_common_abs.c"

+

+/*

+ * pj_ioqueue_name()

+ */

+PJ_DEF(const char*) pj_ioqueue_name(void)

+{

+#if defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0

+	return "epoll-kernel";

+#else

+	return "epoll";

+#endif

+}

+

+/*

+ * pj_ioqueue_create()

+ *

+ * Create select ioqueue.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 

+                                       pj_size_t max_fd,

+                                       pj_ioqueue_t **p_ioqueue)

+{

+    pj_ioqueue_t *ioqueue;

+    pj_status_t rc;

+    pj_lock_t *lock;

+

+    /* Check that arguments are valid. */

+    PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && 

+                     max_fd > 0, PJ_EINVAL);

+

+    /* Check that size of pj_ioqueue_op_key_t is sufficient */

+    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=

+                     sizeof(union operation_key), PJ_EBUG);

+

+    ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));

+

+    ioqueue_init(ioqueue);

+

+    ioqueue->max = max_fd;

+    ioqueue->count = 0;

+    pj_list_init(&ioqueue->hlist);

+

+    rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);

+    if (rc != PJ_SUCCESS)

+        return rc;

+

+    ioqueue->epfd = os_epoll_create(max_fd);

+    if (ioqueue->epfd < 0) {

+	ioqueue_destroy(ioqueue);

+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

+    }

+    

+    PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue));

+

+    *p_ioqueue = ioqueue;

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_ioqueue_destroy()

+ *

+ * Destroy ioqueue.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)

+{

+    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

+    PJ_ASSERT_RETURN(ioqueue->epfd > 0, PJ_EINVALIDOP);

+

+    pj_lock_acquire(ioqueue->lock);

+    os_close(ioqueue->epfd);

+    ioqueue->epfd = 0;

+    return ioqueue_destroy(ioqueue);

+}

+

+/*

+ * pj_ioqueue_register_sock()

+ *

+ * Register a socket to ioqueue.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

+					      pj_ioqueue_t *ioqueue,

+					      pj_sock_t sock,

+					      void *user_data,

+					      const pj_ioqueue_callback *cb,

+                                              pj_ioqueue_key_t **p_key)

+{

+    pj_ioqueue_key_t *key = NULL;

+    pj_uint32_t value;

+    struct epoll_event ev;

+    int status;

+    pj_status_t rc = PJ_SUCCESS;

+    

+    PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&

+                     cb && p_key, PJ_EINVAL);

+

+    pj_lock_acquire(ioqueue->lock);

+

+    if (ioqueue->count >= ioqueue->max) {

+        rc = PJ_ETOOMANY;

+	TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: too many files"));

+	goto on_return;

+    }

+

+    /* Set socket to nonblocking. */

+    value = 1;

+    if ((rc=os_ioctl(sock, FIONBIO, (ioctl_val_type)&value))) {

+	TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: ioctl rc=%d", 

+                rc));

+        rc = pj_get_netos_error();

+	goto on_return;

+    }

+

+    /* Create key. */

+    key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));

+    rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);

+    if (rc != PJ_SUCCESS) {

+	key = NULL;

+	goto on_return;

+    }

+

+    /* os_epoll_ctl. */

+    ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;

+    ev.epoll_data = (epoll_data_type)key;

+    status = os_epoll_ctl(ioqueue->epfd, EPOLL_CTL_ADD, sock, &ev);

+    if (status < 0) {

+	rc = pj_get_os_error();

+	key = NULL;

+	TRACE_((THIS_FILE, 

+                "pj_ioqueue_register_sock error: os_epoll_ctl rc=%d", 

+                status));

+	goto on_return;

+    }

+    

+    /* Register */

+    pj_list_insert_before(&ioqueue->hlist, key);

+    ++ioqueue->count;

+

+on_return:

+    *p_key = key;

+    pj_lock_release(ioqueue->lock);

+    

+    return rc;

+}

+

+/*

+ * pj_ioqueue_unregister()

+ *

+ * Unregister handle from ioqueue.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)

+{

+    pj_ioqueue_t *ioqueue;

+    struct epoll_event ev;

+    int status;

+    

+    PJ_ASSERT_RETURN(key != NULL, PJ_EINVAL);

+

+    ioqueue = key->ioqueue;

+    pj_lock_acquire(ioqueue->lock);

+

+    pj_assert(ioqueue->count > 0);

+    --ioqueue->count;

+    pj_list_erase(key);

+

+    ev.events = 0;

+    ev.epoll_data = (epoll_data_type)key;

+    status = os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_DEL, key->fd, &ev);

+    if (status != 0) {

+	pj_status_t rc = pj_get_os_error();

+	pj_lock_release(ioqueue->lock);

+	return rc;

+    }

+

+    pj_lock_release(ioqueue->lock);

+

+    /* Destroy the key. */

+    ioqueue_destroy_key(key);

+

+    return PJ_SUCCESS;

+}

+

+/* ioqueue_remove_from_set()

+ * This function is called from ioqueue_dispatch_event() to instruct

+ * the ioqueue to remove the specified descriptor from ioqueue's descriptor

+ * set for the specified event.

+ */

+static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,

+                                     pj_sock_t fd, 

+                                     enum ioqueue_event_type event_type)

+{

+}

+

+/*

+ * ioqueue_add_to_set()

+ * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc

+ * to instruct the ioqueue to add the specified handle to ioqueue's descriptor

+ * set for the specified event.

+ */

+static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,

+                                pj_sock_t fd,

+                                enum ioqueue_event_type event_type )

+{

+}

+

+/*

+ * pj_ioqueue_poll()

+ *

+ */

+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)

+{

+    int i, count, processed;

+    struct epoll_event events[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];

+    int msec;

+    struct queue {

+	pj_ioqueue_key_t	*key;

+	enum ioqueue_event_type	 event_type;

+    } queue[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];

+    

+    PJ_CHECK_STACK();

+

+    msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000;

+    

+    count = os_epoll_wait( ioqueue->epfd, events, PJ_ARRAY_SIZE(events), msec);

+    if (count <= 0)

+	return count;

+

+    /* Lock ioqueue. */

+    pj_lock_acquire(ioqueue->lock);

+

+    for (processed=0, i=0; i<count; ++i) {

+	pj_ioqueue_key_t *h = (pj_ioqueue_key_t*)(epoll_data_type)

+				events[i].epoll_data;

+

+	/*

+	 * Check readability.

+	 */

+	if ((events[i].events & EPOLLIN) && 

+	    (key_has_pending_read(h) || key_has_pending_accept(h))) {

+	    queue[processed].key = h;

+	    queue[processed].event_type = READABLE_EVENT;

+	    ++processed;

+	}

+

+	/*

+	 * Check for writeability.

+	 */

+	if ((events[i].events & EPOLLOUT) && key_has_pending_write(h)) {

+	    queue[processed].key = h;

+	    queue[processed].event_type = WRITEABLE_EVENT;

+	    ++processed;

+	}

+

+#if PJ_HAS_TCP

+	/*

+	 * Check for completion of connect() operation.

+	 */

+	if ((events[i].events & EPOLLOUT) && (h->connecting)) {

+	    queue[processed].key = h;

+	    queue[processed].event_type = WRITEABLE_EVENT;

+	    ++processed;

+	}

+#endif /* PJ_HAS_TCP */

+	

+	/*

+	 * Check for error condition.

+	 */

+	if (events[i].events & EPOLLERR && (h->connecting)) {

+	    queue[processed].key = h;

+	    queue[processed].event_type = EXCEPTION_EVENT;

+	    ++processed;

+	}

+    }

+    pj_lock_release(ioqueue->lock);

+

+    /* Now process the events. */

+    for (i=0; i<processed; ++i) {

+	switch (queue[i].event_type) {

+        case READABLE_EVENT:

+            ioqueue_dispatch_read_event(ioqueue, queue[i].key);

+            break;

+        case WRITEABLE_EVENT:

+            ioqueue_dispatch_write_event(ioqueue, queue[i].key);

+            break;

+        case EXCEPTION_EVENT:

+            ioqueue_dispatch_exception_event(ioqueue, queue[i].key);

+            break;

+        case NO_EVENT:

+            pj_assert(!"Invalid event!");

+            break;

+        }

+    }

+

+    return processed;

+}

+

diff --git a/pjlib/src/pj/ioqueue_linux_kernel.c b/pjlib/src/pj/ioqueue_linux_kernel.c
index 9ac8dda..deaca1e 100644
--- a/pjlib/src/pj/ioqueue_linux_kernel.c
+++ b/pjlib/src/pj/ioqueue_linux_kernel.c
@@ -1,146 +1,167 @@
-/* $Id$
- *
- */
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/log.h>
-#include <pj/list.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/sock.h>
-
-#define THIS_FILE   "ioqueue"
-
-#define PJ_IOQUEUE_IS_READ_OP(op)   \
-	((op & PJ_IOQUEUE_OP_READ)  || (op & PJ_IOQUEUE_OP_RECV_FROM))
-#define PJ_IOQUEUE_IS_WRITE_OP(op)  \
-	((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))
-
-
-#if PJ_HAS_TCP
-#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	(op & PJ_IOQUEUE_OP_ACCEPT)
-#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	(op & PJ_IOQUEUE_OP_CONNECT)
-#else
-#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	0
-#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	0
-#endif
-
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-#  define VALIDATE_FD_SET		1
-#else
-#  define VALIDATE_FD_SET		0
-#endif
-
-struct pj_ioqueue_key_t
-{
-    PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)
-    pj_sock_t		    fd;
-    pj_ioqueue_operation_e  op;
-    void		   *user_data;
-    pj_ioqueue_callback	    cb;
-};
-
-struct pj_ioqueue_t
-{
-};
-
-PJ_DEF(pj_ioqueue_t*) pj_ioqueue_create(pj_pool_t *pool, pj_size_t max_fd)
-{
-    return NULL;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)
-{
-    return 0;
-}
-
-PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool,
-					       pj_ioqueue_t *ioque,
-					       pj_oshandle_t sock,
-					       void *user_data,
-					       const pj_ioqueue_callback *cb)
-{
-    return NULL;
-}
-
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,
-					   pj_ioqueue_key_t *key)
-{
-    return -1;
-}
-
-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
-{
-    return NULL;
-}
-
-
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)
-{
-    return -1;
-}
-
-PJ_DEF(int) pj_ioqueue_read( pj_ioqueue_t *ioque,
-			     pj_ioqueue_key_t *key,
-			     void *buffer,
-			     pj_size_t buflen)
-{
-    return -1;
-}
-
-PJ_DEF(int) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,
-				 pj_ioqueue_key_t *key,
-				 void *buffer,
-				 pj_size_t buflen,
-				 pj_sockaddr_t *addr,
-				 int *addrlen)
-{
-    return -1;
-}
-
-PJ_DEF(int) pj_ioqueue_write( pj_ioqueue_t *ioque,
-			      pj_ioqueue_key_t *key,
-			      const void *data,
-			      pj_size_t datalen)
-{
-    return -1;
-}
-
-PJ_DEF(int) pj_ioqueue_sendto( pj_ioqueue_t *ioque,
-			       pj_ioqueue_key_t *key,
-			       const void *data,
-			       pj_size_t datalen,
-			       const pj_sockaddr_t *addr,
-			       int addrlen)
-{
-    return -1;
-}
-
-#if PJ_HAS_TCP
-/*
- * Initiate overlapped accept() operation.
- */
-PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,
-			       pj_ioqueue_key_t *key,
-			       pj_sock_t *new_sock,
-			       pj_sockaddr_t *local,
-			       pj_sockaddr_t *remote,
-			       int *addrlen)
-{
-    return -1;
-}
-
-/*
- * Initiate overlapped connect() operation (well, it's non-blocking actually,
- * since there's no overlapped version of connect()).
- */
-PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,
-					pj_ioqueue_key_t *key,
-					const pj_sockaddr_t *addr,
-					int addrlen )
-{
-    return -1;
-}
-#endif	/* PJ_HAS_TCP */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/ioqueue.h>

+#include <pj/os.h>

+#include <pj/log.h>

+#include <pj/list.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/assert.h>

+#include <pj/sock.h>

+

+#define THIS_FILE   "ioqueue"

+

+#define PJ_IOQUEUE_IS_READ_OP(op)   \

+	((op & PJ_IOQUEUE_OP_READ)  || (op & PJ_IOQUEUE_OP_RECV_FROM))

+#define PJ_IOQUEUE_IS_WRITE_OP(op)  \

+	((op & PJ_IOQUEUE_OP_WRITE) || (op & PJ_IOQUEUE_OP_SEND_TO))

+

+

+#if PJ_HAS_TCP

+#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	(op & PJ_IOQUEUE_OP_ACCEPT)

+#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	(op & PJ_IOQUEUE_OP_CONNECT)

+#else

+#  define PJ_IOQUEUE_IS_ACCEPT_OP(op)	0

+#  define PJ_IOQUEUE_IS_CONNECT_OP(op)	0

+#endif

+

+#if defined(PJ_DEBUG) && PJ_DEBUG != 0

+#  define VALIDATE_FD_SET		1

+#else

+#  define VALIDATE_FD_SET		0

+#endif

+

+struct pj_ioqueue_key_t

+{

+    PJ_DECL_LIST_MEMBER(struct pj_ioqueue_key_t)

+    pj_sock_t		    fd;

+    pj_ioqueue_operation_e  op;

+    void		   *user_data;

+    pj_ioqueue_callback	    cb;

+};

+

+struct pj_ioqueue_t

+{

+};

+

+PJ_DEF(pj_ioqueue_t*) pj_ioqueue_create(pj_pool_t *pool, pj_size_t max_fd)

+{

+    return NULL;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioque)

+{

+    return 0;

+}

+

+PJ_DEF(pj_ioqueue_key_t*) pj_ioqueue_register( pj_pool_t *pool,

+					       pj_ioqueue_t *ioque,

+					       pj_oshandle_t sock,

+					       void *user_data,

+					       const pj_ioqueue_callback *cb)

+{

+    return NULL;

+}

+

+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_t *ioque,

+					   pj_ioqueue_key_t *key)

+{

+    return -1;

+}

+

+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )

+{

+    return NULL;

+}

+

+

+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioque, const pj_time_val *timeout)

+{

+    return -1;

+}

+

+PJ_DEF(int) pj_ioqueue_read( pj_ioqueue_t *ioque,

+			     pj_ioqueue_key_t *key,

+			     void *buffer,

+			     pj_size_t buflen)

+{

+    return -1;

+}

+

+PJ_DEF(int) pj_ioqueue_recvfrom( pj_ioqueue_t *ioque,

+				 pj_ioqueue_key_t *key,

+				 void *buffer,

+				 pj_size_t buflen,

+				 pj_sockaddr_t *addr,

+				 int *addrlen)

+{

+    return -1;

+}

+

+PJ_DEF(int) pj_ioqueue_write( pj_ioqueue_t *ioque,

+			      pj_ioqueue_key_t *key,

+			      const void *data,

+			      pj_size_t datalen)

+{

+    return -1;

+}

+

+PJ_DEF(int) pj_ioqueue_sendto( pj_ioqueue_t *ioque,

+			       pj_ioqueue_key_t *key,

+			       const void *data,

+			       pj_size_t datalen,

+			       const pj_sockaddr_t *addr,

+			       int addrlen)

+{

+    return -1;

+}

+

+#if PJ_HAS_TCP

+/*

+ * Initiate overlapped accept() operation.

+ */

+PJ_DEF(int) pj_ioqueue_accept( pj_ioqueue_t *ioqueue,

+			       pj_ioqueue_key_t *key,

+			       pj_sock_t *new_sock,

+			       pj_sockaddr_t *local,

+			       pj_sockaddr_t *remote,

+			       int *addrlen)

+{

+    return -1;

+}

+

+/*

+ * Initiate overlapped connect() operation (well, it's non-blocking actually,

+ * since there's no overlapped version of connect()).

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_t *ioqueue,

+					pj_ioqueue_key_t *key,

+					const pj_sockaddr_t *addr,

+					int addrlen )

+{

+    return -1;

+}

+#endif	/* PJ_HAS_TCP */

+

diff --git a/pjlib/src/pj/ioqueue_select.c b/pjlib/src/pj/ioqueue_select.c
index 09318d4..de1e97c 100644
--- a/pjlib/src/pj/ioqueue_select.c
+++ b/pjlib/src/pj/ioqueue_select.c
@@ -1,514 +1,535 @@
-/* $Id$
- */
-/*
- * sock_select.c
- *
- * This is the implementation of IOQueue using pj_sock_select().
- * It runs anywhere where pj_sock_select() is available (currently
- * Win32, Linux, Linux kernel, etc.).
- */
-
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/lock.h>
-#include <pj/log.h>
-#include <pj/list.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/sock.h>
-#include <pj/compat/socket.h>
-#include <pj/sock_select.h>
-#include <pj/errno.h>
-
-/*
- * Include declaration from common abstraction.
- */
-#include "ioqueue_common_abs.h"
-
-/*
- * ISSUES with ioqueue_select()
- *
- * EAGAIN/EWOULDBLOCK error in recv():
- *  - when multiple threads are working with the ioqueue, application
- *    may receive EAGAIN or EWOULDBLOCK in the receive callback.
- *    This error happens because more than one thread is watching for
- *    the same descriptor set, so when all of them call recv() or recvfrom()
- *    simultaneously, only one will succeed and the rest will get the error.
- *
- */
-#define THIS_FILE   "ioq_select"
-
-/*
- * The select ioqueue relies on socket functions (pj_sock_xxx()) to return
- * the correct error code.
- */
-#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)
-#   error "Error reporting must be enabled for this function to work!"
-#endif
-
-/**
- * Get the number of descriptors in the set. This is defined in sock_select.c
- * This function will only return the number of sockets set from PJ_FD_SET
- * operation. When the set is modified by other means (such as by select()),
- * the count will not be reflected here.
- *
- * That's why don't export this function in the header file, to avoid
- * misunderstanding.
- *
- * @param fdsetp    The descriptor set.
- *
- * @return          Number of descriptors in the set.
- */
-PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp);
-
-
-/*
- * During debugging build, VALIDATE_FD_SET is set.
- * This will check the validity of the fd_sets.
- */
-/*
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-#  define VALIDATE_FD_SET		1
-#else
-#  define VALIDATE_FD_SET		0
-#endif
-*/
-#define VALIDATE_FD_SET     0
-
-/*
- * This describes each key.
- */
-struct pj_ioqueue_key_t
-{
-    DECLARE_COMMON_KEY
-};
-
-/*
- * This describes the I/O queue itself.
- */
-struct pj_ioqueue_t
-{
-    DECLARE_COMMON_IOQUEUE
-
-    unsigned		max, count;
-    pj_ioqueue_key_t	key_list;
-    pj_fd_set_t		rfdset;
-    pj_fd_set_t		wfdset;
-#if PJ_HAS_TCP
-    pj_fd_set_t		xfdset;
-#endif
-};
-
-/* Include implementation for common abstraction after we declare
- * pj_ioqueue_key_t and pj_ioqueue_t.
- */
-#include "ioqueue_common_abs.c"
-
-/*
- * pj_ioqueue_name()
- */
-PJ_DEF(const char*) pj_ioqueue_name(void)
-{
-    return "select";
-}
-
-/*
- * pj_ioqueue_create()
- *
- * Create select ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
-                                       pj_size_t max_fd,
-                                       pj_ioqueue_t **p_ioqueue)
-{
-    pj_ioqueue_t *ioqueue;
-    pj_lock_t *lock;
-    pj_status_t rc;
-
-    /* Check that arguments are valid. */
-    PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && 
-                     max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES, 
-                     PJ_EINVAL);
-
-    /* Check that size of pj_ioqueue_op_key_t is sufficient */
-    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
-                     sizeof(union operation_key), PJ_EBUG);
-
-    ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
-
-    ioqueue_init(ioqueue);
-
-    ioqueue->max = max_fd;
-    ioqueue->count = 0;
-    PJ_FD_ZERO(&ioqueue->rfdset);
-    PJ_FD_ZERO(&ioqueue->wfdset);
-#if PJ_HAS_TCP
-    PJ_FD_ZERO(&ioqueue->xfdset);
-#endif
-    pj_list_init(&ioqueue->key_list);
-
-    rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
-    if (rc != PJ_SUCCESS)
-        return rc;
-
-    PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue));
-
-    *p_ioqueue = ioqueue;
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_destroy()
- *
- * Destroy ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
-{
-    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
-
-    pj_lock_acquire(ioqueue->lock);
-    return ioqueue_destroy(ioqueue);
-}
-
-
-/*
- * pj_ioqueue_register_sock()
- *
- * Register a handle to ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
-					      pj_ioqueue_t *ioqueue,
-					      pj_sock_t sock,
-					      void *user_data,
-					      const pj_ioqueue_callback *cb,
-                                              pj_ioqueue_key_t **p_key)
-{
-    pj_ioqueue_key_t *key = NULL;
-    pj_uint32_t value;
-    pj_status_t rc = PJ_SUCCESS;
-    
-    PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
-                     cb && p_key, PJ_EINVAL);
-
-    pj_lock_acquire(ioqueue->lock);
-
-    if (ioqueue->count >= ioqueue->max) {
-        rc = PJ_ETOOMANY;
-	goto on_return;
-    }
-
-    /* Set socket to nonblocking. */
-    value = 1;
-#ifdef PJ_WIN32
-    if (ioctlsocket(sock, FIONBIO, (u_long*)&value)) {
-#else
-    if (ioctl(sock, FIONBIO, &value)) {
-#endif
-        rc = pj_get_netos_error();
-	goto on_return;
-    }
-
-    /* Create key. */
-    key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
-    rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
-    if (rc != PJ_SUCCESS) {
-	key = NULL;
-	goto on_return;
-    }
-
-    /* Register */
-    pj_list_insert_before(&ioqueue->key_list, key);
-    ++ioqueue->count;
-
-on_return:
-    /* On error, socket may be left in non-blocking mode. */
-    *p_key = key;
-    pj_lock_release(ioqueue->lock);
-    
-    return rc;
-}
-
-/*
- * pj_ioqueue_unregister()
- *
- * Unregister handle from ioqueue.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
-{
-    pj_ioqueue_t *ioqueue;
-
-    PJ_ASSERT_RETURN(key, PJ_EINVAL);
-
-    ioqueue = key->ioqueue;
-
-    pj_lock_acquire(ioqueue->lock);
-
-    pj_assert(ioqueue->count > 0);
-    --ioqueue->count;
-    pj_list_erase(key);
-    PJ_FD_CLR(key->fd, &ioqueue->rfdset);
-    PJ_FD_CLR(key->fd, &ioqueue->wfdset);
-#if PJ_HAS_TCP
-    PJ_FD_CLR(key->fd, &ioqueue->xfdset);
-#endif
-
-    /* ioqueue_destroy may try to acquire key's mutex.
-     * Since normally the order of locking is to lock key's mutex first
-     * then ioqueue's mutex, ioqueue_destroy may deadlock unless we
-     * release ioqueue's mutex first.
-     */
-    pj_lock_release(ioqueue->lock);
-
-    /* Destroy the key. */
-    ioqueue_destroy_key(key);
-
-    return PJ_SUCCESS;
-}
-
-
-/* This supposed to check whether the fd_set values are consistent
- * with the operation currently set in each key.
- */
-#if VALIDATE_FD_SET
-static void validate_sets(const pj_ioqueue_t *ioqueue,
-			  const pj_fd_set_t *rfdset,
-			  const pj_fd_set_t *wfdset,
-			  const pj_fd_set_t *xfdset)
-{
-    pj_ioqueue_key_t *key;
-
-    /*
-     * This basicly would not work anymore.
-     * We need to lock key before performing the check, but we can't do
-     * so because we're holding ioqueue mutex. If we acquire key's mutex
-     * now, the will cause deadlock.
-     */
-    pj_assert(0);
-
-    key = ioqueue->key_list.next;
-    while (key != &ioqueue->key_list) {
-	if (!pj_list_empty(&key->read_list)
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-	    || !pj_list_empty(&key->accept_list)
-#endif
-	    ) 
-	{
-	    pj_assert(PJ_FD_ISSET(key->fd, rfdset));
-	} 
-	else {
-	    pj_assert(PJ_FD_ISSET(key->fd, rfdset) == 0);
-	}
-	if (!pj_list_empty(&key->write_list)
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-	    || key->connecting
-#endif
-	   )
-	{
-	    pj_assert(PJ_FD_ISSET(key->fd, wfdset));
-	}
-	else {
-	    pj_assert(PJ_FD_ISSET(key->fd, wfdset) == 0);
-	}
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-	if (key->connecting)
-	{
-	    pj_assert(PJ_FD_ISSET(key->fd, xfdset));
-	}
-	else {
-	    pj_assert(PJ_FD_ISSET(key->fd, xfdset) == 0);
-	}
-#endif /* PJ_HAS_TCP */
-
-	key = key->next;
-    }
-}
-#endif	/* VALIDATE_FD_SET */
-
-
-/* ioqueue_remove_from_set()
- * This function is called from ioqueue_dispatch_event() to instruct
- * the ioqueue to remove the specified descriptor from ioqueue's descriptor
- * set for the specified event.
- */
-static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
-                                     pj_sock_t fd, 
-                                     enum ioqueue_event_type event_type)
-{
-    pj_lock_acquire(ioqueue->lock);
-
-    if (event_type == READABLE_EVENT)
-        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->rfdset);
-    else if (event_type == WRITEABLE_EVENT)
-        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->wfdset);
-    else if (event_type == EXCEPTION_EVENT)
-        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->xfdset);
-    else
-        pj_assert(0);
-
-    pj_lock_release(ioqueue->lock);
-}
-
-/*
- * ioqueue_add_to_set()
- * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
- * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
- * set for the specified event.
- */
-static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
-                                pj_sock_t fd,
-                                enum ioqueue_event_type event_type )
-{
-    pj_lock_acquire(ioqueue->lock);
-
-    if (event_type == READABLE_EVENT)
-        PJ_FD_SET((pj_sock_t)fd, &ioqueue->rfdset);
-    else if (event_type == WRITEABLE_EVENT)
-        PJ_FD_SET((pj_sock_t)fd, &ioqueue->wfdset);
-    else if (event_type == EXCEPTION_EVENT)
-        PJ_FD_SET((pj_sock_t)fd, &ioqueue->xfdset);
-    else
-        pj_assert(0);
-
-    pj_lock_release(ioqueue->lock);
-}
-
-/*
- * pj_ioqueue_poll()
- *
- * Few things worth written:
- *
- *  - we used to do only one callback called per poll, but it didn't go
- *    very well. The reason is because on some situation, the write 
- *    callback gets called all the time, thus doesn't give the read
- *    callback to get called. This happens, for example, when user
- *    submit write operation inside the write callback.
- *    As the result, we changed the behaviour so that now multiple
- *    callbacks are called in a single poll. It should be fast too,
- *    just that we need to be carefull with the ioqueue data structs.
- *
- *  - to guarantee preemptiveness etc, the poll function must strictly
- *    work on fd_set copy of the ioqueue (not the original one).
- */
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
-{
-    pj_fd_set_t rfdset, wfdset, xfdset;
-    int count, counter;
-    pj_ioqueue_key_t *h;
-    struct event
-    {
-        pj_ioqueue_key_t	*key;
-        enum ioqueue_event_type  event_type;
-    } event[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
-
-    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
-
-    /* Lock ioqueue before making fd_set copies */
-    pj_lock_acquire(ioqueue->lock);
-
-    /* We will only do select() when there are sockets to be polled.
-     * Otherwise select() will return error.
-     */
-    if (PJ_FD_COUNT(&ioqueue->rfdset)==0 &&
-        PJ_FD_COUNT(&ioqueue->wfdset)==0 &&
-        PJ_FD_COUNT(&ioqueue->xfdset)==0)
-    {
-        pj_lock_release(ioqueue->lock);
-        if (timeout)
-            pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout));
-        return 0;
-    }
-
-    /* Copy ioqueue's pj_fd_set_t to local variables. */
-    pj_memcpy(&rfdset, &ioqueue->rfdset, sizeof(pj_fd_set_t));
-    pj_memcpy(&wfdset, &ioqueue->wfdset, sizeof(pj_fd_set_t));
-#if PJ_HAS_TCP
-    pj_memcpy(&xfdset, &ioqueue->xfdset, sizeof(pj_fd_set_t));
-#else
-    PJ_FD_ZERO(&xfdset);
-#endif
-
-#if VALIDATE_FD_SET
-    validate_sets(ioqueue, &rfdset, &wfdset, &xfdset);
-#endif
-
-    /* Unlock ioqueue before select(). */
-    pj_lock_release(ioqueue->lock);
-
-    count = pj_sock_select(FD_SETSIZE, &rfdset, &wfdset, &xfdset, timeout);
-    
-    if (count <= 0)
-	return count;
-    else if (count > PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL)
-        count = PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL;
-
-    /* Scan descriptor sets for event and add the events in the event
-     * array to be processed later in this function. We do this so that
-     * events can be processed in parallel without holding ioqueue lock.
-     */
-    pj_lock_acquire(ioqueue->lock);
-
-    counter = 0;
-
-    /* Scan for writable sockets first to handle piggy-back data
-     * coming with accept().
-     */
-    h = ioqueue->key_list.next;
-    for ( ; h!=&ioqueue->key_list && counter<count; h = h->next) {
-	if ( (key_has_pending_write(h) || key_has_pending_connect(h))
-	     && PJ_FD_ISSET(h->fd, &wfdset))
-        {
-            event[counter].key = h;
-            event[counter].event_type = WRITEABLE_EVENT;
-            ++counter;
-        }
-
-        /* Scan for readable socket. */
-	if ((key_has_pending_read(h) || key_has_pending_accept(h))
-            && PJ_FD_ISSET(h->fd, &rfdset))
-        {
-            event[counter].key = h;
-            event[counter].event_type = READABLE_EVENT;
-            ++counter;
-	}
-
-#if PJ_HAS_TCP
-        if (key_has_pending_connect(h) && PJ_FD_ISSET(h->fd, &xfdset)) {
-            event[counter].key = h;
-            event[counter].event_type = EXCEPTION_EVENT;
-            ++counter;
-        }
-#endif
-    }
-
-    pj_lock_release(ioqueue->lock);
-
-    count = counter;
-
-    /* Now process all events. The dispatch functions will take care
-     * of locking in each of the key
-     */
-    for (counter=0; counter<count; ++counter) {
-        switch (event[counter].event_type) {
-        case READABLE_EVENT:
-            ioqueue_dispatch_read_event(ioqueue, event[counter].key);
-            break;
-        case WRITEABLE_EVENT:
-            ioqueue_dispatch_write_event(ioqueue, event[counter].key);
-            break;
-        case EXCEPTION_EVENT:
-            ioqueue_dispatch_exception_event(ioqueue, event[counter].key);
-            break;
-        case NO_EVENT:
-            pj_assert(!"Invalid event!");
-            break;
-        }
-    }
-
-    return count;
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/*

+ * sock_select.c

+ *

+ * This is the implementation of IOQueue using pj_sock_select().

+ * It runs anywhere where pj_sock_select() is available (currently

+ * Win32, Linux, Linux kernel, etc.).

+ */

+

+#include <pj/ioqueue.h>

+#include <pj/os.h>

+#include <pj/lock.h>

+#include <pj/log.h>

+#include <pj/list.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/assert.h>

+#include <pj/sock.h>

+#include <pj/compat/socket.h>

+#include <pj/sock_select.h>

+#include <pj/errno.h>

+

+/*

+ * Include declaration from common abstraction.

+ */

+#include "ioqueue_common_abs.h"

+

+/*

+ * ISSUES with ioqueue_select()

+ *

+ * EAGAIN/EWOULDBLOCK error in recv():

+ *  - when multiple threads are working with the ioqueue, application

+ *    may receive EAGAIN or EWOULDBLOCK in the receive callback.

+ *    This error happens because more than one thread is watching for

+ *    the same descriptor set, so when all of them call recv() or recvfrom()

+ *    simultaneously, only one will succeed and the rest will get the error.

+ *

+ */

+#define THIS_FILE   "ioq_select"

+

+/*

+ * The select ioqueue relies on socket functions (pj_sock_xxx()) to return

+ * the correct error code.

+ */

+#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)

+#   error "Error reporting must be enabled for this function to work!"

+#endif

+

+/**

+ * Get the number of descriptors in the set. This is defined in sock_select.c

+ * This function will only return the number of sockets set from PJ_FD_SET

+ * operation. When the set is modified by other means (such as by select()),

+ * the count will not be reflected here.

+ *

+ * That's why don't export this function in the header file, to avoid

+ * misunderstanding.

+ *

+ * @param fdsetp    The descriptor set.

+ *

+ * @return          Number of descriptors in the set.

+ */

+PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp);

+

+

+/*

+ * During debugging build, VALIDATE_FD_SET is set.

+ * This will check the validity of the fd_sets.

+ */

+/*

+#if defined(PJ_DEBUG) && PJ_DEBUG != 0

+#  define VALIDATE_FD_SET		1

+#else

+#  define VALIDATE_FD_SET		0

+#endif

+*/

+#define VALIDATE_FD_SET     0

+

+/*

+ * This describes each key.

+ */

+struct pj_ioqueue_key_t

+{

+    DECLARE_COMMON_KEY

+};

+

+/*

+ * This describes the I/O queue itself.

+ */

+struct pj_ioqueue_t

+{

+    DECLARE_COMMON_IOQUEUE

+

+    unsigned		max, count;

+    pj_ioqueue_key_t	key_list;

+    pj_fd_set_t		rfdset;

+    pj_fd_set_t		wfdset;

+#if PJ_HAS_TCP

+    pj_fd_set_t		xfdset;

+#endif

+};

+

+/* Include implementation for common abstraction after we declare

+ * pj_ioqueue_key_t and pj_ioqueue_t.

+ */

+#include "ioqueue_common_abs.c"

+

+/*

+ * pj_ioqueue_name()

+ */

+PJ_DEF(const char*) pj_ioqueue_name(void)

+{

+    return "select";

+}

+

+/*

+ * pj_ioqueue_create()

+ *

+ * Create select ioqueue.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 

+                                       pj_size_t max_fd,

+                                       pj_ioqueue_t **p_ioqueue)

+{

+    pj_ioqueue_t *ioqueue;

+    pj_lock_t *lock;

+    pj_status_t rc;

+

+    /* Check that arguments are valid. */

+    PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL && 

+                     max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES, 

+                     PJ_EINVAL);

+

+    /* Check that size of pj_ioqueue_op_key_t is sufficient */

+    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=

+                     sizeof(union operation_key), PJ_EBUG);

+

+    ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));

+

+    ioqueue_init(ioqueue);

+

+    ioqueue->max = max_fd;

+    ioqueue->count = 0;

+    PJ_FD_ZERO(&ioqueue->rfdset);

+    PJ_FD_ZERO(&ioqueue->wfdset);

+#if PJ_HAS_TCP

+    PJ_FD_ZERO(&ioqueue->xfdset);

+#endif

+    pj_list_init(&ioqueue->key_list);

+

+    rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);

+    if (rc != PJ_SUCCESS)

+        return rc;

+

+    PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue));

+

+    *p_ioqueue = ioqueue;

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_ioqueue_destroy()

+ *

+ * Destroy ioqueue.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)

+{

+    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

+

+    pj_lock_acquire(ioqueue->lock);

+    return ioqueue_destroy(ioqueue);

+}

+

+

+/*

+ * pj_ioqueue_register_sock()

+ *

+ * Register a handle to ioqueue.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

+					      pj_ioqueue_t *ioqueue,

+					      pj_sock_t sock,

+					      void *user_data,

+					      const pj_ioqueue_callback *cb,

+                                              pj_ioqueue_key_t **p_key)

+{

+    pj_ioqueue_key_t *key = NULL;

+    pj_uint32_t value;

+    pj_status_t rc = PJ_SUCCESS;

+    

+    PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&

+                     cb && p_key, PJ_EINVAL);

+

+    pj_lock_acquire(ioqueue->lock);

+

+    if (ioqueue->count >= ioqueue->max) {

+        rc = PJ_ETOOMANY;

+	goto on_return;

+    }

+

+    /* Set socket to nonblocking. */

+    value = 1;

+#ifdef PJ_WIN32

+    if (ioctlsocket(sock, FIONBIO, (u_long*)&value)) {

+#else

+    if (ioctl(sock, FIONBIO, &value)) {

+#endif

+        rc = pj_get_netos_error();

+	goto on_return;

+    }

+

+    /* Create key. */

+    key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));

+    rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);

+    if (rc != PJ_SUCCESS) {

+	key = NULL;

+	goto on_return;

+    }

+

+    /* Register */

+    pj_list_insert_before(&ioqueue->key_list, key);

+    ++ioqueue->count;

+

+on_return:

+    /* On error, socket may be left in non-blocking mode. */

+    *p_key = key;

+    pj_lock_release(ioqueue->lock);

+    

+    return rc;

+}

+

+/*

+ * pj_ioqueue_unregister()

+ *

+ * Unregister handle from ioqueue.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)

+{

+    pj_ioqueue_t *ioqueue;

+

+    PJ_ASSERT_RETURN(key, PJ_EINVAL);

+

+    ioqueue = key->ioqueue;

+

+    pj_lock_acquire(ioqueue->lock);

+

+    pj_assert(ioqueue->count > 0);

+    --ioqueue->count;

+    pj_list_erase(key);

+    PJ_FD_CLR(key->fd, &ioqueue->rfdset);

+    PJ_FD_CLR(key->fd, &ioqueue->wfdset);

+#if PJ_HAS_TCP

+    PJ_FD_CLR(key->fd, &ioqueue->xfdset);

+#endif

+

+    /* ioqueue_destroy may try to acquire key's mutex.

+     * Since normally the order of locking is to lock key's mutex first

+     * then ioqueue's mutex, ioqueue_destroy may deadlock unless we

+     * release ioqueue's mutex first.

+     */

+    pj_lock_release(ioqueue->lock);

+

+    /* Destroy the key. */

+    ioqueue_destroy_key(key);

+

+    return PJ_SUCCESS;

+}

+

+

+/* This supposed to check whether the fd_set values are consistent

+ * with the operation currently set in each key.

+ */

+#if VALIDATE_FD_SET

+static void validate_sets(const pj_ioqueue_t *ioqueue,

+			  const pj_fd_set_t *rfdset,

+			  const pj_fd_set_t *wfdset,

+			  const pj_fd_set_t *xfdset)

+{

+    pj_ioqueue_key_t *key;

+

+    /*

+     * This basicly would not work anymore.

+     * We need to lock key before performing the check, but we can't do

+     * so because we're holding ioqueue mutex. If we acquire key's mutex

+     * now, the will cause deadlock.

+     */

+    pj_assert(0);

+

+    key = ioqueue->key_list.next;

+    while (key != &ioqueue->key_list) {

+	if (!pj_list_empty(&key->read_list)

+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

+	    || !pj_list_empty(&key->accept_list)

+#endif

+	    ) 

+	{

+	    pj_assert(PJ_FD_ISSET(key->fd, rfdset));

+	} 

+	else {

+	    pj_assert(PJ_FD_ISSET(key->fd, rfdset) == 0);

+	}

+	if (!pj_list_empty(&key->write_list)

+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

+	    || key->connecting

+#endif

+	   )

+	{

+	    pj_assert(PJ_FD_ISSET(key->fd, wfdset));

+	}

+	else {

+	    pj_assert(PJ_FD_ISSET(key->fd, wfdset) == 0);

+	}

+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

+	if (key->connecting)

+	{

+	    pj_assert(PJ_FD_ISSET(key->fd, xfdset));

+	}

+	else {

+	    pj_assert(PJ_FD_ISSET(key->fd, xfdset) == 0);

+	}

+#endif /* PJ_HAS_TCP */

+

+	key = key->next;

+    }

+}

+#endif	/* VALIDATE_FD_SET */

+

+

+/* ioqueue_remove_from_set()

+ * This function is called from ioqueue_dispatch_event() to instruct

+ * the ioqueue to remove the specified descriptor from ioqueue's descriptor

+ * set for the specified event.

+ */

+static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,

+                                     pj_sock_t fd, 

+                                     enum ioqueue_event_type event_type)

+{

+    pj_lock_acquire(ioqueue->lock);

+

+    if (event_type == READABLE_EVENT)

+        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->rfdset);

+    else if (event_type == WRITEABLE_EVENT)

+        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->wfdset);

+    else if (event_type == EXCEPTION_EVENT)

+        PJ_FD_CLR((pj_sock_t)fd, &ioqueue->xfdset);

+    else

+        pj_assert(0);

+

+    pj_lock_release(ioqueue->lock);

+}

+

+/*

+ * ioqueue_add_to_set()

+ * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc

+ * to instruct the ioqueue to add the specified handle to ioqueue's descriptor

+ * set for the specified event.

+ */

+static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,

+                                pj_sock_t fd,

+                                enum ioqueue_event_type event_type )

+{

+    pj_lock_acquire(ioqueue->lock);

+

+    if (event_type == READABLE_EVENT)

+        PJ_FD_SET((pj_sock_t)fd, &ioqueue->rfdset);

+    else if (event_type == WRITEABLE_EVENT)

+        PJ_FD_SET((pj_sock_t)fd, &ioqueue->wfdset);

+    else if (event_type == EXCEPTION_EVENT)

+        PJ_FD_SET((pj_sock_t)fd, &ioqueue->xfdset);

+    else

+        pj_assert(0);

+

+    pj_lock_release(ioqueue->lock);

+}

+

+/*

+ * pj_ioqueue_poll()

+ *

+ * Few things worth written:

+ *

+ *  - we used to do only one callback called per poll, but it didn't go

+ *    very well. The reason is because on some situation, the write 

+ *    callback gets called all the time, thus doesn't give the read

+ *    callback to get called. This happens, for example, when user

+ *    submit write operation inside the write callback.

+ *    As the result, we changed the behaviour so that now multiple

+ *    callbacks are called in a single poll. It should be fast too,

+ *    just that we need to be carefull with the ioqueue data structs.

+ *

+ *  - to guarantee preemptiveness etc, the poll function must strictly

+ *    work on fd_set copy of the ioqueue (not the original one).

+ */

+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)

+{

+    pj_fd_set_t rfdset, wfdset, xfdset;

+    int count, counter;

+    pj_ioqueue_key_t *h;

+    struct event

+    {

+        pj_ioqueue_key_t	*key;

+        enum ioqueue_event_type  event_type;

+    } event[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];

+

+    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

+

+    /* Lock ioqueue before making fd_set copies */

+    pj_lock_acquire(ioqueue->lock);

+

+    /* We will only do select() when there are sockets to be polled.

+     * Otherwise select() will return error.

+     */

+    if (PJ_FD_COUNT(&ioqueue->rfdset)==0 &&

+        PJ_FD_COUNT(&ioqueue->wfdset)==0 &&

+        PJ_FD_COUNT(&ioqueue->xfdset)==0)

+    {

+        pj_lock_release(ioqueue->lock);

+        if (timeout)

+            pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout));

+        return 0;

+    }

+

+    /* Copy ioqueue's pj_fd_set_t to local variables. */

+    pj_memcpy(&rfdset, &ioqueue->rfdset, sizeof(pj_fd_set_t));

+    pj_memcpy(&wfdset, &ioqueue->wfdset, sizeof(pj_fd_set_t));

+#if PJ_HAS_TCP

+    pj_memcpy(&xfdset, &ioqueue->xfdset, sizeof(pj_fd_set_t));

+#else

+    PJ_FD_ZERO(&xfdset);

+#endif

+

+#if VALIDATE_FD_SET

+    validate_sets(ioqueue, &rfdset, &wfdset, &xfdset);

+#endif

+

+    /* Unlock ioqueue before select(). */

+    pj_lock_release(ioqueue->lock);

+

+    count = pj_sock_select(FD_SETSIZE, &rfdset, &wfdset, &xfdset, timeout);

+    

+    if (count <= 0)

+	return count;

+    else if (count > PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL)

+        count = PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL;

+

+    /* Scan descriptor sets for event and add the events in the event

+     * array to be processed later in this function. We do this so that

+     * events can be processed in parallel without holding ioqueue lock.

+     */

+    pj_lock_acquire(ioqueue->lock);

+

+    counter = 0;

+

+    /* Scan for writable sockets first to handle piggy-back data

+     * coming with accept().

+     */

+    h = ioqueue->key_list.next;

+    for ( ; h!=&ioqueue->key_list && counter<count; h = h->next) {

+	if ( (key_has_pending_write(h) || key_has_pending_connect(h))

+	     && PJ_FD_ISSET(h->fd, &wfdset))

+        {

+            event[counter].key = h;

+            event[counter].event_type = WRITEABLE_EVENT;

+            ++counter;

+        }

+

+        /* Scan for readable socket. */

+	if ((key_has_pending_read(h) || key_has_pending_accept(h))

+            && PJ_FD_ISSET(h->fd, &rfdset))

+        {

+            event[counter].key = h;

+            event[counter].event_type = READABLE_EVENT;

+            ++counter;

+	}

+

+#if PJ_HAS_TCP

+        if (key_has_pending_connect(h) && PJ_FD_ISSET(h->fd, &xfdset)) {

+            event[counter].key = h;

+            event[counter].event_type = EXCEPTION_EVENT;

+            ++counter;

+        }

+#endif

+    }

+

+    pj_lock_release(ioqueue->lock);

+

+    count = counter;

+

+    /* Now process all events. The dispatch functions will take care

+     * of locking in each of the key

+     */

+    for (counter=0; counter<count; ++counter) {

+        switch (event[counter].event_type) {

+        case READABLE_EVENT:

+            ioqueue_dispatch_read_event(ioqueue, event[counter].key);

+            break;

+        case WRITEABLE_EVENT:

+            ioqueue_dispatch_write_event(ioqueue, event[counter].key);

+            break;

+        case EXCEPTION_EVENT:

+            ioqueue_dispatch_exception_event(ioqueue, event[counter].key);

+            break;

+        case NO_EVENT:

+            pj_assert(!"Invalid event!");

+            break;

+        }

+    }

+

+    return count;

+}

+

diff --git a/pjlib/src/pj/ioqueue_winnt.c b/pjlib/src/pj/ioqueue_winnt.c
index 777cb6b..7e3e31b 100644
--- a/pjlib/src/pj/ioqueue_winnt.c
+++ b/pjlib/src/pj/ioqueue_winnt.c
@@ -1,896 +1,917 @@
-/* $Id$
- */
-#include <pj/ioqueue.h>
-#include <pj/os.h>
-#include <pj/lock.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/sock.h>
-#include <pj/array.h>
-#include <pj/log.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-
-
-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
-#  include <winsock2.h>
-#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
-#  include <winsock.h>
-#endif
-
-#if defined(PJ_HAS_MSWSOCK_H) && PJ_HAS_MSWSOCK_H != 0
-#  include <mswsock.h>
-#endif
-
-
-/* The address specified in AcceptEx() must be 16 more than the size of
- * SOCKADDR (source: MSDN).
- */
-#define ACCEPT_ADDR_LEN	    (sizeof(pj_sockaddr_in)+16)
-
-typedef struct generic_overlapped
-{
-    WSAOVERLAPPED	   overlapped;
-    pj_ioqueue_operation_e operation;
-} generic_overlapped;
-
-/*
- * OVERLAPPPED structure for send and receive.
- */
-typedef struct ioqueue_overlapped
-{
-    WSAOVERLAPPED	   overlapped;
-    pj_ioqueue_operation_e operation;
-    WSABUF		   wsabuf;
-    pj_sockaddr_in         dummy_addr;
-    int                    dummy_addrlen;
-} ioqueue_overlapped;
-
-#if PJ_HAS_TCP
-/*
- * OVERLAP structure for accept.
- */
-typedef struct ioqueue_accept_rec
-{
-    WSAOVERLAPPED	    overlapped;
-    pj_ioqueue_operation_e  operation;
-    pj_sock_t		    newsock;
-    pj_sock_t		   *newsock_ptr;
-    int			   *addrlen;
-    void		   *remote;
-    void		   *local;
-    char		    accept_buf[2 * ACCEPT_ADDR_LEN];
-} ioqueue_accept_rec;
-#endif
-
-/*
- * Structure to hold pending operation key.
- */
-union operation_key
-{
-    generic_overlapped      generic;
-    ioqueue_overlapped      overlapped;
-#if PJ_HAS_TCP
-    ioqueue_accept_rec      accept;
-#endif
-};
-
-/* Type of handle in the key. */
-enum handle_type
-{
-    HND_IS_UNKNOWN,
-    HND_IS_FILE,
-    HND_IS_SOCKET,
-};
-
-/*
- * Structure for individual socket.
- */
-struct pj_ioqueue_key_t
-{
-    pj_ioqueue_t       *ioqueue;
-    HANDLE		hnd;
-    void	       *user_data;
-    enum handle_type    hnd_type;
-#if PJ_HAS_TCP
-    int			connecting;
-#endif
-    pj_ioqueue_callback	cb;
-};
-
-/*
- * IO Queue structure.
- */
-struct pj_ioqueue_t
-{
-    HANDLE	      iocp;
-    pj_lock_t        *lock;
-    pj_bool_t         auto_delete_lock;
-    unsigned	      event_count;
-    HANDLE	      event_pool[MAXIMUM_WAIT_OBJECTS+1];
-#if PJ_HAS_TCP
-    unsigned	      connecting_count;
-    HANDLE	      connecting_handles[MAXIMUM_WAIT_OBJECTS+1];
-    pj_ioqueue_key_t *connecting_keys[MAXIMUM_WAIT_OBJECTS+1];
-#endif
-};
-
-
-#if PJ_HAS_TCP
-/*
- * Process the socket when the overlapped accept() completed.
- */
-static void ioqueue_on_accept_complete(ioqueue_accept_rec *accept_overlapped)
-{
-    struct sockaddr *local;
-    struct sockaddr *remote;
-    int locallen, remotelen;
-
-    PJ_CHECK_STACK();
-
-    /* Operation complete immediately. */
-    GetAcceptExSockaddrs( accept_overlapped->accept_buf,
-			  0, 
-			  ACCEPT_ADDR_LEN,
-			  ACCEPT_ADDR_LEN,
-			  &local,
-			  &locallen,
-			  &remote,
-			  &remotelen);
-    if (*accept_overlapped->addrlen > locallen) {
-        pj_memcpy(accept_overlapped->local, local, locallen);
-        pj_memcpy(accept_overlapped->remote, remote, locallen);
-    } else {
-        pj_memset(accept_overlapped->local, 0, *accept_overlapped->addrlen);
-        pj_memset(accept_overlapped->remote, 0, *accept_overlapped->addrlen);
-    }
-    *accept_overlapped->addrlen = locallen;
-    if (accept_overlapped->newsock_ptr)
-        *accept_overlapped->newsock_ptr = accept_overlapped->newsock;
-    accept_overlapped->operation = 0;
-    accept_overlapped->newsock = PJ_INVALID_SOCKET;
-}
-
-static void erase_connecting_socket( pj_ioqueue_t *ioqueue, unsigned pos)
-{
-    pj_ioqueue_key_t *key = ioqueue->connecting_keys[pos];
-    HANDLE hEvent = ioqueue->connecting_handles[pos];
-
-    /* Remove key from array of connecting handles. */
-    pj_array_erase(ioqueue->connecting_keys, sizeof(key),
-		   ioqueue->connecting_count, pos);
-    pj_array_erase(ioqueue->connecting_handles, sizeof(HANDLE),
-		   ioqueue->connecting_count, pos);
-    --ioqueue->connecting_count;
-
-    /* Disassociate the socket from the event. */
-    WSAEventSelect((pj_sock_t)key->hnd, hEvent, 0);
-
-    /* Put event object to pool. */
-    if (ioqueue->event_count < MAXIMUM_WAIT_OBJECTS) {
-	ioqueue->event_pool[ioqueue->event_count++] = hEvent;
-    } else {
-	/* Shouldn't happen. There should be no more pending connections
-	 * than max. 
-	 */
-	pj_assert(0);
-	CloseHandle(hEvent);
-    }
-
-}
-
-/*
- * Poll for the completion of non-blocking connect().
- * If there's a completion, the function return the key of the completed
- * socket, and 'result' argument contains the connect() result. If connect()
- * succeeded, 'result' will have value zero, otherwise will have the error
- * code.
- */
-static pj_ioqueue_key_t *check_connecting( pj_ioqueue_t *ioqueue, 
-					   pj_ssize_t *connect_err )
-{
-    pj_ioqueue_key_t *key = NULL;
-
-    if (ioqueue->connecting_count) {
-	DWORD result;
-
-	pj_lock_acquire(ioqueue->lock);
-	result = WaitForMultipleObjects(ioqueue->connecting_count,
-					ioqueue->connecting_handles,
-					FALSE, 0);
-	if (result >= WAIT_OBJECT_0 && 
-	    result < WAIT_OBJECT_0+ioqueue->connecting_count) 
-	{
-	    WSANETWORKEVENTS net_events;
-
-	    /* Got completed connect(). */
-	    unsigned pos = result - WAIT_OBJECT_0;
-	    key = ioqueue->connecting_keys[pos];
-
-	    /* See whether connect has succeeded. */
-	    WSAEnumNetworkEvents((pj_sock_t)key->hnd, 
-				 ioqueue->connecting_handles[pos], 
-				 &net_events);
-	    *connect_err = 
-                PJ_STATUS_FROM_OS(net_events.iErrorCode[FD_CONNECT_BIT]);
-
-	    /* Erase socket from pending connect. */
-	    erase_connecting_socket(ioqueue, pos);
-	}
-	pj_lock_release(ioqueue->lock);
-    }
-    return key;
-}
-#endif
-
-/*
- * pj_ioqueue_name()
- */
-PJ_DEF(const char*) pj_ioqueue_name(void)
-{
-    return "iocp";
-}
-
-/*
- * pj_ioqueue_create()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 
-				       pj_size_t max_fd,
-				       pj_ioqueue_t **p_ioqueue)
-{
-    pj_ioqueue_t *ioqueue;
-    pj_status_t rc;
-
-    PJ_UNUSED_ARG(max_fd);
-    PJ_ASSERT_RETURN(pool && p_ioqueue, PJ_EINVAL);
-
-    rc = sizeof(union operation_key);
-
-    /* Check that sizeof(pj_ioqueue_op_key_t) makes sense. */
-    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= 
-                     sizeof(union operation_key), PJ_EBUG);
-
-    ioqueue = pj_pool_zalloc(pool, sizeof(*ioqueue));
-    ioqueue->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
-    if (ioqueue->iocp == NULL)
-	return PJ_RETURN_OS_ERROR(GetLastError());
-
-    rc = pj_lock_create_simple_mutex(pool, NULL, &ioqueue->lock);
-    if (rc != PJ_SUCCESS) {
-	CloseHandle(ioqueue->iocp);
-	return rc;
-    }
-
-    ioqueue->auto_delete_lock = PJ_TRUE;
-
-    *p_ioqueue = ioqueue;
-
-    PJ_LOG(4, ("pjlib", "WinNT IOCP I/O Queue created (%p)", ioqueue));
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_destroy()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioqueue )
-{
-    unsigned i;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
-
-    /* Destroy events in the pool */
-    for (i=0; i<ioqueue->event_count; ++i) {
-	CloseHandle(ioqueue->event_pool[i]);
-    }
-    ioqueue->event_count = 0;
-
-    if (CloseHandle(ioqueue->iocp) != TRUE)
-	return PJ_RETURN_OS_ERROR(GetLastError());
-
-    if (ioqueue->auto_delete_lock)
-        pj_lock_destroy(ioqueue->lock);
-
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_set_lock()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue, 
-					 pj_lock_t *lock,
-					 pj_bool_t auto_delete )
-{
-    PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);
-
-    if (ioqueue->auto_delete_lock) {
-        pj_lock_destroy(ioqueue->lock);
-    }
-
-    ioqueue->lock = lock;
-    ioqueue->auto_delete_lock = auto_delete;
-
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_register_sock()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
-					      pj_ioqueue_t *ioqueue,
-					      pj_sock_t sock,
-					      void *user_data,
-					      const pj_ioqueue_callback *cb,
-					      pj_ioqueue_key_t **key )
-{
-    HANDLE hioq;
-    pj_ioqueue_key_t *rec;
-    u_long value;
-    int rc;
-
-    PJ_ASSERT_RETURN(pool && ioqueue && cb && key, PJ_EINVAL);
-
-    /* Build the key for this socket. */
-    rec = pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
-    rec->ioqueue = ioqueue;
-    rec->hnd = (HANDLE)sock;
-    rec->hnd_type = HND_IS_SOCKET;
-    rec->user_data = user_data;
-    pj_memcpy(&rec->cb, cb, sizeof(pj_ioqueue_callback));
-
-    /* Set socket to nonblocking. */
-    value = 1;
-    rc = ioctlsocket(sock, FIONBIO, &value);
-    if (rc != 0) {
-        return PJ_RETURN_OS_ERROR(WSAGetLastError());
-    }
-
-    /* Associate with IOCP */
-    hioq = CreateIoCompletionPort((HANDLE)sock, ioqueue->iocp, (DWORD)rec, 0);
-    if (!hioq) {
-	return PJ_RETURN_OS_ERROR(GetLastError());
-    }
-
-    *key = rec;
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_unregister()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )
-{
-    PJ_ASSERT_RETURN(key, PJ_EINVAL);
-
-#if PJ_HAS_TCP
-    if (key->connecting) {
-	unsigned pos;
-        pj_ioqueue_t *ioqueue;
-
-        ioqueue = key->ioqueue;
-
-	/* Erase from connecting_handles */
-	pj_lock_acquire(ioqueue->lock);
-	for (pos=0; pos < ioqueue->connecting_count; ++pos) {
-	    if (ioqueue->connecting_keys[pos] == key) {
-		erase_connecting_socket(ioqueue, pos);
-		break;
-	    }
-	}
-	key->connecting = 0;
-	pj_lock_release(ioqueue->lock);
-    }
-#endif
-    if (key->hnd_type == HND_IS_FILE) {
-        CloseHandle(key->hnd);
-    }
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_get_user_data()
- */
-PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )
-{
-    PJ_ASSERT_RETURN(key, NULL);
-    return key->user_data;
-}
-
-/*
- * pj_ioqueue_set_user_data()
- */
-PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,
-                                              void *user_data,
-                                              void **old_data )
-{
-    PJ_ASSERT_RETURN(key, PJ_EINVAL);
-    
-    if (old_data)
-        *old_data = key->user_data;
-
-    key->user_data = user_data;
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_ioqueue_poll()
- *
- * Poll for events.
- */
-PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
-{
-    DWORD dwMsec, dwBytesTransfered, dwKey;
-    generic_overlapped *pOv;
-    pj_ioqueue_key_t *key;
-    pj_ssize_t size_status;
-    BOOL rc;
-
-    PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL);
-
-    /* Check the connecting array. */
-#if PJ_HAS_TCP
-    key = check_connecting(ioqueue, &size_status);
-    if (key != NULL) {
-	key->cb.on_connect_complete(key, (int)size_status);
-	return 1;
-    }
-#endif
-
-    /* Calculate miliseconds timeout for GetQueuedCompletionStatus */
-    dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE;
-
-    /* Poll for completion status. */
-    rc = GetQueuedCompletionStatus(ioqueue->iocp, &dwBytesTransfered, &dwKey,
-				   (OVERLAPPED**)&pOv, dwMsec);
-
-    /* The return value is:
-     * - nonzero if event was dequeued.
-     * - zero and pOv==NULL if no event was dequeued.
-     * - zero and pOv!=NULL if event for failed I/O was dequeued.
-     */
-    if (pOv) {
-	/* Event was dequeued for either successfull or failed I/O */
-	key = (pj_ioqueue_key_t*)dwKey;
-	size_status = dwBytesTransfered;
-	switch (pOv->operation) {
-	case PJ_IOQUEUE_OP_READ:
-	case PJ_IOQUEUE_OP_RECV:
-	case PJ_IOQUEUE_OP_RECV_FROM:
-            pOv->operation = 0;
-            if (key->cb.on_read_complete)
-	        key->cb.on_read_complete(key, (pj_ioqueue_op_key_t*)pOv, 
-                                         size_status);
-	    break;
-	case PJ_IOQUEUE_OP_WRITE:
-	case PJ_IOQUEUE_OP_SEND:
-	case PJ_IOQUEUE_OP_SEND_TO:
-            pOv->operation = 0;
-            if (key->cb.on_write_complete)
-	        key->cb.on_write_complete(key, (pj_ioqueue_op_key_t*)pOv, 
-                                                size_status);
-	    break;
-#if PJ_HAS_TCP
-	case PJ_IOQUEUE_OP_ACCEPT:
-	    /* special case for accept. */
-	    ioqueue_on_accept_complete((ioqueue_accept_rec*)pOv);
-            if (key->cb.on_accept_complete) {
-                ioqueue_accept_rec *accept_rec = (ioqueue_accept_rec*)pOv;
-	        key->cb.on_accept_complete(key, 
-                                           (pj_ioqueue_op_key_t*)pOv, 
-                                           accept_rec->newsock,
-                                           PJ_SUCCESS);
-            }
-	    break;
-	case PJ_IOQUEUE_OP_CONNECT:
-#endif
-	case PJ_IOQUEUE_OP_NONE:
-	    pj_assert(0);
-	    break;
-	}
-	return 1;
-    }
-
-    if (GetLastError()==WAIT_TIMEOUT) {
-	/* Check the connecting array (again). */
-#if PJ_HAS_TCP
-	key = check_connecting(ioqueue, &size_status);
-	if (key != NULL) {
-	    key->cb.on_connect_complete(key, (int)size_status);
-	    return 1;
-	}
-#endif
-	return 0;
-    }
-    return -1;
-}
-
-/*
- * pj_ioqueue_recv()
- *
- * Initiate overlapped WSARecv() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_recv(  pj_ioqueue_key_t *key,
-                                      pj_ioqueue_op_key_t *op_key,
-				      void *buffer,
-				      pj_ssize_t *length,
-				      unsigned flags )
-{
-    /*
-     * Ideally we should just call pj_ioqueue_recvfrom() with NULL addr and
-     * addrlen here. But unfortunately it generates EINVAL... :-(
-     *  -bennylp
-     */
-    int rc;
-    DWORD bytesRead;
-    DWORD dwFlags = 0;
-    union operation_key *op_key_rec;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);
-
-    op_key_rec = (union operation_key*)op_key->internal__;
-    op_key_rec->overlapped.wsabuf.buf = buffer;
-    op_key_rec->overlapped.wsabuf.len = *length;
-
-    dwFlags = flags;
-    
-    /* Try non-overlapped received first to see if data is
-     * immediately available.
-     */
-    rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
-                 &bytesRead, &dwFlags, NULL, NULL);
-    if (rc == 0) {
-        *length = bytesRead;
-        return PJ_SUCCESS;
-    } else {
-        DWORD dwError = WSAGetLastError();
-        if (dwError != WSAEWOULDBLOCK) {
-            *length = -1;
-            return PJ_RETURN_OS_ERROR(dwError);
-        }
-    }
-
-    /*
-     * No immediate data available.
-     * Register overlapped Recv() operation.
-     */
-    pj_memset(&op_key_rec->overlapped.overlapped, 0,
-              sizeof(op_key_rec->overlapped.overlapped));
-    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;
-
-    rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1, 
-                  &bytesRead, &dwFlags, 
-		  &op_key_rec->overlapped.overlapped, NULL);
-    if (rc == SOCKET_ERROR) {
-	DWORD dwStatus = WSAGetLastError();
-        if (dwStatus!=WSA_IO_PENDING) {
-            *length = -1;
-            return PJ_STATUS_FROM_OS(dwStatus);
-        }
-    }
-
-    /* Pending operation has been scheduled. */
-    return PJ_EPENDING;
-}
-
-/*
- * pj_ioqueue_recvfrom()
- *
- * Initiate overlapped RecvFrom() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,
-                                         pj_ioqueue_op_key_t *op_key,
-					 void *buffer,
-					 pj_ssize_t *length,
-                                         unsigned flags,
-					 pj_sockaddr_t *addr,
-					 int *addrlen)
-{
-    int rc;
-    DWORD bytesRead;
-    DWORD dwFlags = 0;
-    union operation_key *op_key_rec;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(key && op_key && buffer, PJ_EINVAL);
-
-    op_key_rec = (union operation_key*)op_key->internal__;
-    op_key_rec->overlapped.wsabuf.buf = buffer;
-    op_key_rec->overlapped.wsabuf.len = *length;
-
-    dwFlags = flags;
-    
-    /* Try non-overlapped received first to see if data is
-     * immediately available.
-     */
-    rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
-                     &bytesRead, &dwFlags, addr, addrlen, NULL, NULL);
-    if (rc == 0) {
-        *length = bytesRead;
-        return PJ_SUCCESS;
-    } else {
-        DWORD dwError = WSAGetLastError();
-        if (dwError != WSAEWOULDBLOCK) {
-            *length = -1;
-            return PJ_RETURN_OS_ERROR(dwError);
-        }
-    }
-
-    /*
-     * No immediate data available.
-     * Register overlapped Recv() operation.
-     */
-    pj_memset(&op_key_rec->overlapped.overlapped, 0,
-              sizeof(op_key_rec->overlapped.overlapped));
-    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;
-
-    rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1, 
-                     &bytesRead, &dwFlags, addr, addrlen,
-		     &op_key_rec->overlapped.overlapped, NULL);
-    if (rc == SOCKET_ERROR) {
-	DWORD dwStatus = WSAGetLastError();
-        if (dwStatus!=WSA_IO_PENDING) {
-            *length = -1;
-            return PJ_STATUS_FROM_OS(dwStatus);
-        }
-    } 
-    
-    /* Pending operation has been scheduled. */
-    return PJ_EPENDING;
-}
-
-/*
- * pj_ioqueue_send()
- *
- * Initiate overlapped Send operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_send(  pj_ioqueue_key_t *key,
-                                      pj_ioqueue_op_key_t *op_key,
-				      const void *data,
-				      pj_ssize_t *length,
-				      unsigned flags )
-{
-    return pj_ioqueue_sendto(key, op_key, data, length, flags, NULL, 0);
-}
-
-
-/*
- * pj_ioqueue_sendto()
- *
- * Initiate overlapped SendTo operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,
-                                       pj_ioqueue_op_key_t *op_key,
-				       const void *data,
-				       pj_ssize_t *length,
-                                       unsigned flags,
-				       const pj_sockaddr_t *addr,
-				       int addrlen)
-{
-    int rc;
-    DWORD bytesWritten;
-    DWORD dwFlags;
-    union operation_key *op_key_rec;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(key && op_key && data, PJ_EINVAL);
-    
-    op_key_rec = (union operation_key*)op_key->internal__;
-
-    dwFlags = flags;
-
-    /*
-     * First try blocking write.
-     */
-    op_key_rec->overlapped.wsabuf.buf = (void*)data;
-    op_key_rec->overlapped.wsabuf.len = *length;
-
-    rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
-                   &bytesWritten, dwFlags, addr, addrlen,
-                   NULL, NULL);
-    if (rc == 0) {
-        *length = bytesWritten;
-        return PJ_SUCCESS;
-    } else {
-        DWORD dwStatus = WSAGetLastError();
-        if (dwStatus != WSAEWOULDBLOCK) {
-            *length = -1;
-            return PJ_RETURN_OS_ERROR(dwStatus);
-        }
-    }
-
-    /*
-     * Data can't be sent immediately.
-     * Schedule asynchronous WSASend().
-     */
-    pj_memset(&op_key_rec->overlapped.overlapped, 0,
-              sizeof(op_key_rec->overlapped.overlapped));
-    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_SEND;
-
-    rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,
-                   &bytesWritten,  dwFlags, addr, addrlen,
-		   &op_key_rec->overlapped.overlapped, NULL);
-    if (rc == SOCKET_ERROR) {
-	DWORD dwStatus = WSAGetLastError();
-        if (dwStatus!=WSA_IO_PENDING)
-            return PJ_STATUS_FROM_OS(dwStatus);
-    }
-
-    /* Asynchronous operation successfully submitted. */
-    return PJ_EPENDING;
-}
-
-#if PJ_HAS_TCP
-
-/*
- * pj_ioqueue_accept()
- *
- * Initiate overlapped accept() operation.
- */
-PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,
-                                       pj_ioqueue_op_key_t *op_key,
-			               pj_sock_t *new_sock,
-			               pj_sockaddr_t *local,
-			               pj_sockaddr_t *remote,
-			               int *addrlen)
-{
-    BOOL rc;
-    DWORD bytesReceived;
-    pj_status_t status;
-    union operation_key *op_key_rec;
-    SOCKET sock;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);
-
-    /*
-     * See if there is a new connection immediately available.
-     */
-    sock = WSAAccept((SOCKET)key->hnd, remote, addrlen, NULL, 0);
-    if (sock != INVALID_SOCKET) {
-        /* Yes! New socket is available! */
-        int status;
-
-        status = getsockname(sock, local, addrlen);
-        if (status != 0) {
-            DWORD dwError = WSAGetLastError();
-            closesocket(sock);
-            return PJ_RETURN_OS_ERROR(dwError);
-        }
-
-        *new_sock = sock;
-        return PJ_SUCCESS;
-
-    } else {
-        DWORD dwError = WSAGetLastError();
-        if (dwError != WSAEWOULDBLOCK) {
-            return PJ_RETURN_OS_ERROR(dwError);
-        }
-    }
-
-    /*
-     * No connection is immediately available.
-     * Must schedule an asynchronous operation.
-     */
-    op_key_rec = (union operation_key*)op_key->internal__;
-    
-    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, 
-                            &op_key_rec->accept.newsock);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* On WinXP or later, use SO_UPDATE_ACCEPT_CONTEXT so that socket 
-     * addresses can be obtained with getsockname() and getpeername().
-     */
-    status = setsockopt(op_key_rec->accept.newsock, SOL_SOCKET,
-                        SO_UPDATE_ACCEPT_CONTEXT, 
-                        (char*)&key->hnd, sizeof(SOCKET));
-    /* SO_UPDATE_ACCEPT_CONTEXT is for WinXP or later.
-     * So ignore the error status.
-     */
-
-    op_key_rec->accept.operation = PJ_IOQUEUE_OP_ACCEPT;
-    op_key_rec->accept.addrlen = addrlen;
-    op_key_rec->accept.local = local;
-    op_key_rec->accept.remote = remote;
-    op_key_rec->accept.newsock_ptr = new_sock;
-    pj_memset(&op_key_rec->accept.overlapped, 0, 
-	      sizeof(op_key_rec->accept.overlapped));
-
-    rc = AcceptEx( (SOCKET)key->hnd, (SOCKET)op_key_rec->accept.newsock,
-		   op_key_rec->accept.accept_buf,
-		   0, ACCEPT_ADDR_LEN, ACCEPT_ADDR_LEN,
-		   &bytesReceived,
-		   &op_key_rec->accept.overlapped );
-
-    if (rc == TRUE) {
-	ioqueue_on_accept_complete(&op_key_rec->accept);
-	return PJ_SUCCESS;
-    } else {
-	DWORD dwStatus = WSAGetLastError();
-	if (dwStatus!=WSA_IO_PENDING)
-            return PJ_STATUS_FROM_OS(dwStatus);
-    }
-
-    /* Asynchronous Accept() has been submitted. */
-    return PJ_EPENDING;
-}
-
-
-/*
- * pj_ioqueue_connect()
- *
- * Initiate overlapped connect() operation (well, it's non-blocking actually,
- * since there's no overlapped version of connect()).
- */
-PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,
-					const pj_sockaddr_t *addr,
-					int addrlen )
-{
-    HANDLE hEvent;
-    pj_ioqueue_t *ioqueue;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);
-
-    /* Initiate connect() */
-    if (connect((pj_sock_t)key->hnd, addr, addrlen) != 0) {
-	DWORD dwStatus;
-	dwStatus = WSAGetLastError();
-        if (dwStatus != WSAEWOULDBLOCK) {
-	    return PJ_RETURN_OS_ERROR(dwStatus);
-	}
-    } else {
-	/* Connect has completed immediately! */
-	return PJ_SUCCESS;
-    }
-
-    ioqueue = key->ioqueue;
-
-    /* Add to the array of connecting socket to be polled */
-    pj_lock_acquire(ioqueue->lock);
-
-    if (ioqueue->connecting_count >= MAXIMUM_WAIT_OBJECTS) {
-	pj_lock_release(ioqueue->lock);
-	return PJ_ETOOMANYCONN;
-    }
-
-    /* Get or create event object. */
-    if (ioqueue->event_count) {
-	hEvent = ioqueue->event_pool[ioqueue->event_count - 1];
-	--ioqueue->event_count;
-    } else {
-	hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-	if (hEvent == NULL) {
-	    DWORD dwStatus = GetLastError();
-	    pj_lock_release(ioqueue->lock);
-	    return PJ_STATUS_FROM_OS(dwStatus);
-	}
-    }
-
-    /* Mark key as connecting.
-     * We can't use array index since key can be removed dynamically. 
-     */
-    key->connecting = 1;
-
-    /* Associate socket events to the event object. */
-    if (WSAEventSelect((pj_sock_t)key->hnd, hEvent, FD_CONNECT) != 0) {
-	CloseHandle(hEvent);
-	pj_lock_release(ioqueue->lock);
-	return PJ_RETURN_OS_ERROR(WSAGetLastError());
-    }
-
-    /* Add to array. */
-    ioqueue->connecting_keys[ ioqueue->connecting_count ] = key;
-    ioqueue->connecting_handles[ ioqueue->connecting_count ] = hEvent;
-    ioqueue->connecting_count++;
-
-    pj_lock_release(ioqueue->lock);
-
-    return PJ_EPENDING;
-}
-#endif	/* #if PJ_HAS_TCP */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/ioqueue.h>

+#include <pj/os.h>

+#include <pj/lock.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/sock.h>

+#include <pj/array.h>

+#include <pj/log.h>

+#include <pj/assert.h>

+#include <pj/errno.h>

+

+

+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0

+#  include <winsock2.h>

+#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0

+#  include <winsock.h>

+#endif

+

+#if defined(PJ_HAS_MSWSOCK_H) && PJ_HAS_MSWSOCK_H != 0

+#  include <mswsock.h>

+#endif

+

+

+/* The address specified in AcceptEx() must be 16 more than the size of

+ * SOCKADDR (source: MSDN).

+ */

+#define ACCEPT_ADDR_LEN	    (sizeof(pj_sockaddr_in)+16)

+

+typedef struct generic_overlapped

+{

+    WSAOVERLAPPED	   overlapped;

+    pj_ioqueue_operation_e operation;

+} generic_overlapped;

+

+/*

+ * OVERLAPPPED structure for send and receive.

+ */

+typedef struct ioqueue_overlapped

+{

+    WSAOVERLAPPED	   overlapped;

+    pj_ioqueue_operation_e operation;

+    WSABUF		   wsabuf;

+    pj_sockaddr_in         dummy_addr;

+    int                    dummy_addrlen;

+} ioqueue_overlapped;

+

+#if PJ_HAS_TCP

+/*

+ * OVERLAP structure for accept.

+ */

+typedef struct ioqueue_accept_rec

+{

+    WSAOVERLAPPED	    overlapped;

+    pj_ioqueue_operation_e  operation;

+    pj_sock_t		    newsock;

+    pj_sock_t		   *newsock_ptr;

+    int			   *addrlen;

+    void		   *remote;

+    void		   *local;

+    char		    accept_buf[2 * ACCEPT_ADDR_LEN];

+} ioqueue_accept_rec;

+#endif

+

+/*

+ * Structure to hold pending operation key.

+ */

+union operation_key

+{

+    generic_overlapped      generic;

+    ioqueue_overlapped      overlapped;

+#if PJ_HAS_TCP

+    ioqueue_accept_rec      accept;

+#endif

+};

+

+/* Type of handle in the key. */

+enum handle_type

+{

+    HND_IS_UNKNOWN,

+    HND_IS_FILE,

+    HND_IS_SOCKET,

+};

+

+/*

+ * Structure for individual socket.

+ */

+struct pj_ioqueue_key_t

+{

+    pj_ioqueue_t       *ioqueue;

+    HANDLE		hnd;

+    void	       *user_data;

+    enum handle_type    hnd_type;

+#if PJ_HAS_TCP

+    int			connecting;

+#endif

+    pj_ioqueue_callback	cb;

+};

+

+/*

+ * IO Queue structure.

+ */

+struct pj_ioqueue_t

+{

+    HANDLE	      iocp;

+    pj_lock_t        *lock;

+    pj_bool_t         auto_delete_lock;

+    unsigned	      event_count;

+    HANDLE	      event_pool[MAXIMUM_WAIT_OBJECTS+1];

+#if PJ_HAS_TCP

+    unsigned	      connecting_count;

+    HANDLE	      connecting_handles[MAXIMUM_WAIT_OBJECTS+1];

+    pj_ioqueue_key_t *connecting_keys[MAXIMUM_WAIT_OBJECTS+1];

+#endif

+};

+

+

+#if PJ_HAS_TCP

+/*

+ * Process the socket when the overlapped accept() completed.

+ */

+static void ioqueue_on_accept_complete(ioqueue_accept_rec *accept_overlapped)

+{

+    struct sockaddr *local;

+    struct sockaddr *remote;

+    int locallen, remotelen;

+

+    PJ_CHECK_STACK();

+

+    /* Operation complete immediately. */

+    GetAcceptExSockaddrs( accept_overlapped->accept_buf,

+			  0, 

+			  ACCEPT_ADDR_LEN,

+			  ACCEPT_ADDR_LEN,

+			  &local,

+			  &locallen,

+			  &remote,

+			  &remotelen);

+    if (*accept_overlapped->addrlen > locallen) {

+        pj_memcpy(accept_overlapped->local, local, locallen);

+        pj_memcpy(accept_overlapped->remote, remote, locallen);

+    } else {

+        pj_memset(accept_overlapped->local, 0, *accept_overlapped->addrlen);

+        pj_memset(accept_overlapped->remote, 0, *accept_overlapped->addrlen);

+    }

+    *accept_overlapped->addrlen = locallen;

+    if (accept_overlapped->newsock_ptr)

+        *accept_overlapped->newsock_ptr = accept_overlapped->newsock;

+    accept_overlapped->operation = 0;

+    accept_overlapped->newsock = PJ_INVALID_SOCKET;

+}

+

+static void erase_connecting_socket( pj_ioqueue_t *ioqueue, unsigned pos)

+{

+    pj_ioqueue_key_t *key = ioqueue->connecting_keys[pos];

+    HANDLE hEvent = ioqueue->connecting_handles[pos];

+

+    /* Remove key from array of connecting handles. */

+    pj_array_erase(ioqueue->connecting_keys, sizeof(key),

+		   ioqueue->connecting_count, pos);

+    pj_array_erase(ioqueue->connecting_handles, sizeof(HANDLE),

+		   ioqueue->connecting_count, pos);

+    --ioqueue->connecting_count;

+

+    /* Disassociate the socket from the event. */

+    WSAEventSelect((pj_sock_t)key->hnd, hEvent, 0);

+

+    /* Put event object to pool. */

+    if (ioqueue->event_count < MAXIMUM_WAIT_OBJECTS) {

+	ioqueue->event_pool[ioqueue->event_count++] = hEvent;

+    } else {

+	/* Shouldn't happen. There should be no more pending connections

+	 * than max. 

+	 */

+	pj_assert(0);

+	CloseHandle(hEvent);

+    }

+

+}

+

+/*

+ * Poll for the completion of non-blocking connect().

+ * If there's a completion, the function return the key of the completed

+ * socket, and 'result' argument contains the connect() result. If connect()

+ * succeeded, 'result' will have value zero, otherwise will have the error

+ * code.

+ */

+static pj_ioqueue_key_t *check_connecting( pj_ioqueue_t *ioqueue, 

+					   pj_ssize_t *connect_err )

+{

+    pj_ioqueue_key_t *key = NULL;

+

+    if (ioqueue->connecting_count) {

+	DWORD result;

+

+	pj_lock_acquire(ioqueue->lock);

+	result = WaitForMultipleObjects(ioqueue->connecting_count,

+					ioqueue->connecting_handles,

+					FALSE, 0);

+	if (result >= WAIT_OBJECT_0 && 

+	    result < WAIT_OBJECT_0+ioqueue->connecting_count) 

+	{

+	    WSANETWORKEVENTS net_events;

+

+	    /* Got completed connect(). */

+	    unsigned pos = result - WAIT_OBJECT_0;

+	    key = ioqueue->connecting_keys[pos];

+

+	    /* See whether connect has succeeded. */

+	    WSAEnumNetworkEvents((pj_sock_t)key->hnd, 

+				 ioqueue->connecting_handles[pos], 

+				 &net_events);

+	    *connect_err = 

+                PJ_STATUS_FROM_OS(net_events.iErrorCode[FD_CONNECT_BIT]);

+

+	    /* Erase socket from pending connect. */

+	    erase_connecting_socket(ioqueue, pos);

+	}

+	pj_lock_release(ioqueue->lock);

+    }

+    return key;

+}

+#endif

+

+/*

+ * pj_ioqueue_name()

+ */

+PJ_DEF(const char*) pj_ioqueue_name(void)

+{

+    return "iocp";

+}

+

+/*

+ * pj_ioqueue_create()

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool, 

+				       pj_size_t max_fd,

+				       pj_ioqueue_t **p_ioqueue)

+{

+    pj_ioqueue_t *ioqueue;

+    pj_status_t rc;

+

+    PJ_UNUSED_ARG(max_fd);

+    PJ_ASSERT_RETURN(pool && p_ioqueue, PJ_EINVAL);

+

+    rc = sizeof(union operation_key);

+

+    /* Check that sizeof(pj_ioqueue_op_key_t) makes sense. */

+    PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >= 

+                     sizeof(union operation_key), PJ_EBUG);

+

+    ioqueue = pj_pool_zalloc(pool, sizeof(*ioqueue));

+    ioqueue->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

+    if (ioqueue->iocp == NULL)

+	return PJ_RETURN_OS_ERROR(GetLastError());

+

+    rc = pj_lock_create_simple_mutex(pool, NULL, &ioqueue->lock);

+    if (rc != PJ_SUCCESS) {

+	CloseHandle(ioqueue->iocp);

+	return rc;

+    }

+

+    ioqueue->auto_delete_lock = PJ_TRUE;

+

+    *p_ioqueue = ioqueue;

+

+    PJ_LOG(4, ("pjlib", "WinNT IOCP I/O Queue created (%p)", ioqueue));

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_ioqueue_destroy()

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_destroy( pj_ioqueue_t *ioqueue )

+{

+    unsigned i;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);

+

+    /* Destroy events in the pool */

+    for (i=0; i<ioqueue->event_count; ++i) {

+	CloseHandle(ioqueue->event_pool[i]);

+    }

+    ioqueue->event_count = 0;

+

+    if (CloseHandle(ioqueue->iocp) != TRUE)

+	return PJ_RETURN_OS_ERROR(GetLastError());

+

+    if (ioqueue->auto_delete_lock)

+        pj_lock_destroy(ioqueue->lock);

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_ioqueue_set_lock()

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_set_lock( pj_ioqueue_t *ioqueue, 

+					 pj_lock_t *lock,

+					 pj_bool_t auto_delete )

+{

+    PJ_ASSERT_RETURN(ioqueue && lock, PJ_EINVAL);

+

+    if (ioqueue->auto_delete_lock) {

+        pj_lock_destroy(ioqueue->lock);

+    }

+

+    ioqueue->lock = lock;

+    ioqueue->auto_delete_lock = auto_delete;

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_ioqueue_register_sock()

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,

+					      pj_ioqueue_t *ioqueue,

+					      pj_sock_t sock,

+					      void *user_data,

+					      const pj_ioqueue_callback *cb,

+					      pj_ioqueue_key_t **key )

+{

+    HANDLE hioq;

+    pj_ioqueue_key_t *rec;

+    u_long value;

+    int rc;

+

+    PJ_ASSERT_RETURN(pool && ioqueue && cb && key, PJ_EINVAL);

+

+    /* Build the key for this socket. */

+    rec = pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));

+    rec->ioqueue = ioqueue;

+    rec->hnd = (HANDLE)sock;

+    rec->hnd_type = HND_IS_SOCKET;

+    rec->user_data = user_data;

+    pj_memcpy(&rec->cb, cb, sizeof(pj_ioqueue_callback));

+

+    /* Set socket to nonblocking. */

+    value = 1;

+    rc = ioctlsocket(sock, FIONBIO, &value);

+    if (rc != 0) {

+        return PJ_RETURN_OS_ERROR(WSAGetLastError());

+    }

+

+    /* Associate with IOCP */

+    hioq = CreateIoCompletionPort((HANDLE)sock, ioqueue->iocp, (DWORD)rec, 0);

+    if (!hioq) {

+	return PJ_RETURN_OS_ERROR(GetLastError());

+    }

+

+    *key = rec;

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_ioqueue_unregister()

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key )

+{

+    PJ_ASSERT_RETURN(key, PJ_EINVAL);

+

+#if PJ_HAS_TCP

+    if (key->connecting) {

+	unsigned pos;

+        pj_ioqueue_t *ioqueue;

+

+        ioqueue = key->ioqueue;

+

+	/* Erase from connecting_handles */

+	pj_lock_acquire(ioqueue->lock);

+	for (pos=0; pos < ioqueue->connecting_count; ++pos) {

+	    if (ioqueue->connecting_keys[pos] == key) {

+		erase_connecting_socket(ioqueue, pos);

+		break;

+	    }

+	}

+	key->connecting = 0;

+	pj_lock_release(ioqueue->lock);

+    }

+#endif

+    if (key->hnd_type == HND_IS_FILE) {

+        CloseHandle(key->hnd);

+    }

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_ioqueue_get_user_data()

+ */

+PJ_DEF(void*) pj_ioqueue_get_user_data( pj_ioqueue_key_t *key )

+{

+    PJ_ASSERT_RETURN(key, NULL);

+    return key->user_data;

+}

+

+/*

+ * pj_ioqueue_set_user_data()

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_set_user_data( pj_ioqueue_key_t *key,

+                                              void *user_data,

+                                              void **old_data )

+{

+    PJ_ASSERT_RETURN(key, PJ_EINVAL);

+    

+    if (old_data)

+        *old_data = key->user_data;

+

+    key->user_data = user_data;

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_ioqueue_poll()

+ *

+ * Poll for events.

+ */

+PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)

+{

+    DWORD dwMsec, dwBytesTransfered, dwKey;

+    generic_overlapped *pOv;

+    pj_ioqueue_key_t *key;

+    pj_ssize_t size_status;

+    BOOL rc;

+

+    PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL);

+

+    /* Check the connecting array. */

+#if PJ_HAS_TCP

+    key = check_connecting(ioqueue, &size_status);

+    if (key != NULL) {

+	key->cb.on_connect_complete(key, (int)size_status);

+	return 1;

+    }

+#endif

+

+    /* Calculate miliseconds timeout for GetQueuedCompletionStatus */

+    dwMsec = timeout ? timeout->sec*1000 + timeout->msec : INFINITE;

+

+    /* Poll for completion status. */

+    rc = GetQueuedCompletionStatus(ioqueue->iocp, &dwBytesTransfered, &dwKey,

+				   (OVERLAPPED**)&pOv, dwMsec);

+

+    /* The return value is:

+     * - nonzero if event was dequeued.

+     * - zero and pOv==NULL if no event was dequeued.

+     * - zero and pOv!=NULL if event for failed I/O was dequeued.

+     */

+    if (pOv) {

+	/* Event was dequeued for either successfull or failed I/O */

+	key = (pj_ioqueue_key_t*)dwKey;

+	size_status = dwBytesTransfered;

+	switch (pOv->operation) {

+	case PJ_IOQUEUE_OP_READ:

+	case PJ_IOQUEUE_OP_RECV:

+	case PJ_IOQUEUE_OP_RECV_FROM:

+            pOv->operation = 0;

+            if (key->cb.on_read_complete)

+	        key->cb.on_read_complete(key, (pj_ioqueue_op_key_t*)pOv, 

+                                         size_status);

+	    break;

+	case PJ_IOQUEUE_OP_WRITE:

+	case PJ_IOQUEUE_OP_SEND:

+	case PJ_IOQUEUE_OP_SEND_TO:

+            pOv->operation = 0;

+            if (key->cb.on_write_complete)

+	        key->cb.on_write_complete(key, (pj_ioqueue_op_key_t*)pOv, 

+                                                size_status);

+	    break;

+#if PJ_HAS_TCP

+	case PJ_IOQUEUE_OP_ACCEPT:

+	    /* special case for accept. */

+	    ioqueue_on_accept_complete((ioqueue_accept_rec*)pOv);

+            if (key->cb.on_accept_complete) {

+                ioqueue_accept_rec *accept_rec = (ioqueue_accept_rec*)pOv;

+	        key->cb.on_accept_complete(key, 

+                                           (pj_ioqueue_op_key_t*)pOv, 

+                                           accept_rec->newsock,

+                                           PJ_SUCCESS);

+            }

+	    break;

+	case PJ_IOQUEUE_OP_CONNECT:

+#endif

+	case PJ_IOQUEUE_OP_NONE:

+	    pj_assert(0);

+	    break;

+	}

+	return 1;

+    }

+

+    if (GetLastError()==WAIT_TIMEOUT) {

+	/* Check the connecting array (again). */

+#if PJ_HAS_TCP

+	key = check_connecting(ioqueue, &size_status);

+	if (key != NULL) {

+	    key->cb.on_connect_complete(key, (int)size_status);

+	    return 1;

+	}

+#endif

+	return 0;

+    }

+    return -1;

+}

+

+/*

+ * pj_ioqueue_recv()

+ *

+ * Initiate overlapped WSARecv() operation.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_recv(  pj_ioqueue_key_t *key,

+                                      pj_ioqueue_op_key_t *op_key,

+				      void *buffer,

+				      pj_ssize_t *length,

+				      unsigned flags )

+{

+    /*

+     * Ideally we should just call pj_ioqueue_recvfrom() with NULL addr and

+     * addrlen here. But unfortunately it generates EINVAL... :-(

+     *  -bennylp

+     */

+    int rc;

+    DWORD bytesRead;

+    DWORD dwFlags = 0;

+    union operation_key *op_key_rec;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(key && op_key && buffer && length, PJ_EINVAL);

+

+    op_key_rec = (union operation_key*)op_key->internal__;

+    op_key_rec->overlapped.wsabuf.buf = buffer;

+    op_key_rec->overlapped.wsabuf.len = *length;

+

+    dwFlags = flags;

+    

+    /* Try non-overlapped received first to see if data is

+     * immediately available.

+     */

+    rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,

+                 &bytesRead, &dwFlags, NULL, NULL);

+    if (rc == 0) {

+        *length = bytesRead;

+        return PJ_SUCCESS;

+    } else {

+        DWORD dwError = WSAGetLastError();

+        if (dwError != WSAEWOULDBLOCK) {

+            *length = -1;

+            return PJ_RETURN_OS_ERROR(dwError);

+        }

+    }

+

+    /*

+     * No immediate data available.

+     * Register overlapped Recv() operation.

+     */

+    pj_memset(&op_key_rec->overlapped.overlapped, 0,

+              sizeof(op_key_rec->overlapped.overlapped));

+    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;

+

+    rc = WSARecv((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1, 

+                  &bytesRead, &dwFlags, 

+		  &op_key_rec->overlapped.overlapped, NULL);

+    if (rc == SOCKET_ERROR) {

+	DWORD dwStatus = WSAGetLastError();

+        if (dwStatus!=WSA_IO_PENDING) {

+            *length = -1;

+            return PJ_STATUS_FROM_OS(dwStatus);

+        }

+    }

+

+    /* Pending operation has been scheduled. */

+    return PJ_EPENDING;

+}

+

+/*

+ * pj_ioqueue_recvfrom()

+ *

+ * Initiate overlapped RecvFrom() operation.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_recvfrom( pj_ioqueue_key_t *key,

+                                         pj_ioqueue_op_key_t *op_key,

+					 void *buffer,

+					 pj_ssize_t *length,

+                                         unsigned flags,

+					 pj_sockaddr_t *addr,

+					 int *addrlen)

+{

+    int rc;

+    DWORD bytesRead;

+    DWORD dwFlags = 0;

+    union operation_key *op_key_rec;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(key && op_key && buffer, PJ_EINVAL);

+

+    op_key_rec = (union operation_key*)op_key->internal__;

+    op_key_rec->overlapped.wsabuf.buf = buffer;

+    op_key_rec->overlapped.wsabuf.len = *length;

+

+    dwFlags = flags;

+    

+    /* Try non-overlapped received first to see if data is

+     * immediately available.

+     */

+    rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,

+                     &bytesRead, &dwFlags, addr, addrlen, NULL, NULL);

+    if (rc == 0) {

+        *length = bytesRead;

+        return PJ_SUCCESS;

+    } else {

+        DWORD dwError = WSAGetLastError();

+        if (dwError != WSAEWOULDBLOCK) {

+            *length = -1;

+            return PJ_RETURN_OS_ERROR(dwError);

+        }

+    }

+

+    /*

+     * No immediate data available.

+     * Register overlapped Recv() operation.

+     */

+    pj_memset(&op_key_rec->overlapped.overlapped, 0,

+              sizeof(op_key_rec->overlapped.overlapped));

+    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_RECV;

+

+    rc = WSARecvFrom((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1, 

+                     &bytesRead, &dwFlags, addr, addrlen,

+		     &op_key_rec->overlapped.overlapped, NULL);

+    if (rc == SOCKET_ERROR) {

+	DWORD dwStatus = WSAGetLastError();

+        if (dwStatus!=WSA_IO_PENDING) {

+            *length = -1;

+            return PJ_STATUS_FROM_OS(dwStatus);

+        }

+    } 

+    

+    /* Pending operation has been scheduled. */

+    return PJ_EPENDING;

+}

+

+/*

+ * pj_ioqueue_send()

+ *

+ * Initiate overlapped Send operation.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_send(  pj_ioqueue_key_t *key,

+                                      pj_ioqueue_op_key_t *op_key,

+				      const void *data,

+				      pj_ssize_t *length,

+				      unsigned flags )

+{

+    return pj_ioqueue_sendto(key, op_key, data, length, flags, NULL, 0);

+}

+

+

+/*

+ * pj_ioqueue_sendto()

+ *

+ * Initiate overlapped SendTo operation.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_sendto( pj_ioqueue_key_t *key,

+                                       pj_ioqueue_op_key_t *op_key,

+				       const void *data,

+				       pj_ssize_t *length,

+                                       unsigned flags,

+				       const pj_sockaddr_t *addr,

+				       int addrlen)

+{

+    int rc;

+    DWORD bytesWritten;

+    DWORD dwFlags;

+    union operation_key *op_key_rec;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(key && op_key && data, PJ_EINVAL);

+    

+    op_key_rec = (union operation_key*)op_key->internal__;

+

+    dwFlags = flags;

+

+    /*

+     * First try blocking write.

+     */

+    op_key_rec->overlapped.wsabuf.buf = (void*)data;

+    op_key_rec->overlapped.wsabuf.len = *length;

+

+    rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,

+                   &bytesWritten, dwFlags, addr, addrlen,

+                   NULL, NULL);

+    if (rc == 0) {

+        *length = bytesWritten;

+        return PJ_SUCCESS;

+    } else {

+        DWORD dwStatus = WSAGetLastError();

+        if (dwStatus != WSAEWOULDBLOCK) {

+            *length = -1;

+            return PJ_RETURN_OS_ERROR(dwStatus);

+        }

+    }

+

+    /*

+     * Data can't be sent immediately.

+     * Schedule asynchronous WSASend().

+     */

+    pj_memset(&op_key_rec->overlapped.overlapped, 0,

+              sizeof(op_key_rec->overlapped.overlapped));

+    op_key_rec->overlapped.operation = PJ_IOQUEUE_OP_SEND;

+

+    rc = WSASendTo((SOCKET)key->hnd, &op_key_rec->overlapped.wsabuf, 1,

+                   &bytesWritten,  dwFlags, addr, addrlen,

+		   &op_key_rec->overlapped.overlapped, NULL);

+    if (rc == SOCKET_ERROR) {

+	DWORD dwStatus = WSAGetLastError();

+        if (dwStatus!=WSA_IO_PENDING)

+            return PJ_STATUS_FROM_OS(dwStatus);

+    }

+

+    /* Asynchronous operation successfully submitted. */

+    return PJ_EPENDING;

+}

+

+#if PJ_HAS_TCP

+

+/*

+ * pj_ioqueue_accept()

+ *

+ * Initiate overlapped accept() operation.

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_accept( pj_ioqueue_key_t *key,

+                                       pj_ioqueue_op_key_t *op_key,

+			               pj_sock_t *new_sock,

+			               pj_sockaddr_t *local,

+			               pj_sockaddr_t *remote,

+			               int *addrlen)

+{

+    BOOL rc;

+    DWORD bytesReceived;

+    pj_status_t status;

+    union operation_key *op_key_rec;

+    SOCKET sock;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(key && op_key && new_sock, PJ_EINVAL);

+

+    /*

+     * See if there is a new connection immediately available.

+     */

+    sock = WSAAccept((SOCKET)key->hnd, remote, addrlen, NULL, 0);

+    if (sock != INVALID_SOCKET) {

+        /* Yes! New socket is available! */

+        int status;

+

+        status = getsockname(sock, local, addrlen);

+        if (status != 0) {

+            DWORD dwError = WSAGetLastError();

+            closesocket(sock);

+            return PJ_RETURN_OS_ERROR(dwError);

+        }

+

+        *new_sock = sock;

+        return PJ_SUCCESS;

+

+    } else {

+        DWORD dwError = WSAGetLastError();

+        if (dwError != WSAEWOULDBLOCK) {

+            return PJ_RETURN_OS_ERROR(dwError);

+        }

+    }

+

+    /*

+     * No connection is immediately available.

+     * Must schedule an asynchronous operation.

+     */

+    op_key_rec = (union operation_key*)op_key->internal__;

+    

+    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, 

+                            &op_key_rec->accept.newsock);

+    if (status != PJ_SUCCESS)

+	return status;

+

+    /* On WinXP or later, use SO_UPDATE_ACCEPT_CONTEXT so that socket 

+     * addresses can be obtained with getsockname() and getpeername().

+     */

+    status = setsockopt(op_key_rec->accept.newsock, SOL_SOCKET,

+                        SO_UPDATE_ACCEPT_CONTEXT, 

+                        (char*)&key->hnd, sizeof(SOCKET));

+    /* SO_UPDATE_ACCEPT_CONTEXT is for WinXP or later.

+     * So ignore the error status.

+     */

+

+    op_key_rec->accept.operation = PJ_IOQUEUE_OP_ACCEPT;

+    op_key_rec->accept.addrlen = addrlen;

+    op_key_rec->accept.local = local;

+    op_key_rec->accept.remote = remote;

+    op_key_rec->accept.newsock_ptr = new_sock;

+    pj_memset(&op_key_rec->accept.overlapped, 0, 

+	      sizeof(op_key_rec->accept.overlapped));

+

+    rc = AcceptEx( (SOCKET)key->hnd, (SOCKET)op_key_rec->accept.newsock,

+		   op_key_rec->accept.accept_buf,

+		   0, ACCEPT_ADDR_LEN, ACCEPT_ADDR_LEN,

+		   &bytesReceived,

+		   &op_key_rec->accept.overlapped );

+

+    if (rc == TRUE) {

+	ioqueue_on_accept_complete(&op_key_rec->accept);

+	return PJ_SUCCESS;

+    } else {

+	DWORD dwStatus = WSAGetLastError();

+	if (dwStatus!=WSA_IO_PENDING)

+            return PJ_STATUS_FROM_OS(dwStatus);

+    }

+

+    /* Asynchronous Accept() has been submitted. */

+    return PJ_EPENDING;

+}

+

+

+/*

+ * pj_ioqueue_connect()

+ *

+ * Initiate overlapped connect() operation (well, it's non-blocking actually,

+ * since there's no overlapped version of connect()).

+ */

+PJ_DEF(pj_status_t) pj_ioqueue_connect( pj_ioqueue_key_t *key,

+					const pj_sockaddr_t *addr,

+					int addrlen )

+{

+    HANDLE hEvent;

+    pj_ioqueue_t *ioqueue;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(key && addr && addrlen, PJ_EINVAL);

+

+    /* Initiate connect() */

+    if (connect((pj_sock_t)key->hnd, addr, addrlen) != 0) {

+	DWORD dwStatus;

+	dwStatus = WSAGetLastError();

+        if (dwStatus != WSAEWOULDBLOCK) {

+	    return PJ_RETURN_OS_ERROR(dwStatus);

+	}

+    } else {

+	/* Connect has completed immediately! */

+	return PJ_SUCCESS;

+    }

+

+    ioqueue = key->ioqueue;

+

+    /* Add to the array of connecting socket to be polled */

+    pj_lock_acquire(ioqueue->lock);

+

+    if (ioqueue->connecting_count >= MAXIMUM_WAIT_OBJECTS) {

+	pj_lock_release(ioqueue->lock);

+	return PJ_ETOOMANYCONN;

+    }

+

+    /* Get or create event object. */

+    if (ioqueue->event_count) {

+	hEvent = ioqueue->event_pool[ioqueue->event_count - 1];

+	--ioqueue->event_count;

+    } else {

+	hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

+	if (hEvent == NULL) {

+	    DWORD dwStatus = GetLastError();

+	    pj_lock_release(ioqueue->lock);

+	    return PJ_STATUS_FROM_OS(dwStatus);

+	}

+    }

+

+    /* Mark key as connecting.

+     * We can't use array index since key can be removed dynamically. 

+     */

+    key->connecting = 1;

+

+    /* Associate socket events to the event object. */

+    if (WSAEventSelect((pj_sock_t)key->hnd, hEvent, FD_CONNECT) != 0) {

+	CloseHandle(hEvent);

+	pj_lock_release(ioqueue->lock);

+	return PJ_RETURN_OS_ERROR(WSAGetLastError());

+    }

+

+    /* Add to array. */

+    ioqueue->connecting_keys[ ioqueue->connecting_count ] = key;

+    ioqueue->connecting_handles[ ioqueue->connecting_count ] = hEvent;

+    ioqueue->connecting_count++;

+

+    pj_lock_release(ioqueue->lock);

+

+    return PJ_EPENDING;

+}

+#endif	/* #if PJ_HAS_TCP */

+

 

 PJ_DEF(void) pj_ioqueue_op_key_init( pj_ioqueue_op_key_t *op_key,

 				     pj_size_t size )

diff --git a/pjlib/src/pj/list.c b/pjlib/src/pj/list.c
index a85108c..3ffbfdc 100644
--- a/pjlib/src/pj/list.c
+++ b/pjlib/src/pj/list.c
@@ -1,9 +1,30 @@
-/* $Id$
- */
-#include <pj/list.h>
-
-#if !PJ_FUNCTIONS_ARE_INLINED
-#  include <pj/list_i.h>
-#endif
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/list.h>

+

+#if !PJ_FUNCTIONS_ARE_INLINED

+#  include <pj/list_i.h>

+#endif

+

+

diff --git a/pjlib/src/pj/lock.c b/pjlib/src/pj/lock.c
index a81e132..ff6236a 100644
--- a/pjlib/src/pj/lock.c
+++ b/pjlib/src/pj/lock.c
@@ -1,178 +1,199 @@
-/* $Id$
- */
-#include <pj/lock.h>
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/errno.h>
-
-
-typedef void LOCK_OBJ;
-
-/*
- * Lock structure.
- */
-struct pj_lock_t
-{
-    LOCK_OBJ *lock_object;
-
-    pj_status_t	(*acquire)	(LOCK_OBJ*);
-    pj_status_t	(*tryacquire)	(LOCK_OBJ*);
-    pj_status_t	(*release)	(LOCK_OBJ*);
-    pj_status_t	(*destroy)	(LOCK_OBJ*);
-};
-
-typedef pj_status_t (*FPTR)(LOCK_OBJ*);
-
-/******************************************************************************
- * Implementation of lock object with mutex.
- */
-static pj_lock_t mutex_lock_template = 
-{
-    NULL,
-    (FPTR) &pj_mutex_lock,
-    (FPTR) &pj_mutex_trylock,
-    (FPTR) &pj_mutex_unlock,
-    (FPTR) &pj_mutex_destroy
-};
-
-static pj_status_t create_mutex_lock( pj_pool_t *pool,
-				      const char *name,
-				      int type,
-				      pj_lock_t **lock )
-{
-    pj_lock_t *p_lock;
-    pj_status_t rc;
-
-    PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
-
-    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
-    if (!p_lock)
-	return PJ_ENOMEM;
-
-    pj_memcpy(p_lock, &mutex_lock_template, sizeof(pj_lock_t));
-    rc = pj_mutex_create(pool, name, type, (pj_mutex_t**)&p_lock->lock_object);
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    *lock = p_lock;
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,
-						 const char *name,
-						 pj_lock_t **lock )
-{
-    return create_mutex_lock(pool, name, PJ_MUTEX_SIMPLE, lock);
-}
-
-PJ_DEF(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,
-						    const char *name,
-						    pj_lock_t **lock )
-{
-    return create_mutex_lock(pool, name, PJ_MUTEX_RECURSE, lock);
-}
-
-
-/******************************************************************************
- * Implementation of NULL lock object.
- */
-static pj_status_t null_op(void *arg)
-{
-    PJ_UNUSED_ARG(arg);
-    return PJ_SUCCESS;
-}
-
-static pj_lock_t null_lock_template = 
-{
-    NULL,
-    &null_op,
-    &null_op,
-    &null_op,
-    &null_op
-};
-
-PJ_DEF(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,
-					       const char *name,
-					       pj_lock_t **lock )
-{
-    PJ_UNUSED_ARG(name);
-    PJ_UNUSED_ARG(pool);
-
-    PJ_ASSERT_RETURN(lock, PJ_EINVAL);
-
-    *lock = &null_lock_template;
-    return PJ_SUCCESS;
-}
-
-
-/******************************************************************************
- * Implementation of semaphore lock object.
- */
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-
-static pj_lock_t sem_lock_template = 
-{
-    NULL,
-    (FPTR) &pj_sem_wait,
-    (FPTR) &pj_sem_trywait,
-    (FPTR) &pj_sem_post,
-    (FPTR) &pj_sem_destroy
-};
-
-PJ_DEF(pj_status_t) pj_lock_create_semaphore(  pj_pool_t *pool,
-					       const char *name,
-					       unsigned initial,
-					       unsigned max,
-					       pj_lock_t **lock )
-{
-    pj_lock_t *p_lock;
-    pj_status_t rc;
-
-    PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);
-
-    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));
-    if (!p_lock)
-	return PJ_ENOMEM;
-
-    pj_memcpy(p_lock, &sem_lock_template, sizeof(pj_lock_t));
-    rc = pj_sem_create( pool, name, initial, max, 
-		        (pj_sem_t**)&p_lock->lock_object);
-    if (rc != PJ_SUCCESS)
-        return rc;
-
-    *lock = p_lock;
-
-    return PJ_SUCCESS;
-}
-
-
-#endif	/* PJ_HAS_SEMAPHORE */
-
-
-PJ_DEF(pj_status_t) pj_lock_acquire( pj_lock_t *lock )
-{
-    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
-    return (*lock->acquire)(lock->lock_object);
-}
-
-PJ_DEF(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock )
-{
-    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
-    return (*lock->tryacquire)(lock->lock_object);
-}
-
-PJ_DEF(pj_status_t) pj_lock_release( pj_lock_t *lock )
-{
-    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
-    return (*lock->release)(lock->lock_object);
-}
-
-PJ_DEF(pj_status_t) pj_lock_destroy( pj_lock_t *lock )
-{
-    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);
-    return (*lock->destroy)(lock->lock_object);
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/lock.h>

+#include <pj/os.h>

+#include <pj/assert.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/errno.h>

+

+

+typedef void LOCK_OBJ;

+

+/*

+ * Lock structure.

+ */

+struct pj_lock_t

+{

+    LOCK_OBJ *lock_object;

+

+    pj_status_t	(*acquire)	(LOCK_OBJ*);

+    pj_status_t	(*tryacquire)	(LOCK_OBJ*);

+    pj_status_t	(*release)	(LOCK_OBJ*);

+    pj_status_t	(*destroy)	(LOCK_OBJ*);

+};

+

+typedef pj_status_t (*FPTR)(LOCK_OBJ*);

+

+/******************************************************************************

+ * Implementation of lock object with mutex.

+ */

+static pj_lock_t mutex_lock_template = 

+{

+    NULL,

+    (FPTR) &pj_mutex_lock,

+    (FPTR) &pj_mutex_trylock,

+    (FPTR) &pj_mutex_unlock,

+    (FPTR) &pj_mutex_destroy

+};

+

+static pj_status_t create_mutex_lock( pj_pool_t *pool,

+				      const char *name,

+				      int type,

+				      pj_lock_t **lock )

+{

+    pj_lock_t *p_lock;

+    pj_status_t rc;

+

+    PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);

+

+    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));

+    if (!p_lock)

+	return PJ_ENOMEM;

+

+    pj_memcpy(p_lock, &mutex_lock_template, sizeof(pj_lock_t));

+    rc = pj_mutex_create(pool, name, type, (pj_mutex_t**)&p_lock->lock_object);

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    *lock = p_lock;

+    return PJ_SUCCESS;

+}

+

+

+PJ_DEF(pj_status_t) pj_lock_create_simple_mutex( pj_pool_t *pool,

+						 const char *name,

+						 pj_lock_t **lock )

+{

+    return create_mutex_lock(pool, name, PJ_MUTEX_SIMPLE, lock);

+}

+

+PJ_DEF(pj_status_t) pj_lock_create_recursive_mutex( pj_pool_t *pool,

+						    const char *name,

+						    pj_lock_t **lock )

+{

+    return create_mutex_lock(pool, name, PJ_MUTEX_RECURSE, lock);

+}

+

+

+/******************************************************************************

+ * Implementation of NULL lock object.

+ */

+static pj_status_t null_op(void *arg)

+{

+    PJ_UNUSED_ARG(arg);

+    return PJ_SUCCESS;

+}

+

+static pj_lock_t null_lock_template = 

+{

+    NULL,

+    &null_op,

+    &null_op,

+    &null_op,

+    &null_op

+};

+

+PJ_DEF(pj_status_t) pj_lock_create_null_mutex( pj_pool_t *pool,

+					       const char *name,

+					       pj_lock_t **lock )

+{

+    PJ_UNUSED_ARG(name);

+    PJ_UNUSED_ARG(pool);

+

+    PJ_ASSERT_RETURN(lock, PJ_EINVAL);

+

+    *lock = &null_lock_template;

+    return PJ_SUCCESS;

+}

+

+

+/******************************************************************************

+ * Implementation of semaphore lock object.

+ */

+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

+

+static pj_lock_t sem_lock_template = 

+{

+    NULL,

+    (FPTR) &pj_sem_wait,

+    (FPTR) &pj_sem_trywait,

+    (FPTR) &pj_sem_post,

+    (FPTR) &pj_sem_destroy

+};

+

+PJ_DEF(pj_status_t) pj_lock_create_semaphore(  pj_pool_t *pool,

+					       const char *name,

+					       unsigned initial,

+					       unsigned max,

+					       pj_lock_t **lock )

+{

+    pj_lock_t *p_lock;

+    pj_status_t rc;

+

+    PJ_ASSERT_RETURN(pool && lock, PJ_EINVAL);

+

+    p_lock = pj_pool_alloc(pool, sizeof(pj_lock_t));

+    if (!p_lock)

+	return PJ_ENOMEM;

+

+    pj_memcpy(p_lock, &sem_lock_template, sizeof(pj_lock_t));

+    rc = pj_sem_create( pool, name, initial, max, 

+		        (pj_sem_t**)&p_lock->lock_object);

+    if (rc != PJ_SUCCESS)

+        return rc;

+

+    *lock = p_lock;

+

+    return PJ_SUCCESS;

+}

+

+

+#endif	/* PJ_HAS_SEMAPHORE */

+

+

+PJ_DEF(pj_status_t) pj_lock_acquire( pj_lock_t *lock )

+{

+    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);

+    return (*lock->acquire)(lock->lock_object);

+}

+

+PJ_DEF(pj_status_t) pj_lock_tryacquire( pj_lock_t *lock )

+{

+    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);

+    return (*lock->tryacquire)(lock->lock_object);

+}

+

+PJ_DEF(pj_status_t) pj_lock_release( pj_lock_t *lock )

+{

+    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);

+    return (*lock->release)(lock->lock_object);

+}

+

+PJ_DEF(pj_status_t) pj_lock_destroy( pj_lock_t *lock )

+{

+    PJ_ASSERT_RETURN(lock != NULL, PJ_EINVAL);

+    return (*lock->destroy)(lock->lock_object);

+}

+

diff --git a/pjlib/src/pj/log.c b/pjlib/src/pj/log.c
index adbf98f..92802ee 100644
--- a/pjlib/src/pj/log.c
+++ b/pjlib/src/pj/log.c
@@ -1,208 +1,229 @@
-/* $Id$
- */
-#include <pj/types.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/os.h>
-#include <pj/compat/vsprintf.h>
-#include <pj/compat/stdarg.h>
-
-#if PJ_LOG_MAX_LEVEL >= 1
-
-static int log_max_level = PJ_LOG_MAX_LEVEL;
-static pj_log_func *log_writer = &pj_log_write;
-static unsigned log_decor = PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC |
-			    PJ_LOG_HAS_SENDER | PJ_LOG_HAS_NEWLINE;
-
-#if PJ_LOG_USE_STACK_BUFFER==0
-static char log_buffer[PJ_LOG_MAX_SIZE];
-#endif
-
-PJ_DEF(void) pj_log_set_decor(unsigned decor)
-{
-    log_decor = decor;
-}
-
-PJ_DEF(unsigned) pj_log_get_decor(void)
-{
-    return log_decor;
-}
-
-PJ_DEF(void) pj_log_set_level(int level)
-{
-    log_max_level = level;
-}
-
-PJ_DEF(int) pj_log_get_level(void)
-{
-    return log_max_level;
-}
-
-PJ_DEF(void) pj_log_set_log_func( pj_log_func *func )
-{
-    log_writer = func;
-}
-
-PJ_DEF(pj_log_func*) pj_log_get_log_func(void)
-{
-    return log_writer;
-}
-
-static void pj_log(const char *sender, int level, 
-		   const char *format, va_list marker)
-{
-    pj_time_val now;
-    pj_parsed_time ptime;
-    char *pre;
-#if PJ_LOG_USE_STACK_BUFFER
-    char log_buffer[PJ_LOG_MAX_SIZE];
-#endif
-    int len;
-
-    PJ_CHECK_STACK();
-
-    if (level > log_max_level)
-	return;
-
-    /* Get current date/time. */
-    pj_gettimeofday(&now);
-    pj_time_decode(&now, &ptime);
-
-    pre = log_buffer;
-    if (log_decor & PJ_LOG_HAS_DAY_NAME) {
-	static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed",
-				       "Thu", "Fri", "Sat"};
-	strcpy(pre, wdays[ptime.wday]);
-	pre += 3;
-    }
-    if (log_decor & PJ_LOG_HAS_YEAR) {
-	*pre++ = ' ';
-	pre += pj_utoa(ptime.year, pre);
-    }
-    if (log_decor & PJ_LOG_HAS_MONTH) {
-	*pre++ = '-';
-	pre += pj_utoa_pad(ptime.mon, pre, 2, '0');
-    }
-    if (log_decor & PJ_LOG_HAS_DAY_OF_MON) {
-	*pre++ = ' ';
-	pre += pj_utoa_pad(ptime.day, pre, 2, '0');
-    }
-    if (log_decor & PJ_LOG_HAS_TIME) {
-	*pre++ = ' ';
-	pre += pj_utoa_pad(ptime.hour, pre, 2, '0');
-	*pre++ = ':';
-	pre += pj_utoa_pad(ptime.min, pre, 2, '0');
-	*pre++ = ':';
-	pre += pj_utoa_pad(ptime.sec, pre, 2, '0');
-    }
-    if (log_decor & PJ_LOG_HAS_MICRO_SEC) {
-	*pre++ = '.';
-	pre += pj_utoa_pad(ptime.msec, pre, 3, '0');
-    }
-    if (log_decor & PJ_LOG_HAS_SENDER) {
-	enum { SENDER_WIDTH = 12 };
-	int sender_len = strlen(sender);
-	*pre++ = ' ';
-	if (sender_len <= SENDER_WIDTH) {
-	    while (sender_len < SENDER_WIDTH)
-		*pre++ = ' ', ++sender_len;
-	    while (*sender)
-		*pre++ = *sender++;
-	} else {
-	    int i;
-	    for (i=0; i<SENDER_WIDTH; ++i)
-		*pre++ = *sender++;
-	}
-    }
-
-    if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE)
-	*pre++ = ' ';
-
-    len = pre - log_buffer;
-
-    /* Print the whole message to the string log_buffer. */
-    len = len + vsnprintf(pre, sizeof(log_buffer)-len, format, marker);
-    if (len > 0 && len < sizeof(log_buffer)-1) {
-	if (log_decor & PJ_LOG_HAS_NEWLINE) {
-	    log_buffer[len++] = '\n';
-	}
-	log_buffer[len++] = '\0';
-    } else {
-	len = sizeof(log_buffer)-1;
-	if (log_decor & PJ_LOG_HAS_NEWLINE) {
-	    log_buffer[sizeof(log_buffer)-2] = '\n';
-	}
-	log_buffer[sizeof(log_buffer)-1] = '\0';
-    }
-
-    if (log_writer)
-	(*log_writer)(level, log_buffer, len);
-}
-
-PJ_DEF(void) pj_log_0(const char *obj, const char *format, ...)
-{
-    va_list arg;
-    va_start(arg, format);
-    pj_log(obj, 0, format, arg);
-    va_end(arg);
-}
-
-PJ_DEF(void) pj_log_1(const char *obj, const char *format, ...)
-{
-    va_list arg;
-    va_start(arg, format);
-    pj_log(obj, 1, format, arg);
-    va_end(arg);
-}
-#endif	/* PJ_LOG_MAX_LEVEL >= 1 */
-
-#if PJ_LOG_MAX_LEVEL >= 2
-PJ_DEF(void) pj_log_2(const char *obj, const char *format, ...)
-{
-    va_list arg;
-    va_start(arg, format);
-    pj_log(obj, 2, format, arg);
-    va_end(arg);
-}
-#endif
-
-#if PJ_LOG_MAX_LEVEL >= 3
-PJ_DEF(void) pj_log_3(const char *obj, const char *format, ...)
-{
-    va_list arg;
-    va_start(arg, format);
-    pj_log(obj, 3, format, arg);
-    va_end(arg);
-}
-#endif
-
-#if PJ_LOG_MAX_LEVEL >= 4
-PJ_DEF(void) pj_log_4(const char *obj, const char *format, ...)
-{
-    va_list arg;
-    va_start(arg, format);
-    pj_log(obj, 4, format, arg);
-    va_end(arg);
-}
-#endif
-
-#if PJ_LOG_MAX_LEVEL >= 5
-PJ_DEF(void) pj_log_5(const char *obj, const char *format, ...)
-{
-    va_list arg;
-    va_start(arg, format);
-    pj_log(obj, 5, format, arg);
-    va_end(arg);
-}
-#endif
-
-#if PJ_LOG_MAX_LEVEL >= 6
-PJ_DEF(void) pj_log_6(const char *obj, const char *format, ...)
-{
-    va_list arg;
-    va_start(arg, format);
-    pj_log(obj, 6, format, arg);
-    va_end(arg);
-}
-#endif
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/types.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/os.h>

+#include <pj/compat/vsprintf.h>

+#include <pj/compat/stdarg.h>

+

+#if PJ_LOG_MAX_LEVEL >= 1

+

+static int log_max_level = PJ_LOG_MAX_LEVEL;

+static pj_log_func *log_writer = &pj_log_write;

+static unsigned log_decor = PJ_LOG_HAS_TIME | PJ_LOG_HAS_MICRO_SEC |

+			    PJ_LOG_HAS_SENDER | PJ_LOG_HAS_NEWLINE;

+

+#if PJ_LOG_USE_STACK_BUFFER==0

+static char log_buffer[PJ_LOG_MAX_SIZE];

+#endif

+

+PJ_DEF(void) pj_log_set_decor(unsigned decor)

+{

+    log_decor = decor;

+}

+

+PJ_DEF(unsigned) pj_log_get_decor(void)

+{

+    return log_decor;

+}

+

+PJ_DEF(void) pj_log_set_level(int level)

+{

+    log_max_level = level;

+}

+

+PJ_DEF(int) pj_log_get_level(void)

+{

+    return log_max_level;

+}

+

+PJ_DEF(void) pj_log_set_log_func( pj_log_func *func )

+{

+    log_writer = func;

+}

+

+PJ_DEF(pj_log_func*) pj_log_get_log_func(void)

+{

+    return log_writer;

+}

+

+static void pj_log(const char *sender, int level, 

+		   const char *format, va_list marker)

+{

+    pj_time_val now;

+    pj_parsed_time ptime;

+    char *pre;

+#if PJ_LOG_USE_STACK_BUFFER

+    char log_buffer[PJ_LOG_MAX_SIZE];

+#endif

+    int len;

+

+    PJ_CHECK_STACK();

+

+    if (level > log_max_level)

+	return;

+

+    /* Get current date/time. */

+    pj_gettimeofday(&now);

+    pj_time_decode(&now, &ptime);

+

+    pre = log_buffer;

+    if (log_decor & PJ_LOG_HAS_DAY_NAME) {

+	static const char *wdays[] = { "Sun", "Mon", "Tue", "Wed",

+				       "Thu", "Fri", "Sat"};

+	strcpy(pre, wdays[ptime.wday]);

+	pre += 3;

+    }

+    if (log_decor & PJ_LOG_HAS_YEAR) {

+	*pre++ = ' ';

+	pre += pj_utoa(ptime.year, pre);

+    }

+    if (log_decor & PJ_LOG_HAS_MONTH) {

+	*pre++ = '-';

+	pre += pj_utoa_pad(ptime.mon, pre, 2, '0');

+    }

+    if (log_decor & PJ_LOG_HAS_DAY_OF_MON) {

+	*pre++ = ' ';

+	pre += pj_utoa_pad(ptime.day, pre, 2, '0');

+    }

+    if (log_decor & PJ_LOG_HAS_TIME) {

+	*pre++ = ' ';

+	pre += pj_utoa_pad(ptime.hour, pre, 2, '0');

+	*pre++ = ':';

+	pre += pj_utoa_pad(ptime.min, pre, 2, '0');

+	*pre++ = ':';

+	pre += pj_utoa_pad(ptime.sec, pre, 2, '0');

+    }

+    if (log_decor & PJ_LOG_HAS_MICRO_SEC) {

+	*pre++ = '.';

+	pre += pj_utoa_pad(ptime.msec, pre, 3, '0');

+    }

+    if (log_decor & PJ_LOG_HAS_SENDER) {

+	enum { SENDER_WIDTH = 12 };

+	int sender_len = strlen(sender);

+	*pre++ = ' ';

+	if (sender_len <= SENDER_WIDTH) {

+	    while (sender_len < SENDER_WIDTH)

+		*pre++ = ' ', ++sender_len;

+	    while (*sender)

+		*pre++ = *sender++;

+	} else {

+	    int i;

+	    for (i=0; i<SENDER_WIDTH; ++i)

+		*pre++ = *sender++;

+	}

+    }

+

+    if (log_decor != 0 && log_decor != PJ_LOG_HAS_NEWLINE)

+	*pre++ = ' ';

+

+    len = pre - log_buffer;

+

+    /* Print the whole message to the string log_buffer. */

+    len = len + vsnprintf(pre, sizeof(log_buffer)-len, format, marker);

+    if (len > 0 && len < sizeof(log_buffer)-1) {

+	if (log_decor & PJ_LOG_HAS_NEWLINE) {

+	    log_buffer[len++] = '\n';

+	}

+	log_buffer[len++] = '\0';

+    } else {

+	len = sizeof(log_buffer)-1;

+	if (log_decor & PJ_LOG_HAS_NEWLINE) {

+	    log_buffer[sizeof(log_buffer)-2] = '\n';

+	}

+	log_buffer[sizeof(log_buffer)-1] = '\0';

+    }

+

+    if (log_writer)

+	(*log_writer)(level, log_buffer, len);

+}

+

+PJ_DEF(void) pj_log_0(const char *obj, const char *format, ...)

+{

+    va_list arg;

+    va_start(arg, format);

+    pj_log(obj, 0, format, arg);

+    va_end(arg);

+}

+

+PJ_DEF(void) pj_log_1(const char *obj, const char *format, ...)

+{

+    va_list arg;

+    va_start(arg, format);

+    pj_log(obj, 1, format, arg);

+    va_end(arg);

+}

+#endif	/* PJ_LOG_MAX_LEVEL >= 1 */

+

+#if PJ_LOG_MAX_LEVEL >= 2

+PJ_DEF(void) pj_log_2(const char *obj, const char *format, ...)

+{

+    va_list arg;

+    va_start(arg, format);

+    pj_log(obj, 2, format, arg);

+    va_end(arg);

+}

+#endif

+

+#if PJ_LOG_MAX_LEVEL >= 3

+PJ_DEF(void) pj_log_3(const char *obj, const char *format, ...)

+{

+    va_list arg;

+    va_start(arg, format);

+    pj_log(obj, 3, format, arg);

+    va_end(arg);

+}

+#endif

+

+#if PJ_LOG_MAX_LEVEL >= 4

+PJ_DEF(void) pj_log_4(const char *obj, const char *format, ...)

+{

+    va_list arg;

+    va_start(arg, format);

+    pj_log(obj, 4, format, arg);

+    va_end(arg);

+}

+#endif

+

+#if PJ_LOG_MAX_LEVEL >= 5

+PJ_DEF(void) pj_log_5(const char *obj, const char *format, ...)

+{

+    va_list arg;

+    va_start(arg, format);

+    pj_log(obj, 5, format, arg);

+    va_end(arg);

+}

+#endif

+

+#if PJ_LOG_MAX_LEVEL >= 6

+PJ_DEF(void) pj_log_6(const char *obj, const char *format, ...)

+{

+    va_list arg;

+    va_start(arg, format);

+    pj_log(obj, 6, format, arg);

+    va_end(arg);

+}

+#endif

+

diff --git a/pjlib/src/pj/log_writer_printk.c b/pjlib/src/pj/log_writer_printk.c
index 2581ef2..da20598 100644
--- a/pjlib/src/pj/log_writer_printk.c
+++ b/pjlib/src/pj/log_writer_printk.c
@@ -1,12 +1,33 @@
-/* $Id$
- *
- */
-#include <pj/log.h>
-#include <pj/os.h>
-
-PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
-{
-    PJ_CHECK_STACK();
-    printk(KERN_INFO "%s", buffer);
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/log.h>

+#include <pj/os.h>

+

+PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)

+{

+    PJ_CHECK_STACK();

+    printk(KERN_INFO "%s", buffer);

+}

+

diff --git a/pjlib/src/pj/log_writer_stdout.c b/pjlib/src/pj/log_writer_stdout.c
index 196f1c3..d301002 100644
--- a/pjlib/src/pj/log_writer_stdout.c
+++ b/pjlib/src/pj/log_writer_stdout.c
@@ -1,54 +1,75 @@
-/* $Id$
- */
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/compat/stdfileio.h>
-
-#define CLR_FATAL    (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R)
-#define CLR_WARNING  (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G)
-#define CLR_INFO     (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | \
-		      PJ_TERM_COLOR_B)
-#define CLR_DEFAULT  (PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B)
-
-static void term_set_color(int level)
-{
-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
-    unsigned attr = 0;
-    switch (level) {
-    case 0:
-    case 1: attr = CLR_FATAL; 
-	break;
-    case 2: attr = CLR_WARNING; 
-	break;
-    case 3: attr = CLR_INFO; 
-	break;
-    default:
-	attr = CLR_DEFAULT;
-	break;
-    }
-
-    pj_term_set_color(attr);
-#endif
-}
-
-static void term_restore_color(void)
-{
-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
-    pj_term_set_color(CLR_DEFAULT);
-#endif
-}
-
-
-PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(len);
-
-    /* Copy to terminal/file. */
-    term_set_color(level);
-    fputs(buffer, stdout);
-    term_restore_color();
-
-    fflush(stdout);
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/log.h>

+#include <pj/os.h>

+#include <pj/compat/stdfileio.h>

+

+#define CLR_FATAL    (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R)

+#define CLR_WARNING  (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G)

+#define CLR_INFO     (PJ_TERM_COLOR_BRIGHT | PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | \

+		      PJ_TERM_COLOR_B)

+#define CLR_DEFAULT  (PJ_TERM_COLOR_R | PJ_TERM_COLOR_G | PJ_TERM_COLOR_B)

+

+static void term_set_color(int level)

+{

+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

+    unsigned attr = 0;

+    switch (level) {

+    case 0:

+    case 1: attr = CLR_FATAL; 

+	break;

+    case 2: attr = CLR_WARNING; 

+	break;

+    case 3: attr = CLR_INFO; 

+	break;

+    default:

+	attr = CLR_DEFAULT;

+	break;

+    }

+

+    pj_term_set_color(attr);

+#endif

+}

+

+static void term_restore_color(void)

+{

+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

+    pj_term_set_color(CLR_DEFAULT);

+#endif

+}

+

+

+PJ_DEF(void) pj_log_write(int level, const char *buffer, int len)

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(len);

+

+    /* Copy to terminal/file. */

+    term_set_color(level);

+    fputs(buffer, stdout);

+    term_restore_color();

+

+    fflush(stdout);

+}

+

diff --git a/pjlib/src/pj/os_core_linux_kernel.c b/pjlib/src/pj/os_core_linux_kernel.c
index 1433708..2bb2acf 100644
--- a/pjlib/src/pj/os_core_linux_kernel.c
+++ b/pjlib/src/pj/os_core_linux_kernel.c
@@ -1,674 +1,695 @@
-/* $Id$
- *
- */
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/except.h>
-#include <pj/errno.h>
-#include <pj/string.h>
-#include <pj/compat/high_precision.h>
-#include <pj/compat/sprintf.h>
-
-#include <linux/config.h>
-#include <linux/version.h>
-#if defined(MODVERSIONS)
-#include <linux/modversions.h>
-#endif
-#include <linux/kernel.h>
-#include <linux/sched.h>
-//#include <linux/tqueue.h>
-#include <linux/wait.h>
-#include <linux/signal.h>
-
-#include <asm/atomic.h>
-#include <asm/unistd.h>
-#include <asm/semaphore.h>
-
-#define THIS_FILE   "oslinuxkern"
-
-struct pj_thread_t
-{
-    /** Thread's name. */
-    char obj_name[PJ_MAX_OBJ_NAME];
-
-    /** Linux task structure for thread. */
-    struct task_struct *thread;	
-
-    /** Flags (specified in pj_thread_create) */
-    unsigned flags;
-
-    /** Task queue needed to launch thread. */
-    //struct tq_struct	tq;	
-
-    /** Semaphore needed to control thread startup. */
-    struct semaphore	startstop_sem;
-
-    /** Semaphore to suspend thread during startup. */
-    struct semaphore	suspend_sem;
-
-    /** Queue thread is waiting on. Gets initialized by
-        thread_initialize, can be used by thread itself.
-     */
-    wait_queue_head_t	queue;
-
-    /** Flag to tell thread whether to die or not.
-        When the thread receives a signal, it must check
-        the value of terminate and call thread_deinitialize and terminate
-        if set.
-     */
-    int terminate;    
-
-    /** Thread's entry. */
-    pj_thread_proc *func;
-
-    /** Argument. */
-    void *arg;
-};
-
-struct pj_atomic_t
-{
-    atomic_t atom;
-};
-
-struct pj_mutex_t
-{
-    struct semaphore sem;
-    pj_bool_t	     recursive;
-    pj_thread_t	    *owner;
-    int		     own_count;
-};
-
-struct pj_sem_t
-{
-    struct semaphore sem;
-};
-
-/*
- * Static global variables.
- */
-#define MAX_TLS_ID  32
-static void *tls_values[MAX_TLS_ID];
-static int tls_id;
-static long thread_tls_id;
-static spinlock_t critical_section = SPIN_LOCK_UNLOCKED;
-static unsigned long spinlock_flags;
-static pj_thread_t main_thread;
-
-/* private functions */
-//#define TRACE_(expr)	PJ_LOG(3,expr)
-#define TRACE_(x)
-
-
-/* This must be called in the context of the new thread. */
-static void thread_initialize( pj_thread_t *thread )
-{
-    TRACE_((THIS_FILE, "---new thread initializing..."));
-
-    /* Set TLS */
-    pj_thread_local_set(thread_tls_id, thread);
-
-    /* fill in thread structure */
-    thread->thread = current;
-    pj_assert(thread->thread != NULL);
-
-    /* set signal mask to what we want to respond */
-    siginitsetinv(&current->blocked, 
-		  sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
-
-    /* initialise wait queue */
-    init_waitqueue_head(&thread->queue);
-
-    /* initialise termination flag */
-    thread->terminate = 0;
-
-    /* set name of this process (max 15 chars + 0 !) */
-    thread->obj_name[15] = '\0';
-    sprintf(current->comm, thread->obj_name);
-        
-    /* tell the creator that we are ready and let him continue */
-    up(&thread->startstop_sem);	
-}
-
-/* cleanup of thread. Called by the exiting thread. */
-static void thread_deinitialize(pj_thread_t *thread)
-{
-    /* we are terminating */
-
-    /* lock the kernel, the exit will unlock it */
-    thread->thread = NULL;
-    mb();
-
-    /* notify the stop_kthread() routine that we are terminating. */
-    up(&thread->startstop_sem);
-
-    /* the kernel_thread that called clone() does a do_exit here. */
-
-    /* there is no race here between execution of the "killer" and 
-       real termination of the thread (race window between up and do_exit), 
-       since both the thread and the "killer" function are running with 
-       the kernel lock held.
-       The kernel lock will be freed after the thread exited, so the code
-       is really not executed anymore as soon as the unload functions gets
-       the kernel lock back.
-       The init process may not have made the cleanup of the process here,
-       but the cleanup can be done safely with the module unloaded.
-    */
-
-}
-
-static int thread_proc(void *arg)
-{
-    pj_thread_t *thread = arg;
-
-    TRACE_((THIS_FILE, "---new thread starting!"));
-
-    /* Initialize thread. */
-    thread_initialize( thread );
-
-    /* Wait if created suspended. */
-    if (thread->flags & PJ_THREAD_SUSPENDED) {
-	TRACE_((THIS_FILE, "---new thread suspended..."));
-	down(&thread->suspend_sem);
-    }
-
-    TRACE_((THIS_FILE, "---new thread running..."));
-
-    pj_assert(thread->func != NULL);
-
-    /* Call thread's entry. */
-    (*thread->func)(thread->arg);
-
-    TRACE_((THIS_FILE, "---thread exiting..."));
-
-    /* Cleanup thread. */
-    thread_deinitialize(thread);
-
-    return 0;
-}
-
-/* The very task entry. */
-static void kthread_launcher(void *arg)
-{
-    TRACE_((THIS_FILE, "...launching thread!..."));
-    kernel_thread(&thread_proc, arg, 0);
-}
-
-PJ_DEF(pj_status_t) pj_init(void)
-{
-    pj_status_t rc;
-
-    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
-
-    rc = pj_thread_init();
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    /* Initialize exception ID for the pool. 
-     * Must do so after critical section is configured.
-     */
-    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
-    if (rc != PJ_SUCCESS)
-        return rc;
-
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_uint32_t) pj_getpid(void)
-{
-    return 1;
-}
-
-PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
-					 pj_thread_desc desc,
-					 pj_thread_t **ptr_thread)
-{
-    char stack_ptr;
-    pj_thread_t *thread = (pj_thread_t *)desc;
-    pj_str_t thread_name = pj_str((char*)cstr_thread_name);
-
-    /* Size sanity check. */
-    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
-	pj_assert(!"Not enough pj_thread_desc size!");
-	return PJ_EBUG;
-    }
-
-    /* If a thread descriptor has been registered before, just return it. */
-    if (pj_thread_local_get (thread_tls_id) != 0) {
-	*ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
-	return PJ_SUCCESS;
-    }
-
-    /* Initialize and set the thread entry. */
-    pj_memset(desc, 0, sizeof(struct pj_thread_t));
-
-    if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
-	pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
-    else
-	pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);
-    
-    /* Initialize. */
-    thread_initialize(thread);
-
-    /* Eat semaphore. */
-    down(&thread->startstop_sem);
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-    thread->stk_start = &stack_ptr;
-    thread->stk_size = 0xFFFFFFFFUL;
-    thread->stk_max_usage = 0;
-#else
-    stack_ptr = '\0';
-#endif
-
-    *ptr_thread = thread;
-    return PJ_SUCCESS;
-}
-
-
-pj_status_t pj_thread_init(void)
-{
-    pj_status_t rc;
-    pj_thread_t *dummy;
-    
-    rc = pj_thread_local_alloc(&thread_tls_id);
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy);
-}
-
-PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name,
-				      pj_thread_proc *proc, void *arg,
-				      pj_size_t stack_size, unsigned flags,
-				      pj_thread_t **ptr_thread)
-{
-    pj_thread_t *thread;
-
-    TRACE_((THIS_FILE, "pj_thread_create()"));
-    
-    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
-
-    thread = pj_pool_zalloc(pool, sizeof(pj_thread_t));
-    if (!thread)
-	return PJ_ENOMEM;
-
-    PJ_UNUSED_ARG(stack_size);
-
-    /* Thread name. */
-    if (!thread_name) 
-	thread_name = "thr%p";
-    
-    if (strchr(thread_name, '%')) {
-	pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread);
-    } else {
-	strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME);
-	thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
-    }
-    
-    /* Init thread's semaphore. */
-    TRACE_((THIS_FILE, "...init semaphores..."));
-    init_MUTEX_LOCKED(&thread->startstop_sem);
-    init_MUTEX_LOCKED(&thread->suspend_sem);
-
-    thread->flags = flags;
-
-    if ((flags & PJ_THREAD_SUSPENDED) == 0) {
-	up(&thread->suspend_sem);
-    }
-
-    /* Store the functions and argument. */
-    thread->func = proc;
-    thread->arg = arg;
-    
-    /* Save return value. */
-    *ptr_thread = thread;
-    
-    /* Create the new thread by running a task through keventd. */
-
-#if 0
-    /* Initialize the task queue struct. */
-    thread->tq.sync = 0;
-    INIT_LIST_HEAD(&thread->tq.list);
-    thread->tq.routine = kthread_launcher;
-    thread->tq.data = thread;
-
-    /* and schedule it for execution. */
-    schedule_task(&thread->tq);
-#endif
-    kthread_launcher(thread);
-
-    /* Wait until thread has reached the setup_thread routine. */
-    TRACE_((THIS_FILE, "...wait for the new thread..."));
-    down(&thread->startstop_sem);
-
-    TRACE_((THIS_FILE, "...main thread resumed..."));
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread)
-{
-    return thread->obj_name;
-}
-
-PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread)
-{
-    up(&thread->suspend_sem);
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_thread_t*) pj_thread_this(void)
-{
-    return (pj_thread_t*)pj_thread_local_get(thread_tls_id);
-}
-
-PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
-{
-    TRACE_((THIS_FILE, "pj_thread_join()"));
-    down(&p->startstop_sem);
-    TRACE_((THIS_FILE, "  joined!"));
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread)
-{
-    PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP);
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
-{
-    pj_highprec_t ticks;
-    pj_thread_t *thread = pj_thread_this();
-
-    PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG);
-    
-    /* Use high precision calculation to make sure we don't
-     * crop values:
-     *
-     *	ticks = HZ * msec / 1000
-     */
-    ticks = HZ;
-    pj_highprec_mul(ticks, msec);
-    pj_highprec_div(ticks, 1000);
-
-    TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks));
-    interruptible_sleep_on_timeout( &thread->queue, ticks);
-    return PJ_SUCCESS;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
-				      pj_atomic_value_t value,
-				      pj_atomic_t **ptr_var)
-{
-    pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
-    if (!t) return PJ_ENOMEM;
-
-    atomic_set(&t->atom, value);
-    *ptr_var = t;
-    
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
-{
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value)
-{
-    atomic_set(&var->atom, value);
-}
-
-PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var)
-{
-    return atomic_read(&var->atom);
-}
-
-PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var)
-{
-    atomic_inc(&var->atom);
-}
-
-PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var)
-{
-    atomic_dec(&var->atom);
-}
-
-PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value )
-{
-    atomic_add(value, &var->atom);
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
-{
-    if (tls_id >= MAX_TLS_ID)
-	return PJ_ETOOMANY;
-    
-    *index = tls_id++;
-
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(void) pj_thread_local_free(long index)
-{
-    pj_assert(index >= 0 && index < MAX_TLS_ID);
-}
-
-PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
-{
-    pj_assert(index >= 0 && index < MAX_TLS_ID);
-    tls_values[index] = value;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(void*) pj_thread_local_get(long index)
-{
-    pj_assert(index >= 0 && index < MAX_TLS_ID);
-    return tls_values[index];
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(void) pj_enter_critical_section(void)
-{
-    spin_lock_irqsave(&critical_section, spinlock_flags);
-}
-
-PJ_DEF(void) pj_leave_critical_section(void)
-{
-    spin_unlock_irqrestore(&critical_section, spinlock_flags);
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool, 
-				     const char *name, 
-				     int type,
-				     pj_mutex_t **ptr_mutex)
-{
-    pj_mutex_t *mutex;
-    
-    PJ_UNUSED_ARG(name);
-
-    mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t));
-    if (!mutex)
-	return PJ_ENOMEM;
-
-    init_MUTEX(&mutex->sem);
-
-    mutex->recursive = (type == PJ_MUTEX_RECURSE);
-    mutex->owner = NULL;
-    mutex->own_count = 0;
-    
-    /* Done. */
-    *ptr_mutex = mutex;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,
-					    pj_mutex_t **mutex )
-{
-    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
-}
-
-PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
-					       const char *name,
-					       pj_mutex_t **mutex )
-{
-    return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);
-}
-
-PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
-{
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-    if (mutex->recursive) {
-	pj_thread_t *this_thread = pj_thread_this();
-	if (mutex->owner == this_thread) {
-	    ++mutex->own_count;
-	} else {
-	    down(&mutex->sem);
-	    pj_assert(mutex->own_count == 0);
-	    mutex->owner = this_thread;
-	    mutex->own_count = 1;
-	}
-    } else {
-	down(&mutex->sem);
-    }
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
-{
-    long rc;
-
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-    if (mutex->recursive) {
-	pj_thread_t *this_thread = pj_thread_this();
-	if (mutex->owner == this_thread) {
-	    ++mutex->own_count;
-	} else {
-	    rc = down_interruptible(&mutex->sem);
-	    if (rc != 0)
-		return PJ_RETURN_OS_ERROR(-rc);
-	    pj_assert(mutex->own_count == 0);
-	    mutex->owner = this_thread;
-	    mutex->own_count = 1;
-	}
-    } else {
-	int rc = down_trylock(&mutex->sem);
-	if (rc != 0)
-	    return PJ_RETURN_OS_ERROR(-rc);
-    }
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
-{
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-    if (mutex->recursive) {
-	pj_thread_t *this_thread = pj_thread_this();
-	if (mutex->owner == this_thread) {
-	    pj_assert(mutex->own_count > 0);
-	    --mutex->own_count;
-	    if (mutex->own_count == 0) {
-		mutex->owner = NULL;
-		up(&mutex->sem);
-	    }
-	} else {
-	    pj_assert(!"Not owner!");
-	    return PJ_EINVALIDOP;
-	}
-    } else {
-	up(&mutex->sem);
-    }
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
-{
-    PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL);
-
-    return PJ_SUCCESS;
-}
-
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
-{
-    if (mutex->recursive)
-	return mutex->owner == pj_thread_this();
-    else
-	return 1;
-}
-#endif	/* PJ_DEBUG */
-
-
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-
-PJ_DEF(pj_status_t) pj_sem_create(  pj_pool_t *pool, 
-                                    const char *name,
-				    unsigned initial, 
-                                    unsigned max,
-				    pj_sem_t **sem)
-{
-    pj_sem_t *sem;
-
-    PJ_UNUSED_ARG(max);
-
-    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-    
-    sem = pj_pool_alloc(pool, sizeof(pj_sem_t));
-    sema_init(&sem->sem, initial);
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
-{
-    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-
-    down(&sem->sem);
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
-{
-    int rc;
-
-    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-
-    rc = down_trylock(&sem->sem);
-    if (rc != 0) {
-	return PJ_RETURN_OS_ERROR(-rc);
-    } else {
-	return PJ_SUCCESS;
-    }
-}
-
-PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
-{
-    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-
-    up(&sem->sem);
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
-{
-    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);
-
-    return PJ_SUCCESS;
-}
-
-#endif	/* PJ_HAS_SEMAPHORE */
-
-
-
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/os.h>

+#include <pj/assert.h>

+#include <pj/pool.h>

+#include <pj/log.h>

+#include <pj/except.h>

+#include <pj/errno.h>

+#include <pj/string.h>

+#include <pj/compat/high_precision.h>

+#include <pj/compat/sprintf.h>

+

+#include <linux/config.h>

+#include <linux/version.h>

+#if defined(MODVERSIONS)

+#include <linux/modversions.h>

+#endif

+#include <linux/kernel.h>

+#include <linux/sched.h>

+//#include <linux/tqueue.h>

+#include <linux/wait.h>

+#include <linux/signal.h>

+

+#include <asm/atomic.h>

+#include <asm/unistd.h>

+#include <asm/semaphore.h>

+

+#define THIS_FILE   "oslinuxkern"

+

+struct pj_thread_t

+{

+    /** Thread's name. */

+    char obj_name[PJ_MAX_OBJ_NAME];

+

+    /** Linux task structure for thread. */

+    struct task_struct *thread;	

+

+    /** Flags (specified in pj_thread_create) */

+    unsigned flags;

+

+    /** Task queue needed to launch thread. */

+    //struct tq_struct	tq;	

+

+    /** Semaphore needed to control thread startup. */

+    struct semaphore	startstop_sem;

+

+    /** Semaphore to suspend thread during startup. */

+    struct semaphore	suspend_sem;

+

+    /** Queue thread is waiting on. Gets initialized by

+        thread_initialize, can be used by thread itself.

+     */

+    wait_queue_head_t	queue;

+

+    /** Flag to tell thread whether to die or not.

+        When the thread receives a signal, it must check

+        the value of terminate and call thread_deinitialize and terminate

+        if set.

+     */

+    int terminate;    

+

+    /** Thread's entry. */

+    pj_thread_proc *func;

+

+    /** Argument. */

+    void *arg;

+};

+

+struct pj_atomic_t

+{

+    atomic_t atom;

+};

+

+struct pj_mutex_t

+{

+    struct semaphore sem;

+    pj_bool_t	     recursive;

+    pj_thread_t	    *owner;

+    int		     own_count;

+};

+

+struct pj_sem_t

+{

+    struct semaphore sem;

+};

+

+/*

+ * Static global variables.

+ */

+#define MAX_TLS_ID  32

+static void *tls_values[MAX_TLS_ID];

+static int tls_id;

+static long thread_tls_id;

+static spinlock_t critical_section = SPIN_LOCK_UNLOCKED;

+static unsigned long spinlock_flags;

+static pj_thread_t main_thread;

+

+/* private functions */

+//#define TRACE_(expr)	PJ_LOG(3,expr)

+#define TRACE_(x)

+

+

+/* This must be called in the context of the new thread. */

+static void thread_initialize( pj_thread_t *thread )

+{

+    TRACE_((THIS_FILE, "---new thread initializing..."));

+

+    /* Set TLS */

+    pj_thread_local_set(thread_tls_id, thread);

+

+    /* fill in thread structure */

+    thread->thread = current;

+    pj_assert(thread->thread != NULL);

+

+    /* set signal mask to what we want to respond */

+    siginitsetinv(&current->blocked, 

+		  sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));

+

+    /* initialise wait queue */

+    init_waitqueue_head(&thread->queue);

+

+    /* initialise termination flag */

+    thread->terminate = 0;

+

+    /* set name of this process (max 15 chars + 0 !) */

+    thread->obj_name[15] = '\0';

+    sprintf(current->comm, thread->obj_name);

+        

+    /* tell the creator that we are ready and let him continue */

+    up(&thread->startstop_sem);	

+}

+

+/* cleanup of thread. Called by the exiting thread. */

+static void thread_deinitialize(pj_thread_t *thread)

+{

+    /* we are terminating */

+

+    /* lock the kernel, the exit will unlock it */

+    thread->thread = NULL;

+    mb();

+

+    /* notify the stop_kthread() routine that we are terminating. */

+    up(&thread->startstop_sem);

+

+    /* the kernel_thread that called clone() does a do_exit here. */

+

+    /* there is no race here between execution of the "killer" and 

+       real termination of the thread (race window between up and do_exit), 

+       since both the thread and the "killer" function are running with 

+       the kernel lock held.

+       The kernel lock will be freed after the thread exited, so the code

+       is really not executed anymore as soon as the unload functions gets

+       the kernel lock back.

+       The init process may not have made the cleanup of the process here,

+       but the cleanup can be done safely with the module unloaded.

+    */

+

+}

+

+static int thread_proc(void *arg)

+{

+    pj_thread_t *thread = arg;

+

+    TRACE_((THIS_FILE, "---new thread starting!"));

+

+    /* Initialize thread. */

+    thread_initialize( thread );

+

+    /* Wait if created suspended. */

+    if (thread->flags & PJ_THREAD_SUSPENDED) {

+	TRACE_((THIS_FILE, "---new thread suspended..."));

+	down(&thread->suspend_sem);

+    }

+

+    TRACE_((THIS_FILE, "---new thread running..."));

+

+    pj_assert(thread->func != NULL);

+

+    /* Call thread's entry. */

+    (*thread->func)(thread->arg);

+

+    TRACE_((THIS_FILE, "---thread exiting..."));

+

+    /* Cleanup thread. */

+    thread_deinitialize(thread);

+

+    return 0;

+}

+

+/* The very task entry. */

+static void kthread_launcher(void *arg)

+{

+    TRACE_((THIS_FILE, "...launching thread!..."));

+    kernel_thread(&thread_proc, arg, 0);

+}

+

+PJ_DEF(pj_status_t) pj_init(void)

+{

+    pj_status_t rc;

+

+    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));

+

+    rc = pj_thread_init();

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    /* Initialize exception ID for the pool. 

+     * Must do so after critical section is configured.

+     */

+    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);

+    if (rc != PJ_SUCCESS)

+        return rc;

+

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_uint32_t) pj_getpid(void)

+{

+    return 1;

+}

+

+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,

+					 pj_thread_desc desc,

+					 pj_thread_t **ptr_thread)

+{

+    char stack_ptr;

+    pj_thread_t *thread = (pj_thread_t *)desc;

+    pj_str_t thread_name = pj_str((char*)cstr_thread_name);

+

+    /* Size sanity check. */

+    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {

+	pj_assert(!"Not enough pj_thread_desc size!");

+	return PJ_EBUG;

+    }

+

+    /* If a thread descriptor has been registered before, just return it. */

+    if (pj_thread_local_get (thread_tls_id) != 0) {

+	*ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);

+	return PJ_SUCCESS;

+    }

+

+    /* Initialize and set the thread entry. */

+    pj_memset(desc, 0, sizeof(struct pj_thread_t));

+

+    if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)

+	pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);

+    else

+	pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);

+    

+    /* Initialize. */

+    thread_initialize(thread);

+

+    /* Eat semaphore. */

+    down(&thread->startstop_sem);

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+    thread->stk_start = &stack_ptr;

+    thread->stk_size = 0xFFFFFFFFUL;

+    thread->stk_max_usage = 0;

+#else

+    stack_ptr = '\0';

+#endif

+

+    *ptr_thread = thread;

+    return PJ_SUCCESS;

+}

+

+

+pj_status_t pj_thread_init(void)

+{

+    pj_status_t rc;

+    pj_thread_t *dummy;

+    

+    rc = pj_thread_local_alloc(&thread_tls_id);

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    return pj_thread_register("pjlib-main", (long*)&main_thread, &dummy);

+}

+

+PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, const char *thread_name,

+				      pj_thread_proc *proc, void *arg,

+				      pj_size_t stack_size, unsigned flags,

+				      pj_thread_t **ptr_thread)

+{

+    pj_thread_t *thread;

+

+    TRACE_((THIS_FILE, "pj_thread_create()"));

+    

+    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);

+

+    thread = pj_pool_zalloc(pool, sizeof(pj_thread_t));

+    if (!thread)

+	return PJ_ENOMEM;

+

+    PJ_UNUSED_ARG(stack_size);

+

+    /* Thread name. */

+    if (!thread_name) 

+	thread_name = "thr%p";

+    

+    if (strchr(thread_name, '%')) {

+	pj_snprintf(thread->obj_name, PJ_MAX_OBJ_NAME, thread_name, thread);

+    } else {

+	strncpy(thread->obj_name, thread_name, PJ_MAX_OBJ_NAME);

+	thread->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

+    }

+    

+    /* Init thread's semaphore. */

+    TRACE_((THIS_FILE, "...init semaphores..."));

+    init_MUTEX_LOCKED(&thread->startstop_sem);

+    init_MUTEX_LOCKED(&thread->suspend_sem);

+

+    thread->flags = flags;

+

+    if ((flags & PJ_THREAD_SUSPENDED) == 0) {

+	up(&thread->suspend_sem);

+    }

+

+    /* Store the functions and argument. */

+    thread->func = proc;

+    thread->arg = arg;

+    

+    /* Save return value. */

+    *ptr_thread = thread;

+    

+    /* Create the new thread by running a task through keventd. */

+

+#if 0

+    /* Initialize the task queue struct. */

+    thread->tq.sync = 0;

+    INIT_LIST_HEAD(&thread->tq.list);

+    thread->tq.routine = kthread_launcher;

+    thread->tq.data = thread;

+

+    /* and schedule it for execution. */

+    schedule_task(&thread->tq);

+#endif

+    kthread_launcher(thread);

+

+    /* Wait until thread has reached the setup_thread routine. */

+    TRACE_((THIS_FILE, "...wait for the new thread..."));

+    down(&thread->startstop_sem);

+

+    TRACE_((THIS_FILE, "...main thread resumed..."));

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *thread)

+{

+    return thread->obj_name;

+}

+

+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *thread)

+{

+    up(&thread->suspend_sem);

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_thread_t*) pj_thread_this(void)

+{

+    return (pj_thread_t*)pj_thread_local_get(thread_tls_id);

+}

+

+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)

+{

+    TRACE_((THIS_FILE, "pj_thread_join()"));

+    down(&p->startstop_sem);

+    TRACE_((THIS_FILE, "  joined!"));

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *thread)

+{

+    PJ_ASSERT_RETURN(thread != NULL, PJ_EINVALIDOP);

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)

+{

+    pj_highprec_t ticks;

+    pj_thread_t *thread = pj_thread_this();

+

+    PJ_ASSERT_RETURN(thread != NULL, PJ_EBUG);

+    

+    /* Use high precision calculation to make sure we don't

+     * crop values:

+     *

+     *	ticks = HZ * msec / 1000

+     */

+    ticks = HZ;

+    pj_highprec_mul(ticks, msec);

+    pj_highprec_div(ticks, 1000);

+

+    TRACE_((THIS_FILE, "this thread will sleep for %u ticks", ticks));

+    interruptible_sleep_on_timeout( &thread->queue, ticks);

+    return PJ_SUCCESS;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 

+				      pj_atomic_value_t value,

+				      pj_atomic_t **ptr_var)

+{

+    pj_atomic_t *t = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));

+    if (!t) return PJ_ENOMEM;

+

+    atomic_set(&t->atom, value);

+    *ptr_var = t;

+    

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )

+{

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(void) pj_atomic_set(pj_atomic_t *var, pj_atomic_value_t value)

+{

+    atomic_set(&var->atom, value);

+}

+

+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *var)

+{

+    return atomic_read(&var->atom);

+}

+

+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *var)

+{

+    atomic_inc(&var->atom);

+}

+

+PJ_DEF(void) pj_atomic_dec(pj_atomic_t *var)

+{

+    atomic_dec(&var->atom);

+}

+

+PJ_DEF(void) pj_atomic_add( pj_atomic_t *var, pj_atomic_value_t value )

+{

+    atomic_add(value, &var->atom);

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)

+{

+    if (tls_id >= MAX_TLS_ID)

+	return PJ_ETOOMANY;

+    

+    *index = tls_id++;

+

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(void) pj_thread_local_free(long index)

+{

+    pj_assert(index >= 0 && index < MAX_TLS_ID);

+}

+

+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)

+{

+    pj_assert(index >= 0 && index < MAX_TLS_ID);

+    tls_values[index] = value;

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(void*) pj_thread_local_get(long index)

+{

+    pj_assert(index >= 0 && index < MAX_TLS_ID);

+    return tls_values[index];

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+PJ_DEF(void) pj_enter_critical_section(void)

+{

+    spin_lock_irqsave(&critical_section, spinlock_flags);

+}

+

+PJ_DEF(void) pj_leave_critical_section(void)

+{

+    spin_unlock_irqrestore(&critical_section, spinlock_flags);

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+PJ_DEF(pj_status_t) pj_mutex_create( pj_pool_t *pool, 

+				     const char *name, 

+				     int type,

+				     pj_mutex_t **ptr_mutex)

+{

+    pj_mutex_t *mutex;

+    

+    PJ_UNUSED_ARG(name);

+

+    mutex = pj_pool_alloc(pool, sizeof(pj_mutex_t));

+    if (!mutex)

+	return PJ_ENOMEM;

+

+    init_MUTEX(&mutex->sem);

+

+    mutex->recursive = (type == PJ_MUTEX_RECURSE);

+    mutex->owner = NULL;

+    mutex->own_count = 0;

+    

+    /* Done. */

+    *ptr_mutex = mutex;

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, const char *name,

+					    pj_mutex_t **mutex )

+{

+    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);

+}

+

+PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,

+					       const char *name,

+					       pj_mutex_t **mutex )

+{

+    return pj_mutex_create( pool, name, PJ_MUTEX_RECURSE, mutex);

+}

+

+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)

+{

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+    if (mutex->recursive) {

+	pj_thread_t *this_thread = pj_thread_this();

+	if (mutex->owner == this_thread) {

+	    ++mutex->own_count;

+	} else {

+	    down(&mutex->sem);

+	    pj_assert(mutex->own_count == 0);

+	    mutex->owner = this_thread;

+	    mutex->own_count = 1;

+	}

+    } else {

+	down(&mutex->sem);

+    }

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)

+{

+    long rc;

+

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+    if (mutex->recursive) {

+	pj_thread_t *this_thread = pj_thread_this();

+	if (mutex->owner == this_thread) {

+	    ++mutex->own_count;

+	} else {

+	    rc = down_interruptible(&mutex->sem);

+	    if (rc != 0)

+		return PJ_RETURN_OS_ERROR(-rc);

+	    pj_assert(mutex->own_count == 0);

+	    mutex->owner = this_thread;

+	    mutex->own_count = 1;

+	}

+    } else {

+	int rc = down_trylock(&mutex->sem);

+	if (rc != 0)

+	    return PJ_RETURN_OS_ERROR(-rc);

+    }

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)

+{

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+    if (mutex->recursive) {

+	pj_thread_t *this_thread = pj_thread_this();

+	if (mutex->owner == this_thread) {

+	    pj_assert(mutex->own_count > 0);

+	    --mutex->own_count;

+	    if (mutex->own_count == 0) {

+		mutex->owner = NULL;

+		up(&mutex->sem);

+	    }

+	} else {

+	    pj_assert(!"Not owner!");

+	    return PJ_EINVALIDOP;

+	}

+    } else {

+	up(&mutex->sem);

+    }

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)

+{

+    PJ_ASSERT_RETURN(mutex != NULL, PJ_EINVAL);

+

+    return PJ_SUCCESS;

+}

+

+#if defined(PJ_DEBUG) && PJ_DEBUG != 0

+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)

+{

+    if (mutex->recursive)

+	return mutex->owner == pj_thread_this();

+    else

+	return 1;

+}

+#endif	/* PJ_DEBUG */

+

+

+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

+

+PJ_DEF(pj_status_t) pj_sem_create(  pj_pool_t *pool, 

+                                    const char *name,

+				    unsigned initial, 

+                                    unsigned max,

+				    pj_sem_t **sem)

+{

+    pj_sem_t *sem;

+

+    PJ_UNUSED_ARG(max);

+

+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);

+    

+    sem = pj_pool_alloc(pool, sizeof(pj_sem_t));

+    sema_init(&sem->sem, initial);

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)

+{

+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);

+

+    down(&sem->sem);

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)

+{

+    int rc;

+

+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);

+

+    rc = down_trylock(&sem->sem);

+    if (rc != 0) {

+	return PJ_RETURN_OS_ERROR(-rc);

+    } else {

+	return PJ_SUCCESS;

+    }

+}

+

+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)

+{

+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);

+

+    up(&sem->sem);

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)

+{

+    PJ_ASSERT_RETURN(pool && sem, PJ_EINVAL);

+

+    return PJ_SUCCESS;

+}

+

+#endif	/* PJ_HAS_SEMAPHORE */

+

+

+

+

diff --git a/pjlib/src/pj/os_core_unix.c b/pjlib/src/pj/os_core_unix.c
index cc57aab..5956adb 100644
--- a/pjlib/src/pj/os_core_unix.c
+++ b/pjlib/src/pj/os_core_unix.c
@@ -1,563 +1,584 @@
-/* $Id$
- *
- */
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/rand.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/compat/sprintf.h>
-#include <pj/except.h>
-#include <pj/errno.h>
-
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-#  include <semaphore.h>
-#endif
-
-#include <unistd.h>	    // getpid()
-#include <errno.h>	    // errno
-
-#define __USE_GNU
-//uncomment this to get pthread_mutexattr_settype declaration.
-//unfortunately this causes syntax error in pthread.h! :(
-//#define __USE_UNIX98
-#include <pthread.h>
-
-#define THIS_FILE   "osunix"
-
-struct pj_thread_t
-{
-    char	    obj_name[PJ_MAX_OBJ_NAME];
-    pthread_t	    thread;
-    pj_thread_proc *proc;
-    void	   *arg;
-
-    pj_mutex_t	   *suspended_mutex;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-    pj_uint32_t	    stk_size;
-    pj_uint32_t	    stk_max_usage;
-    char	   *stk_start;
-    const char	   *caller_file;
-    int		    caller_line;
-#endif
-};
-
-struct pj_atomic_t
-{
-    pj_mutex_t	       *mutex;
-    pj_atomic_value_t	value;
-};
-
-struct pj_mutex_t
-{
-    pthread_mutex_t     mutex;
-    char		obj_name[PJ_MAX_OBJ_NAME];
-#if PJ_DEBUG
-    int		        nesting_level;
-    pj_thread_t	       *owner;
-#endif
-};
-
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-struct pj_sem_t
-{
-    sem_t		sem;
-    char		obj_name[PJ_MAX_OBJ_NAME];
-};
-#endif /* PJ_HAS_SEMAPHORE */
-
-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
-struct pj_event_t
-{
-    char		obj_name[PJ_MAX_OBJ_NAME];
-};
-#endif	/* PJ_HAS_EVENT_OBJ */
-
-
-#if PJ_HAS_THREADS
-    static pj_thread_t main_thread;
-    static long thread_tls_id;
-    static pj_mutex_t critical_section;
-#else
-#   define MAX_THREADS 32
-    static int tls_flag[MAX_THREADS];
-    static void *tls[MAX_THREADS];
-#endif
-
-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);
-
-/*
- * pj_init(void).
- * Init PJLIB!
- */
-PJ_DEF(pj_status_t) pj_init(void)
-{
-    char dummy_guid[PJ_GUID_MAX_LENGTH];
-    pj_str_t guid;
-    pj_status_t rc;
-
-    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
-
-#if PJ_HAS_THREADS
-    /* Init this thread's TLS. */
-    if ((rc=pj_thread_init()) != 0) {
-	return rc;
-    }
-
-    /* Critical section. */
-    if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_SIMPLE)) != 0)
-	return rc;
-
-#endif
-
-    /* Initialize exception ID for the pool. 
-     * Must do so after critical section is configured.
-     */
-    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
-    if (rc != PJ_SUCCESS)
-        return rc;
-    
-    /* Init random seed. */
-    pj_srand( clock() );
-
-    /* Startup GUID. */
-    guid.ptr = dummy_guid;
-    pj_generate_unique_string( &guid );
-
-    /* Initialize exception ID for the pool. 
-     * Must do so after critical section is configured.
-     */
-    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
-    if (rc != PJ_SUCCESS)
-        return rc;
-
-    /* Startup timestamp */
-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
-    {
-	pj_timestamp dummy_ts;
-	if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {
-	    return rc;
-	}
-    }
-#endif   
-
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_getpid(void)
- */
-PJ_DEF(pj_uint32_t) pj_getpid(void)
-{
-    PJ_CHECK_STACK();
-    return getpid();
-}
-
-/*
- * pj_thread_register(..)
- */
-PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
-					 pj_thread_desc desc,
-					 pj_thread_t **ptr_thread)
-{
-#if PJ_HAS_THREADS
-    char stack_ptr;
-    pj_status_t rc;
-    pj_thread_t *thread = (pj_thread_t *)desc;
-    pj_str_t thread_name = pj_str((char*)cstr_thread_name);
-
-    /* Size sanity check. */
-    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
-	pj_assert(!"Not enough pj_thread_desc size!");
-	return PJ_EBUG;
-    }
-
-    /* If a thread descriptor has been registered before, just return it. */
-    if (pj_thread_local_get (thread_tls_id) != 0) {
-	*ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
-	return PJ_SUCCESS;
-    }
-
-    /* Initialize and set the thread entry. */
-    pj_memset(desc, 0, sizeof(struct pj_thread_t));
-    thread->thread = pthread_self();
-
-    if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
-	pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);
-    else
-	pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);
-    
-    rc = pj_thread_local_set(thread_tls_id, thread);
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-    thread->stk_start = &stack_ptr;
-    thread->stk_size = 0xFFFFFFFFUL;
-    thread->stk_max_usage = 0;
-#else
-    stack_ptr = '\0';
-#endif
-
-    *ptr_thread = thread;
-    return PJ_SUCCESS;
-#else
-    pj_thread_t *thread = (pj_thread_t*)desc;
-    *ptr_thread = thread;
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_thread_init(void)
- */
-pj_status_t pj_thread_init(void)
-{
-#if PJ_HAS_THREADS
-    pj_status_t rc;
-    pj_thread_t *dummy;
-
-    rc = pj_thread_local_alloc(&thread_tls_id );
-    if (rc != PJ_SUCCESS) {
-	return rc;
-    }
-    return pj_thread_register("thr%p", (long*)&main_thread, &dummy);
-#else
-    PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!"));
-    return PJ_EINVALIDOP;
-#endif
-}
-
-#if PJ_HAS_THREADS
-/*
- * thread_main()
- *
- * This is the main entry for all threads.
- */
-static void *thread_main(void *param)
-{
-    pj_thread_t *rec = param;
-    void *result;
-    pj_status_t rc;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-    rec->stk_start = (char*)&rec;
-#endif
-
-    /* Set current thread id. */
-    rc = pj_thread_local_set(thread_tls_id, rec);
-    if (rc != PJ_SUCCESS) {
-	pj_assert(!"Thread TLS ID is not set (pj_init() error?)");
-    }
-
-    /* Check if suspension is required. */
-    if (rec->suspended_mutex)
-	pj_mutex_lock(rec->suspended_mutex);
-
-    PJ_LOG(6,(rec->obj_name, "Thread started"));
-
-    /* Call user's entry! */
-    result = (void*)(long)(*rec->proc)(rec->arg);
-
-    /* Done. */
-    PJ_LOG(6,(rec->obj_name, "Thread quitting"));
-    return result;
-}
-#endif
-
-/*
- * pj_thread_create(...)
- */
-PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, 
-				      const char *thread_name,
-				      pj_thread_proc *proc, 
-				      void *arg,
-				      pj_size_t stack_size, 
-				      unsigned flags,
-				      pj_thread_t **ptr_thread)
-{
-#if PJ_HAS_THREADS
-    pj_thread_t *rec;
-    int rc;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);
-
-    /* Create thread record and assign name for the thread */
-    rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));
-    if (!rec)
-	return PJ_ENOMEM;
-    
-    /* Set name. */
-    if (!thread_name) 
-	thread_name = "thr%p";
-    
-    if (strchr(thread_name, '%')) {
-	pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
-    } else {
-	strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
-	rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
-    }
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-    rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;
-    rec->stk_max_usage = 0;
-#endif
-
-    /* Emulate suspended thread with mutex. */
-    if (flags & PJ_THREAD_SUSPENDED) {
-	rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);
-	if (rc != PJ_SUCCESS)
-	    return rc;
-
-	pj_mutex_lock(rec->suspended_mutex);
-    } else {
-	pj_assert(rec->suspended_mutex == NULL);
-    }
-    
-    PJ_LOG(6, (rec->obj_name, "Thread created"));
-
-    /* Create the thread. */
-    rec->proc = proc;
-    rec->arg = arg;
-    rc = pthread_create( &rec->thread, NULL, thread_main, rec);
-    if (rc != 0)
-	return PJ_RETURN_OS_ERROR(rc);
-
-    *ptr_thread = rec;
-    return PJ_SUCCESS;
-#else
-    pj_assert(!"Threading is disabled!");
-    return PJ_EINVALIDOP;
-#endif
-}
-
-/*
- * pj_thread-get_name()
- */
-PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
-{
-#if PJ_HAS_THREADS
-    pj_thread_t *rec = (pj_thread_t*)p;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(p, "");
-
-    return rec->obj_name;
-#else
-    return "";
-#endif
-}
-
-/*
- * pj_thread_resume()
- */
-PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
-{
-    pj_status_t rc;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(p, PJ_EINVAL);
-
-    rc = pj_mutex_unlock(p->suspended_mutex);
-
-    return rc;
-}
-
-/*
- * pj_thread_this()
- */
-PJ_DEF(pj_thread_t*) pj_thread_this(void)
-{
-#if PJ_HAS_THREADS
-    pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
-    pj_assert(rec != NULL);
-
-    /*
-     * MUST NOT check stack because this function is called
-     * by PJ_CHECK_STACK() itself!!!
-     *
-     */
-
-    return rec;
-#else
-    pj_assert(!"Threading is not enabled!");
-    return NULL;
-#endif
-}
-
-/*
- * pj_thread_join()
- */
-PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
-{
-#if PJ_HAS_THREADS
-    pj_thread_t *rec = (pj_thread_t *)p;
-    void *ret;
-    int result;
-
-    PJ_CHECK_STACK();
-
-    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
-    result = pthread_join( rec->thread, &ret);
-
-    if (result == 0)
-	return PJ_SUCCESS;
-    else
-	return PJ_RETURN_OS_ERROR(result);
-#else
-    PJ_CHECK_STACK();
-    pj_assert(!"No multithreading support!");
-    return PJ_EINVALIDOP;
-#endif
-}
-
-/*
- * pj_thread_destroy()
- */
-PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
-{
-    /* This function is used to destroy thread handle in other platforms.
-     * I suppose there's nothing to do here..
-     */
-    PJ_CHECK_STACK();
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_thread_sleep()
- */
-PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
-{
-    PJ_CHECK_STACK();
-    return usleep(msec * 1000);
-}
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-/*
- * pj_thread_check_stack()
- * Implementation for PJ_CHECK_STACK()
- */
-PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
-{
-    char stk_ptr;
-    pj_uint32_t usage;
-    pj_thread_t *thread = pj_thread_this();
-
-    /* Calculate current usage. */
-    usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
-		thread->stk_start - &stk_ptr;
-
-    /* Assert if stack usage is dangerously high. */
-    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
-
-    /* Keep statistic. */
-    if (usage > thread->stk_max_usage) {
-	thread->stk_max_usage = usage;
-	thread->caller_file = file;
-	thread->caller_line = line;
-    }
-}
-
-/*
- * pj_thread_get_stack_max_usage()
- */
-PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
-{
-    return thread->stk_max_usage;
-}
-
-/*
- * pj_thread_get_stack_info()
- */
-PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
-					      const char **file,
-					      int *line )
-{
-    pj_assert(thread);
-
-    *file = thread->caller_file;
-    *line = thread->caller_line;
-    return 0;
-}
-
-#endif	/* PJ_OS_HAS_CHECK_STACK */
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * pj_atomic_create()
- */
-PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
-				      pj_atomic_value_t initial,
-				      pj_atomic_t **ptr_atomic)
-{
-    pj_status_t rc;
-    pj_atomic_t *atomic_var = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));
-    if (!atomic_var)
-	return PJ_ENOMEM;
-    
-#if PJ_HAS_THREADS
-    rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);
-    if (rc != PJ_SUCCESS)
-	return rc;
-#endif
-    atomic_var->value = initial;
-
-    *ptr_atomic = atomic_var;
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_atomic_destroy()
- */
-PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )
-{
-    PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL);
-#if PJ_HAS_THREADS
-    return pj_mutex_destroy( atomic_var->mutex );
-#else
-    return 0;
-#endif
-}
-
-/*
- * pj_atomic_set()
- */
-PJ_DEF(void) pj_atomic_set(pj_atomic_t *atomic_var, pj_atomic_value_t value)
-{
-    PJ_CHECK_STACK();
-
-#if PJ_HAS_THREADS
-    pj_mutex_lock( atomic_var->mutex );
-#endif
-    atomic_var->value = value;
-#if PJ_HAS_THREADS
-    pj_mutex_unlock( atomic_var->mutex);
-#endif 
-}
-
-/*
- * pj_atomic_get()
- */
-PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
-{
-    pj_atomic_value_t oldval;
-    
-    PJ_CHECK_STACK();
-
-#if PJ_HAS_THREADS
-    pj_mutex_lock( atomic_var->mutex );
-#endif
-    oldval = atomic_var->value;
-#if PJ_HAS_THREADS
-    pj_mutex_unlock( atomic_var->mutex);
-#endif
-    return oldval;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/os.h>

+#include <pj/assert.h>

+#include <pj/pool.h>

+#include <pj/log.h>

+#include <pj/rand.h>

+#include <pj/string.h>

+#include <pj/guid.h>

+#include <pj/compat/sprintf.h>

+#include <pj/except.h>

+#include <pj/errno.h>

+

+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

+#  include <semaphore.h>

+#endif

+

+#include <unistd.h>	    // getpid()

+#include <errno.h>	    // errno

+

+#define __USE_GNU

+//uncomment this to get pthread_mutexattr_settype declaration.

+//unfortunately this causes syntax error in pthread.h! :(

+//#define __USE_UNIX98

+#include <pthread.h>

+

+#define THIS_FILE   "osunix"

+

+struct pj_thread_t

+{

+    char	    obj_name[PJ_MAX_OBJ_NAME];

+    pthread_t	    thread;

+    pj_thread_proc *proc;

+    void	   *arg;

+

+    pj_mutex_t	   *suspended_mutex;

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+    pj_uint32_t	    stk_size;

+    pj_uint32_t	    stk_max_usage;

+    char	   *stk_start;

+    const char	   *caller_file;

+    int		    caller_line;

+#endif

+};

+

+struct pj_atomic_t

+{

+    pj_mutex_t	       *mutex;

+    pj_atomic_value_t	value;

+};

+

+struct pj_mutex_t

+{

+    pthread_mutex_t     mutex;

+    char		obj_name[PJ_MAX_OBJ_NAME];

+#if PJ_DEBUG

+    int		        nesting_level;

+    pj_thread_t	       *owner;

+#endif

+};

+

+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

+struct pj_sem_t

+{

+    sem_t		sem;

+    char		obj_name[PJ_MAX_OBJ_NAME];

+};

+#endif /* PJ_HAS_SEMAPHORE */

+

+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0

+struct pj_event_t

+{

+    char		obj_name[PJ_MAX_OBJ_NAME];

+};

+#endif	/* PJ_HAS_EVENT_OBJ */

+

+

+#if PJ_HAS_THREADS

+    static pj_thread_t main_thread;

+    static long thread_tls_id;

+    static pj_mutex_t critical_section;

+#else

+#   define MAX_THREADS 32

+    static int tls_flag[MAX_THREADS];

+    static void *tls[MAX_THREADS];

+#endif

+

+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type);

+

+/*

+ * pj_init(void).

+ * Init PJLIB!

+ */

+PJ_DEF(pj_status_t) pj_init(void)

+{

+    char dummy_guid[PJ_GUID_MAX_LENGTH];

+    pj_str_t guid;

+    pj_status_t rc;

+

+    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));

+

+#if PJ_HAS_THREADS

+    /* Init this thread's TLS. */

+    if ((rc=pj_thread_init()) != 0) {

+	return rc;

+    }

+

+    /* Critical section. */

+    if ((rc=init_mutex(&critical_section, "critsec", PJ_MUTEX_SIMPLE)) != 0)

+	return rc;

+

+#endif

+

+    /* Initialize exception ID for the pool. 

+     * Must do so after critical section is configured.

+     */

+    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);

+    if (rc != PJ_SUCCESS)

+        return rc;

+    

+    /* Init random seed. */

+    pj_srand( clock() );

+

+    /* Startup GUID. */

+    guid.ptr = dummy_guid;

+    pj_generate_unique_string( &guid );

+

+    /* Initialize exception ID for the pool. 

+     * Must do so after critical section is configured.

+     */

+    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);

+    if (rc != PJ_SUCCESS)

+        return rc;

+

+    /* Startup timestamp */

+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

+    {

+	pj_timestamp dummy_ts;

+	if ((rc=pj_get_timestamp(&dummy_ts)) != 0) {

+	    return rc;

+	}

+    }

+#endif   

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_getpid(void)

+ */

+PJ_DEF(pj_uint32_t) pj_getpid(void)

+{

+    PJ_CHECK_STACK();

+    return getpid();

+}

+

+/*

+ * pj_thread_register(..)

+ */

+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,

+					 pj_thread_desc desc,

+					 pj_thread_t **ptr_thread)

+{

+#if PJ_HAS_THREADS

+    char stack_ptr;

+    pj_status_t rc;

+    pj_thread_t *thread = (pj_thread_t *)desc;

+    pj_str_t thread_name = pj_str((char*)cstr_thread_name);

+

+    /* Size sanity check. */

+    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {

+	pj_assert(!"Not enough pj_thread_desc size!");

+	return PJ_EBUG;

+    }

+

+    /* If a thread descriptor has been registered before, just return it. */

+    if (pj_thread_local_get (thread_tls_id) != 0) {

+	*ptr_thread = (pj_thread_t*)pj_thread_local_get (thread_tls_id);

+	return PJ_SUCCESS;

+    }

+

+    /* Initialize and set the thread entry. */

+    pj_memset(desc, 0, sizeof(struct pj_thread_t));

+    thread->thread = pthread_self();

+

+    if(cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)

+	pj_sprintf(thread->obj_name, cstr_thread_name, thread->thread);

+    else

+	pj_sprintf(thread->obj_name, "thr%p", (void*)thread->thread);

+    

+    rc = pj_thread_local_set(thread_tls_id, thread);

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+    thread->stk_start = &stack_ptr;

+    thread->stk_size = 0xFFFFFFFFUL;

+    thread->stk_max_usage = 0;

+#else

+    stack_ptr = '\0';

+#endif

+

+    *ptr_thread = thread;

+    return PJ_SUCCESS;

+#else

+    pj_thread_t *thread = (pj_thread_t*)desc;

+    *ptr_thread = thread;

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_thread_init(void)

+ */

+pj_status_t pj_thread_init(void)

+{

+#if PJ_HAS_THREADS

+    pj_status_t rc;

+    pj_thread_t *dummy;

+

+    rc = pj_thread_local_alloc(&thread_tls_id );

+    if (rc != PJ_SUCCESS) {

+	return rc;

+    }

+    return pj_thread_register("thr%p", (long*)&main_thread, &dummy);

+#else

+    PJ_LOG(2,(THIS_FILE, "Thread init error. Threading is not enabled!"));

+    return PJ_EINVALIDOP;

+#endif

+}

+

+#if PJ_HAS_THREADS

+/*

+ * thread_main()

+ *

+ * This is the main entry for all threads.

+ */

+static void *thread_main(void *param)

+{

+    pj_thread_t *rec = param;

+    void *result;

+    pj_status_t rc;

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+    rec->stk_start = (char*)&rec;

+#endif

+

+    /* Set current thread id. */

+    rc = pj_thread_local_set(thread_tls_id, rec);

+    if (rc != PJ_SUCCESS) {

+	pj_assert(!"Thread TLS ID is not set (pj_init() error?)");

+    }

+

+    /* Check if suspension is required. */

+    if (rec->suspended_mutex)

+	pj_mutex_lock(rec->suspended_mutex);

+

+    PJ_LOG(6,(rec->obj_name, "Thread started"));

+

+    /* Call user's entry! */

+    result = (void*)(long)(*rec->proc)(rec->arg);

+

+    /* Done. */

+    PJ_LOG(6,(rec->obj_name, "Thread quitting"));

+    return result;

+}

+#endif

+

+/*

+ * pj_thread_create(...)

+ */

+PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, 

+				      const char *thread_name,

+				      pj_thread_proc *proc, 

+				      void *arg,

+				      pj_size_t stack_size, 

+				      unsigned flags,

+				      pj_thread_t **ptr_thread)

+{

+#if PJ_HAS_THREADS

+    pj_thread_t *rec;

+    int rc;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(pool && proc && ptr_thread, PJ_EINVAL);

+

+    /* Create thread record and assign name for the thread */

+    rec = (struct pj_thread_t*) pj_pool_zalloc(pool, sizeof(pj_thread_t));

+    if (!rec)

+	return PJ_ENOMEM;

+    

+    /* Set name. */

+    if (!thread_name) 

+	thread_name = "thr%p";

+    

+    if (strchr(thread_name, '%')) {

+	pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);

+    } else {

+	strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);

+	rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

+    }

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+    rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;

+    rec->stk_max_usage = 0;

+#endif

+

+    /* Emulate suspended thread with mutex. */

+    if (flags & PJ_THREAD_SUSPENDED) {

+	rc = pj_mutex_create_simple(pool, NULL, &rec->suspended_mutex);

+	if (rc != PJ_SUCCESS)

+	    return rc;

+

+	pj_mutex_lock(rec->suspended_mutex);

+    } else {

+	pj_assert(rec->suspended_mutex == NULL);

+    }

+    

+    PJ_LOG(6, (rec->obj_name, "Thread created"));

+

+    /* Create the thread. */

+    rec->proc = proc;

+    rec->arg = arg;

+    rc = pthread_create( &rec->thread, NULL, thread_main, rec);

+    if (rc != 0)

+	return PJ_RETURN_OS_ERROR(rc);

+

+    *ptr_thread = rec;

+    return PJ_SUCCESS;

+#else

+    pj_assert(!"Threading is disabled!");

+    return PJ_EINVALIDOP;

+#endif

+}

+

+/*

+ * pj_thread-get_name()

+ */

+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)

+{

+#if PJ_HAS_THREADS

+    pj_thread_t *rec = (pj_thread_t*)p;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(p, "");

+

+    return rec->obj_name;

+#else

+    return "";

+#endif

+}

+

+/*

+ * pj_thread_resume()

+ */

+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)

+{

+    pj_status_t rc;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(p, PJ_EINVAL);

+

+    rc = pj_mutex_unlock(p->suspended_mutex);

+

+    return rc;

+}

+

+/*

+ * pj_thread_this()

+ */

+PJ_DEF(pj_thread_t*) pj_thread_this(void)

+{

+#if PJ_HAS_THREADS

+    pj_thread_t *rec = pj_thread_local_get(thread_tls_id);

+    pj_assert(rec != NULL);

+

+    /*

+     * MUST NOT check stack because this function is called

+     * by PJ_CHECK_STACK() itself!!!

+     *

+     */

+

+    return rec;

+#else

+    pj_assert(!"Threading is not enabled!");

+    return NULL;

+#endif

+}

+

+/*

+ * pj_thread_join()

+ */

+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)

+{

+#if PJ_HAS_THREADS

+    pj_thread_t *rec = (pj_thread_t *)p;

+    void *ret;

+    int result;

+

+    PJ_CHECK_STACK();

+

+    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));

+    result = pthread_join( rec->thread, &ret);

+

+    if (result == 0)

+	return PJ_SUCCESS;

+    else

+	return PJ_RETURN_OS_ERROR(result);

+#else

+    PJ_CHECK_STACK();

+    pj_assert(!"No multithreading support!");

+    return PJ_EINVALIDOP;

+#endif

+}

+

+/*

+ * pj_thread_destroy()

+ */

+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)

+{

+    /* This function is used to destroy thread handle in other platforms.

+     * I suppose there's nothing to do here..

+     */

+    PJ_CHECK_STACK();

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_thread_sleep()

+ */

+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)

+{

+    PJ_CHECK_STACK();

+    return usleep(msec * 1000);

+}

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+/*

+ * pj_thread_check_stack()

+ * Implementation for PJ_CHECK_STACK()

+ */

+PJ_DEF(void) pj_thread_check_stack(const char *file, int line)

+{

+    char stk_ptr;

+    pj_uint32_t usage;

+    pj_thread_t *thread = pj_thread_this();

+

+    /* Calculate current usage. */

+    usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :

+		thread->stk_start - &stk_ptr;

+

+    /* Assert if stack usage is dangerously high. */

+    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));

+

+    /* Keep statistic. */

+    if (usage > thread->stk_max_usage) {

+	thread->stk_max_usage = usage;

+	thread->caller_file = file;

+	thread->caller_line = line;

+    }

+}

+

+/*

+ * pj_thread_get_stack_max_usage()

+ */

+PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)

+{

+    return thread->stk_max_usage;

+}

+

+/*

+ * pj_thread_get_stack_info()

+ */

+PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,

+					      const char **file,

+					      int *line )

+{

+    pj_assert(thread);

+

+    *file = thread->caller_file;

+    *line = thread->caller_line;

+    return 0;

+}

+

+#endif	/* PJ_OS_HAS_CHECK_STACK */

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * pj_atomic_create()

+ */

+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 

+				      pj_atomic_value_t initial,

+				      pj_atomic_t **ptr_atomic)

+{

+    pj_status_t rc;

+    pj_atomic_t *atomic_var = pj_pool_calloc(pool, 1, sizeof(pj_atomic_t));

+    if (!atomic_var)

+	return PJ_ENOMEM;

+    

+#if PJ_HAS_THREADS

+    rc = pj_mutex_create(pool, "atm%p", PJ_MUTEX_SIMPLE, &atomic_var->mutex);

+    if (rc != PJ_SUCCESS)

+	return rc;

+#endif

+    atomic_var->value = initial;

+

+    *ptr_atomic = atomic_var;

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_atomic_destroy()

+ */

+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *atomic_var )

+{

+    PJ_ASSERT_RETURN(atomic_var, PJ_EINVAL);

+#if PJ_HAS_THREADS

+    return pj_mutex_destroy( atomic_var->mutex );

+#else

+    return 0;

+#endif

+}

+

+/*

+ * pj_atomic_set()

+ */

+PJ_DEF(void) pj_atomic_set(pj_atomic_t *atomic_var, pj_atomic_value_t value)

+{

+    PJ_CHECK_STACK();

+

+#if PJ_HAS_THREADS

+    pj_mutex_lock( atomic_var->mutex );

+#endif

+    atomic_var->value = value;

+#if PJ_HAS_THREADS

+    pj_mutex_unlock( atomic_var->mutex);

+#endif 

+}

+

+/*

+ * pj_atomic_get()

+ */

+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)

+{

+    pj_atomic_value_t oldval;

+    

+    PJ_CHECK_STACK();

+

+#if PJ_HAS_THREADS

+    pj_mutex_lock( atomic_var->mutex );

+#endif

+    oldval = atomic_var->value;

+#if PJ_HAS_THREADS

+    pj_mutex_unlock( atomic_var->mutex);

+#endif

+    return oldval;

+}

+

 /*

  * pj_atomic_inc_and_get()

  */

@@ -577,33 +598,33 @@
 

     return new_value;

 }

-/*
- * pj_atomic_inc()
- */
-PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
-{
-    pj_atomic_inc_and_get(atomic_var);
-}
-
-/*
- * pj_atomic_dec_and_get()
- */
-PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)
+/*

+ * pj_atomic_inc()

+ */

+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)

+{

+    pj_atomic_inc_and_get(atomic_var);

+}

+

+/*

+ * pj_atomic_dec_and_get()

+ */

+PJ_DEF(pj_atomic_value_t) pj_atomic_dec_and_get(pj_atomic_t *atomic_var)

 {

     pj_atomic_value_t new_value;

-
-    PJ_CHECK_STACK();
-
-#if PJ_HAS_THREADS
-    pj_mutex_lock( atomic_var->mutex );
-#endif
-    new_value = --atomic_var->value;
-#if PJ_HAS_THREADS
-    pj_mutex_unlock( atomic_var->mutex);
+

+    PJ_CHECK_STACK();

+

+#if PJ_HAS_THREADS

+    pj_mutex_lock( atomic_var->mutex );

+#endif

+    new_value = --atomic_var->value;

+#if PJ_HAS_THREADS

+    pj_mutex_unlock( atomic_var->mutex);

 #endif

 

-    return new_value;
-}
+    return new_value;

+}

 

 /*

  * pj_atomic_dec()

@@ -612,29 +633,29 @@
 {

     pj_atomic_dec_and_get(atomic_var);

 }

-
-/*
- * pj_atomic_add_and_get()
- */ 
+

+/*

+ * pj_atomic_add_and_get()

+ */ 

 PJ_DEF(pj_atomic_value_t) pj_atomic_add_and_get( pj_atomic_t *atomic_var, 

-                                                 pj_atomic_value_t value )
+                                                 pj_atomic_value_t value )

 {

     pj_atomic_value_t new_value;

-
-#if PJ_HAS_THREADS
-    pj_mutex_lock(atomic_var->mutex);
-#endif
-    
+

+#if PJ_HAS_THREADS

+    pj_mutex_lock(atomic_var->mutex);

+#endif

+    

     atomic_var->value += value;

-    new_value = atomic_var->value;
-
-#if PJ_HAS_THREADS
-    pj_mutex_unlock(atomic_var->mutex);
+    new_value = atomic_var->value;

+

+#if PJ_HAS_THREADS

+    pj_mutex_unlock(atomic_var->mutex);

 #endif

 

-    return new_value;
-}
-
+    return new_value;

+}

+

 /*

  * pj_atomic_add()

  */ 

@@ -643,598 +664,598 @@
 {

     pj_atomic_add_and_get(atomic_var, value);

 }

-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * pj_thread_local_alloc()
- */
-PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index)
-{
-#if PJ_HAS_THREADS
-    pthread_key_t key;
-    int rc;
-
-    PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL);
-
-    pj_assert( sizeof(pthread_key_t) <= sizeof(long));
-    if ((rc=pthread_key_create(&key, NULL)) != 0)
-	return PJ_RETURN_OS_ERROR(rc);
-
-    *p_index = key;
-    return PJ_SUCCESS;
-#else
-    int i;
-    for (i=0; i<MAX_THREADS; ++i) {
-	if (tls_flag[i] == 0)
-	    break;
-    }
-    if (i == MAX_THREADS) 
-	return PJ_ETOOMANY;
-    
-    tls_flag[i] = 1;
-    tls[i] = NULL;
-
-    *p_index = i;
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_thread_local_free()
- */
-PJ_DEF(void) pj_thread_local_free(long index)
-{
-    PJ_CHECK_STACK();
-#if PJ_HAS_THREADS
-    pthread_key_delete(index);
-#else
-    tls_flag[index] = 0;
-#endif
-}
-
-/*
- * pj_thread_local_set()
- */
-PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
-{
-    //Can't check stack because this function is called in the
-    //beginning before main thread is initialized.
-    //PJ_CHECK_STACK();
-#if PJ_HAS_THREADS
-    int rc=pthread_setspecific(index, value);
-    return rc==0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);
-#else
-    pj_assert(index >= 0 && index < MAX_THREADS);
-    tls[index] = value;
-    return PJ_SUCCESS;
-#endif
-}
-
-PJ_DEF(void*) pj_thread_local_get(long index)
-{
-    //Can't check stack because this function is called
-    //by PJ_CHECK_STACK() itself!!!
-    //PJ_CHECK_STACK();
-#if PJ_HAS_THREADS
-    return pthread_getspecific(index);
-#else
-    pj_assert(index >= 0 && index < MAX_THREADS);
-    return tls[index];
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(void) pj_enter_critical_section(void)
-{
-#if PJ_HAS_THREADS
-    pj_mutex_lock(&critical_section);
-#endif
-}
-
-PJ_DEF(void) pj_leave_critical_section(void)
-{
-#if PJ_HAS_THREADS
-    pj_mutex_unlock(&critical_section);
-#endif
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)
-{
-#if PJ_HAS_THREADS
-    pthread_mutexattr_t attr;
-    int rc;
-
-    PJ_CHECK_STACK();
-
-    pthread_mutexattr_init(&attr);
-
-    if (type == PJ_MUTEX_SIMPLE) {
-#if defined(PJ_LINUX) && PJ_LINUX!=0
-	extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);
-	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);
-#else
-	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
-#endif
-    } else {
-#if defined(PJ_LINUX) && PJ_LINUX!=0
-	extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);
-	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
-#else
-	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
-#endif
-    }
-    
-    if (rc != 0) {
-	return PJ_RETURN_OS_ERROR(rc);
-    }
-
-    rc = pthread_mutex_init(&mutex->mutex, &attr);
-    if (rc != 0) {
-	return PJ_RETURN_OS_ERROR(rc);
-    }
-    
-#if PJ_DEBUG
-    /* Set owner. */
-    mutex->nesting_level = 0;
-    mutex->owner = NULL;
-#endif
-
-    /* Set name. */
-    if (!name) {
-	name = "mtx%p";
-    }
-    if (strchr(name, '%')) {
-	pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
-    } else {
-	strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
-	mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
-    }
-
-    PJ_LOG(6, (mutex->obj_name, "Mutex created"));
-    return PJ_SUCCESS;
-#else /* PJ_HAS_THREADS */
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_mutex_create()
- */
-PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 
-				    const char *name, 
-				    int type,
-				    pj_mutex_t **ptr_mutex)
-{
-#if PJ_HAS_THREADS
-    pj_status_t rc;
-    pj_mutex_t *mutex;
-
-    PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL);
-
-    mutex = pj_pool_alloc(pool, sizeof(*mutex));
-    if (!mutex) return PJ_ENOMEM;
-
-    if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS)
-	return rc;
-    
-    *ptr_mutex = mutex;
-    return PJ_SUCCESS;
-#else /* PJ_HAS_THREADS */
-    return (pj_mutex_t*)1;
-#endif
-}
-
-/*
- * pj_mutex_create_simple()
- */
-PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, 
-                                            const char *name,
-					    pj_mutex_t **mutex )
-{
-    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
-}
-
-/*
- * pj_mutex_create_recursive()
- */
-PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
-					       const char *name,
-					       pj_mutex_t **mutex )
-{
-    return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
-}
-
-/*
- * pj_mutex_lock()
- */
-PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
-{
-#if PJ_HAS_THREADS
-    pj_status_t status;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", 
-				pj_thread_this()->obj_name));
-
-    status = pthread_mutex_lock( &mutex->mutex );
-
-    PJ_LOG(6,(mutex->obj_name, 
-	      (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"),
-	      pj_thread_this()->obj_name));
-
-#if PJ_DEBUG
-    if (status == PJ_SUCCESS) {
-	mutex->owner = pj_thread_this();
-	++mutex->nesting_level;
-    }
-#endif
-
-    if (status == 0)
-	return PJ_SUCCESS;
-    else
-	return PJ_RETURN_OS_ERROR(status);
-#else	/* PJ_HAS_THREADS */
-    pj_assert( mutex == (pj_mutex_t*)1 );
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_mutex_unlock()
- */
-PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
-{
-#if PJ_HAS_THREADS
-    pj_status_t status;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-#if PJ_DEBUG
-    pj_assert(mutex->owner == pj_thread_this());
-    if (--mutex->nesting_level == 0) {
-	mutex->owner = NULL;
-    }
-#endif
-
-    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", 
-				pj_thread_this()->obj_name));
-
-    status = pthread_mutex_unlock( &mutex->mutex );
-    if (status == 0)
-	return PJ_SUCCESS;
-    else
-	return PJ_RETURN_OS_ERROR(status);
-
-#else /* PJ_HAS_THREADS */
-    pj_assert( mutex == (pj_mutex_t*)1 );
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_mutex_trylock()
- */
-PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
-{
-#if PJ_HAS_THREADS
-    int status;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-    status = pthread_mutex_trylock( &mutex->mutex );
-
-    if (status==0) {
-	PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", 
-				  pj_thread_this()->obj_name));
-
-#if PJ_DEBUG
-	mutex->owner = pj_thread_this();
-	++mutex->nesting_level;
-#endif
-    }
-    
-    if (status==0)
-	return PJ_SUCCESS;
-    else
-	return PJ_RETURN_OS_ERROR(status);
-#else	/* PJ_HAS_THREADS */
-    pj_assert( mutex == (pj_mutex_t*)1);
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_mutex_destroy()
- */
-PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
-{
-    int status;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-#if PJ_HAS_THREADS
-    PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));
-    status = pthread_mutex_destroy( &mutex->mutex );
-    if (status == 0)
-	return PJ_SUCCESS;
-    else
-	return PJ_RETURN_OS_ERROR(status);
-#else
-    pj_assert( mutex == (pj_mutex_t*)1 );
-    status = PJ_SUCCESS;
-    return status;
-#endif
-}
-
-#if PJ_DEBUG
-PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
-{
-#if PJ_HAS_THREADS
-    return mutex->owner == pj_thread_this();
-#else
-    return 1;
-#endif
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-
-/*
- * pj_sem_create()
- */
-PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 
-				   const char *name,
-				   unsigned initial, 
-				   unsigned max,
-				   pj_sem_t **ptr_sem)
-{
-#if PJ_HAS_THREADS
-    pj_sem_t *sem;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);
-
-    sem = pj_pool_alloc(pool, sizeof(*sem));    
-    if (!sem) return PJ_ENOMEM;
-
-    if (sem_init( &sem->sem, 0, initial) != 0) 
-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-    
-    /* Set name. */
-    if (!name) {
-	name = "sem%p";
-    }
-    if (strchr(name, '%')) {
-	pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
-    } else {
-	strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
-	sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
-    }
-
-    PJ_LOG(6, (sem->obj_name, "Semaphore created"));
-
-    *ptr_sem = sem;
-    return PJ_SUCCESS;
-#else
-    *ptr_sem = (pj_sem_t*)1;
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_sem_wait()
- */
-PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
-{
-#if PJ_HAS_THREADS
-    int result;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
-    PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", 
-			      pj_thread_this()->obj_name));
-
-    result = sem_wait( &sem->sem );
-    
-    if (result == 0) {
-	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 
-				  pj_thread_this()->obj_name));
-    } else {
-	PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", 
-				  pj_thread_this()->obj_name));
-    }
-
-    if (result == 0)
-	return PJ_SUCCESS;
-    else
-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-#else
-    pj_assert( sem == (pj_sem_t*) 1 );
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_sem_trywait()
- */
-PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
-{
-#if PJ_HAS_THREADS
-    int result;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
-    result = sem_trywait( &sem->sem );
-    
-    if (result == 0) {
-	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 
-				  pj_thread_this()->obj_name));
-    } 
-    if (result == 0)
-	return PJ_SUCCESS;
-    else
-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-#else
-    pj_assert( sem == (pj_sem_t*)1 );
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_sem_post()
- */
-PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
-{
-#if PJ_HAS_THREADS
-    int result;
-    PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
-			      pj_thread_this()->obj_name));
-    result = sem_post( &sem->sem );
-
-    if (result == 0)
-	return PJ_SUCCESS;
-    else
-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-#else
-    pj_assert( sem == (pj_sem_t*) 1);
-    return PJ_SUCCESS;
-#endif
-}
-
-/*
- * pj_sem_destroy()
- */
-PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
-{
-#if PJ_HAS_THREADS
-    int result;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
-    PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
-			      pj_thread_this()->obj_name));
-    result = sem_destroy( &sem->sem );
-
-    if (result == 0)
-	return PJ_SUCCESS;
-    else
-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-#else
-    pj_assert( sem == (pj_sem_t*) 1 );
-    return PJ_SUCCESS;
-#endif
-}
-
-#endif	/* PJ_HAS_SEMAPHORE */
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
-
-/*
- * pj_event_create()
- */
-PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,
-				    pj_bool_t manual_reset, pj_bool_t initial,
-				    pj_event_t **ptr_event)
-{
-    pj_assert(!"Not supported!");
-    PJ_UNUSED_ARG(pool);
-    PJ_UNUSED_ARG(name);
-    PJ_UNUSED_ARG(manual_reset);
-    PJ_UNUSED_ARG(initial);
-    PJ_UNUSED_ARG(ptr_event);
-    return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_wait()
- */
-PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
-{
-    PJ_UNUSED_ARG(event);
-    return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_trywait()
- */
-PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
-{
-    PJ_UNUSED_ARG(event);
-    return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_set()
- */
-PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
-{
-    PJ_UNUSED_ARG(event);
-    return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_pulse()
- */
-PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
-{
-    PJ_UNUSED_ARG(event);
-    return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_reset()
- */
-PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
-{
-    PJ_UNUSED_ARG(event);
-    return PJ_EINVALIDOP;
-}
-
-/*
- * pj_event_destroy()
- */
-PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
-{
-    PJ_UNUSED_ARG(event);
-    return PJ_EINVALIDOP;
-}
-
-#endif	/* PJ_HAS_EVENT_OBJ */
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
-/*
- * Terminal
- */
-
-/**
- * Set terminal color.
- */
-PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
-{
-    PJ_UNUSED_ARG(color);
-    return PJ_EINVALIDOP;
-}
-
-/**
- * Get current terminal foreground color.
- */
-PJ_DEF(pj_color_t) pj_term_get_color(void)
-{
-    return 0;
-}
-
-#endif	/* PJ_TERM_HAS_COLOR */
-
+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * pj_thread_local_alloc()

+ */

+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *p_index)

+{

+#if PJ_HAS_THREADS

+    pthread_key_t key;

+    int rc;

+

+    PJ_ASSERT_RETURN(p_index != NULL, PJ_EINVAL);

+

+    pj_assert( sizeof(pthread_key_t) <= sizeof(long));

+    if ((rc=pthread_key_create(&key, NULL)) != 0)

+	return PJ_RETURN_OS_ERROR(rc);

+

+    *p_index = key;

+    return PJ_SUCCESS;

+#else

+    int i;

+    for (i=0; i<MAX_THREADS; ++i) {

+	if (tls_flag[i] == 0)

+	    break;

+    }

+    if (i == MAX_THREADS) 

+	return PJ_ETOOMANY;

+    

+    tls_flag[i] = 1;

+    tls[i] = NULL;

+

+    *p_index = i;

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_thread_local_free()

+ */

+PJ_DEF(void) pj_thread_local_free(long index)

+{

+    PJ_CHECK_STACK();

+#if PJ_HAS_THREADS

+    pthread_key_delete(index);

+#else

+    tls_flag[index] = 0;

+#endif

+}

+

+/*

+ * pj_thread_local_set()

+ */

+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)

+{

+    //Can't check stack because this function is called in the

+    //beginning before main thread is initialized.

+    //PJ_CHECK_STACK();

+#if PJ_HAS_THREADS

+    int rc=pthread_setspecific(index, value);

+    return rc==0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(rc);

+#else

+    pj_assert(index >= 0 && index < MAX_THREADS);

+    tls[index] = value;

+    return PJ_SUCCESS;

+#endif

+}

+

+PJ_DEF(void*) pj_thread_local_get(long index)

+{

+    //Can't check stack because this function is called

+    //by PJ_CHECK_STACK() itself!!!

+    //PJ_CHECK_STACK();

+#if PJ_HAS_THREADS

+    return pthread_getspecific(index);

+#else

+    pj_assert(index >= 0 && index < MAX_THREADS);

+    return tls[index];

+#endif

+}

+

+///////////////////////////////////////////////////////////////////////////////

+PJ_DEF(void) pj_enter_critical_section(void)

+{

+#if PJ_HAS_THREADS

+    pj_mutex_lock(&critical_section);

+#endif

+}

+

+PJ_DEF(void) pj_leave_critical_section(void)

+{

+#if PJ_HAS_THREADS

+    pj_mutex_unlock(&critical_section);

+#endif

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name, int type)

+{

+#if PJ_HAS_THREADS

+    pthread_mutexattr_t attr;

+    int rc;

+

+    PJ_CHECK_STACK();

+

+    pthread_mutexattr_init(&attr);

+

+    if (type == PJ_MUTEX_SIMPLE) {

+#if defined(PJ_LINUX) && PJ_LINUX!=0

+	extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);

+	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);

+#else

+	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);

+#endif

+    } else {

+#if defined(PJ_LINUX) && PJ_LINUX!=0

+	extern int pthread_mutexattr_settype(pthread_mutexattr_t*,int);

+	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);

+#else

+	rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

+#endif

+    }

+    

+    if (rc != 0) {

+	return PJ_RETURN_OS_ERROR(rc);

+    }

+

+    rc = pthread_mutex_init(&mutex->mutex, &attr);

+    if (rc != 0) {

+	return PJ_RETURN_OS_ERROR(rc);

+    }

+    

+#if PJ_DEBUG

+    /* Set owner. */

+    mutex->nesting_level = 0;

+    mutex->owner = NULL;

+#endif

+

+    /* Set name. */

+    if (!name) {

+	name = "mtx%p";

+    }

+    if (strchr(name, '%')) {

+	pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);

+    } else {

+	strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);

+	mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

+    }

+

+    PJ_LOG(6, (mutex->obj_name, "Mutex created"));

+    return PJ_SUCCESS;

+#else /* PJ_HAS_THREADS */

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_mutex_create()

+ */

+PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 

+				    const char *name, 

+				    int type,

+				    pj_mutex_t **ptr_mutex)

+{

+#if PJ_HAS_THREADS

+    pj_status_t rc;

+    pj_mutex_t *mutex;

+

+    PJ_ASSERT_RETURN(pool && ptr_mutex, PJ_EINVAL);

+

+    mutex = pj_pool_alloc(pool, sizeof(*mutex));

+    if (!mutex) return PJ_ENOMEM;

+

+    if ((rc=init_mutex(mutex, name, type)) != PJ_SUCCESS)

+	return rc;

+    

+    *ptr_mutex = mutex;

+    return PJ_SUCCESS;

+#else /* PJ_HAS_THREADS */

+    return (pj_mutex_t*)1;

+#endif

+}

+

+/*

+ * pj_mutex_create_simple()

+ */

+PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, 

+                                            const char *name,

+					    pj_mutex_t **mutex )

+{

+    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);

+}

+

+/*

+ * pj_mutex_create_recursive()

+ */

+PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,

+					       const char *name,

+					       pj_mutex_t **mutex )

+{

+    return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);

+}

+

+/*

+ * pj_mutex_lock()

+ */

+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)

+{

+#if PJ_HAS_THREADS

+    pj_status_t status;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", 

+				pj_thread_this()->obj_name));

+

+    status = pthread_mutex_lock( &mutex->mutex );

+

+    PJ_LOG(6,(mutex->obj_name, 

+	      (status==0 ? "Mutex acquired by thread %s" : "FAILED by %s"),

+	      pj_thread_this()->obj_name));

+

+#if PJ_DEBUG

+    if (status == PJ_SUCCESS) {

+	mutex->owner = pj_thread_this();

+	++mutex->nesting_level;

+    }

+#endif

+

+    if (status == 0)

+	return PJ_SUCCESS;

+    else

+	return PJ_RETURN_OS_ERROR(status);

+#else	/* PJ_HAS_THREADS */

+    pj_assert( mutex == (pj_mutex_t*)1 );

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_mutex_unlock()

+ */

+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)

+{

+#if PJ_HAS_THREADS

+    pj_status_t status;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+#if PJ_DEBUG

+    pj_assert(mutex->owner == pj_thread_this());

+    if (--mutex->nesting_level == 0) {

+	mutex->owner = NULL;

+    }

+#endif

+

+    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", 

+				pj_thread_this()->obj_name));

+

+    status = pthread_mutex_unlock( &mutex->mutex );

+    if (status == 0)

+	return PJ_SUCCESS;

+    else

+	return PJ_RETURN_OS_ERROR(status);

+

+#else /* PJ_HAS_THREADS */

+    pj_assert( mutex == (pj_mutex_t*)1 );

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_mutex_trylock()

+ */

+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)

+{

+#if PJ_HAS_THREADS

+    int status;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+    status = pthread_mutex_trylock( &mutex->mutex );

+

+    if (status==0) {

+	PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", 

+				  pj_thread_this()->obj_name));

+

+#if PJ_DEBUG

+	mutex->owner = pj_thread_this();

+	++mutex->nesting_level;

+#endif

+    }

+    

+    if (status==0)

+	return PJ_SUCCESS;

+    else

+	return PJ_RETURN_OS_ERROR(status);

+#else	/* PJ_HAS_THREADS */

+    pj_assert( mutex == (pj_mutex_t*)1);

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_mutex_destroy()

+ */

+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)

+{

+    int status;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+#if PJ_HAS_THREADS

+    PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));

+    status = pthread_mutex_destroy( &mutex->mutex );

+    if (status == 0)

+	return PJ_SUCCESS;

+    else

+	return PJ_RETURN_OS_ERROR(status);

+#else

+    pj_assert( mutex == (pj_mutex_t*)1 );

+    status = PJ_SUCCESS;

+    return status;

+#endif

+}

+

+#if PJ_DEBUG

+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)

+{

+#if PJ_HAS_THREADS

+    return mutex->owner == pj_thread_this();

+#else

+    return 1;

+#endif

+}

+#endif

+

+///////////////////////////////////////////////////////////////////////////////

+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

+

+/*

+ * pj_sem_create()

+ */

+PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 

+				   const char *name,

+				   unsigned initial, 

+				   unsigned max,

+				   pj_sem_t **ptr_sem)

+{

+#if PJ_HAS_THREADS

+    pj_sem_t *sem;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(pool != NULL && ptr_sem != NULL, PJ_EINVAL);

+

+    sem = pj_pool_alloc(pool, sizeof(*sem));    

+    if (!sem) return PJ_ENOMEM;

+

+    if (sem_init( &sem->sem, 0, initial) != 0) 

+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

+    

+    /* Set name. */

+    if (!name) {

+	name = "sem%p";

+    }

+    if (strchr(name, '%')) {

+	pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);

+    } else {

+	strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);

+	sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

+    }

+

+    PJ_LOG(6, (sem->obj_name, "Semaphore created"));

+

+    *ptr_sem = sem;

+    return PJ_SUCCESS;

+#else

+    *ptr_sem = (pj_sem_t*)1;

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_sem_wait()

+ */

+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)

+{

+#if PJ_HAS_THREADS

+    int result;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

+

+    PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", 

+			      pj_thread_this()->obj_name));

+

+    result = sem_wait( &sem->sem );

+    

+    if (result == 0) {

+	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 

+				  pj_thread_this()->obj_name));

+    } else {

+	PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", 

+				  pj_thread_this()->obj_name));

+    }

+

+    if (result == 0)

+	return PJ_SUCCESS;

+    else

+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

+#else

+    pj_assert( sem == (pj_sem_t*) 1 );

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_sem_trywait()

+ */

+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)

+{

+#if PJ_HAS_THREADS

+    int result;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

+

+    result = sem_trywait( &sem->sem );

+    

+    if (result == 0) {

+	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 

+				  pj_thread_this()->obj_name));

+    } 

+    if (result == 0)

+	return PJ_SUCCESS;

+    else

+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

+#else

+    pj_assert( sem == (pj_sem_t*)1 );

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_sem_post()

+ */

+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)

+{

+#if PJ_HAS_THREADS

+    int result;

+    PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",

+			      pj_thread_this()->obj_name));

+    result = sem_post( &sem->sem );

+

+    if (result == 0)

+	return PJ_SUCCESS;

+    else

+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

+#else

+    pj_assert( sem == (pj_sem_t*) 1);

+    return PJ_SUCCESS;

+#endif

+}

+

+/*

+ * pj_sem_destroy()

+ */

+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)

+{

+#if PJ_HAS_THREADS

+    int result;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

+

+    PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",

+			      pj_thread_this()->obj_name));

+    result = sem_destroy( &sem->sem );

+

+    if (result == 0)

+	return PJ_SUCCESS;

+    else

+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

+#else

+    pj_assert( sem == (pj_sem_t*) 1 );

+    return PJ_SUCCESS;

+#endif

+}

+

+#endif	/* PJ_HAS_SEMAPHORE */

+

+///////////////////////////////////////////////////////////////////////////////

+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0

+

+/*

+ * pj_event_create()

+ */

+PJ_DEF(pj_status_t) pj_event_create(pj_pool_t *pool, const char *name,

+				    pj_bool_t manual_reset, pj_bool_t initial,

+				    pj_event_t **ptr_event)

+{

+    pj_assert(!"Not supported!");

+    PJ_UNUSED_ARG(pool);

+    PJ_UNUSED_ARG(name);

+    PJ_UNUSED_ARG(manual_reset);

+    PJ_UNUSED_ARG(initial);

+    PJ_UNUSED_ARG(ptr_event);

+    return PJ_EINVALIDOP;

+}

+

+/*

+ * pj_event_wait()

+ */

+PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)

+{

+    PJ_UNUSED_ARG(event);

+    return PJ_EINVALIDOP;

+}

+

+/*

+ * pj_event_trywait()

+ */

+PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)

+{

+    PJ_UNUSED_ARG(event);

+    return PJ_EINVALIDOP;

+}

+

+/*

+ * pj_event_set()

+ */

+PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)

+{

+    PJ_UNUSED_ARG(event);

+    return PJ_EINVALIDOP;

+}

+

+/*

+ * pj_event_pulse()

+ */

+PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)

+{

+    PJ_UNUSED_ARG(event);

+    return PJ_EINVALIDOP;

+}

+

+/*

+ * pj_event_reset()

+ */

+PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)

+{

+    PJ_UNUSED_ARG(event);

+    return PJ_EINVALIDOP;

+}

+

+/*

+ * pj_event_destroy()

+ */

+PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)

+{

+    PJ_UNUSED_ARG(event);

+    return PJ_EINVALIDOP;

+}

+

+#endif	/* PJ_HAS_EVENT_OBJ */

+

+///////////////////////////////////////////////////////////////////////////////

+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

+/*

+ * Terminal

+ */

+

+/**

+ * Set terminal color.

+ */

+PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)

+{

+    PJ_UNUSED_ARG(color);

+    return PJ_EINVALIDOP;

+}

+

+/**

+ * Get current terminal foreground color.

+ */

+PJ_DEF(pj_color_t) pj_term_get_color(void)

+{

+    return 0;

+}

+

+#endif	/* PJ_TERM_HAS_COLOR */

+

diff --git a/pjlib/src/pj/os_core_win32.c b/pjlib/src/pj/os_core_win32.c
index be770d5..c4c4304 100644
--- a/pjlib/src/pj/os_core_win32.c
+++ b/pjlib/src/pj/os_core_win32.c
@@ -1,517 +1,538 @@
-/* $Id$
- */
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/rand.h>
-#include <pj/assert.h>
-#include <pj/compat/vsprintf.h>
-#include <pj/compat/sprintf.h>
-#include <pj/errno.h>
-#include <pj/except.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
-#  include <winsock.h>
-#endif
-
-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
-#  include <winsock2.h>
-#endif
-
-/*
- * Implementation of pj_thread_t.
- */
-struct pj_thread_t
-{
-    char	    obj_name[PJ_MAX_OBJ_NAME];
-    HANDLE	    hthread;
-    DWORD	    idthread;
-    pj_thread_proc *proc;
-    void	   *arg;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-    pj_uint32_t	    stk_size;
-    pj_uint32_t	    stk_max_usage;
-    char	   *stk_start;
-    const char	   *caller_file;
-    int		    caller_line;
-#endif
-};
-
-
-/*
- * Implementation of pj_mutex_t.
- */
-struct pj_mutex_t
-{
-#if PJ_WIN32_WINNT >= 0x0400
-    CRITICAL_SECTION	crit;
-#else
-    HANDLE		hMutex;
-#endif
-    char		obj_name[PJ_MAX_OBJ_NAME];
-#if PJ_DEBUG
-    int		        nesting_level;
-    pj_thread_t	       *owner;
-#endif
-};
-
-/*
- * Implementation of pj_sem_t.
- */
-typedef struct pj_sem_t
-{
-    HANDLE		hSemaphore;
-    char		obj_name[PJ_MAX_OBJ_NAME];
-} pj_mem_t;
-
-
-/*
- * Implementation of pj_event_t.
- */
-struct pj_event_t
-{
-    HANDLE		hEvent;
-    char		obj_name[PJ_MAX_OBJ_NAME];
-};
-
-/*
- * Implementation of pj_atomic_t.
- */
-struct pj_atomic_t
-{
-    long value;
-};
-
-/*
- * Static global variables.
- */
-static pj_thread_desc main_thread;
-static long thread_tls_id;
-static pj_mutex_t critical_section_mutex;
-
-
-/*
- * Some static prototypes.
- */
-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);
-
-
-/*
- * pj_init(void).
- * Init PJLIB!
- */
-PJ_DEF(pj_status_t) pj_init(void)
-{
-    WSADATA wsa;
-    char dummy_guid[32]; /* use maximum GUID length */
-    pj_str_t guid;
-    pj_status_t rc;
-
-    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));
-
-    /* Init Winsock.. */
-    if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
-	PJ_LOG(1, ("pj_init", "Winsock initialization has returned an error"));
-	return PJ_RETURN_OS_ERROR(WSAGetLastError());
-    }
-
-    /* Init this thread's TLS. */
-    if ((rc=pj_thread_init()) != PJ_SUCCESS) {
-	PJ_LOG(1, ("pj_init", "Thread initialization has returned an error"));
-	return rc;
-    }
-    
-    /* Init random seed. */
-    pj_srand( GetCurrentProcessId() );
-
-    /* Startup GUID. */
-    guid.ptr = dummy_guid;
-    pj_generate_unique_string( &guid );
-
-    /* Initialize critical section. */
-    if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS)
-	return rc;
-
-    /* Initialize exception ID for the pool. 
-     * Must do so after critical section is configured.
-     */
-    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);
-    if (rc != PJ_SUCCESS)
-        return rc;
-
-    /* Startup timestamp */
-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
-    {
-	pj_timestamp dummy_ts;
-	if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {
-	    PJ_LOG(1, ("pj_init", "Unable to initialize timestamp"));
-	    return rc;
-	}
-    }
-#endif   
-
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_getpid(void)
- */
-PJ_DEF(pj_uint32_t) pj_getpid(void)
-{
-    PJ_CHECK_STACK();
-    return GetCurrentProcessId();
-}
-
-/*
- * pj_thread_register(..)
- */
-PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,
-					 pj_thread_desc desc,
-                                         pj_thread_t **thread_ptr)
-{
-    char stack_ptr;
-    pj_status_t rc;
-    pj_thread_t *thread = (pj_thread_t *)desc;
-    pj_str_t thread_name = pj_str((char*)cstr_thread_name);
-
-    /* Size sanity check. */
-    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {
-	pj_assert(!"Not enough pj_thread_desc size!");
-	return PJ_EBUG;
-    }
-
-    /* If a thread descriptor has been registered before, just return it. */
-    if (pj_thread_local_get (thread_tls_id) != 0) {
-	*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);
-        return PJ_SUCCESS;
-    }
-
-    /* Initialize and set the thread entry. */
-    pj_memset(desc, 0, sizeof(struct pj_thread_t));
-    thread->hthread = GetCurrentThread();
-    thread->idthread = GetCurrentThreadId();
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-    thread->stk_start = &stack_ptr;
-    thread->stk_size = 0xFFFFFFFFUL;
-    thread->stk_max_usage = 0;
-#else
-    stack_ptr = '\0';
-#endif
-
-    if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)
-	pj_sprintf(thread->obj_name, cstr_thread_name, thread->idthread);
-    else
-	pj_sprintf(thread->obj_name, "thr%p", (void*)thread->idthread);
-    
-    rc = pj_thread_local_set(thread_tls_id, thread);
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    *thread_ptr = thread;
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_thread_init(void)
- */
-pj_status_t pj_thread_init(void)
-{
-    pj_status_t rc;
-    pj_thread_t *thread;
-
-    rc = pj_thread_local_alloc(&thread_tls_id);
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    return pj_thread_register("thr%p", main_thread, &thread);
-}
-
-static DWORD WINAPI thread_main(void *param)
-{
-    pj_thread_t *rec = param;
-    DWORD result;
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-    rec->stk_start = (char*)&rec;
-#endif
-
-    PJ_LOG(6,(rec->obj_name, "Thread started"));
-
-    if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) {
-	pj_assert(!"TLS is not set (pj_init() error?)");
-    }
-
-    result = (*rec->proc)(rec->arg);
-
-    PJ_LOG(6,(rec->obj_name, "Thread quitting"));
-    return (DWORD)result;
-}
-
-/*
- * pj_thread_create(...)
- */
-PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, 
-                                      const char *thread_name,
-				      pj_thread_proc *proc, 
-                                      void *arg,
-				      pj_size_t stack_size, 
-				      unsigned flags,
-                                      pj_thread_t **thread_ptr)
-{
-    DWORD dwflags = 0;
-    pj_thread_t *rec;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL);
-
-    /* Set flags */
-    if (flags & PJ_THREAD_SUSPENDED)
-	dwflags |= CREATE_SUSPENDED;
-
-    /* Create thread record and assign name for the thread */
-    rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t));
-    if (!rec)
-	return PJ_ENOMEM;
-
-    /* Set name. */
-    if (!thread_name)
-	thread_name = "thr%p";
-
-    if (strchr(thread_name, '%')) {
-	pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);
-    } else {
-	strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);
-	rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
-    }
-
-    PJ_LOG(6, (rec->obj_name, "Thread created"));
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
-    rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;
-    rec->stk_max_usage = 0;
-#endif
-
-    /* Create the thread. */
-    rec->proc = proc;
-    rec->arg = arg;
-    rec->hthread = CreateThread(NULL, stack_size, 
-				thread_main, rec,
-				dwflags, &rec->idthread);
-    if (rec->hthread == NULL)
-	return PJ_RETURN_OS_ERROR(GetLastError());
-
-    /* Success! */
-    *thread_ptr = rec;
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_thread-get_name()
- */
-PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)
-{
-    pj_thread_t *rec = (pj_thread_t*)p;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(p, "");
-
-    return rec->obj_name;
-}
-
-/*
- * pj_thread_resume()
- */
-PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)
-{
-    pj_thread_t *rec = (pj_thread_t*)p;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(p, PJ_EINVAL);
-
-    if (ResumeThread(rec->hthread) == (DWORD)-1)
-        return PJ_RETURN_OS_ERROR(GetLastError());
-    else
-        return PJ_SUCCESS;
-}
-
-/*
- * pj_thread_this()
- */
-PJ_DEF(pj_thread_t*) pj_thread_this(void)
-{
-    pj_thread_t *rec = pj_thread_local_get(thread_tls_id);
-    pj_assert(rec != NULL);
-
-    /*
-     * MUST NOT check stack because this function is called
-     * by PJ_CHECK_STACK() itself!!!
-     *
-     */
-
-    return rec;
-}
-
-/*
- * pj_thread_join()
- */
-PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)
-{
-    pj_thread_t *rec = (pj_thread_t *)p;
-    DWORD rc;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(p, PJ_EINVAL);
-
-    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));
-
-    rc = WaitForSingleObject(rec->hthread, INFINITE);
-
-    if (rc==WAIT_OBJECT_0)
-        return PJ_SUCCESS;
-    else if (rc==WAIT_TIMEOUT)
-        return PJ_ETIMEDOUT;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_thread_destroy()
- */
-PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)
-{
-    pj_thread_t *rec = (pj_thread_t *)p;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(p, PJ_EINVAL);
-
-    if (CloseHandle(rec->hthread) == TRUE)
-        return PJ_SUCCESS;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_thread_sleep()
- */
-PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)
-{
-    PJ_CHECK_STACK();
-    Sleep(msec);
-    return PJ_SUCCESS;
-}
-
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
-/*
- * pj_thread_check_stack()
- * Implementation for PJ_CHECK_STACK()
- */
-PJ_DEF(void) pj_thread_check_stack(const char *file, int line)
-{
-    char stk_ptr;
-    pj_uint32_t usage;
-    pj_thread_t *thread = pj_thread_this();
-
-    pj_assert(thread);
-
-    /* Calculate current usage. */
-    usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :
-		thread->stk_start - &stk_ptr;
-
-    /* Assert if stack usage is dangerously high. */
-    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));
-
-    /* Keep statistic. */
-    if (usage > thread->stk_max_usage) {
-	thread->stk_max_usage = usage;
-	thread->caller_file = file;
-	thread->caller_line = line;
-    }
-
-}
-
-/*
- * pj_thread_get_stack_max_usage()
- */
-PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)
-{
-    return thread->stk_max_usage;
-}
-
-/*
- * pj_thread_get_stack_info()
- */
-PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,
-					      const char **file,
-					      int *line )
-{
-    pj_assert(thread);
-
-    *file = thread->caller_file;
-    *line = thread->caller_line;
-    return 0;
-}
-
-#endif	/* PJ_OS_HAS_CHECK_STACK */
-
-
-///////////////////////////////////////////////////////////////////////////////
-
-/*
- * pj_atomic_create()
- */
-PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 
-                                      pj_atomic_value_t initial,
-                                      pj_atomic_t **atomic_ptr)
-{
-    pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t));
-    if (!atomic_var)
-	return PJ_ENOMEM;
-
-    atomic_var->value = initial;
-    *atomic_ptr = atomic_var;
-
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_atomic_destroy()
- */
-PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )
-{
-    PJ_UNUSED_ARG(var);
-    PJ_ASSERT_RETURN(var, PJ_EINVAL);
-
-    return 0;
-}
-
-/*
- * pj_atomic_set()
- */
-PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value)
-{
-    PJ_CHECK_STACK();
-
-    InterlockedExchange(&atomic_var->value, value);
-}
-
-/*
- * pj_atomic_get()
- */
-PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(atomic_var, 0);
-
-    return atomic_var->value;
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/os.h>

+#include <pj/pool.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/guid.h>

+#include <pj/rand.h>

+#include <pj/assert.h>

+#include <pj/compat/vsprintf.h>

+#include <pj/compat/sprintf.h>

+#include <pj/errno.h>

+#include <pj/except.h>

+#include <stddef.h>

+#include <stdlib.h>

+#include <stdio.h>

+

+#if defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0

+#  include <winsock.h>

+#endif

+

+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0

+#  include <winsock2.h>

+#endif

+

+/*

+ * Implementation of pj_thread_t.

+ */

+struct pj_thread_t

+{

+    char	    obj_name[PJ_MAX_OBJ_NAME];

+    HANDLE	    hthread;

+    DWORD	    idthread;

+    pj_thread_proc *proc;

+    void	   *arg;

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+    pj_uint32_t	    stk_size;

+    pj_uint32_t	    stk_max_usage;

+    char	   *stk_start;

+    const char	   *caller_file;

+    int		    caller_line;

+#endif

+};

+

+

+/*

+ * Implementation of pj_mutex_t.

+ */

+struct pj_mutex_t

+{

+#if PJ_WIN32_WINNT >= 0x0400

+    CRITICAL_SECTION	crit;

+#else

+    HANDLE		hMutex;

+#endif

+    char		obj_name[PJ_MAX_OBJ_NAME];

+#if PJ_DEBUG

+    int		        nesting_level;

+    pj_thread_t	       *owner;

+#endif

+};

+

+/*

+ * Implementation of pj_sem_t.

+ */

+typedef struct pj_sem_t

+{

+    HANDLE		hSemaphore;

+    char		obj_name[PJ_MAX_OBJ_NAME];

+} pj_mem_t;

+

+

+/*

+ * Implementation of pj_event_t.

+ */

+struct pj_event_t

+{

+    HANDLE		hEvent;

+    char		obj_name[PJ_MAX_OBJ_NAME];

+};

+

+/*

+ * Implementation of pj_atomic_t.

+ */

+struct pj_atomic_t

+{

+    long value;

+};

+

+/*

+ * Static global variables.

+ */

+static pj_thread_desc main_thread;

+static long thread_tls_id;

+static pj_mutex_t critical_section_mutex;

+

+

+/*

+ * Some static prototypes.

+ */

+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name);

+

+

+/*

+ * pj_init(void).

+ * Init PJLIB!

+ */

+PJ_DEF(pj_status_t) pj_init(void)

+{

+    WSADATA wsa;

+    char dummy_guid[32]; /* use maximum GUID length */

+    pj_str_t guid;

+    pj_status_t rc;

+

+    PJ_LOG(5, ("pj_init", "Initializing PJ Library.."));

+

+    /* Init Winsock.. */

+    if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {

+	PJ_LOG(1, ("pj_init", "Winsock initialization has returned an error"));

+	return PJ_RETURN_OS_ERROR(WSAGetLastError());

+    }

+

+    /* Init this thread's TLS. */

+    if ((rc=pj_thread_init()) != PJ_SUCCESS) {

+	PJ_LOG(1, ("pj_init", "Thread initialization has returned an error"));

+	return rc;

+    }

+    

+    /* Init random seed. */

+    pj_srand( GetCurrentProcessId() );

+

+    /* Startup GUID. */

+    guid.ptr = dummy_guid;

+    pj_generate_unique_string( &guid );

+

+    /* Initialize critical section. */

+    if ((rc=init_mutex(&critical_section_mutex, "pj%p")) != PJ_SUCCESS)

+	return rc;

+

+    /* Initialize exception ID for the pool. 

+     * Must do so after critical section is configured.

+     */

+    rc = pj_exception_id_alloc("PJLIB/No memory", &PJ_NO_MEMORY_EXCEPTION);

+    if (rc != PJ_SUCCESS)

+        return rc;

+

+    /* Startup timestamp */

+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

+    {

+	pj_timestamp dummy_ts;

+	if ((rc=pj_get_timestamp(&dummy_ts)) != PJ_SUCCESS) {

+	    PJ_LOG(1, ("pj_init", "Unable to initialize timestamp"));

+	    return rc;

+	}

+    }

+#endif   

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_getpid(void)

+ */

+PJ_DEF(pj_uint32_t) pj_getpid(void)

+{

+    PJ_CHECK_STACK();

+    return GetCurrentProcessId();

+}

+

+/*

+ * pj_thread_register(..)

+ */

+PJ_DEF(pj_status_t) pj_thread_register ( const char *cstr_thread_name,

+					 pj_thread_desc desc,

+                                         pj_thread_t **thread_ptr)

+{

+    char stack_ptr;

+    pj_status_t rc;

+    pj_thread_t *thread = (pj_thread_t *)desc;

+    pj_str_t thread_name = pj_str((char*)cstr_thread_name);

+

+    /* Size sanity check. */

+    if (sizeof(pj_thread_desc) < sizeof(pj_thread_t)) {

+	pj_assert(!"Not enough pj_thread_desc size!");

+	return PJ_EBUG;

+    }

+

+    /* If a thread descriptor has been registered before, just return it. */

+    if (pj_thread_local_get (thread_tls_id) != 0) {

+	*thread_ptr = (pj_thread_t*)pj_thread_local_get (thread_tls_id);

+        return PJ_SUCCESS;

+    }

+

+    /* Initialize and set the thread entry. */

+    pj_memset(desc, 0, sizeof(struct pj_thread_t));

+    thread->hthread = GetCurrentThread();

+    thread->idthread = GetCurrentThreadId();

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+    thread->stk_start = &stack_ptr;

+    thread->stk_size = 0xFFFFFFFFUL;

+    thread->stk_max_usage = 0;

+#else

+    stack_ptr = '\0';

+#endif

+

+    if (cstr_thread_name && pj_strlen(&thread_name) < sizeof(thread->obj_name)-1)

+	pj_sprintf(thread->obj_name, cstr_thread_name, thread->idthread);

+    else

+	pj_sprintf(thread->obj_name, "thr%p", (void*)thread->idthread);

+    

+    rc = pj_thread_local_set(thread_tls_id, thread);

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    *thread_ptr = thread;

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_thread_init(void)

+ */

+pj_status_t pj_thread_init(void)

+{

+    pj_status_t rc;

+    pj_thread_t *thread;

+

+    rc = pj_thread_local_alloc(&thread_tls_id);

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    return pj_thread_register("thr%p", main_thread, &thread);

+}

+

+static DWORD WINAPI thread_main(void *param)

+{

+    pj_thread_t *rec = param;

+    DWORD result;

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+    rec->stk_start = (char*)&rec;

+#endif

+

+    PJ_LOG(6,(rec->obj_name, "Thread started"));

+

+    if (pj_thread_local_set(thread_tls_id, rec) != PJ_SUCCESS) {

+	pj_assert(!"TLS is not set (pj_init() error?)");

+    }

+

+    result = (*rec->proc)(rec->arg);

+

+    PJ_LOG(6,(rec->obj_name, "Thread quitting"));

+    return (DWORD)result;

+}

+

+/*

+ * pj_thread_create(...)

+ */

+PJ_DEF(pj_status_t) pj_thread_create( pj_pool_t *pool, 

+                                      const char *thread_name,

+				      pj_thread_proc *proc, 

+                                      void *arg,

+				      pj_size_t stack_size, 

+				      unsigned flags,

+                                      pj_thread_t **thread_ptr)

+{

+    DWORD dwflags = 0;

+    pj_thread_t *rec;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(pool && proc && thread_ptr, PJ_EINVAL);

+

+    /* Set flags */

+    if (flags & PJ_THREAD_SUSPENDED)

+	dwflags |= CREATE_SUSPENDED;

+

+    /* Create thread record and assign name for the thread */

+    rec = (struct pj_thread_t*) pj_pool_calloc(pool, 1, sizeof(pj_thread_t));

+    if (!rec)

+	return PJ_ENOMEM;

+

+    /* Set name. */

+    if (!thread_name)

+	thread_name = "thr%p";

+

+    if (strchr(thread_name, '%')) {

+	pj_snprintf(rec->obj_name, PJ_MAX_OBJ_NAME, thread_name, rec);

+    } else {

+	strncpy(rec->obj_name, thread_name, PJ_MAX_OBJ_NAME);

+	rec->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

+    }

+

+    PJ_LOG(6, (rec->obj_name, "Thread created"));

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0

+    rec->stk_size = stack_size ? stack_size : 0xFFFFFFFFUL;

+    rec->stk_max_usage = 0;

+#endif

+

+    /* Create the thread. */

+    rec->proc = proc;

+    rec->arg = arg;

+    rec->hthread = CreateThread(NULL, stack_size, 

+				thread_main, rec,

+				dwflags, &rec->idthread);

+    if (rec->hthread == NULL)

+	return PJ_RETURN_OS_ERROR(GetLastError());

+

+    /* Success! */

+    *thread_ptr = rec;

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_thread-get_name()

+ */

+PJ_DEF(const char*) pj_thread_get_name(pj_thread_t *p)

+{

+    pj_thread_t *rec = (pj_thread_t*)p;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(p, "");

+

+    return rec->obj_name;

+}

+

+/*

+ * pj_thread_resume()

+ */

+PJ_DEF(pj_status_t) pj_thread_resume(pj_thread_t *p)

+{

+    pj_thread_t *rec = (pj_thread_t*)p;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(p, PJ_EINVAL);

+

+    if (ResumeThread(rec->hthread) == (DWORD)-1)

+        return PJ_RETURN_OS_ERROR(GetLastError());

+    else

+        return PJ_SUCCESS;

+}

+

+/*

+ * pj_thread_this()

+ */

+PJ_DEF(pj_thread_t*) pj_thread_this(void)

+{

+    pj_thread_t *rec = pj_thread_local_get(thread_tls_id);

+    pj_assert(rec != NULL);

+

+    /*

+     * MUST NOT check stack because this function is called

+     * by PJ_CHECK_STACK() itself!!!

+     *

+     */

+

+    return rec;

+}

+

+/*

+ * pj_thread_join()

+ */

+PJ_DEF(pj_status_t) pj_thread_join(pj_thread_t *p)

+{

+    pj_thread_t *rec = (pj_thread_t *)p;

+    DWORD rc;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(p, PJ_EINVAL);

+

+    PJ_LOG(6, (pj_thread_this()->obj_name, "Joining thread %s", p->obj_name));

+

+    rc = WaitForSingleObject(rec->hthread, INFINITE);

+

+    if (rc==WAIT_OBJECT_0)

+        return PJ_SUCCESS;

+    else if (rc==WAIT_TIMEOUT)

+        return PJ_ETIMEDOUT;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_thread_destroy()

+ */

+PJ_DEF(pj_status_t) pj_thread_destroy(pj_thread_t *p)

+{

+    pj_thread_t *rec = (pj_thread_t *)p;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(p, PJ_EINVAL);

+

+    if (CloseHandle(rec->hthread) == TRUE)

+        return PJ_SUCCESS;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_thread_sleep()

+ */

+PJ_DEF(pj_status_t) pj_thread_sleep(unsigned msec)

+{

+    PJ_CHECK_STACK();

+    Sleep(msec);

+    return PJ_SUCCESS;

+}

+

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0

+/*

+ * pj_thread_check_stack()

+ * Implementation for PJ_CHECK_STACK()

+ */

+PJ_DEF(void) pj_thread_check_stack(const char *file, int line)

+{

+    char stk_ptr;

+    pj_uint32_t usage;

+    pj_thread_t *thread = pj_thread_this();

+

+    pj_assert(thread);

+

+    /* Calculate current usage. */

+    usage = (&stk_ptr > thread->stk_start) ? &stk_ptr - thread->stk_start :

+		thread->stk_start - &stk_ptr;

+

+    /* Assert if stack usage is dangerously high. */

+    pj_assert("STACK OVERFLOW!! " && (usage <= thread->stk_size - 128));

+

+    /* Keep statistic. */

+    if (usage > thread->stk_max_usage) {

+	thread->stk_max_usage = usage;

+	thread->caller_file = file;

+	thread->caller_line = line;

+    }

+

+}

+

+/*

+ * pj_thread_get_stack_max_usage()

+ */

+PJ_DEF(pj_uint32_t) pj_thread_get_stack_max_usage(pj_thread_t *thread)

+{

+    return thread->stk_max_usage;

+}

+

+/*

+ * pj_thread_get_stack_info()

+ */

+PJ_DEF(pj_status_t) pj_thread_get_stack_info( pj_thread_t *thread,

+					      const char **file,

+					      int *line )

+{

+    pj_assert(thread);

+

+    *file = thread->caller_file;

+    *line = thread->caller_line;

+    return 0;

+}

+

+#endif	/* PJ_OS_HAS_CHECK_STACK */

+

+

+///////////////////////////////////////////////////////////////////////////////

+

+/*

+ * pj_atomic_create()

+ */

+PJ_DEF(pj_status_t) pj_atomic_create( pj_pool_t *pool, 

+                                      pj_atomic_value_t initial,

+                                      pj_atomic_t **atomic_ptr)

+{

+    pj_atomic_t *atomic_var = pj_pool_alloc(pool, sizeof(pj_atomic_t));

+    if (!atomic_var)

+	return PJ_ENOMEM;

+

+    atomic_var->value = initial;

+    *atomic_ptr = atomic_var;

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_atomic_destroy()

+ */

+PJ_DEF(pj_status_t) pj_atomic_destroy( pj_atomic_t *var )

+{

+    PJ_UNUSED_ARG(var);

+    PJ_ASSERT_RETURN(var, PJ_EINVAL);

+

+    return 0;

+}

+

+/*

+ * pj_atomic_set()

+ */

+PJ_DEF(void) pj_atomic_set( pj_atomic_t *atomic_var, pj_atomic_value_t value)

+{

+    PJ_CHECK_STACK();

+

+    InterlockedExchange(&atomic_var->value, value);

+}

+

+/*

+ * pj_atomic_get()

+ */

+PJ_DEF(pj_atomic_value_t) pj_atomic_get(pj_atomic_t *atomic_var)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(atomic_var, 0);

+

+    return atomic_var->value;

+}

+

 /*

  * pj_atomic_inc_and_get()

  */

@@ -526,13 +547,13 @@
 #endif

 }

 

-/*
- * pj_atomic_inc()
- */
-PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)
+/*

+ * pj_atomic_inc()

+ */

+PJ_DEF(void) pj_atomic_inc(pj_atomic_t *atomic_var)

 {

-    pj_atomic_inc_and_get(atomic_var);
-}
+    pj_atomic_inc_and_get(atomic_var);

+}

 

 /*

  * pj_atomic_dec_and_get()

@@ -548,26 +569,26 @@
 #endif

 }

 

-/*
- * pj_atomic_dec()
- */
-PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)
-{
-    pj_atomic_dec_and_get(atomic_var);
-}
-
-/*
- * pj_atomic_add()
- */
-PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,
-			    pj_atomic_value_t value )
-{
+/*

+ * pj_atomic_dec()

+ */

+PJ_DEF(void) pj_atomic_dec(pj_atomic_t *atomic_var)

+{

+    pj_atomic_dec_and_get(atomic_var);

+}

+

+/*

+ * pj_atomic_add()

+ */

+PJ_DEF(void) pj_atomic_add( pj_atomic_t *atomic_var,

+			    pj_atomic_value_t value )

+{

 #if defined(PJ_WIN32_WINNT) && PJ_WIN32_WINNT >= 0x0400

     InterlockedExchangeAdd( &atomic_var->value, value );

 #else

 #   error Fix me

-#endif
-}
+#endif

+}

 

 /*

  * pj_atomic_add_and_get()

@@ -581,635 +602,635 @@
 #else

 #   error Fix me

 #endif

-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * pj_thread_local_alloc()
- */
-PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)
-{
-    PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL);
-
-    //Can't check stack because this function is called in the
-    //beginning before main thread is initialized.
-    //PJ_CHECK_STACK();
-
-    *index = TlsAlloc();
-
-    if (*index == TLS_OUT_OF_INDEXES)
-        return PJ_RETURN_OS_ERROR(GetLastError());
-    else
-        return PJ_SUCCESS;
-}
-
-/*
- * pj_thread_local_free()
- */
-PJ_DEF(void) pj_thread_local_free(long index)
-{
-    PJ_CHECK_STACK();
-    TlsFree(index);
-}
-
-/*
- * pj_thread_local_set()
- */
-PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)
-{
-    BOOL rc;
-
-    //Can't check stack because this function is called in the
-    //beginning before main thread is initialized.
-    //PJ_CHECK_STACK();
-    rc = TlsSetValue(index, value);
-    return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_thread_local_get()
- */
-PJ_DEF(void*) pj_thread_local_get(long index)
-{
-    //Can't check stack because this function is called
-    //by PJ_CHECK_STACK() itself!!!
-    //PJ_CHECK_STACK();
-    return TlsGetValue(index);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name)
-{
-
-    PJ_CHECK_STACK();
-
-#if PJ_WIN32_WINNT >= 0x0400
-    InitializeCriticalSection(&mutex->crit);
-#else
-    mutex->hMutex = CreateMutex(NULL, FALSE, NULL);
-    if (!mutex->hMutex) {
-	return PJ_RETURN_OS_ERROR(GetLastError());
-    }
-#endif
-
-#if PJ_DEBUG
-    /* Set owner. */
-    mutex->nesting_level = 0;
-    mutex->owner = NULL;
-#endif
-
-    /* Set name. */
-    if (!name) {
-	name = "mtx%p";
-    }
-    if (strchr(name, '%')) {
-	pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);
-    } else {
-	strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);
-	mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
-    }
-
-    PJ_LOG(6, (mutex->obj_name, "Mutex created"));
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_mutex_create()
- */
-PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 
-                                    const char *name, 
-                                    int type,
-                                    pj_mutex_t **mutex_ptr)
-{
-    pj_status_t rc;
-    pj_mutex_t *mutex;
-
-    PJ_UNUSED_ARG(type);
-    PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL);
-
-    mutex = pj_pool_alloc(pool, sizeof(*mutex));
-    if (!mutex)
-        return PJ_ENOMEM;
-
-    rc = init_mutex(mutex, name);
-    if (rc != PJ_SUCCESS)
-        return rc;
-
-    *mutex_ptr = mutex;
-
-    return PJ_SUCCESS;
-}
-
-/*
- * pj_mutex_create_simple()
- */
-PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, 
-                                            const char *name,
-					    pj_mutex_t **mutex )
-{
-    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);
-}
-
-/*
- * pj_mutex_create_recursive()
- */
-PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,
-					       const char *name,
-					       pj_mutex_t **mutex )
-{
-    return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);
-}
-
-/*
- * pj_mutex_lock()
- */
-PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)
-{
-    pj_status_t status;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", 
-				pj_thread_this()->obj_name));
-
-#if PJ_WIN32_WINNT >= 0x0400
-    EnterCriticalSection(&mutex->crit);
-    status=PJ_SUCCESS;
-#else
-    if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0)
-        status = PJ_SUCCESS;
-    else
-        status = PJ_STATUS_FROM_OS(GetLastError());
-
-#endif
-    PJ_LOG(6,(mutex->obj_name, 
-	      (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"),
-	      pj_thread_this()->obj_name));
-
-#if PJ_DEBUG
-    if (status == PJ_SUCCESS) {
-	mutex->owner = pj_thread_this();
-	++mutex->nesting_level;
-    }
-#endif
-
-    return status;
-}
-
-/*
- * pj_mutex_unlock()
- */
-PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)
-{
-    pj_status_t status;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-#if PJ_DEBUG
-    pj_assert(mutex->owner == pj_thread_this());
-    if (--mutex->nesting_level == 0) {
-	mutex->owner = NULL;
-    }
-#endif
-
-    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", 
-				pj_thread_this()->obj_name));
-
-#if PJ_WIN32_WINNT >= 0x0400
-    LeaveCriticalSection(&mutex->crit);
-    status=PJ_SUCCESS;
-#else
-    status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS : 
-                PJ_STATUS_FROM_OS(GetLastError());
-#endif
-    return status;
-}
-
-/*
- * pj_mutex_trylock()
- */
-PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)
-{
-    pj_status_t status;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-#if PJ_WIN32_WINNT >= 0x0400
-    status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN;
-#else
-    status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ? 
-                PJ_SUCCESS : PJ_ETIMEDOUT;
-#endif
-    if (status==PJ_SUCCESS) {
-	PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", 
-				  pj_thread_this()->obj_name));
-
-#if PJ_DEBUG
-	mutex->owner = pj_thread_this();
-	++mutex->nesting_level;
-#endif
-    }
-    return status;
-}
-
-/*
- * pj_mutex_destroy()
- */
-PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);
-
-    PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));
-
-#if PJ_WIN32_WINNT >= 0x0400
-    DeleteCriticalSection(&mutex->crit);
-    return PJ_SUCCESS;
-#else
-    return CloseHandle(mutex->hMutex) ? PJ_SUCCESS : 
-            PJ_RETURN_OS_ERROR(GetLastError());
-#endif
-}
-
-#if PJ_DEBUG
-/*
- * pj_mutex_is_locked()
- */
-PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)
-{
-    return mutex->owner == pj_thread_this();
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * pj_enter_critical_section()
- */
-PJ_DEF(void) pj_enter_critical_section(void)
-{
-    pj_mutex_lock(&critical_section_mutex);
-}
-
-
-/*
- * pj_leave_critical_section()
- */
-PJ_DEF(void) pj_leave_critical_section(void)
-{
-    pj_mutex_unlock(&critical_section_mutex);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-
-/*
- * pj_sem_create()
- */
-PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 
-                                   const char *name,
-				   unsigned initial, 
-                                   unsigned max,
-                                   pj_sem_t **sem_ptr)
-{
-    pj_sem_t *sem;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL);
-
-    sem = pj_pool_alloc(pool, sizeof(*sem));    
-    sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL);
-    if (!sem->hSemaphore)
-	return PJ_RETURN_OS_ERROR(GetLastError());
-
-    /* Set name. */
-    if (!name) {
-	name = "sem%p";
-    }
-    if (strchr(name, '%')) {
-	pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);
-    } else {
-	strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);
-	sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
-    }
-
-    PJ_LOG(6, (sem->obj_name, "Semaphore created"));
-
-    *sem_ptr = sem;
-    return PJ_SUCCESS;
-}
-
-static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout)
-{
-    DWORD result;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
-    PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", 
-			      pj_thread_this()->obj_name));
-
-    result = WaitForSingleObject(sem->hSemaphore, timeout);
-    if (result == WAIT_OBJECT_0) {
-	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 
-				  pj_thread_this()->obj_name));
-    } else {
-	PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", 
-				  pj_thread_this()->obj_name));
-    }
-
-    if (result==WAIT_OBJECT_0)
-        return PJ_SUCCESS;
-    else if (result==WAIT_TIMEOUT)
-        return PJ_ETIMEDOUT;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_sem_wait()
- */
-PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
-    return pj_sem_wait_for(sem, INFINITE);
-}
-
-/*
- * pj_sem_trywait()
- */
-PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
-    return pj_sem_wait_for(sem, 0);
-}
-
-/*
- * pj_sem_post()
- */
-PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
-    PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",
-			      pj_thread_this()->obj_name));
-
-    if (ReleaseSemaphore(sem->hSemaphore, 1, NULL))
-        return PJ_SUCCESS;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_sem_destroy()
- */
-PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(sem, PJ_EINVAL);
-
-    PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",
-			      pj_thread_this()->obj_name));
-
-    if (CloseHandle(sem->hSemaphore))
-        return PJ_SUCCESS;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-#endif	/* PJ_HAS_SEMAPHORE */
-///////////////////////////////////////////////////////////////////////////////
-
-
-#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0
-
-/*
- * pj_event_create()
- */
-PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool, 
-                                     const char *name,
-				     pj_bool_t manual_reset, 
-                                     pj_bool_t initial,
-                                     pj_event_t **event_ptr)
-{
-    pj_event_t *event;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL);
-
-    event = pj_pool_alloc(pool, sizeof(*event));
-    if (!event)
-        return PJ_ENOMEM;
-
-    event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE, 
-				initial?TRUE:FALSE, NULL);
-
-    if (!event->hEvent)
-	return PJ_RETURN_OS_ERROR(GetLastError());
-
-    /* Set name. */
-    if (!name) {
-	name = "evt%p";
-    }
-    if (strchr(name, '%')) {
-	pj_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event);
-    } else {
-	strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME);
-	event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
-    }
-
-    PJ_LOG(6, (event->obj_name, "Event created"));
-
-    *event_ptr = event;
-    return PJ_SUCCESS;
-}
-
-static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout)
-{
-    DWORD result;
-
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
-    PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting", 
-			        pj_thread_this()->obj_name));
-
-    result = WaitForSingleObject(event->hEvent, timeout);
-    if (result == WAIT_OBJECT_0) {
-	PJ_LOG(6, (event->obj_name, "Event: thread %s is released", 
-				    pj_thread_this()->obj_name));
-    } else {
-	PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire", 
-				    pj_thread_this()->obj_name));
-    }
-
-    if (result==WAIT_OBJECT_0)
-        return PJ_SUCCESS;
-    else if (result==WAIT_TIMEOUT)
-        return PJ_ETIMEDOUT;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_event_wait()
- */
-PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)
-{
-    PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
-    return pj_event_wait_for(event, INFINITE);
-}
-
-/*
- * pj_event_trywait()
- */
-PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)
-{
-    PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
-    return pj_event_wait_for(event, 0);
-}
-
-/*
- * pj_event_set()
- */
-PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
-    PJ_LOG(6, (event->obj_name, "Setting event"));
-
-    if (SetEvent(event->hEvent))
-        return PJ_SUCCESS;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_event_pulse()
- */
-PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
-    PJ_LOG(6, (event->obj_name, "Pulsing event"));
-
-    if (PulseEvent(event->hEvent))
-        return PJ_SUCCESS;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_event_reset()
- */
-PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
-    PJ_LOG(6, (event->obj_name, "Event is reset"));
-
-    if (ResetEvent(event->hEvent))
-        return PJ_SUCCESS;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_event_destroy()
- */
-PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(event, PJ_EINVAL);
-
-    PJ_LOG(6, (event->obj_name, "Event is destroying"));
-
-    if (CloseHandle(event->hEvent))
-        return PJ_SUCCESS;
-    else
-        return PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-#endif	/* PJ_HAS_EVENT_OBJ */
-
-///////////////////////////////////////////////////////////////////////////////
-#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0
-/*
- * Terminal color
- */
-
-static WORD pj_color_to_os_attr(pj_color_t color)
-{
-    WORD attr = 0;
-
-    if (color & PJ_TERM_COLOR_R)
-	attr |= FOREGROUND_RED;
-    if (color & PJ_TERM_COLOR_G)
-	attr |= FOREGROUND_GREEN;
-    if (color & PJ_TERM_COLOR_B)
-	attr |= FOREGROUND_BLUE;
-    if (color & PJ_TERM_COLOR_BRIGHT)
-	attr |= FOREGROUND_INTENSITY;
-
-    return attr;
-}
-
-static pj_color_t os_attr_to_pj_color(WORD attr)
-{
-    int color = 0;
-
-    if (attr & FOREGROUND_RED)
-	color |= PJ_TERM_COLOR_R;
-    if (attr & FOREGROUND_GREEN)
-	color |= PJ_TERM_COLOR_G;
-    if (attr & FOREGROUND_BLUE)
-	color |= PJ_TERM_COLOR_B;
-    if (attr & FOREGROUND_INTENSITY)
-	color |= PJ_TERM_COLOR_BRIGHT;
-
-    return color;
-}
-
-
-/*
- * pj_term_set_color()
- */
-PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)
-{
-    BOOL rc;
-    WORD attr = 0;
-
-    PJ_CHECK_STACK();
-
-    attr = pj_color_to_os_attr(color);
-    rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr);
-    return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());
-}
-
-/*
- * pj_term_get_color()
- * Get current terminal foreground color.
- */
-PJ_DEF(pj_color_t) pj_term_get_color(void)
-{
-    CONSOLE_SCREEN_BUFFER_INFO info;
-
-    PJ_CHECK_STACK();
-
-    GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info);
-    return os_attr_to_pj_color(info.wAttributes);
-}
-
-#endif	/* PJ_TERM_HAS_COLOR */
+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * pj_thread_local_alloc()

+ */

+PJ_DEF(pj_status_t) pj_thread_local_alloc(long *index)

+{

+    PJ_ASSERT_RETURN(index != NULL, PJ_EINVAL);

+

+    //Can't check stack because this function is called in the

+    //beginning before main thread is initialized.

+    //PJ_CHECK_STACK();

+

+    *index = TlsAlloc();

+

+    if (*index == TLS_OUT_OF_INDEXES)

+        return PJ_RETURN_OS_ERROR(GetLastError());

+    else

+        return PJ_SUCCESS;

+}

+

+/*

+ * pj_thread_local_free()

+ */

+PJ_DEF(void) pj_thread_local_free(long index)

+{

+    PJ_CHECK_STACK();

+    TlsFree(index);

+}

+

+/*

+ * pj_thread_local_set()

+ */

+PJ_DEF(pj_status_t) pj_thread_local_set(long index, void *value)

+{

+    BOOL rc;

+

+    //Can't check stack because this function is called in the

+    //beginning before main thread is initialized.

+    //PJ_CHECK_STACK();

+    rc = TlsSetValue(index, value);

+    return rc!=0 ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_thread_local_get()

+ */

+PJ_DEF(void*) pj_thread_local_get(long index)

+{

+    //Can't check stack because this function is called

+    //by PJ_CHECK_STACK() itself!!!

+    //PJ_CHECK_STACK();

+    return TlsGetValue(index);

+}

+

+///////////////////////////////////////////////////////////////////////////////

+static pj_status_t init_mutex(pj_mutex_t *mutex, const char *name)

+{

+

+    PJ_CHECK_STACK();

+

+#if PJ_WIN32_WINNT >= 0x0400

+    InitializeCriticalSection(&mutex->crit);

+#else

+    mutex->hMutex = CreateMutex(NULL, FALSE, NULL);

+    if (!mutex->hMutex) {

+	return PJ_RETURN_OS_ERROR(GetLastError());

+    }

+#endif

+

+#if PJ_DEBUG

+    /* Set owner. */

+    mutex->nesting_level = 0;

+    mutex->owner = NULL;

+#endif

+

+    /* Set name. */

+    if (!name) {

+	name = "mtx%p";

+    }

+    if (strchr(name, '%')) {

+	pj_snprintf(mutex->obj_name, PJ_MAX_OBJ_NAME, name, mutex);

+    } else {

+	strncpy(mutex->obj_name, name, PJ_MAX_OBJ_NAME);

+	mutex->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

+    }

+

+    PJ_LOG(6, (mutex->obj_name, "Mutex created"));

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_mutex_create()

+ */

+PJ_DEF(pj_status_t) pj_mutex_create(pj_pool_t *pool, 

+                                    const char *name, 

+                                    int type,

+                                    pj_mutex_t **mutex_ptr)

+{

+    pj_status_t rc;

+    pj_mutex_t *mutex;

+

+    PJ_UNUSED_ARG(type);

+    PJ_ASSERT_RETURN(pool && mutex_ptr, PJ_EINVAL);

+

+    mutex = pj_pool_alloc(pool, sizeof(*mutex));

+    if (!mutex)

+        return PJ_ENOMEM;

+

+    rc = init_mutex(mutex, name);

+    if (rc != PJ_SUCCESS)

+        return rc;

+

+    *mutex_ptr = mutex;

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * pj_mutex_create_simple()

+ */

+PJ_DEF(pj_status_t) pj_mutex_create_simple( pj_pool_t *pool, 

+                                            const char *name,

+					    pj_mutex_t **mutex )

+{

+    return pj_mutex_create(pool, name, PJ_MUTEX_SIMPLE, mutex);

+}

+

+/*

+ * pj_mutex_create_recursive()

+ */

+PJ_DEF(pj_status_t) pj_mutex_create_recursive( pj_pool_t *pool,

+					       const char *name,

+					       pj_mutex_t **mutex )

+{

+    return pj_mutex_create(pool, name, PJ_MUTEX_RECURSE, mutex);

+}

+

+/*

+ * pj_mutex_lock()

+ */

+PJ_DEF(pj_status_t) pj_mutex_lock(pj_mutex_t *mutex)

+{

+    pj_status_t status;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+    PJ_LOG(6,(mutex->obj_name, "Mutex: thread %s is waiting", 

+				pj_thread_this()->obj_name));

+

+#if PJ_WIN32_WINNT >= 0x0400

+    EnterCriticalSection(&mutex->crit);

+    status=PJ_SUCCESS;

+#else

+    if (WaitForSingleObject(mutex->hMutex, INFINITE)==WAIT_OBJECT_0)

+        status = PJ_SUCCESS;

+    else

+        status = PJ_STATUS_FROM_OS(GetLastError());

+

+#endif

+    PJ_LOG(6,(mutex->obj_name, 

+	      (status==PJ_SUCCESS ? "Mutex acquired by thread %s" : "FAILED by %s"),

+	      pj_thread_this()->obj_name));

+

+#if PJ_DEBUG

+    if (status == PJ_SUCCESS) {

+	mutex->owner = pj_thread_this();

+	++mutex->nesting_level;

+    }

+#endif

+

+    return status;

+}

+

+/*

+ * pj_mutex_unlock()

+ */

+PJ_DEF(pj_status_t) pj_mutex_unlock(pj_mutex_t *mutex)

+{

+    pj_status_t status;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+#if PJ_DEBUG

+    pj_assert(mutex->owner == pj_thread_this());

+    if (--mutex->nesting_level == 0) {

+	mutex->owner = NULL;

+    }

+#endif

+

+    PJ_LOG(6,(mutex->obj_name, "Mutex released by thread %s", 

+				pj_thread_this()->obj_name));

+

+#if PJ_WIN32_WINNT >= 0x0400

+    LeaveCriticalSection(&mutex->crit);

+    status=PJ_SUCCESS;

+#else

+    status = ReleaseMutex(mutex->hMutex) ? PJ_SUCCESS : 

+                PJ_STATUS_FROM_OS(GetLastError());

+#endif

+    return status;

+}

+

+/*

+ * pj_mutex_trylock()

+ */

+PJ_DEF(pj_status_t) pj_mutex_trylock(pj_mutex_t *mutex)

+{

+    pj_status_t status;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+#if PJ_WIN32_WINNT >= 0x0400

+    status=TryEnterCriticalSection(&mutex->crit) ? PJ_SUCCESS : PJ_EUNKNOWN;

+#else

+    status = WaitForSingleObject(mutex->hMutex, 0)==WAIT_OBJECT_0 ? 

+                PJ_SUCCESS : PJ_ETIMEDOUT;

+#endif

+    if (status==PJ_SUCCESS) {

+	PJ_LOG(6,(mutex->obj_name, "Mutex acquired by thread %s", 

+				  pj_thread_this()->obj_name));

+

+#if PJ_DEBUG

+	mutex->owner = pj_thread_this();

+	++mutex->nesting_level;

+#endif

+    }

+    return status;

+}

+

+/*

+ * pj_mutex_destroy()

+ */

+PJ_DEF(pj_status_t) pj_mutex_destroy(pj_mutex_t *mutex)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(mutex, PJ_EINVAL);

+

+    PJ_LOG(6,(mutex->obj_name, "Mutex destroyed"));

+

+#if PJ_WIN32_WINNT >= 0x0400

+    DeleteCriticalSection(&mutex->crit);

+    return PJ_SUCCESS;

+#else

+    return CloseHandle(mutex->hMutex) ? PJ_SUCCESS : 

+            PJ_RETURN_OS_ERROR(GetLastError());

+#endif

+}

+

+#if PJ_DEBUG

+/*

+ * pj_mutex_is_locked()

+ */

+PJ_DEF(pj_bool_t) pj_mutex_is_locked(pj_mutex_t *mutex)

+{

+    return mutex->owner == pj_thread_this();

+}

+#endif

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * pj_enter_critical_section()

+ */

+PJ_DEF(void) pj_enter_critical_section(void)

+{

+    pj_mutex_lock(&critical_section_mutex);

+}

+

+

+/*

+ * pj_leave_critical_section()

+ */

+PJ_DEF(void) pj_leave_critical_section(void)

+{

+    pj_mutex_unlock(&critical_section_mutex);

+}

+

+///////////////////////////////////////////////////////////////////////////////

+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

+

+/*

+ * pj_sem_create()

+ */

+PJ_DEF(pj_status_t) pj_sem_create( pj_pool_t *pool, 

+                                   const char *name,

+				   unsigned initial, 

+                                   unsigned max,

+                                   pj_sem_t **sem_ptr)

+{

+    pj_sem_t *sem;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(pool && sem_ptr, PJ_EINVAL);

+

+    sem = pj_pool_alloc(pool, sizeof(*sem));    

+    sem->hSemaphore = CreateSemaphore(NULL, initial, max, NULL);

+    if (!sem->hSemaphore)

+	return PJ_RETURN_OS_ERROR(GetLastError());

+

+    /* Set name. */

+    if (!name) {

+	name = "sem%p";

+    }

+    if (strchr(name, '%')) {

+	pj_snprintf(sem->obj_name, PJ_MAX_OBJ_NAME, name, sem);

+    } else {

+	strncpy(sem->obj_name, name, PJ_MAX_OBJ_NAME);

+	sem->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

+    }

+

+    PJ_LOG(6, (sem->obj_name, "Semaphore created"));

+

+    *sem_ptr = sem;

+    return PJ_SUCCESS;

+}

+

+static pj_status_t pj_sem_wait_for(pj_sem_t *sem, unsigned timeout)

+{

+    DWORD result;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

+

+    PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s is waiting", 

+			      pj_thread_this()->obj_name));

+

+    result = WaitForSingleObject(sem->hSemaphore, timeout);

+    if (result == WAIT_OBJECT_0) {

+	PJ_LOG(6, (sem->obj_name, "Semaphore acquired by thread %s", 

+				  pj_thread_this()->obj_name));

+    } else {

+	PJ_LOG(6, (sem->obj_name, "Semaphore: thread %s FAILED to acquire", 

+				  pj_thread_this()->obj_name));

+    }

+

+    if (result==WAIT_OBJECT_0)

+        return PJ_SUCCESS;

+    else if (result==WAIT_TIMEOUT)

+        return PJ_ETIMEDOUT;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_sem_wait()

+ */

+PJ_DEF(pj_status_t) pj_sem_wait(pj_sem_t *sem)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

+

+    return pj_sem_wait_for(sem, INFINITE);

+}

+

+/*

+ * pj_sem_trywait()

+ */

+PJ_DEF(pj_status_t) pj_sem_trywait(pj_sem_t *sem)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

+

+    return pj_sem_wait_for(sem, 0);

+}

+

+/*

+ * pj_sem_post()

+ */

+PJ_DEF(pj_status_t) pj_sem_post(pj_sem_t *sem)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

+

+    PJ_LOG(6, (sem->obj_name, "Semaphore released by thread %s",

+			      pj_thread_this()->obj_name));

+

+    if (ReleaseSemaphore(sem->hSemaphore, 1, NULL))

+        return PJ_SUCCESS;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_sem_destroy()

+ */

+PJ_DEF(pj_status_t) pj_sem_destroy(pj_sem_t *sem)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(sem, PJ_EINVAL);

+

+    PJ_LOG(6, (sem->obj_name, "Semaphore destroyed by thread %s",

+			      pj_thread_this()->obj_name));

+

+    if (CloseHandle(sem->hSemaphore))

+        return PJ_SUCCESS;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+#endif	/* PJ_HAS_SEMAPHORE */

+///////////////////////////////////////////////////////////////////////////////

+

+

+#if defined(PJ_HAS_EVENT_OBJ) && PJ_HAS_EVENT_OBJ != 0

+

+/*

+ * pj_event_create()

+ */

+PJ_DEF(pj_status_t) pj_event_create( pj_pool_t *pool, 

+                                     const char *name,

+				     pj_bool_t manual_reset, 

+                                     pj_bool_t initial,

+                                     pj_event_t **event_ptr)

+{

+    pj_event_t *event;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(pool && event_ptr, PJ_EINVAL);

+

+    event = pj_pool_alloc(pool, sizeof(*event));

+    if (!event)

+        return PJ_ENOMEM;

+

+    event->hEvent = CreateEvent(NULL, manual_reset?TRUE:FALSE, 

+				initial?TRUE:FALSE, NULL);

+

+    if (!event->hEvent)

+	return PJ_RETURN_OS_ERROR(GetLastError());

+

+    /* Set name. */

+    if (!name) {

+	name = "evt%p";

+    }

+    if (strchr(name, '%')) {

+	pj_snprintf(event->obj_name, PJ_MAX_OBJ_NAME, name, event);

+    } else {

+	strncpy(event->obj_name, name, PJ_MAX_OBJ_NAME);

+	event->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';

+    }

+

+    PJ_LOG(6, (event->obj_name, "Event created"));

+

+    *event_ptr = event;

+    return PJ_SUCCESS;

+}

+

+static pj_status_t pj_event_wait_for(pj_event_t *event, unsigned timeout)

+{

+    DWORD result;

+

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(event, PJ_EINVAL);

+

+    PJ_LOG(6, (event->obj_name, "Event: thread %s is waiting", 

+			        pj_thread_this()->obj_name));

+

+    result = WaitForSingleObject(event->hEvent, timeout);

+    if (result == WAIT_OBJECT_0) {

+	PJ_LOG(6, (event->obj_name, "Event: thread %s is released", 

+				    pj_thread_this()->obj_name));

+    } else {

+	PJ_LOG(6, (event->obj_name, "Event: thread %s FAILED to acquire", 

+				    pj_thread_this()->obj_name));

+    }

+

+    if (result==WAIT_OBJECT_0)

+        return PJ_SUCCESS;

+    else if (result==WAIT_TIMEOUT)

+        return PJ_ETIMEDOUT;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_event_wait()

+ */

+PJ_DEF(pj_status_t) pj_event_wait(pj_event_t *event)

+{

+    PJ_ASSERT_RETURN(event, PJ_EINVAL);

+

+    return pj_event_wait_for(event, INFINITE);

+}

+

+/*

+ * pj_event_trywait()

+ */

+PJ_DEF(pj_status_t) pj_event_trywait(pj_event_t *event)

+{

+    PJ_ASSERT_RETURN(event, PJ_EINVAL);

+

+    return pj_event_wait_for(event, 0);

+}

+

+/*

+ * pj_event_set()

+ */

+PJ_DEF(pj_status_t) pj_event_set(pj_event_t *event)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(event, PJ_EINVAL);

+

+    PJ_LOG(6, (event->obj_name, "Setting event"));

+

+    if (SetEvent(event->hEvent))

+        return PJ_SUCCESS;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_event_pulse()

+ */

+PJ_DEF(pj_status_t) pj_event_pulse(pj_event_t *event)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(event, PJ_EINVAL);

+

+    PJ_LOG(6, (event->obj_name, "Pulsing event"));

+

+    if (PulseEvent(event->hEvent))

+        return PJ_SUCCESS;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_event_reset()

+ */

+PJ_DEF(pj_status_t) pj_event_reset(pj_event_t *event)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(event, PJ_EINVAL);

+

+    PJ_LOG(6, (event->obj_name, "Event is reset"));

+

+    if (ResetEvent(event->hEvent))

+        return PJ_SUCCESS;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_event_destroy()

+ */

+PJ_DEF(pj_status_t) pj_event_destroy(pj_event_t *event)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(event, PJ_EINVAL);

+

+    PJ_LOG(6, (event->obj_name, "Event is destroying"));

+

+    if (CloseHandle(event->hEvent))

+        return PJ_SUCCESS;

+    else

+        return PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+#endif	/* PJ_HAS_EVENT_OBJ */

+

+///////////////////////////////////////////////////////////////////////////////

+#if defined(PJ_TERM_HAS_COLOR) && PJ_TERM_HAS_COLOR != 0

+/*

+ * Terminal color

+ */

+

+static WORD pj_color_to_os_attr(pj_color_t color)

+{

+    WORD attr = 0;

+

+    if (color & PJ_TERM_COLOR_R)

+	attr |= FOREGROUND_RED;

+    if (color & PJ_TERM_COLOR_G)

+	attr |= FOREGROUND_GREEN;

+    if (color & PJ_TERM_COLOR_B)

+	attr |= FOREGROUND_BLUE;

+    if (color & PJ_TERM_COLOR_BRIGHT)

+	attr |= FOREGROUND_INTENSITY;

+

+    return attr;

+}

+

+static pj_color_t os_attr_to_pj_color(WORD attr)

+{

+    int color = 0;

+

+    if (attr & FOREGROUND_RED)

+	color |= PJ_TERM_COLOR_R;

+    if (attr & FOREGROUND_GREEN)

+	color |= PJ_TERM_COLOR_G;

+    if (attr & FOREGROUND_BLUE)

+	color |= PJ_TERM_COLOR_B;

+    if (attr & FOREGROUND_INTENSITY)

+	color |= PJ_TERM_COLOR_BRIGHT;

+

+    return color;

+}

+

+

+/*

+ * pj_term_set_color()

+ */

+PJ_DEF(pj_status_t) pj_term_set_color(pj_color_t color)

+{

+    BOOL rc;

+    WORD attr = 0;

+

+    PJ_CHECK_STACK();

+

+    attr = pj_color_to_os_attr(color);

+    rc = SetConsoleTextAttribute( GetStdHandle(STD_OUTPUT_HANDLE), attr);

+    return rc ? PJ_SUCCESS : PJ_RETURN_OS_ERROR(GetLastError());

+}

+

+/*

+ * pj_term_get_color()

+ * Get current terminal foreground color.

+ */

+PJ_DEF(pj_color_t) pj_term_get_color(void)

+{

+    CONSOLE_SCREEN_BUFFER_INFO info;

+

+    PJ_CHECK_STACK();

+

+    GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &info);

+    return os_attr_to_pj_color(info.wAttributes);

+}

+

+#endif	/* PJ_TERM_HAS_COLOR */

diff --git a/pjlib/src/pj/os_error_linux_kernel.c b/pjlib/src/pj/os_error_linux_kernel.c
index cd5dfe7..a6ecb1a 100644
--- a/pjlib/src/pj/os_error_linux_kernel.c
+++ b/pjlib/src/pj/os_error_linux_kernel.c
@@ -1,65 +1,86 @@
-/* $Id$
- *
- */
-#include <pj/string.h>
-#include <pj/compat/errno.h>
-#include <linux/config.h>
-#include <linux/version.h>
-#if defined(MODVERSIONS)
-#include <linux/modversions.h>
-#endif
-#include <linux/kernel.h>
-#include <linux/errno.h>
-
-int kernel_errno;
-
-PJ_DEF(pj_status_t) pj_get_os_error(void)
-{
-    return errno;
-}
-
-PJ_DEF(void) pj_set_os_error(pj_status_t code)
-{
-    errno = code;
-}
-
-PJ_DEF(pj_status_t) pj_get_netos_error(void)
-{
-    return errno;
-}
-
-PJ_DEF(void) pj_set_netos_error(pj_status_t code)
-{
-    errno = code;
-}
-
-/* 
- * platform_strerror()
- *
- * Platform specific error message. This file is called by pj_strerror() 
- * in errno.c 
- */
-int platform_strerror( pj_os_err_type os_errcode, 
-                       char *buf, pj_size_t bufsize)
-{
-    char errmsg[32];
-    int len;
-    
-    /* Handle EINVAL as special case so that it'll pass errno test. */
-    if (os_errcode==EINVAL)
-	strcpy(errmsg, "Invalid value");
-    else
-	sprintf(errmsg, "errno=%d", os_errcode);
-    
-    len = strlen(errmsg);
-
-    if (len >= bufsize)
-	len = bufsize-1;
-
-    pj_memcpy(buf, errmsg, len);
-    buf[len] = '\0';
-
-    return len;
-}
-
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/string.h>

+#include <pj/compat/errno.h>

+#include <linux/config.h>

+#include <linux/version.h>

+#if defined(MODVERSIONS)

+#include <linux/modversions.h>

+#endif

+#include <linux/kernel.h>

+#include <linux/errno.h>

+

+int kernel_errno;

+

+PJ_DEF(pj_status_t) pj_get_os_error(void)

+{

+    return errno;

+}

+

+PJ_DEF(void) pj_set_os_error(pj_status_t code)

+{

+    errno = code;

+}

+

+PJ_DEF(pj_status_t) pj_get_netos_error(void)

+{

+    return errno;

+}

+

+PJ_DEF(void) pj_set_netos_error(pj_status_t code)

+{

+    errno = code;

+}

+

+/* 

+ * platform_strerror()

+ *

+ * Platform specific error message. This file is called by pj_strerror() 

+ * in errno.c 

+ */

+int platform_strerror( pj_os_err_type os_errcode, 

+                       char *buf, pj_size_t bufsize)

+{

+    char errmsg[32];

+    int len;

+    

+    /* Handle EINVAL as special case so that it'll pass errno test. */

+    if (os_errcode==EINVAL)

+	strcpy(errmsg, "Invalid value");

+    else

+	sprintf(errmsg, "errno=%d", os_errcode);

+    

+    len = strlen(errmsg);

+

+    if (len >= bufsize)

+	len = bufsize-1;

+

+    pj_memcpy(buf, errmsg, len);

+    buf[len] = '\0';

+

+    return len;

+}

+

+

diff --git a/pjlib/src/pj/os_error_unix.c b/pjlib/src/pj/os_error_unix.c
index acb1f80..fa902b6 100644
--- a/pjlib/src/pj/os_error_unix.c
+++ b/pjlib/src/pj/os_error_unix.c
@@ -1,54 +1,75 @@
-/* $Id$
- *
- */
-/* 
- * $Log: /pjproject-0.3/pjlib/src/pj/os_error_unix.c $
- * 
- * 1     10/14/05 12:19a Bennylp
- * Created.
- *
- */
-#include <pj/errno.h>
-#include <pj/string.h>
-#include <errno.h>
-
-PJ_DEF(pj_status_t) pj_get_os_error(void)
-{
-    return PJ_STATUS_FROM_OS(errno);
-}
-
-PJ_DEF(void) pj_set_os_error(pj_status_t code)
-{
-    errno = PJ_STATUS_TO_OS(code);
-}
-
-PJ_DEF(pj_status_t) pj_get_netos_error(void)
-{
-    return PJ_STATUS_FROM_OS(errno);
-}
-
-PJ_DEF(void) pj_set_netos_error(pj_status_t code)
-{
-    errno = PJ_STATUS_TO_OS(code);
-}
-
-/* 
- * platform_strerror()
- *
- * Platform specific error message. This file is called by pj_strerror() 
- * in errno.c 
- */
-int platform_strerror( pj_os_err_type os_errcode, 
-                       char *buf, pj_size_t bufsize)
-{
-    const char *syserr = strerror(os_errcode);
-    pj_size_t len = syserr ? strlen(syserr) : 0;
-
-    if (len >= bufsize) len = bufsize - 1;
-    if (len > 0)
-	pj_memcpy(buf, syserr, len);
-    buf[len] = '\0';
-    return len;
-}
-
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* 

+ * $Log: /pjproject-0.3/pjlib/src/pj/os_error_unix.c $

+ * 

+ * 1     10/14/05 12:19a Bennylp

+ * Created.

+ *

+ */

+#include <pj/errno.h>

+#include <pj/string.h>

+#include <errno.h>

+

+PJ_DEF(pj_status_t) pj_get_os_error(void)

+{

+    return PJ_STATUS_FROM_OS(errno);

+}

+

+PJ_DEF(void) pj_set_os_error(pj_status_t code)

+{

+    errno = PJ_STATUS_TO_OS(code);

+}

+

+PJ_DEF(pj_status_t) pj_get_netos_error(void)

+{

+    return PJ_STATUS_FROM_OS(errno);

+}

+

+PJ_DEF(void) pj_set_netos_error(pj_status_t code)

+{

+    errno = PJ_STATUS_TO_OS(code);

+}

+

+/* 

+ * platform_strerror()

+ *

+ * Platform specific error message. This file is called by pj_strerror() 

+ * in errno.c 

+ */

+int platform_strerror( pj_os_err_type os_errcode, 

+                       char *buf, pj_size_t bufsize)

+{

+    const char *syserr = strerror(os_errcode);

+    pj_size_t len = syserr ? strlen(syserr) : 0;

+

+    if (len >= bufsize) len = bufsize - 1;

+    if (len > 0)

+	pj_memcpy(buf, syserr, len);

+    buf[len] = '\0';

+    return len;

+}

+

+

diff --git a/pjlib/src/pj/os_error_win32.c b/pjlib/src/pj/os_error_win32.c
index 23da7cf..8274467 100644
--- a/pjlib/src/pj/os_error_win32.c
+++ b/pjlib/src/pj/os_error_win32.c
@@ -1,149 +1,170 @@
-/* $Id$
- */
-#include <pj/errno.h>
-#include <pj/assert.h>
-#include <pj/compat/stdarg.h>
-#include <pj/compat/sprintf.h>
-#include <pj/compat/vsprintf.h>
-#include <pj/string.h>
-
-
-#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0
-#  include <winsock2.h>
-#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0
-#  include <winsock.h>
-#endif
-
-
-/*
- * From Apache's APR:
- */
-static const struct {
-    pj_os_err_type code;
-    const char *msg;
-} gaErrorList[] = {
-    {WSAEINTR,           "Interrupted system call"},
-    {WSAEBADF,           "Bad file number"},
-    {WSAEACCES,          "Permission denied"},
-    {WSAEFAULT,          "Bad address"},
-    {WSAEINVAL,          "Invalid argument"},
-    {WSAEMFILE,          "Too many open sockets"},
-    {WSAEWOULDBLOCK,     "Operation would block"},
-    {WSAEINPROGRESS,     "Operation now in progress"},
-    {WSAEALREADY,        "Operation already in progress"},
-    {WSAENOTSOCK,        "Socket operation on non-socket"},
-    {WSAEDESTADDRREQ,    "Destination address required"},
-    {WSAEMSGSIZE,        "Message too long"},
-    {WSAEPROTOTYPE,      "Protocol wrong type for socket"},
-    {WSAENOPROTOOPT,     "Bad protocol option"},
-    {WSAEPROTONOSUPPORT, "Protocol not supported"},
-    {WSAESOCKTNOSUPPORT, "Socket type not supported"},
-    {WSAEOPNOTSUPP,      "Operation not supported on socket"},
-    {WSAEPFNOSUPPORT,    "Protocol family not supported"},
-    {WSAEAFNOSUPPORT,    "Address family not supported"},
-    {WSAEADDRINUSE,      "Address already in use"},
-    {WSAEADDRNOTAVAIL,   "Can't assign requested address"},
-    {WSAENETDOWN,        "Network is down"},
-    {WSAENETUNREACH,     "Network is unreachable"},
-    {WSAENETRESET,       "Net connection reset"},
-    {WSAECONNABORTED,    "Software caused connection abort"},
-    {WSAECONNRESET,      "Connection reset by peer"},
-    {WSAENOBUFS,         "No buffer space available"},
-    {WSAEISCONN,         "Socket is already connected"},
-    {WSAENOTCONN,        "Socket is not connected"},
-    {WSAESHUTDOWN,       "Can't send after socket shutdown"},
-    {WSAETOOMANYREFS,    "Too many references, can't splice"},
-    {WSAETIMEDOUT,       "Connection timed out"},
-    {WSAECONNREFUSED,    "Connection refused"},
-    {WSAELOOP,           "Too many levels of symbolic links"},
-    {WSAENAMETOOLONG,    "File name too long"},
-    {WSAEHOSTDOWN,       "Host is down"},
-    {WSAEHOSTUNREACH,    "No route to host"},
-    {WSAENOTEMPTY,       "Directory not empty"},
-    {WSAEPROCLIM,        "Too many processes"},
-    {WSAEUSERS,          "Too many users"},
-    {WSAEDQUOT,          "Disc quota exceeded"},
-    {WSAESTALE,          "Stale NFS file handle"},
-    {WSAEREMOTE,         "Too many levels of remote in path"},
-    {WSASYSNOTREADY,     "Network system is unavailable"},
-    {WSAVERNOTSUPPORTED, "Winsock version out of range"},
-    {WSANOTINITIALISED,  "WSAStartup not yet called"},
-    {WSAEDISCON,         "Graceful shutdown in progress"},
-    {WSAHOST_NOT_FOUND,  "Host not found"},
-    {WSANO_DATA,         "No host data of that type was found"},
-    {0,                  NULL}
-};
-
-
-PJ_DEF(pj_status_t) pj_get_os_error(void)
-{
-    return PJ_STATUS_FROM_OS(GetLastError());
-}
-
-PJ_DEF(void) pj_set_os_error(pj_status_t code)
-{
-    SetLastError(PJ_STATUS_TO_OS(code));
-}
-
-PJ_DEF(pj_status_t) pj_get_netos_error(void)
-{
-    return PJ_STATUS_FROM_OS(WSAGetLastError());
-}
-
-PJ_DEF(void) pj_set_netos_error(pj_status_t code)
-{
-    WSASetLastError(PJ_STATUS_TO_OS(code));
-}
-
-/* 
- * platform_strerror()
- *
- * Platform specific error message. This file is called by pj_strerror() 
- * in errno.c 
- */
-int platform_strerror( pj_os_err_type os_errcode, 
-                       char *buf, pj_size_t bufsize)
-{
-    int len;
-
-    pj_assert(buf != NULL);
-    pj_assert(bufsize >= 0);
-
-    /*
-     * MUST NOT check stack here.
-     * This function might be called from PJ_CHECK_STACK() itself!
-       //PJ_CHECK_STACK();
-     */
-
-    len = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM 
-			 | FORMAT_MESSAGE_IGNORE_INSERTS,
-			 NULL,
-			 os_errcode,
-			 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
-			 (LPTSTR)buf,
-			 (DWORD)bufsize,
-			 NULL);
-
-    if (!len) {
-	int i;
-        for (i = 0; gaErrorList[i].msg; ++i) {
-            if (gaErrorList[i].code == os_errcode) {
-                len = strlen(gaErrorList[i].msg);
-		if ((pj_size_t)len >= bufsize) {
-		    len = bufsize-1;
-		}
-		pj_memcpy(buf, gaErrorList[i].msg, len);
-		buf[len] = '\0';
-                break;
-            }
-        }
-    }
-
-    if (!len) {
-	len = snprintf( buf, bufsize, "Unknown native error %u", (unsigned)os_errcode);
-	buf[len] = '\0';
-    }
-
-    return len;
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/errno.h>

+#include <pj/assert.h>

+#include <pj/compat/stdarg.h>

+#include <pj/compat/sprintf.h>

+#include <pj/compat/vsprintf.h>

+#include <pj/string.h>

+

+

+#if defined(PJ_HAS_WINSOCK2_H) && PJ_HAS_WINSOCK2_H != 0

+#  include <winsock2.h>

+#elif defined(PJ_HAS_WINSOCK_H) && PJ_HAS_WINSOCK_H != 0

+#  include <winsock.h>

+#endif

+

+

+/*

+ * From Apache's APR:

+ */

+static const struct {

+    pj_os_err_type code;

+    const char *msg;

+} gaErrorList[] = {

+    {WSAEINTR,           "Interrupted system call"},

+    {WSAEBADF,           "Bad file number"},

+    {WSAEACCES,          "Permission denied"},

+    {WSAEFAULT,          "Bad address"},

+    {WSAEINVAL,          "Invalid argument"},

+    {WSAEMFILE,          "Too many open sockets"},

+    {WSAEWOULDBLOCK,     "Operation would block"},

+    {WSAEINPROGRESS,     "Operation now in progress"},

+    {WSAEALREADY,        "Operation already in progress"},

+    {WSAENOTSOCK,        "Socket operation on non-socket"},

+    {WSAEDESTADDRREQ,    "Destination address required"},

+    {WSAEMSGSIZE,        "Message too long"},

+    {WSAEPROTOTYPE,      "Protocol wrong type for socket"},

+    {WSAENOPROTOOPT,     "Bad protocol option"},

+    {WSAEPROTONOSUPPORT, "Protocol not supported"},

+    {WSAESOCKTNOSUPPORT, "Socket type not supported"},

+    {WSAEOPNOTSUPP,      "Operation not supported on socket"},

+    {WSAEPFNOSUPPORT,    "Protocol family not supported"},

+    {WSAEAFNOSUPPORT,    "Address family not supported"},

+    {WSAEADDRINUSE,      "Address already in use"},

+    {WSAEADDRNOTAVAIL,   "Can't assign requested address"},

+    {WSAENETDOWN,        "Network is down"},

+    {WSAENETUNREACH,     "Network is unreachable"},

+    {WSAENETRESET,       "Net connection reset"},

+    {WSAECONNABORTED,    "Software caused connection abort"},

+    {WSAECONNRESET,      "Connection reset by peer"},

+    {WSAENOBUFS,         "No buffer space available"},

+    {WSAEISCONN,         "Socket is already connected"},

+    {WSAENOTCONN,        "Socket is not connected"},

+    {WSAESHUTDOWN,       "Can't send after socket shutdown"},

+    {WSAETOOMANYREFS,    "Too many references, can't splice"},

+    {WSAETIMEDOUT,       "Connection timed out"},

+    {WSAECONNREFUSED,    "Connection refused"},

+    {WSAELOOP,           "Too many levels of symbolic links"},

+    {WSAENAMETOOLONG,    "File name too long"},

+    {WSAEHOSTDOWN,       "Host is down"},

+    {WSAEHOSTUNREACH,    "No route to host"},

+    {WSAENOTEMPTY,       "Directory not empty"},

+    {WSAEPROCLIM,        "Too many processes"},

+    {WSAEUSERS,          "Too many users"},

+    {WSAEDQUOT,          "Disc quota exceeded"},

+    {WSAESTALE,          "Stale NFS file handle"},

+    {WSAEREMOTE,         "Too many levels of remote in path"},

+    {WSASYSNOTREADY,     "Network system is unavailable"},

+    {WSAVERNOTSUPPORTED, "Winsock version out of range"},

+    {WSANOTINITIALISED,  "WSAStartup not yet called"},

+    {WSAEDISCON,         "Graceful shutdown in progress"},

+    {WSAHOST_NOT_FOUND,  "Host not found"},

+    {WSANO_DATA,         "No host data of that type was found"},

+    {0,                  NULL}

+};

+

+

+PJ_DEF(pj_status_t) pj_get_os_error(void)

+{

+    return PJ_STATUS_FROM_OS(GetLastError());

+}

+

+PJ_DEF(void) pj_set_os_error(pj_status_t code)

+{

+    SetLastError(PJ_STATUS_TO_OS(code));

+}

+

+PJ_DEF(pj_status_t) pj_get_netos_error(void)

+{

+    return PJ_STATUS_FROM_OS(WSAGetLastError());

+}

+

+PJ_DEF(void) pj_set_netos_error(pj_status_t code)

+{

+    WSASetLastError(PJ_STATUS_TO_OS(code));

+}

+

+/* 

+ * platform_strerror()

+ *

+ * Platform specific error message. This file is called by pj_strerror() 

+ * in errno.c 

+ */

+int platform_strerror( pj_os_err_type os_errcode, 

+                       char *buf, pj_size_t bufsize)

+{

+    int len;

+

+    pj_assert(buf != NULL);

+    pj_assert(bufsize >= 0);

+

+    /*

+     * MUST NOT check stack here.

+     * This function might be called from PJ_CHECK_STACK() itself!

+       //PJ_CHECK_STACK();

+     */

+

+    len = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM 

+			 | FORMAT_MESSAGE_IGNORE_INSERTS,

+			 NULL,

+			 os_errcode,

+			 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 

+			 (LPTSTR)buf,

+			 (DWORD)bufsize,

+			 NULL);

+

+    if (!len) {

+	int i;

+        for (i = 0; gaErrorList[i].msg; ++i) {

+            if (gaErrorList[i].code == os_errcode) {

+                len = strlen(gaErrorList[i].msg);

+		if ((pj_size_t)len >= bufsize) {

+		    len = bufsize-1;

+		}

+		pj_memcpy(buf, gaErrorList[i].msg, len);

+		buf[len] = '\0';

+                break;

+            }

+        }

+    }

+

+    if (!len) {

+	len = snprintf( buf, bufsize, "Unknown native error %u", (unsigned)os_errcode);

+	buf[len] = '\0';

+    }

+

+    return len;

+}

+

diff --git a/pjlib/src/pj/os_time_ansi.c b/pjlib/src/pj/os_time_ansi.c
index 20fc7f6..f4fd486 100644
--- a/pjlib/src/pj/os_time_ansi.c
+++ b/pjlib/src/pj/os_time_ansi.c
@@ -1,56 +1,77 @@
-/* $Id$
- */
-#include <pj/os.h>
-#include <pj/compat/time.h>
-
-///////////////////////////////////////////////////////////////////////////////
-
-PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)
-{
-    struct timeb tb;
-
-    PJ_CHECK_STACK();
-
-    ftime(&tb);
-    tv->sec = tb.time;
-    tv->msec = tb.millitm;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
-{
-    struct tm *local_time;
-
-    PJ_CHECK_STACK();
-
-    local_time = localtime((time_t*)&tv->sec);
-
-    pt->year = local_time->tm_year+1900;
-    pt->mon = local_time->tm_mon;
-    pt->day = local_time->tm_mday;
-    pt->hour = local_time->tm_hour;
-    pt->min = local_time->tm_min;
-    pt->sec = local_time->tm_sec;
-    pt->wday = local_time->tm_wday;
-    pt->yday = local_time->tm_yday;
-    pt->msec = tv->msec;
-
-    return PJ_SUCCESS;
-}
-
-/**
- * Encode parsed time to time value.
- */
-PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
-
-/**
- * Convert local time to GMT.
- */
-PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
-
-/**
- * Convert GMT to local time.
- */
-PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/os.h>

+#include <pj/compat/time.h>

+

+///////////////////////////////////////////////////////////////////////////////

+

+PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)

+{

+    struct timeb tb;

+

+    PJ_CHECK_STACK();

+

+    ftime(&tb);

+    tv->sec = tb.time;

+    tv->msec = tb.millitm;

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)

+{

+    struct tm *local_time;

+

+    PJ_CHECK_STACK();

+

+    local_time = localtime((time_t*)&tv->sec);

+

+    pt->year = local_time->tm_year+1900;

+    pt->mon = local_time->tm_mon;

+    pt->day = local_time->tm_mday;

+    pt->hour = local_time->tm_hour;

+    pt->min = local_time->tm_min;

+    pt->sec = local_time->tm_sec;

+    pt->wday = local_time->tm_wday;

+    pt->yday = local_time->tm_yday;

+    pt->msec = tv->msec;

+

+    return PJ_SUCCESS;

+}

+

+/**

+ * Encode parsed time to time value.

+ */

+PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);

+

+/**

+ * Convert local time to GMT.

+ */

+PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);

+

+/**

+ * Convert GMT to local time.

+ */

+PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);

+

+

diff --git a/pjlib/src/pj/os_time_linux_kernel.c b/pjlib/src/pj/os_time_linux_kernel.c
index 03c0cc2..d9d5ed8 100644
--- a/pjlib/src/pj/os_time_linux_kernel.c
+++ b/pjlib/src/pj/os_time_linux_kernel.c
@@ -1,60 +1,81 @@
-/* $Id$
- *
- */
-/* $Log: /pjproject-0.3/pjlib/src/pj/os_time_linux_kernel.c $
- * 
- * 2     10/14/05 12:26a Bennylp
- * Finished error code framework, some fixes in ioqueue, etc. Pretty
- * major.
- * 
- * 1     9/22/05 10:39a Bennylp
- * Created.
- *
- */
-#include <pj/os.h>
-#include <linux/time.h>
-
-///////////////////////////////////////////////////////////////////////////////
-
-PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)
-{
-    struct timeval tval;
-  
-    do_gettimeofday(&tval);
-    tv->sec = tval.tv_sec;
-    tv->msec = tval.tv_usec / 1000;
-
-    return 0;
-}
-
-PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)
-{
-    pt->year = 2005;
-    pt->mon = 8;
-    pt->day = 20;
-    pt->hour = 16;
-    pt->min = 30;
-    pt->sec = 30;
-    pt->wday = 3;
-    pt->yday = 200;
-    pt->msec = 777;
-
-    return -1;
-}
-
-/**
- * Encode parsed time to time value.
- */
-PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);
-
-/**
- * Convert local time to GMT.
- */
-PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);
-
-/**
- * Convert GMT to local time.
- */
-PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);
-
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* $Log: /pjproject-0.3/pjlib/src/pj/os_time_linux_kernel.c $

+ * 

+ * 2     10/14/05 12:26a Bennylp

+ * Finished error code framework, some fixes in ioqueue, etc. Pretty

+ * major.

+ * 

+ * 1     9/22/05 10:39a Bennylp

+ * Created.

+ *

+ */

+#include <pj/os.h>

+#include <linux/time.h>

+

+///////////////////////////////////////////////////////////////////////////////

+

+PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *tv)

+{

+    struct timeval tval;

+  

+    do_gettimeofday(&tval);

+    tv->sec = tval.tv_sec;

+    tv->msec = tval.tv_usec / 1000;

+

+    return 0;

+}

+

+PJ_DEF(pj_status_t) pj_time_decode(const pj_time_val *tv, pj_parsed_time *pt)

+{

+    pt->year = 2005;

+    pt->mon = 8;

+    pt->day = 20;

+    pt->hour = 16;

+    pt->min = 30;

+    pt->sec = 30;

+    pt->wday = 3;

+    pt->yday = 200;

+    pt->msec = 777;

+

+    return -1;

+}

+

+/**

+ * Encode parsed time to time value.

+ */

+PJ_DEF(pj_status_t) pj_time_encode(const pj_parsed_time *pt, pj_time_val *tv);

+

+/**

+ * Convert local time to GMT.

+ */

+PJ_DEF(pj_status_t) pj_time_local_to_gmt(pj_time_val *tv);

+

+/**

+ * Convert GMT to local time.

+ */

+PJ_DEF(pj_status_t) pj_time_gmt_to_local(pj_time_val *tv);

+

+

diff --git a/pjlib/src/pj/os_timestamp_common.c b/pjlib/src/pj/os_timestamp_common.c
index f9824d5..ddba4cf 100644
--- a/pjlib/src/pj/os_timestamp_common.c
+++ b/pjlib/src/pj/os_timestamp_common.c
@@ -1,119 +1,140 @@
-/* $Id$
- */
-#include <pj/os.h>
-#include <pj/compat/high_precision.h>
-
-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
-
-#define U32MAX  (0xFFFFFFFFUL)
-#define NANOSEC (1000000000UL)
-#define USEC    (1000000UL)
-#define MSEC    (1000)
-
-static pj_highprec_t get_elapsed( const pj_timestamp *start,
-                                  const pj_timestamp *stop )
-{
-    pj_highprec_t elapsed_hi, elapsed_lo;
-
-    elapsed_hi = stop->u32.hi - start->u32.hi;
-    elapsed_lo = stop->u32.lo - start->u32.lo;
-
-    /* elapsed_hi = elapsed_hi * U32MAX */
-    pj_highprec_mul(elapsed_hi, U32MAX);
-
-    return elapsed_hi + elapsed_lo;
-}
-
-static pj_highprec_t elapsed_usec( const pj_timestamp *start,
-                                   const pj_timestamp *stop )
-{
-    pj_timestamp ts_freq;
-    pj_highprec_t freq, elapsed;
-
-    if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
-        return 0;
-
-    /* Convert frequency timestamp */
-    freq = ts_freq.u32.hi;
-    pj_highprec_mul(freq, U32MAX);
-    freq += ts_freq.u32.lo;
-
-    /* Avoid division by zero. */
-    if (freq == 0) freq = 1;
-
-    /* Get elapsed time in cycles. */
-    elapsed = get_elapsed(start, stop);
-
-    /* usec = elapsed * USEC / freq */
-    pj_highprec_mul(elapsed, USEC);
-    pj_highprec_div(elapsed, freq);
-
-    return elapsed;
-}
-
-PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,
-                                        const pj_timestamp *stop )
-{
-    pj_timestamp ts_freq;
-    pj_highprec_t freq, elapsed;
-
-    if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)
-        return 0;
-
-    /* Convert frequency timestamp */
-    freq = ts_freq.u32.hi;
-    pj_highprec_mul(freq, U32MAX);
-    freq += ts_freq.u32.lo;
-
-    /* Avoid division by zero. */
-    if (freq == 0) freq = 1;
-
-    /* Get elapsed time in cycles. */
-    elapsed = get_elapsed(start, stop);
-
-    /* usec = elapsed * USEC / freq */
-    pj_highprec_mul(elapsed, NANOSEC);
-    pj_highprec_div(elapsed, freq);
-
-    return (pj_uint32_t)elapsed;
-}
-
-PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,
-                                     const pj_timestamp *stop )
-{
-    return (pj_uint32_t)elapsed_usec(start, stop);
-}
-
-PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start,
-                                     const pj_timestamp *stop )
-{
-    pj_highprec_t elapsed = elapsed_usec(start, stop);
-    pj_time_val tv_elapsed;
-
-    if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) {
-        tv_elapsed.sec = tv_elapsed.msec = 0;
-        return tv_elapsed;
-    } else {
-        pj_highprec_t sec, msec;
-
-        sec = elapsed;
-        pj_highprec_div(sec, USEC);
-        tv_elapsed.sec = (long)sec;
-
-        msec = elapsed;
-        pj_highprec_mod(msec, USEC);
-        pj_highprec_div(msec, 1000);
-        tv_elapsed.msec = (long)msec;
-
-        return tv_elapsed;
-    }
-}
-
-PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,
-                                      const pj_timestamp *stop )
-{
-    return stop->u32.lo - start->u32.lo;
-}
-
-#endif  /* PJ_HAS_HIGH_RES_TIMER */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/os.h>

+#include <pj/compat/high_precision.h>

+

+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

+

+#define U32MAX  (0xFFFFFFFFUL)

+#define NANOSEC (1000000000UL)

+#define USEC    (1000000UL)

+#define MSEC    (1000)

+

+static pj_highprec_t get_elapsed( const pj_timestamp *start,

+                                  const pj_timestamp *stop )

+{

+    pj_highprec_t elapsed_hi, elapsed_lo;

+

+    elapsed_hi = stop->u32.hi - start->u32.hi;

+    elapsed_lo = stop->u32.lo - start->u32.lo;

+

+    /* elapsed_hi = elapsed_hi * U32MAX */

+    pj_highprec_mul(elapsed_hi, U32MAX);

+

+    return elapsed_hi + elapsed_lo;

+}

+

+static pj_highprec_t elapsed_usec( const pj_timestamp *start,

+                                   const pj_timestamp *stop )

+{

+    pj_timestamp ts_freq;

+    pj_highprec_t freq, elapsed;

+

+    if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)

+        return 0;

+

+    /* Convert frequency timestamp */

+    freq = ts_freq.u32.hi;

+    pj_highprec_mul(freq, U32MAX);

+    freq += ts_freq.u32.lo;

+

+    /* Avoid division by zero. */

+    if (freq == 0) freq = 1;

+

+    /* Get elapsed time in cycles. */

+    elapsed = get_elapsed(start, stop);

+

+    /* usec = elapsed * USEC / freq */

+    pj_highprec_mul(elapsed, USEC);

+    pj_highprec_div(elapsed, freq);

+

+    return elapsed;

+}

+

+PJ_DEF(pj_uint32_t) pj_elapsed_nanosec( const pj_timestamp *start,

+                                        const pj_timestamp *stop )

+{

+    pj_timestamp ts_freq;

+    pj_highprec_t freq, elapsed;

+

+    if (pj_get_timestamp_freq(&ts_freq) != PJ_SUCCESS)

+        return 0;

+

+    /* Convert frequency timestamp */

+    freq = ts_freq.u32.hi;

+    pj_highprec_mul(freq, U32MAX);

+    freq += ts_freq.u32.lo;

+

+    /* Avoid division by zero. */

+    if (freq == 0) freq = 1;

+

+    /* Get elapsed time in cycles. */

+    elapsed = get_elapsed(start, stop);

+

+    /* usec = elapsed * USEC / freq */

+    pj_highprec_mul(elapsed, NANOSEC);

+    pj_highprec_div(elapsed, freq);

+

+    return (pj_uint32_t)elapsed;

+}

+

+PJ_DEF(pj_uint32_t) pj_elapsed_usec( const pj_timestamp *start,

+                                     const pj_timestamp *stop )

+{

+    return (pj_uint32_t)elapsed_usec(start, stop);

+}

+

+PJ_DEF(pj_time_val) pj_elapsed_time( const pj_timestamp *start,

+                                     const pj_timestamp *stop )

+{

+    pj_highprec_t elapsed = elapsed_usec(start, stop);

+    pj_time_val tv_elapsed;

+

+    if (PJ_HIGHPREC_VALUE_IS_ZERO(elapsed)) {

+        tv_elapsed.sec = tv_elapsed.msec = 0;

+        return tv_elapsed;

+    } else {

+        pj_highprec_t sec, msec;

+

+        sec = elapsed;

+        pj_highprec_div(sec, USEC);

+        tv_elapsed.sec = (long)sec;

+

+        msec = elapsed;

+        pj_highprec_mod(msec, USEC);

+        pj_highprec_div(msec, 1000);

+        tv_elapsed.msec = (long)msec;

+

+        return tv_elapsed;

+    }

+}

+

+PJ_DEF(pj_uint32_t) pj_elapsed_cycle( const pj_timestamp *start,

+                                      const pj_timestamp *stop )

+{

+    return stop->u32.lo - start->u32.lo;

+}

+

+#endif  /* PJ_HAS_HIGH_RES_TIMER */

+

diff --git a/pjlib/src/pj/os_timestamp_linux.c b/pjlib/src/pj/os_timestamp_linux.c
index ada9076..15921f9 100644
--- a/pjlib/src/pj/os_timestamp_linux.c
+++ b/pjlib/src/pj/os_timestamp_linux.c
@@ -1,124 +1,145 @@
-/* $Id$
- *
- */
-#include <pj/os.h>
-#include <pj/errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0
-static int machine_speed_mhz;
-static pj_timestamp machine_speed;
-
-static __inline__ unsigned long long int rdtsc()
-{
-    unsigned long long int x;
-    __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
-    return x;
-}
-
-/* Determine machine's CPU MHz to get the counter's frequency.
- */
-static int get_machine_speed_mhz()
-{
-    FILE *strm;
-    char buf[512];
-    int len;
-    char *pos, *end;
-	
-    PJ_CHECK_STACK();
-	
-    /* Open /proc/cpuinfo and read the file */
-    strm = fopen("/proc/cpuinfo", "r");
-    if (!strm)
-        return -1;
-    len = fread(buf, 1, sizeof(buf), strm);
-    fclose(strm);
-    if (len < 1) {
-        return -1;
-    }
-    buf[len] = '\0';
-
-    /* Locate the MHz digit. */
-    pos = strstr(buf, "cpu MHz");
-    if (!pos)
-        return -1;
-    pos = strchr(pos, ':');
-    if (!pos)
-        return -1;
-    end = (pos += 2);
-    while (isdigit(*end)) ++end;
-    *end = '\0';
-
-    /* Return the Mhz part, and give it a +1. */
-    return atoi(pos)+1;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
-    if (machine_speed_mhz == 0) {
-	machine_speed_mhz = get_machine_speed_mhz();
-	if (machine_speed_mhz > 0) {
-	    machine_speed.u64 = machine_speed_mhz * 1000000.0;
-	}
-    }
-    
-    if (machine_speed_mhz == -1) {
-	ts->u64 = 0;
-	return -1;
-    } 
-    ts->u64 = rdtsc();
-    return 0;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
-    if (machine_speed_mhz == 0) {
-	machine_speed_mhz = get_machine_speed_mhz();
-	if (machine_speed_mhz > 0) {
-	    machine_speed.u64 = machine_speed_mhz * 1000000.0;
-	}
-    }
-    
-    if (machine_speed_mhz == -1) {
-	freq->u64 = 1;	/* return 1 to prevent division by zero in apps. */
-	return -1;
-    } 
-
-    freq->u64 = machine_speed.u64;
-    return 0;
-}
-
-#else
-#include <sys/time.h>
-#include <errno.h>
-
-#define USEC_PER_SEC	1000000
-
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
-    struct timeval tv;
-
-    if (gettimeofday(&tv, NULL) != 0) {
-	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
-    }
-
-    ts->u64 = tv.tv_sec;
-    ts->u64 *= USEC_PER_SEC;
-    ts->u64 += tv.tv_usec;
-
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
-    freq->u32.hi = 0;
-    freq->u32.lo = USEC_PER_SEC;
-
-    return PJ_SUCCESS;
-}
-
-#endif
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/os.h>

+#include <pj/errno.h>

+#include <stdio.h>

+#include <string.h>

+#include <stdlib.h>

+#include <ctype.h>

+

+#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0

+static int machine_speed_mhz;

+static pj_timestamp machine_speed;

+

+static __inline__ unsigned long long int rdtsc()

+{

+    unsigned long long int x;

+    __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));

+    return x;

+}

+

+/* Determine machine's CPU MHz to get the counter's frequency.

+ */

+static int get_machine_speed_mhz()

+{

+    FILE *strm;

+    char buf[512];

+    int len;

+    char *pos, *end;

+	

+    PJ_CHECK_STACK();

+	

+    /* Open /proc/cpuinfo and read the file */

+    strm = fopen("/proc/cpuinfo", "r");

+    if (!strm)

+        return -1;

+    len = fread(buf, 1, sizeof(buf), strm);

+    fclose(strm);

+    if (len < 1) {

+        return -1;

+    }

+    buf[len] = '\0';

+

+    /* Locate the MHz digit. */

+    pos = strstr(buf, "cpu MHz");

+    if (!pos)

+        return -1;

+    pos = strchr(pos, ':');

+    if (!pos)

+        return -1;

+    end = (pos += 2);

+    while (isdigit(*end)) ++end;

+    *end = '\0';

+

+    /* Return the Mhz part, and give it a +1. */

+    return atoi(pos)+1;

+}

+

+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)

+{

+    if (machine_speed_mhz == 0) {

+	machine_speed_mhz = get_machine_speed_mhz();

+	if (machine_speed_mhz > 0) {

+	    machine_speed.u64 = machine_speed_mhz * 1000000.0;

+	}

+    }

+    

+    if (machine_speed_mhz == -1) {

+	ts->u64 = 0;

+	return -1;

+    } 

+    ts->u64 = rdtsc();

+    return 0;

+}

+

+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)

+{

+    if (machine_speed_mhz == 0) {

+	machine_speed_mhz = get_machine_speed_mhz();

+	if (machine_speed_mhz > 0) {

+	    machine_speed.u64 = machine_speed_mhz * 1000000.0;

+	}

+    }

+    

+    if (machine_speed_mhz == -1) {

+	freq->u64 = 1;	/* return 1 to prevent division by zero in apps. */

+	return -1;

+    } 

+

+    freq->u64 = machine_speed.u64;

+    return 0;

+}

+

+#else

+#include <sys/time.h>

+#include <errno.h>

+

+#define USEC_PER_SEC	1000000

+

+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)

+{

+    struct timeval tv;

+

+    if (gettimeofday(&tv, NULL) != 0) {

+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());

+    }

+

+    ts->u64 = tv.tv_sec;

+    ts->u64 *= USEC_PER_SEC;

+    ts->u64 += tv.tv_usec;

+

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)

+{

+    freq->u32.hi = 0;

+    freq->u32.lo = USEC_PER_SEC;

+

+    return PJ_SUCCESS;

+}

+

+#endif

+

diff --git a/pjlib/src/pj/os_timestamp_linux_kernel.c b/pjlib/src/pj/os_timestamp_linux_kernel.c
index d70bcfd..0b75c76 100644
--- a/pjlib/src/pj/os_timestamp_linux_kernel.c
+++ b/pjlib/src/pj/os_timestamp_linux_kernel.c
@@ -1,63 +1,84 @@
-/* $Id$
- *
- */
-#include <pj/os.h>
-#include <linux/time.h>
-
-#if 0
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
-    ts->u32.hi = 0;
-    ts->u32.lo = jiffies;
-    return 0;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
-    freq->u32.hi = 0;
-    freq->u32.lo = HZ;
-    return 0;
-}
-#elif 0
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
-    struct timespec tv;
-    
-    tv = CURRENT_TIME;
-
-    ts->u64 = tv.tv_sec;
-    ts->u64 *= NSEC_PER_SEC;
-    ts->u64 += tv.tv_nsec;
-
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
-    freq->u32.hi = 0;
-    freq->u32.lo = NSEC_PER_SEC;
-    return 0;
-}
-#else
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
-    struct timeval tv;
-    
-    do_gettimeofday(&tv);
-
-    ts->u64 = tv.tv_sec;
-    ts->u64 *= USEC_PER_SEC;
-    ts->u64 += tv.tv_usec;
-
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
-    freq->u32.hi = 0;
-    freq->u32.lo = USEC_PER_SEC;
-    return 0;
-}
-
-#endif
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/os.h>

+#include <linux/time.h>

+

+#if 0

+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)

+{

+    ts->u32.hi = 0;

+    ts->u32.lo = jiffies;

+    return 0;

+}

+

+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)

+{

+    freq->u32.hi = 0;

+    freq->u32.lo = HZ;

+    return 0;

+}

+#elif 0

+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)

+{

+    struct timespec tv;

+    

+    tv = CURRENT_TIME;

+

+    ts->u64 = tv.tv_sec;

+    ts->u64 *= NSEC_PER_SEC;

+    ts->u64 += tv.tv_nsec;

+

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)

+{

+    freq->u32.hi = 0;

+    freq->u32.lo = NSEC_PER_SEC;

+    return 0;

+}

+#else

+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)

+{

+    struct timeval tv;

+    

+    do_gettimeofday(&tv);

+

+    ts->u64 = tv.tv_sec;

+    ts->u64 *= USEC_PER_SEC;

+    ts->u64 += tv.tv_usec;

+

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)

+{

+    freq->u32.hi = 0;

+    freq->u32.lo = USEC_PER_SEC;

+    return 0;

+}

+

+#endif

+

diff --git a/pjlib/src/pj/os_timestamp_win32.c b/pjlib/src/pj/os_timestamp_win32.c
index 1cfd81d..1626ca6 100644
--- a/pjlib/src/pj/os_timestamp_win32.c
+++ b/pjlib/src/pj/os_timestamp_win32.c
@@ -1,28 +1,49 @@
-/* $Id$
- */
-#include <pj/os.h>
-#include <pj/errno.h>
-#include <windows.h>
-
-PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
-{
-    LARGE_INTEGER val;
-
-    if (!QueryPerformanceCounter(&val))
-	return PJ_RETURN_OS_ERROR(GetLastError());
-
-    ts->u64 = val.QuadPart;
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
-{
-    LARGE_INTEGER val;
-
-    if (!QueryPerformanceFrequency(&val))
-	return PJ_RETURN_OS_ERROR(GetLastError());
-
-    freq->u64 = val.QuadPart;
-    return PJ_SUCCESS;
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/os.h>

+#include <pj/errno.h>

+#include <windows.h>

+

+PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)

+{

+    LARGE_INTEGER val;

+

+    if (!QueryPerformanceCounter(&val))

+	return PJ_RETURN_OS_ERROR(GetLastError());

+

+    ts->u64 = val.QuadPart;

+    return PJ_SUCCESS;

+}

+

+PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)

+{

+    LARGE_INTEGER val;

+

+    if (!QueryPerformanceFrequency(&val))

+	return PJ_RETURN_OS_ERROR(GetLastError());

+

+    freq->u64 = val.QuadPart;

+    return PJ_SUCCESS;

+}

+

diff --git a/pjlib/src/pj/pool.c b/pjlib/src/pj/pool.c
index 5561612..c5a3192 100644
--- a/pjlib/src/pj/pool.c
+++ b/pjlib/src/pj/pool.c
@@ -1,256 +1,277 @@
-/* $Id$
- */
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/except.h>
-#include <pj/assert.h>
-#include <pj/os.h>
-#include <pj/compat/sprintf.h>
-
-/* Include inline definitions when inlining is disabled. */
-#if !PJ_FUNCTIONS_ARE_INLINED
-#  include <pj/pool_i.h>
-#endif
-
-#define LOG(expr)   PJ_LOG(5,expr)
-
-int PJ_NO_MEMORY_EXCEPTION;
-
-/*
- * Create new block.
- * Create a new big chunk of memory block, from which user allocation will be
- * taken from.
- */
-static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
-{
-    pj_pool_block *block;
-
-    PJ_CHECK_STACK();
-    pj_assert(size >= sizeof(pj_pool_block));
-
-    LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u", 
-	 size, pool->capacity, pool->used_size));
-
-    /* Request memory from allocator. */
-    block = (pj_pool_block*) 
-	(*pool->factory->policy.block_alloc)(pool->factory, size);
-    if (block == NULL) {
-	(*pool->callback)(pool, size);
-	return NULL;
-    }
-
-    /* Add capacity. */
-    pool->capacity += size;
-    pool->used_size += sizeof(pj_pool_block);
-
-    /* Set block attribytes. */
-    block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
-    block->end = ((unsigned char*)block) + size;
-
-    /* Insert in the front of the list. */
-    pj_list_insert_after(&pool->block_list, block);
-
-    LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
-
-    return block;
-}
-
-/*
- * Allocate memory chunk for user from available blocks.
- * This will iterate through block list to find space to allocate the chunk.
- * If no space is available in all the blocks, a new block might be created
- * (depending on whether the pool is allowed to resize).
- */
-PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
-{
-    pj_pool_block *block = pool->block_list.next;
-    void *p;
-    unsigned block_size;
-
-    PJ_CHECK_STACK();
-
-    while (block != &pool->block_list) {
-	p = pj_pool_alloc_from_block(pool, block, size);
-	if (p != NULL)
-	    return p;
-	block = block->next;
-    }
-    /* No available space in all blocks. */
-
-    /* If pool is configured NOT to expand, return error. */
-    if (pool->increment_size == 0) {
-	LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
-	     "(used=%u, cap=%u)",
-	     size, pool->used_size, pool->capacity));
-	(*pool->callback)(pool, size);
-	return NULL;
-    }
-
-    /* If pool is configured to expand, but the increment size
-     * is less than the required size, expand the pool by multiple
-     * increment size
-     */
-    if (pool->increment_size < size + sizeof(pj_pool_block)) {
-        unsigned count;
-        count = (size + pool->increment_size + sizeof(pj_pool_block)) / 
-                pool->increment_size;
-        block_size = count * pool->increment_size;
-
-    } else {
-        block_size = pool->increment_size;
-    }
-
-    LOG((pool->obj_name, 
-	 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
-	 size, block_size, pool->used_size, pool->capacity));
-
-    block = pj_pool_create_block(pool, block_size);
-    if (!block)
-	return NULL;
-
-    p = pj_pool_alloc_from_block(pool, block, size);
-    pj_assert(p != NULL);
-#if PJ_DEBUG
-    if (p == NULL) {
-	p = p;
-    }
-#endif
-    return p;
-}
-
-/*
- * Internal function to initialize pool.
- */
-PJ_DEF(void) pj_pool_init_int(  pj_pool_t *pool, 
-				const char *name,
-				pj_size_t increment_size,
-				pj_pool_callback *callback)
-{
-    pj_pool_block *block;
-
-    PJ_CHECK_STACK();
-
-    pool->increment_size = increment_size;
-    pool->callback = callback;
-    pool->used_size = sizeof(*pool);
-    block = pool->block_list.next;
-    while (block != &pool->block_list) {
-	pool->used_size += sizeof(pj_pool_block);
-	block = block->next;
-    }
-
-    if (name) {
-	if (strchr(name, '%') != NULL) {
-	    sprintf(pool->obj_name, name, pool);
-	} else {
-	    strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
-	}
-    } else {
-	pool->obj_name[0] = '\0';
-    }
-}
-
-/*
- * Create new memory pool.
- */
-PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
-				       pj_size_t initial_size, 
-				       pj_size_t increment_size,
-				       pj_pool_callback *callback)
-{
-    pj_pool_t *pool;
-    pj_pool_block *block;
-    unsigned char *buffer;
-
-    PJ_CHECK_STACK();
-
-    buffer = (*f->policy.block_alloc)(f, initial_size);
-    if (!buffer)
-	return NULL;
-
-    /* Set pool administrative data. */
-    pool = (pj_pool_t*)buffer;
-    pj_memset(pool, 0, sizeof(*pool));
-
-    pj_list_init(&pool->block_list);
-    pool->factory = f;
-
-    /* Create the first block from the memory. */
-    block = (pj_pool_block*) (buffer + sizeof(*pool));
-    block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
-    block->end = buffer + initial_size;
-    pj_list_insert_after(&pool->block_list, block);
-
-    pj_pool_init_int(pool, name, increment_size, callback);
-
-    /* Pool initial capacity and used size */
-    pool->capacity = initial_size;
-
-    LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
-    return pool;
-}
-
-/*
- * Reset the pool to the state when it was created.
- * All blocks will be deallocated except the first block. All memory areas
- * are marked as free.
- */
-static void reset_pool(pj_pool_t *pool)
-{
-    pj_pool_block *block;
-
-    PJ_CHECK_STACK();
-
-    block = pool->block_list.prev;
-    if (block == &pool->block_list)
-	return;
-
-    /* Skip the first block because it is occupying the same memory
-       as the pool itself.
-    */
-    block = block->prev;
-    
-    while (block != &pool->block_list) {
-	pj_pool_block *prev = block->prev;
-	pj_list_erase(block);
-	(*pool->factory->policy.block_free)(pool->factory, block, 
-					    block->end - (unsigned char*)block);
-	block = prev;
-    }
-
-    block = pool->block_list.next;
-    block->cur = block->buf;
-    pool->capacity = block->end - (unsigned char*)pool;
-    pool->used_size = 0;
-}
-
-/*
- * The public function to reset pool.
- */
-PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
-{
-    LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)", 
-	pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));
-
-    reset_pool(pool);
-}
-
-/*
- * Destroy the pool.
- */
-PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
-{
-    pj_size_t initial_size;
-
-    LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p", 
-	pool->capacity, pool->used_size, pool->used_size*100/pool->capacity,
-	((pj_pool_block*)pool->block_list.next)->buf, 
-	((pj_pool_block*)pool->block_list.next)->end));
-
-    reset_pool(pool);
-    initial_size = ((pj_pool_block*)pool->block_list.next)->end - 
-		   (unsigned char*)pool;
-    (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
-}
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/pool.h>

+#include <pj/log.h>

+#include <pj/except.h>

+#include <pj/assert.h>

+#include <pj/os.h>

+#include <pj/compat/sprintf.h>

+

+/* Include inline definitions when inlining is disabled. */

+#if !PJ_FUNCTIONS_ARE_INLINED

+#  include <pj/pool_i.h>

+#endif

+

+#define LOG(expr)   PJ_LOG(5,expr)

+

+int PJ_NO_MEMORY_EXCEPTION;

+

+/*

+ * Create new block.

+ * Create a new big chunk of memory block, from which user allocation will be

+ * taken from.

+ */

+static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)

+{

+    pj_pool_block *block;

+

+    PJ_CHECK_STACK();

+    pj_assert(size >= sizeof(pj_pool_block));

+

+    LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u", 

+	 size, pool->capacity, pool->used_size));

+

+    /* Request memory from allocator. */

+    block = (pj_pool_block*) 

+	(*pool->factory->policy.block_alloc)(pool->factory, size);

+    if (block == NULL) {

+	(*pool->callback)(pool, size);

+	return NULL;

+    }

+

+    /* Add capacity. */

+    pool->capacity += size;

+    pool->used_size += sizeof(pj_pool_block);

+

+    /* Set block attribytes. */

+    block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);

+    block->end = ((unsigned char*)block) + size;

+

+    /* Insert in the front of the list. */

+    pj_list_insert_after(&pool->block_list, block);

+

+    LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));

+

+    return block;

+}

+

+/*

+ * Allocate memory chunk for user from available blocks.

+ * This will iterate through block list to find space to allocate the chunk.

+ * If no space is available in all the blocks, a new block might be created

+ * (depending on whether the pool is allowed to resize).

+ */

+PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)

+{

+    pj_pool_block *block = pool->block_list.next;

+    void *p;

+    unsigned block_size;

+

+    PJ_CHECK_STACK();

+

+    while (block != &pool->block_list) {

+	p = pj_pool_alloc_from_block(pool, block, size);

+	if (p != NULL)

+	    return p;

+	block = block->next;

+    }

+    /* No available space in all blocks. */

+

+    /* If pool is configured NOT to expand, return error. */

+    if (pool->increment_size == 0) {

+	LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "

+	     "(used=%u, cap=%u)",

+	     size, pool->used_size, pool->capacity));

+	(*pool->callback)(pool, size);

+	return NULL;

+    }

+

+    /* If pool is configured to expand, but the increment size

+     * is less than the required size, expand the pool by multiple

+     * increment size

+     */

+    if (pool->increment_size < size + sizeof(pj_pool_block)) {

+        unsigned count;

+        count = (size + pool->increment_size + sizeof(pj_pool_block)) / 

+                pool->increment_size;

+        block_size = count * pool->increment_size;

+

+    } else {

+        block_size = pool->increment_size;

+    }

+

+    LOG((pool->obj_name, 

+	 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",

+	 size, block_size, pool->used_size, pool->capacity));

+

+    block = pj_pool_create_block(pool, block_size);

+    if (!block)

+	return NULL;

+

+    p = pj_pool_alloc_from_block(pool, block, size);

+    pj_assert(p != NULL);

+#if PJ_DEBUG

+    if (p == NULL) {

+	p = p;

+    }

+#endif

+    return p;

+}

+

+/*

+ * Internal function to initialize pool.

+ */

+PJ_DEF(void) pj_pool_init_int(  pj_pool_t *pool, 

+				const char *name,

+				pj_size_t increment_size,

+				pj_pool_callback *callback)

+{

+    pj_pool_block *block;

+

+    PJ_CHECK_STACK();

+

+    pool->increment_size = increment_size;

+    pool->callback = callback;

+    pool->used_size = sizeof(*pool);

+    block = pool->block_list.next;

+    while (block != &pool->block_list) {

+	pool->used_size += sizeof(pj_pool_block);

+	block = block->next;

+    }

+

+    if (name) {

+	if (strchr(name, '%') != NULL) {

+	    sprintf(pool->obj_name, name, pool);

+	} else {

+	    strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);

+	}

+    } else {

+	pool->obj_name[0] = '\0';

+    }

+}

+

+/*

+ * Create new memory pool.

+ */

+PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,

+				       pj_size_t initial_size, 

+				       pj_size_t increment_size,

+				       pj_pool_callback *callback)

+{

+    pj_pool_t *pool;

+    pj_pool_block *block;

+    unsigned char *buffer;

+

+    PJ_CHECK_STACK();

+

+    buffer = (*f->policy.block_alloc)(f, initial_size);

+    if (!buffer)

+	return NULL;

+

+    /* Set pool administrative data. */

+    pool = (pj_pool_t*)buffer;

+    pj_memset(pool, 0, sizeof(*pool));

+

+    pj_list_init(&pool->block_list);

+    pool->factory = f;

+

+    /* Create the first block from the memory. */

+    block = (pj_pool_block*) (buffer + sizeof(*pool));

+    block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);

+    block->end = buffer + initial_size;

+    pj_list_insert_after(&pool->block_list, block);

+

+    pj_pool_init_int(pool, name, increment_size, callback);

+

+    /* Pool initial capacity and used size */

+    pool->capacity = initial_size;

+

+    LOG((pool->obj_name, "pool created, size=%u", pool->capacity));

+    return pool;

+}

+

+/*

+ * Reset the pool to the state when it was created.

+ * All blocks will be deallocated except the first block. All memory areas

+ * are marked as free.

+ */

+static void reset_pool(pj_pool_t *pool)

+{

+    pj_pool_block *block;

+

+    PJ_CHECK_STACK();

+

+    block = pool->block_list.prev;

+    if (block == &pool->block_list)

+	return;

+

+    /* Skip the first block because it is occupying the same memory

+       as the pool itself.

+    */

+    block = block->prev;

+    

+    while (block != &pool->block_list) {

+	pj_pool_block *prev = block->prev;

+	pj_list_erase(block);

+	(*pool->factory->policy.block_free)(pool->factory, block, 

+					    block->end - (unsigned char*)block);

+	block = prev;

+    }

+

+    block = pool->block_list.next;

+    block->cur = block->buf;

+    pool->capacity = block->end - (unsigned char*)pool;

+    pool->used_size = 0;

+}

+

+/*

+ * The public function to reset pool.

+ */

+PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)

+{

+    LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)", 

+	pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));

+

+    reset_pool(pool);

+}

+

+/*

+ * Destroy the pool.

+ */

+PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)

+{

+    pj_size_t initial_size;

+

+    LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p", 

+	pool->capacity, pool->used_size, pool->used_size*100/pool->capacity,

+	((pj_pool_block*)pool->block_list.next)->buf, 

+	((pj_pool_block*)pool->block_list.next)->end));

+

+    reset_pool(pool);

+    initial_size = ((pj_pool_block*)pool->block_list.next)->end - 

+		   (unsigned char*)pool;

+    (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);

+}

+

+

diff --git a/pjlib/src/pj/pool_caching.c b/pjlib/src/pj/pool_caching.c
index d59ed28..20c55dd 100644
--- a/pjlib/src/pj/pool_caching.c
+++ b/pjlib/src/pj/pool_caching.c
@@ -1,205 +1,226 @@
-/* $Id$
- */
-#include <pj/pool.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/os.h>
-
-static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 
-				    const char *name,
-				    pj_size_t initial_size, 
-				    pj_size_t increment_sz,
-				    pj_pool_callback *callback);
-static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool);
-static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail );
-
-static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] = 
-{
-    256, 512, 1024, 2048, 4096, 8192, 12288, 16384, 
-    20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536
-};
-
-
-PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp, 
-				   const pj_pool_factory_policy *policy,
-				   pj_size_t max_capacity)
-{
-    int i;
-
-    PJ_CHECK_STACK();
-
-    pj_memset(cp, 0, sizeof(*cp));
-    
-    cp->max_capacity = max_capacity;
-    pj_list_init(&cp->used_list);
-    for (i=0; i<PJ_CACHING_POOL_ARRAY_SIZE; ++i)
-	pj_list_init(&cp->free_list[i]);
-
-    pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy));
-    cp->factory.create_pool = &cpool_create_pool;
-    cp->factory.release_pool = &cpool_release_pool;
-    cp->factory.dump_status = &cpool_dump_status;
-}
-
-PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )
-{
-    int i;
-    pj_pool_t *pool;
-
-    PJ_CHECK_STACK();
-
-    /* Delete all pool in free list */
-    for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) {
-	pj_pool_t *pool = cp->free_list[i].next;
-	pj_pool_t *next;
-	for (; pool != (void*)&cp->free_list[i]; pool = next) {
-	    next = pool->next;
-	    pj_list_erase(pool);
-	    pj_pool_destroy_int(pool);
-	}
-    }
-
-    /* Delete all pools in used list */
-    pool = cp->used_list.next;
-    while (pool != (pj_pool_t*) &cp->used_list) {
-	pj_pool_t *next = pool->next;
-	pj_list_erase(pool);
-	pj_pool_destroy_int(pool);
-	pool = next;
-    }
-}
-
-static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 
-					      const char *name, 
-					      pj_size_t initial_size, 
-					      pj_size_t increment_sz, 
-					      pj_pool_callback *callback)
-{
-    pj_caching_pool *cp = (pj_caching_pool*)pf;
-    pj_pool_t *pool;
-    int idx;
-
-    PJ_CHECK_STACK();
-
-    /* Use pool factory's policy when callback is NULL */
-    if (callback == NULL) {
-	callback = pf->policy.callback;
-    }
-
-    /* Search the suitable size for the pool. 
-     * We'll just do linear search to the size array, as the array size itself
-     * is only a few elements. Binary search I suspect will be less efficient
-     * for this purpose.
-     */
-    for (idx=0; 
-	 idx < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[idx] < initial_size; 
-	 ++idx)
-	;
-
-    /* Check whether there's a pool in the list. */
-    if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {
-	/* No pool is available. */
-	/* Set minimum size. */
-	if (idx < PJ_CACHING_POOL_ARRAY_SIZE)
-	    initial_size =  pool_sizes[idx];
-
-	/* Create new pool */
-	pool = pj_pool_create_int(&cp->factory, name, initial_size, 
-				  increment_sz, callback);
-	if (!pool)
-	    return NULL;
-
-    } else {
-	/* Get one pool from the list. */
-	pool = cp->free_list[idx].next;
-	pj_list_erase(pool);
-
-	/* Initialize the pool. */
-	pj_pool_init_int(pool, name, increment_sz, callback);
-
-	/* Update pool manager's free capacity. */
-	cp->capacity -= pj_pool_get_capacity(pool);
-
-	PJ_LOG(5, (pool->obj_name, "pool reused, size=%u", pool->capacity));
-    }
-
-    /* Put in used list. */
-    pj_list_insert_before( &cp->used_list, pool );
-
-    /* Increment used count. */
-    ++cp->used_count;
-    return pool;
-}
-
-static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
-{
-    pj_caching_pool *cp = (pj_caching_pool*)pf;
-    int i;
-
-    PJ_CHECK_STACK();
-
-    /* Erase from the used list. */
-    pj_list_erase(pool);
-
-    /* Decrement used count. */
-    --cp->used_count;
-
-    /* Destroy the pool if the size is greater than our size or if the total
-     * capacity in our recycle list (plus the size of the pool) exceeds 
-     * maximum capacity.
-   . */
-    if (pool->capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
-	cp->capacity + pool->capacity > cp->max_capacity)
-    {
-	pj_pool_destroy_int(pool);
-	return;
-    }
-
-    /* Reset pool. */
-    PJ_LOG(4, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", 
-	       pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));
-    pj_pool_reset(pool);
-
-    /*
-     * Otherwise put the pool in our recycle list.
-     */
-    for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[i] != pool->capacity; ++i)
-	;
-
-    pj_assert( i != PJ_CACHING_POOL_ARRAY_SIZE );
-    if (i == PJ_CACHING_POOL_ARRAY_SIZE) {
-	/* Something has gone wrong with the pool. */
-	pj_pool_destroy_int(pool);
-	return;
-    }
-
-    pj_list_insert_after(&cp->free_list[i], pool);
-    cp->capacity += pool->capacity;
-}
-
-static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
-{
-#if PJ_LOG_MAX_LEVEL >= 3
-    pj_caching_pool *cp = (pj_caching_pool*)factory;
-    PJ_LOG(3,("cachpool", " Dumping caching pool:"));
-    PJ_LOG(3,("cachpool", "   Capacity=%u, max_capacity=%u, used_cnt=%u", \
-			     cp->capacity, cp->max_capacity, cp->used_count));
-    if (detail) {
-	pj_pool_t *pool = cp->used_list.next;
-	pj_uint32_t total_used = 0, total_capacity = 0;
-        PJ_LOG(3,("cachpool", "  Dumping all active pools:"));
-	while (pool != (void*)&cp->used_list) {
-	    PJ_LOG(3,("cachpool", "   %12s: %8d of %8d (%d%%) used", pool->obj_name, 
-				  pool->used_size, pool->capacity,
-				  pool->used_size*100/pool->capacity));
-	    total_used += pool->used_size;
-	    total_capacity += pool->capacity;
-	    pool = pool->next;
-	}
-	PJ_LOG(3,("cachpool", "  Total %9d of %9d (%d %%) used!",
-			      total_used, total_capacity,
-			      total_used * 100 / total_capacity));
-    }
-#endif
-}
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/pool.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/assert.h>

+#include <pj/os.h>

+

+static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 

+				    const char *name,

+				    pj_size_t initial_size, 

+				    pj_size_t increment_sz,

+				    pj_pool_callback *callback);

+static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool);

+static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail );

+

+static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] = 

+{

+    256, 512, 1024, 2048, 4096, 8192, 12288, 16384, 

+    20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536

+};

+

+

+PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp, 

+				   const pj_pool_factory_policy *policy,

+				   pj_size_t max_capacity)

+{

+    int i;

+

+    PJ_CHECK_STACK();

+

+    pj_memset(cp, 0, sizeof(*cp));

+    

+    cp->max_capacity = max_capacity;

+    pj_list_init(&cp->used_list);

+    for (i=0; i<PJ_CACHING_POOL_ARRAY_SIZE; ++i)

+	pj_list_init(&cp->free_list[i]);

+

+    pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy));

+    cp->factory.create_pool = &cpool_create_pool;

+    cp->factory.release_pool = &cpool_release_pool;

+    cp->factory.dump_status = &cpool_dump_status;

+}

+

+PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )

+{

+    int i;

+    pj_pool_t *pool;

+

+    PJ_CHECK_STACK();

+

+    /* Delete all pool in free list */

+    for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) {

+	pj_pool_t *pool = cp->free_list[i].next;

+	pj_pool_t *next;

+	for (; pool != (void*)&cp->free_list[i]; pool = next) {

+	    next = pool->next;

+	    pj_list_erase(pool);

+	    pj_pool_destroy_int(pool);

+	}

+    }

+

+    /* Delete all pools in used list */

+    pool = cp->used_list.next;

+    while (pool != (pj_pool_t*) &cp->used_list) {

+	pj_pool_t *next = pool->next;

+	pj_list_erase(pool);

+	pj_pool_destroy_int(pool);

+	pool = next;

+    }

+}

+

+static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 

+					      const char *name, 

+					      pj_size_t initial_size, 

+					      pj_size_t increment_sz, 

+					      pj_pool_callback *callback)

+{

+    pj_caching_pool *cp = (pj_caching_pool*)pf;

+    pj_pool_t *pool;

+    int idx;

+

+    PJ_CHECK_STACK();

+

+    /* Use pool factory's policy when callback is NULL */

+    if (callback == NULL) {

+	callback = pf->policy.callback;

+    }

+

+    /* Search the suitable size for the pool. 

+     * We'll just do linear search to the size array, as the array size itself

+     * is only a few elements. Binary search I suspect will be less efficient

+     * for this purpose.

+     */

+    for (idx=0; 

+	 idx < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[idx] < initial_size; 

+	 ++idx)

+	;

+

+    /* Check whether there's a pool in the list. */

+    if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {

+	/* No pool is available. */

+	/* Set minimum size. */

+	if (idx < PJ_CACHING_POOL_ARRAY_SIZE)

+	    initial_size =  pool_sizes[idx];

+

+	/* Create new pool */

+	pool = pj_pool_create_int(&cp->factory, name, initial_size, 

+				  increment_sz, callback);

+	if (!pool)

+	    return NULL;

+

+    } else {

+	/* Get one pool from the list. */

+	pool = cp->free_list[idx].next;

+	pj_list_erase(pool);

+

+	/* Initialize the pool. */

+	pj_pool_init_int(pool, name, increment_sz, callback);

+

+	/* Update pool manager's free capacity. */

+	cp->capacity -= pj_pool_get_capacity(pool);

+

+	PJ_LOG(5, (pool->obj_name, "pool reused, size=%u", pool->capacity));

+    }

+

+    /* Put in used list. */

+    pj_list_insert_before( &cp->used_list, pool );

+

+    /* Increment used count. */

+    ++cp->used_count;

+    return pool;

+}

+

+static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)

+{

+    pj_caching_pool *cp = (pj_caching_pool*)pf;

+    int i;

+

+    PJ_CHECK_STACK();

+

+    /* Erase from the used list. */

+    pj_list_erase(pool);

+

+    /* Decrement used count. */

+    --cp->used_count;

+

+    /* Destroy the pool if the size is greater than our size or if the total

+     * capacity in our recycle list (plus the size of the pool) exceeds 

+     * maximum capacity.

+   . */

+    if (pool->capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||

+	cp->capacity + pool->capacity > cp->max_capacity)

+    {

+	pj_pool_destroy_int(pool);

+	return;

+    }

+

+    /* Reset pool. */

+    PJ_LOG(4, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", 

+	       pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));

+    pj_pool_reset(pool);

+

+    /*

+     * Otherwise put the pool in our recycle list.

+     */

+    for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[i] != pool->capacity; ++i)

+	;

+

+    pj_assert( i != PJ_CACHING_POOL_ARRAY_SIZE );

+    if (i == PJ_CACHING_POOL_ARRAY_SIZE) {

+	/* Something has gone wrong with the pool. */

+	pj_pool_destroy_int(pool);

+	return;

+    }

+

+    pj_list_insert_after(&cp->free_list[i], pool);

+    cp->capacity += pool->capacity;

+}

+

+static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )

+{

+#if PJ_LOG_MAX_LEVEL >= 3

+    pj_caching_pool *cp = (pj_caching_pool*)factory;

+    PJ_LOG(3,("cachpool", " Dumping caching pool:"));

+    PJ_LOG(3,("cachpool", "   Capacity=%u, max_capacity=%u, used_cnt=%u", \

+			     cp->capacity, cp->max_capacity, cp->used_count));

+    if (detail) {

+	pj_pool_t *pool = cp->used_list.next;

+	pj_uint32_t total_used = 0, total_capacity = 0;

+        PJ_LOG(3,("cachpool", "  Dumping all active pools:"));

+	while (pool != (void*)&cp->used_list) {

+	    PJ_LOG(3,("cachpool", "   %12s: %8d of %8d (%d%%) used", pool->obj_name, 

+				  pool->used_size, pool->capacity,

+				  pool->used_size*100/pool->capacity));

+	    total_used += pool->used_size;

+	    total_capacity += pool->capacity;

+	    pool = pool->next;

+	}

+	PJ_LOG(3,("cachpool", "  Total %9d of %9d (%d %%) used!",

+			      total_used, total_capacity,

+			      total_used * 100 / total_capacity));

+    }

+#endif

+}

diff --git a/pjlib/src/pj/pool_dbg_win32.c b/pjlib/src/pj/pool_dbg_win32.c
index 9e451d7..33aa80d 100644
--- a/pjlib/src/pj/pool_dbg_win32.c
+++ b/pjlib/src/pj/pool_dbg_win32.c
@@ -1,221 +1,242 @@
-/* $Id$
- */
-#include <pj/pool.h>
-
-/* Only if we ARE debugging memory allocations. */
-#if PJ_POOL_DEBUG
-
-#include <pj/list.h>
-#include <pj/log.h>
-
-#include <stdlib.h>
-#include <stdio.h>
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-typedef struct memory_entry
-{
-    PJ_DECL_LIST_MEMBER(struct memory_entry)
-    void *ptr;
-    char *file;
-    int   line;
-} memory_entry;
-
-struct pj_pool_t
-{
-    char	    obj_name[32];
-    HANDLE	    hHeap;
-    memory_entry    first;
-    pj_size_t	    initial_size;
-    pj_size_t	    increment;
-    pj_size_t	    used_size;
-    char	   *file;
-    int		    line;
-};
-
-PJ_DEF(void) pj_pool_set_functions( void *(*malloc_func)(pj_size_t),
-				     void (*free_func)(void *ptr, pj_size_t))
-{
-    /* Ignored. */
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(malloc_func)
-    PJ_UNUSED_ARG(free_func)
-}
-
-PJ_DEF(pj_pool_t*) pj_pool_create_dbg( const char *name,
-				       pj_size_t initial_size, 
-				       pj_size_t increment_size,
-				       pj_pool_callback *callback,
-				       char *file, int line)
-{
-    pj_pool_t *pool;
-    HANDLE hHeap;
-
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(callback)
-
-    /* Create Win32 heap for the pool. */
-    hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
-		       initial_size, 0);
-    if (!hHeap) {
-	return NULL;
-    }
-
-
-    /* Create and initialize the pool structure. */
-    pool = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, 
-		     sizeof(*pool));
-    memset(pool, 0, sizeof(*pool));
-    pool->file = file;
-    pool->line = line;
-    pool->hHeap = hHeap;
-    pool->initial_size = initial_size;
-    pool->increment = increment_size;
-    pool->used_size = 0;
-
-    /* Set name. */
-    if (name) {
-	if (strchr(name, '%') != NULL) {
-	    sprintf(pool->obj_name, name, pool);
-	} else {
-	    strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
-	}
-    } else {
-	pool->obj_name[0] = '\0';
-    }
-
-    /* List pool's entry. */
-    pj_list_init(&pool->first);
-
-    PJ_LOG(3,(pool->obj_name, "Pool created"));
-    return pool;
-}
-
-PJ_DEF(void) pj_pool_destroy( pj_pool_t *pool )
-{
-    memory_entry *entry;
-
-    PJ_CHECK_STACK();
-
-    PJ_LOG(3,(pool->obj_name, "Destoying pool, init_size=%u, used=%u",
-			      pool->initial_size, pool->used_size));
-
-    if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, pool)) {
-	PJ_LOG(2,(pool->obj_name, "Corrupted pool structure, allocated in %s:%d", 
-		  pool->file, pool->line));
-    }
-
-    /* Validate all memory entries in the pool. */
-    for (entry=pool->first.next; entry != &pool->first; entry = entry->next) {
-	if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry)) {
-	    PJ_LOG(2,(pool->obj_name, "Corrupted pool entry, allocated in %s:%d", 
-		      entry->file, entry->line));
-	}
-
-	if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry->ptr)) {
-	    PJ_LOG(2,(pool->obj_name, "Corrupted pool memory, allocated in %s:%d", 
-		      entry->file, entry->line));
-	}
-    }
-
-    /* Destroy heap. */
-    HeapDestroy(pool->hHeap);
-}
-
-PJ_DEF(void) pj_pool_reset( pj_pool_t *pool )
-{
-    /* Do nothing. */
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool)
-}
-
-PJ_DEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool)
-    return 0;
-}
-
-PJ_DEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool)
-    return 0;
-}
-
-PJ_DEF(pj_size_t) pj_pool_get_request_count( pj_pool_t *pool )
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool)
-    return 0;
-}
-
-PJ_DEF(void*) pj_pool_alloc_dbg( pj_pool_t *pool, pj_size_t size, 
-				 char *file, int line)
-{
-    memory_entry *entry;
-    int entry_size;
-
-    PJ_CHECK_STACK();
-
-    entry_size = sizeof(*entry);
-    entry = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
-		      entry_size);
-    entry->file = file;
-    entry->line = line;
-    entry->ptr = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,
-			   size);
-    pj_list_insert_before( &pool->first, entry);
-
-    pool->used_size += size;
-    return entry->ptr;
-}
-
-PJ_DEF(void*) pj_pool_calloc_dbg( pj_pool_t *pool, pj_size_t count, pj_size_t elem,
-				  char *file, int line)
-{
-    void *ptr;
-
-    PJ_CHECK_STACK();
-
-    ptr = pj_pool_alloc_dbg(pool, count*elem, file, line);
-    memset(ptr, 0, count*elem);
-    return ptr;
-}
-
-
-PJ_DEF(void) pj_pool_pool_init( pj_pool_pool_t *pool_pool, 
-				 pj_size_t max_capacity)
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool_pool)
-    PJ_UNUSED_ARG(max_capacity)
-}
-
-PJ_DEF(void) pj_pool_pool_destroy( pj_pool_pool_t *pool_pool )
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool_pool)
-}
-
-PJ_DEF(pj_pool_t*) pj_pool_pool_create_pool( pj_pool_pool_t *pool_pool,
-					      const char *name,
-					      pj_size_t initial_size, 
-					      pj_size_t increment_size,
-					      pj_pool_callback *callback)
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool_pool)
-    return pj_pool_create(name, initial_size, increment_size, callback);
-}
-
-PJ_DEF(void) pj_pool_pool_release_pool( pj_pool_pool_t *pool_pool,
-					pj_pool_t *pool )
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool_pool)
-    pj_pool_destroy(pool);
-}
-
-
-#endif	/* PJ_POOL_DEBUG */
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/pool.h>

+

+/* Only if we ARE debugging memory allocations. */

+#if PJ_POOL_DEBUG

+

+#include <pj/list.h>

+#include <pj/log.h>

+

+#include <stdlib.h>

+#include <stdio.h>

+#define WIN32_LEAN_AND_MEAN

+#include <windows.h>

+

+typedef struct memory_entry

+{

+    PJ_DECL_LIST_MEMBER(struct memory_entry)

+    void *ptr;

+    char *file;

+    int   line;

+} memory_entry;

+

+struct pj_pool_t

+{

+    char	    obj_name[32];

+    HANDLE	    hHeap;

+    memory_entry    first;

+    pj_size_t	    initial_size;

+    pj_size_t	    increment;

+    pj_size_t	    used_size;

+    char	   *file;

+    int		    line;

+};

+

+PJ_DEF(void) pj_pool_set_functions( void *(*malloc_func)(pj_size_t),

+				     void (*free_func)(void *ptr, pj_size_t))

+{

+    /* Ignored. */

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(malloc_func)

+    PJ_UNUSED_ARG(free_func)

+}

+

+PJ_DEF(pj_pool_t*) pj_pool_create_dbg( const char *name,

+				       pj_size_t initial_size, 

+				       pj_size_t increment_size,

+				       pj_pool_callback *callback,

+				       char *file, int line)

+{

+    pj_pool_t *pool;

+    HANDLE hHeap;

+

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(callback)

+

+    /* Create Win32 heap for the pool. */

+    hHeap = HeapCreate(HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,

+		       initial_size, 0);

+    if (!hHeap) {

+	return NULL;

+    }

+

+

+    /* Create and initialize the pool structure. */

+    pool = HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE, 

+		     sizeof(*pool));

+    memset(pool, 0, sizeof(*pool));

+    pool->file = file;

+    pool->line = line;

+    pool->hHeap = hHeap;

+    pool->initial_size = initial_size;

+    pool->increment = increment_size;

+    pool->used_size = 0;

+

+    /* Set name. */

+    if (name) {

+	if (strchr(name, '%') != NULL) {

+	    sprintf(pool->obj_name, name, pool);

+	} else {

+	    strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);

+	}

+    } else {

+	pool->obj_name[0] = '\0';

+    }

+

+    /* List pool's entry. */

+    pj_list_init(&pool->first);

+

+    PJ_LOG(3,(pool->obj_name, "Pool created"));

+    return pool;

+}

+

+PJ_DEF(void) pj_pool_destroy( pj_pool_t *pool )

+{

+    memory_entry *entry;

+

+    PJ_CHECK_STACK();

+

+    PJ_LOG(3,(pool->obj_name, "Destoying pool, init_size=%u, used=%u",

+			      pool->initial_size, pool->used_size));

+

+    if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, pool)) {

+	PJ_LOG(2,(pool->obj_name, "Corrupted pool structure, allocated in %s:%d", 

+		  pool->file, pool->line));

+    }

+

+    /* Validate all memory entries in the pool. */

+    for (entry=pool->first.next; entry != &pool->first; entry = entry->next) {

+	if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry)) {

+	    PJ_LOG(2,(pool->obj_name, "Corrupted pool entry, allocated in %s:%d", 

+		      entry->file, entry->line));

+	}

+

+	if (!HeapValidate( pool->hHeap, HEAP_NO_SERIALIZE, entry->ptr)) {

+	    PJ_LOG(2,(pool->obj_name, "Corrupted pool memory, allocated in %s:%d", 

+		      entry->file, entry->line));

+	}

+    }

+

+    /* Destroy heap. */

+    HeapDestroy(pool->hHeap);

+}

+

+PJ_DEF(void) pj_pool_reset( pj_pool_t *pool )

+{

+    /* Do nothing. */

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool)

+}

+

+PJ_DEF(pj_size_t) pj_pool_get_capacity( pj_pool_t *pool )

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool)

+    return 0;

+}

+

+PJ_DEF(pj_size_t) pj_pool_get_used_size( pj_pool_t *pool )

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool)

+    return 0;

+}

+

+PJ_DEF(pj_size_t) pj_pool_get_request_count( pj_pool_t *pool )

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool)

+    return 0;

+}

+

+PJ_DEF(void*) pj_pool_alloc_dbg( pj_pool_t *pool, pj_size_t size, 

+				 char *file, int line)

+{

+    memory_entry *entry;

+    int entry_size;

+

+    PJ_CHECK_STACK();

+

+    entry_size = sizeof(*entry);

+    entry = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,

+		      entry_size);

+    entry->file = file;

+    entry->line = line;

+    entry->ptr = HeapAlloc(pool->hHeap, HEAP_GENERATE_EXCEPTIONS|HEAP_NO_SERIALIZE,

+			   size);

+    pj_list_insert_before( &pool->first, entry);

+

+    pool->used_size += size;

+    return entry->ptr;

+}

+

+PJ_DEF(void*) pj_pool_calloc_dbg( pj_pool_t *pool, pj_size_t count, pj_size_t elem,

+				  char *file, int line)

+{

+    void *ptr;

+

+    PJ_CHECK_STACK();

+

+    ptr = pj_pool_alloc_dbg(pool, count*elem, file, line);

+    memset(ptr, 0, count*elem);

+    return ptr;

+}

+

+

+PJ_DEF(void) pj_pool_pool_init( pj_pool_pool_t *pool_pool, 

+				 pj_size_t max_capacity)

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool_pool)

+    PJ_UNUSED_ARG(max_capacity)

+}

+

+PJ_DEF(void) pj_pool_pool_destroy( pj_pool_pool_t *pool_pool )

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool_pool)

+}

+

+PJ_DEF(pj_pool_t*) pj_pool_pool_create_pool( pj_pool_pool_t *pool_pool,

+					      const char *name,

+					      pj_size_t initial_size, 

+					      pj_size_t increment_size,

+					      pj_pool_callback *callback)

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool_pool)

+    return pj_pool_create(name, initial_size, increment_size, callback);

+}

+

+PJ_DEF(void) pj_pool_pool_release_pool( pj_pool_pool_t *pool_pool,

+					pj_pool_t *pool )

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool_pool)

+    pj_pool_destroy(pool);

+}

+

+

+#endif	/* PJ_POOL_DEBUG */

diff --git a/pjlib/src/pj/pool_policy_kmalloc.c b/pjlib/src/pj/pool_policy_kmalloc.c
index 267f72f..6b40d31 100644
--- a/pjlib/src/pj/pool_policy_kmalloc.c
+++ b/pjlib/src/pj/pool_policy_kmalloc.c
@@ -1,43 +1,64 @@
-/* $Id$
- *
- */
-#include <pj/pool.h>
-#include <pj/except.h>
-#include <pj/os.h>
-
-
-static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(factory);
-
-    return kmalloc(size, GFP_ATOMIC);
-}
-
-static void default_block_free(pj_pool_factory *factory, 
-			       void *mem, pj_size_t size)
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(factory);
-    PJ_UNUSED_ARG(size);
-
-    kfree(mem);
-}
-
-static void default_pool_callback(pj_pool_t *pool, pj_size_t size)
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool);
-    PJ_UNUSED_ARG(size);
-
-    PJ_THROW(PJ_NO_MEMORY_EXCEPTION);
-}
-
-pj_pool_factory_policy pj_pool_factory_default_policy = 
-{
-    &default_block_alloc,
-    &default_block_free,
-    &default_pool_callback,
-    0
-};
-
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/pool.h>

+#include <pj/except.h>

+#include <pj/os.h>

+

+

+static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(factory);

+

+    return kmalloc(size, GFP_ATOMIC);

+}

+

+static void default_block_free(pj_pool_factory *factory, 

+			       void *mem, pj_size_t size)

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(factory);

+    PJ_UNUSED_ARG(size);

+

+    kfree(mem);

+}

+

+static void default_pool_callback(pj_pool_t *pool, pj_size_t size)

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool);

+    PJ_UNUSED_ARG(size);

+

+    PJ_THROW(PJ_NO_MEMORY_EXCEPTION);

+}

+

+pj_pool_factory_policy pj_pool_factory_default_policy = 

+{

+    &default_block_alloc,

+    &default_block_free,

+    &default_pool_callback,

+    0

+};

+

diff --git a/pjlib/src/pj/pool_policy_malloc.c b/pjlib/src/pj/pool_policy_malloc.c
index bb82cbb..4baf98b 100644
--- a/pjlib/src/pj/pool_policy_malloc.c
+++ b/pjlib/src/pj/pool_policy_malloc.c
@@ -1,46 +1,67 @@
-/* $Id$
- */
-#include <pj/pool.h>
-#include <pj/except.h>
-#include <pj/os.h>
-#include <pj/compat/malloc.h>
-
-/*
- * This file contains pool default policy definition and implementation.
- */
-
-
-static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(factory);
-    PJ_UNUSED_ARG(size);
-
-    return malloc(size);
-}
-
-static void default_block_free(pj_pool_factory *factory, void *mem, pj_size_t size)
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(factory);
-    PJ_UNUSED_ARG(size);
-
-    free(mem);
-}
-
-static void default_pool_callback(pj_pool_t *pool, pj_size_t size)
-{
-    PJ_CHECK_STACK();
-    PJ_UNUSED_ARG(pool);
-    PJ_UNUSED_ARG(size);
-
-    PJ_THROW(PJ_NO_MEMORY_EXCEPTION);
-}
-
-pj_pool_factory_policy pj_pool_factory_default_policy = 
-{
-    &default_block_alloc,
-    &default_block_free,
-    &default_pool_callback,
-    0
-};
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/pool.h>

+#include <pj/except.h>

+#include <pj/os.h>

+#include <pj/compat/malloc.h>

+

+/*

+ * This file contains pool default policy definition and implementation.

+ */

+

+

+static void *default_block_alloc(pj_pool_factory *factory, pj_size_t size)

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(factory);

+    PJ_UNUSED_ARG(size);

+

+    return malloc(size);

+}

+

+static void default_block_free(pj_pool_factory *factory, void *mem, pj_size_t size)

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(factory);

+    PJ_UNUSED_ARG(size);

+

+    free(mem);

+}

+

+static void default_pool_callback(pj_pool_t *pool, pj_size_t size)

+{

+    PJ_CHECK_STACK();

+    PJ_UNUSED_ARG(pool);

+    PJ_UNUSED_ARG(size);

+

+    PJ_THROW(PJ_NO_MEMORY_EXCEPTION);

+}

+

+pj_pool_factory_policy pj_pool_factory_default_policy = 

+{

+    &default_block_alloc,

+    &default_block_free,

+    &default_pool_callback,

+    0

+};

diff --git a/pjlib/src/pj/rand.c b/pjlib/src/pj/rand.c
index a8a2878..df549d5 100644
--- a/pjlib/src/pj/rand.c
+++ b/pjlib/src/pj/rand.c
@@ -1,18 +1,39 @@
-/* $Id$
- */
-#include <pj/rand.h>
-#include <pj/os.h>
-#include <pj/compat/rand.h>
-
-PJ_DEF(void) pj_srand(unsigned int seed)
-{
-    PJ_CHECK_STACK();
-    platform_srand(seed);
-}
-
-PJ_DEF(int) pj_rand(void)
-{
-    PJ_CHECK_STACK();
-    return platform_rand();
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/rand.h>

+#include <pj/os.h>

+#include <pj/compat/rand.h>

+

+PJ_DEF(void) pj_srand(unsigned int seed)

+{

+    PJ_CHECK_STACK();

+    platform_srand(seed);

+}

+

+PJ_DEF(int) pj_rand(void)

+{

+    PJ_CHECK_STACK();

+    return platform_rand();

+}

+

diff --git a/pjlib/src/pj/rbtree.c b/pjlib/src/pj/rbtree.c
index a0babe0..2f548c2 100644
--- a/pjlib/src/pj/rbtree.c
+++ b/pjlib/src/pj/rbtree.c
@@ -1,411 +1,432 @@
-/* $Id$
- */
-#include <pj/rbtree.h>
-#include <pj/os.h>
-
-static void left_rotate( pj_rbtree *tree, pj_rbtree_node *node ) 
-{
-    pj_rbtree_node *rnode, *parent;
-
-    PJ_CHECK_STACK();
-
-    rnode = node->right;
-    if (rnode == tree->null)
-        return;
-    
-    node->right = rnode->left;
-    if (rnode->left != tree->null)
-        rnode->left->parent = node;
-    parent = node->parent;
-    rnode->parent = parent;
-    if (parent != tree->null) {
-        if (parent->left == node)
-	   parent->left = rnode;
-        else
-	   parent->right = rnode;
-    } else {
-        tree->root = rnode;
-    }
-    rnode->left = node;
-    node->parent = rnode;
-}
-
-static void right_rotate( pj_rbtree *tree, pj_rbtree_node *node ) 
-{
-    pj_rbtree_node *lnode, *parent;
-
-    PJ_CHECK_STACK();
-
-    lnode = node->left;
-    if (lnode == tree->null)
-        return;
-
-    node->left = lnode->right;
-    if (lnode->right != tree->null)
-	lnode->right->parent = node;
-    parent = node->parent;
-    lnode->parent = parent;
-
-    if (parent != tree->null) {
-        if (parent->left == node)
-	    parent->left = lnode;
-	else
-	    parent->right = lnode;
-    } else {
-        tree->root = lnode;
-    }
-    lnode->right = node;
-    node->parent = lnode;
-}
-
-static void insert_fixup( pj_rbtree *tree, pj_rbtree_node *node ) 
-{
-    pj_rbtree_node *temp, *parent;
-
-    PJ_CHECK_STACK();
-
-    while (node != tree->root && node->parent->color == PJ_RBCOLOR_RED) {
-        parent = node->parent;
-        if (parent == parent->parent->left) {
-	    temp = parent->parent->right;
-	    if (temp->color == PJ_RBCOLOR_RED) {
-	        temp->color = PJ_RBCOLOR_BLACK;
-	        node = parent;
-	        node->color = PJ_RBCOLOR_BLACK;
-	        node = node->parent;
-	        node->color = PJ_RBCOLOR_RED;
-	    } else {
-	        if (node == parent->right) {
-		   node = parent;
-		   left_rotate(tree, node);
-	        }
-	        temp = node->parent;
-	        temp->color = PJ_RBCOLOR_BLACK;
-	        temp = temp->parent;
-	        temp->color = PJ_RBCOLOR_RED;
-	        right_rotate( tree, temp);
-	    }
-        } else {
-	    temp = parent->parent->left;
-	    if (temp->color == PJ_RBCOLOR_RED) {
-	        temp->color = PJ_RBCOLOR_BLACK;
-	        node = parent;
-	        node->color = PJ_RBCOLOR_BLACK;
-	        node = node->parent;
-	        node->color = PJ_RBCOLOR_RED;
-	    } else {
-	        if (node == parent->left) {
-		    node = parent;
-		    right_rotate(tree, node);
-	        }
-	        temp = node->parent;
-	        temp->color = PJ_RBCOLOR_BLACK;
-	        temp = temp->parent;
-	        temp->color = PJ_RBCOLOR_RED;
-	        left_rotate(tree, temp);
-	   }
-        }
-    }
-	
-    tree->root->color = PJ_RBCOLOR_BLACK;
-}
-
-
-static void delete_fixup( pj_rbtree *tree, pj_rbtree_node *node )
-{
-    pj_rbtree_node *temp;
-
-    PJ_CHECK_STACK();
-
-    while (node != tree->root && node->color == PJ_RBCOLOR_BLACK) {
-        if (node->parent->left == node) {
-	    temp = node->parent->right;
-	    if (temp->color == PJ_RBCOLOR_RED) {
-	        temp->color = PJ_RBCOLOR_BLACK;
-	        node->parent->color = PJ_RBCOLOR_RED;
-	        left_rotate(tree, node->parent);
-	        temp = node->parent->right;
-	    }
-	    if (temp->left->color == PJ_RBCOLOR_BLACK && 
-	        temp->right->color == PJ_RBCOLOR_BLACK) 
-	    {
-	        temp->color = PJ_RBCOLOR_RED;
-	        node = node->parent;
-	    } else {
-	        if (temp->right->color == PJ_RBCOLOR_BLACK) {
-		    temp->left->color = PJ_RBCOLOR_BLACK;
-		    temp->color = PJ_RBCOLOR_RED;
-		    right_rotate( tree, temp);
-		    temp = node->parent->right;
-	        }
-	        temp->color = node->parent->color;
-	        temp->right->color = PJ_RBCOLOR_BLACK;
-	        node->parent->color = PJ_RBCOLOR_BLACK;
-	        left_rotate(tree, node->parent);
-	        node = tree->root;
-	    }
-        } else {
-	    temp = node->parent->left;
-	    if (temp->color == PJ_RBCOLOR_RED) {
-	        temp->color = PJ_RBCOLOR_BLACK;
-	        node->parent->color = PJ_RBCOLOR_RED;
-	        right_rotate( tree, node->parent);
-	        temp = node->parent->left;
-	    }
-	    if (temp->right->color == PJ_RBCOLOR_BLACK && 
-		temp->left->color == PJ_RBCOLOR_BLACK) 
-	    {
-	        temp->color = PJ_RBCOLOR_RED;
-	        node = node->parent;
-	    } else {
-	        if (temp->left->color == PJ_RBCOLOR_BLACK) {
-		    temp->right->color = PJ_RBCOLOR_BLACK;
-		    temp->color = PJ_RBCOLOR_RED;
-		    left_rotate( tree, temp);
-		    temp = node->parent->left;
-	        }
-	        temp->color = node->parent->color;
-	        node->parent->color = PJ_RBCOLOR_BLACK;
-	        temp->left->color = PJ_RBCOLOR_BLACK;
-	        right_rotate(tree, node->parent);
-	        node = tree->root;
-	    }
-        }
-    }
-	
-    node->color = PJ_RBCOLOR_BLACK;
-}
-
-
-PJ_DEF(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp )
-{
-    PJ_CHECK_STACK();
-
-    tree->null = tree->root = &tree->null_node;
-    tree->null->key = NULL;
-    tree->null->user_data = NULL;
-    tree->size = 0;
-    tree->null->left = tree->null->right = tree->null->parent = tree->null;
-    tree->null->color = PJ_RBCOLOR_BLACK;
-    tree->comp = comp;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree )
-{
-    register pj_rbtree_node *node = tree->root;
-    register pj_rbtree_node *null = tree->null;
-    
-    PJ_CHECK_STACK();
-
-    while (node->left != null)
-	node = node->left;
-    return node != null ? node : NULL;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree )
-{
-    register pj_rbtree_node *node = tree->root;
-    register pj_rbtree_node *null = tree->null;
-    
-    PJ_CHECK_STACK();
-
-    while (node->right != null)
-	node = node->right;
-    return node != null ? node : NULL;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, 
-					register pj_rbtree_node *node )
-{
-    register pj_rbtree_node *null = tree->null;
-    
-    PJ_CHECK_STACK();
-
-    if (node->right != null) {
-	for (node=node->right; node->left!=null; node = node->left)
-	    /* void */;
-    } else {
-        register pj_rbtree_node *temp = node->parent;
-        while (temp!=null && temp->right==node) {
-	    node = temp;
-	    temp = temp->parent;
-	}
-	node = temp;
-    }    
-    return node != null ? node : NULL;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, 
-					register pj_rbtree_node *node )
-{
-    register pj_rbtree_node *null = tree->null;
-    
-    PJ_CHECK_STACK();
-
-    if (node->left != null) {
-        for (node=node->left; node->right!=null; node=node->right)
-	   /* void */;
-    } else {
-        register pj_rbtree_node *temp = node->parent;
-        while (temp!=null && temp->left==node) {
-	    node = temp;
-	    temp = temp->parent;
-        }
-        node = temp;
-    }    
-    return node != null ? node : NULL;
-}
-
-PJ_DEF(int) pj_rbtree_insert( pj_rbtree *tree, 
-			      pj_rbtree_node *element )
-{
-    int rv = 0;
-    pj_rbtree_node *node, *parent = tree->null, 
-		   *null = tree->null;
-    pj_rbtree_comp *comp = tree->comp;
-	
-    PJ_CHECK_STACK();
-
-    node = tree->root;	
-    while (node != null) {
-        rv = (*comp)(element->key, node->key);
-        if (rv == 0) {
-	    /* found match, i.e. entry with equal key already exist */
-	    return -1;
-	}    
-	parent = node;
-        node = rv < 0 ? node->left : node->right;
-    }
-
-    element->color = PJ_RBCOLOR_RED;
-    element->left = element->right = null;
-
-    node = element;
-    if (parent != null) {
-        node->parent = parent;
-        if (rv < 0)
-	   parent->left = node;
-        else
-	   parent->right = node;
-        insert_fixup( tree, node);
-    } else {
-        tree->root = node;
-        node->parent = null;
-        node->color = PJ_RBCOLOR_BLACK;
-    }
-	
-    ++tree->size;
-    return 0;
-}
-
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,
-					const void *key )
-{
-    int rv;
-    pj_rbtree_node *node = tree->root;
-    pj_rbtree_node *null = tree->null;
-    pj_rbtree_comp *comp = tree->comp;
-    
-    while (node != null) {
-        rv = (*comp)(key, node->key);
-        if (rv == 0)
-	    return node;
-        node = rv < 0 ? node->left : node->right;
-    }
-    return node != null ? node : NULL;
-}
-
-PJ_DEF(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,
-					 pj_rbtree_node *node )
-{
-    pj_rbtree_node *succ;
-    pj_rbtree_node *null = tree->null;
-    pj_rbtree_node *child;
-    pj_rbtree_node *parent;
-    
-    PJ_CHECK_STACK();
-
-    if (node->left == null || node->right == null) {
-        succ = node;
-    } else {
-        for (succ=node->right; succ->left!=null; succ=succ->left)
-	   /* void */;
-    }
-
-    child = succ->left != null ? succ->left : succ->right;
-    parent = succ->parent;
-    child->parent = parent;
-    
-    if (parent != null) {
-	if (parent->left == succ)
-	    parent->left = child;
-        else
-	   parent->right = child;
-    } else
-        tree->root = child;
-
-    if (succ != node) {
-        succ->parent = node->parent;
-        succ->left = node->left;
-        succ->right = node->right;
-        succ->color = node->color;
-
-        parent = node->parent;
-        if (parent != null) {
-	   if (parent->left==node)
-	        parent->left=succ;
-	   else
-		parent->right=succ;
-        }
-        if (node->left != null)
-	   node->left->parent = succ;;
-        if (node->right != null)
-	    node->right->parent = succ;
-
-        if (tree->root == node)
-	   tree->root = succ;
-    }
-
-    if (succ->color == PJ_RBCOLOR_BLACK) {
-	if (child != null) 
-	    delete_fixup(tree, child);
-        tree->null->color = PJ_RBCOLOR_BLACK;
-    }
-
-    --tree->size;
-    return node;
-}
-
-
-PJ_DEF(unsigned) pj_rbtree_max_height( pj_rbtree *tree,
-				       pj_rbtree_node *node )
-{
-    unsigned l, r;
-    
-    PJ_CHECK_STACK();
-
-    if (node==NULL) 
-	node = tree->root;
-    
-    l = node->left != tree->null ? pj_rbtree_max_height(tree,node->left)+1 : 0;
-    r = node->right != tree->null ? pj_rbtree_max_height(tree,node->right)+1 : 0;
-    return l > r ? l : r;
-}
-
-PJ_DEF(unsigned) pj_rbtree_min_height( pj_rbtree *tree,
-				       pj_rbtree_node *node )
-{
-    unsigned l, r;
-    
-    PJ_CHECK_STACK();
-
-    if (node==NULL) 
-	node=tree->root;
-    
-    l = (node->left != tree->null) ? pj_rbtree_max_height(tree,node->left)+1 : 0;
-    r = (node->right != tree->null) ? pj_rbtree_max_height(tree,node->right)+1 : 0;
-    return l > r ? r : l;
-}
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/rbtree.h>

+#include <pj/os.h>

+

+static void left_rotate( pj_rbtree *tree, pj_rbtree_node *node ) 

+{

+    pj_rbtree_node *rnode, *parent;

+

+    PJ_CHECK_STACK();

+

+    rnode = node->right;

+    if (rnode == tree->null)

+        return;

+    

+    node->right = rnode->left;

+    if (rnode->left != tree->null)

+        rnode->left->parent = node;

+    parent = node->parent;

+    rnode->parent = parent;

+    if (parent != tree->null) {

+        if (parent->left == node)

+	   parent->left = rnode;

+        else

+	   parent->right = rnode;

+    } else {

+        tree->root = rnode;

+    }

+    rnode->left = node;

+    node->parent = rnode;

+}

+

+static void right_rotate( pj_rbtree *tree, pj_rbtree_node *node ) 

+{

+    pj_rbtree_node *lnode, *parent;

+

+    PJ_CHECK_STACK();

+

+    lnode = node->left;

+    if (lnode == tree->null)

+        return;

+

+    node->left = lnode->right;

+    if (lnode->right != tree->null)

+	lnode->right->parent = node;

+    parent = node->parent;

+    lnode->parent = parent;

+

+    if (parent != tree->null) {

+        if (parent->left == node)

+	    parent->left = lnode;

+	else

+	    parent->right = lnode;

+    } else {

+        tree->root = lnode;

+    }

+    lnode->right = node;

+    node->parent = lnode;

+}

+

+static void insert_fixup( pj_rbtree *tree, pj_rbtree_node *node ) 

+{

+    pj_rbtree_node *temp, *parent;

+

+    PJ_CHECK_STACK();

+

+    while (node != tree->root && node->parent->color == PJ_RBCOLOR_RED) {

+        parent = node->parent;

+        if (parent == parent->parent->left) {

+	    temp = parent->parent->right;

+	    if (temp->color == PJ_RBCOLOR_RED) {

+	        temp->color = PJ_RBCOLOR_BLACK;

+	        node = parent;

+	        node->color = PJ_RBCOLOR_BLACK;

+	        node = node->parent;

+	        node->color = PJ_RBCOLOR_RED;

+	    } else {

+	        if (node == parent->right) {

+		   node = parent;

+		   left_rotate(tree, node);

+	        }

+	        temp = node->parent;

+	        temp->color = PJ_RBCOLOR_BLACK;

+	        temp = temp->parent;

+	        temp->color = PJ_RBCOLOR_RED;

+	        right_rotate( tree, temp);

+	    }

+        } else {

+	    temp = parent->parent->left;

+	    if (temp->color == PJ_RBCOLOR_RED) {

+	        temp->color = PJ_RBCOLOR_BLACK;

+	        node = parent;

+	        node->color = PJ_RBCOLOR_BLACK;

+	        node = node->parent;

+	        node->color = PJ_RBCOLOR_RED;

+	    } else {

+	        if (node == parent->left) {

+		    node = parent;

+		    right_rotate(tree, node);

+	        }

+	        temp = node->parent;

+	        temp->color = PJ_RBCOLOR_BLACK;

+	        temp = temp->parent;

+	        temp->color = PJ_RBCOLOR_RED;

+	        left_rotate(tree, temp);

+	   }

+        }

+    }

+	

+    tree->root->color = PJ_RBCOLOR_BLACK;

+}

+

+

+static void delete_fixup( pj_rbtree *tree, pj_rbtree_node *node )

+{

+    pj_rbtree_node *temp;

+

+    PJ_CHECK_STACK();

+

+    while (node != tree->root && node->color == PJ_RBCOLOR_BLACK) {

+        if (node->parent->left == node) {

+	    temp = node->parent->right;

+	    if (temp->color == PJ_RBCOLOR_RED) {

+	        temp->color = PJ_RBCOLOR_BLACK;

+	        node->parent->color = PJ_RBCOLOR_RED;

+	        left_rotate(tree, node->parent);

+	        temp = node->parent->right;

+	    }

+	    if (temp->left->color == PJ_RBCOLOR_BLACK && 

+	        temp->right->color == PJ_RBCOLOR_BLACK) 

+	    {

+	        temp->color = PJ_RBCOLOR_RED;

+	        node = node->parent;

+	    } else {

+	        if (temp->right->color == PJ_RBCOLOR_BLACK) {

+		    temp->left->color = PJ_RBCOLOR_BLACK;

+		    temp->color = PJ_RBCOLOR_RED;

+		    right_rotate( tree, temp);

+		    temp = node->parent->right;

+	        }

+	        temp->color = node->parent->color;

+	        temp->right->color = PJ_RBCOLOR_BLACK;

+	        node->parent->color = PJ_RBCOLOR_BLACK;

+	        left_rotate(tree, node->parent);

+	        node = tree->root;

+	    }

+        } else {

+	    temp = node->parent->left;

+	    if (temp->color == PJ_RBCOLOR_RED) {

+	        temp->color = PJ_RBCOLOR_BLACK;

+	        node->parent->color = PJ_RBCOLOR_RED;

+	        right_rotate( tree, node->parent);

+	        temp = node->parent->left;

+	    }

+	    if (temp->right->color == PJ_RBCOLOR_BLACK && 

+		temp->left->color == PJ_RBCOLOR_BLACK) 

+	    {

+	        temp->color = PJ_RBCOLOR_RED;

+	        node = node->parent;

+	    } else {

+	        if (temp->left->color == PJ_RBCOLOR_BLACK) {

+		    temp->right->color = PJ_RBCOLOR_BLACK;

+		    temp->color = PJ_RBCOLOR_RED;

+		    left_rotate( tree, temp);

+		    temp = node->parent->left;

+	        }

+	        temp->color = node->parent->color;

+	        node->parent->color = PJ_RBCOLOR_BLACK;

+	        temp->left->color = PJ_RBCOLOR_BLACK;

+	        right_rotate(tree, node->parent);

+	        node = tree->root;

+	    }

+        }

+    }

+	

+    node->color = PJ_RBCOLOR_BLACK;

+}

+

+

+PJ_DEF(void) pj_rbtree_init( pj_rbtree *tree, pj_rbtree_comp *comp )

+{

+    PJ_CHECK_STACK();

+

+    tree->null = tree->root = &tree->null_node;

+    tree->null->key = NULL;

+    tree->null->user_data = NULL;

+    tree->size = 0;

+    tree->null->left = tree->null->right = tree->null->parent = tree->null;

+    tree->null->color = PJ_RBCOLOR_BLACK;

+    tree->comp = comp;

+}

+

+PJ_DEF(pj_rbtree_node*) pj_rbtree_first( pj_rbtree *tree )

+{

+    register pj_rbtree_node *node = tree->root;

+    register pj_rbtree_node *null = tree->null;

+    

+    PJ_CHECK_STACK();

+

+    while (node->left != null)

+	node = node->left;

+    return node != null ? node : NULL;

+}

+

+PJ_DEF(pj_rbtree_node*) pj_rbtree_last( pj_rbtree *tree )

+{

+    register pj_rbtree_node *node = tree->root;

+    register pj_rbtree_node *null = tree->null;

+    

+    PJ_CHECK_STACK();

+

+    while (node->right != null)

+	node = node->right;

+    return node != null ? node : NULL;

+}

+

+PJ_DEF(pj_rbtree_node*) pj_rbtree_next( pj_rbtree *tree, 

+					register pj_rbtree_node *node )

+{

+    register pj_rbtree_node *null = tree->null;

+    

+    PJ_CHECK_STACK();

+

+    if (node->right != null) {

+	for (node=node->right; node->left!=null; node = node->left)

+	    /* void */;

+    } else {

+        register pj_rbtree_node *temp = node->parent;

+        while (temp!=null && temp->right==node) {

+	    node = temp;

+	    temp = temp->parent;

+	}

+	node = temp;

+    }    

+    return node != null ? node : NULL;

+}

+

+PJ_DEF(pj_rbtree_node*) pj_rbtree_prev( pj_rbtree *tree, 

+					register pj_rbtree_node *node )

+{

+    register pj_rbtree_node *null = tree->null;

+    

+    PJ_CHECK_STACK();

+

+    if (node->left != null) {

+        for (node=node->left; node->right!=null; node=node->right)

+	   /* void */;

+    } else {

+        register pj_rbtree_node *temp = node->parent;

+        while (temp!=null && temp->left==node) {

+	    node = temp;

+	    temp = temp->parent;

+        }

+        node = temp;

+    }    

+    return node != null ? node : NULL;

+}

+

+PJ_DEF(int) pj_rbtree_insert( pj_rbtree *tree, 

+			      pj_rbtree_node *element )

+{

+    int rv = 0;

+    pj_rbtree_node *node, *parent = tree->null, 

+		   *null = tree->null;

+    pj_rbtree_comp *comp = tree->comp;

+	

+    PJ_CHECK_STACK();

+

+    node = tree->root;	

+    while (node != null) {

+        rv = (*comp)(element->key, node->key);

+        if (rv == 0) {

+	    /* found match, i.e. entry with equal key already exist */

+	    return -1;

+	}    

+	parent = node;

+        node = rv < 0 ? node->left : node->right;

+    }

+

+    element->color = PJ_RBCOLOR_RED;

+    element->left = element->right = null;

+

+    node = element;

+    if (parent != null) {

+        node->parent = parent;

+        if (rv < 0)

+	   parent->left = node;

+        else

+	   parent->right = node;

+        insert_fixup( tree, node);

+    } else {

+        tree->root = node;

+        node->parent = null;

+        node->color = PJ_RBCOLOR_BLACK;

+    }

+	

+    ++tree->size;

+    return 0;

+}

+

+

+PJ_DEF(pj_rbtree_node*) pj_rbtree_find( pj_rbtree *tree,

+					const void *key )

+{

+    int rv;

+    pj_rbtree_node *node = tree->root;

+    pj_rbtree_node *null = tree->null;

+    pj_rbtree_comp *comp = tree->comp;

+    

+    while (node != null) {

+        rv = (*comp)(key, node->key);

+        if (rv == 0)

+	    return node;

+        node = rv < 0 ? node->left : node->right;

+    }

+    return node != null ? node : NULL;

+}

+

+PJ_DEF(pj_rbtree_node*) pj_rbtree_erase( pj_rbtree *tree,

+					 pj_rbtree_node *node )

+{

+    pj_rbtree_node *succ;

+    pj_rbtree_node *null = tree->null;

+    pj_rbtree_node *child;

+    pj_rbtree_node *parent;

+    

+    PJ_CHECK_STACK();

+

+    if (node->left == null || node->right == null) {

+        succ = node;

+    } else {

+        for (succ=node->right; succ->left!=null; succ=succ->left)

+	   /* void */;

+    }

+

+    child = succ->left != null ? succ->left : succ->right;

+    parent = succ->parent;

+    child->parent = parent;

+    

+    if (parent != null) {

+	if (parent->left == succ)

+	    parent->left = child;

+        else

+	   parent->right = child;

+    } else

+        tree->root = child;

+

+    if (succ != node) {

+        succ->parent = node->parent;

+        succ->left = node->left;

+        succ->right = node->right;

+        succ->color = node->color;

+

+        parent = node->parent;

+        if (parent != null) {

+	   if (parent->left==node)

+	        parent->left=succ;

+	   else

+		parent->right=succ;

+        }

+        if (node->left != null)

+	   node->left->parent = succ;;

+        if (node->right != null)

+	    node->right->parent = succ;

+

+        if (tree->root == node)

+	   tree->root = succ;

+    }

+

+    if (succ->color == PJ_RBCOLOR_BLACK) {

+	if (child != null) 

+	    delete_fixup(tree, child);

+        tree->null->color = PJ_RBCOLOR_BLACK;

+    }

+

+    --tree->size;

+    return node;

+}

+

+

+PJ_DEF(unsigned) pj_rbtree_max_height( pj_rbtree *tree,

+				       pj_rbtree_node *node )

+{

+    unsigned l, r;

+    

+    PJ_CHECK_STACK();

+

+    if (node==NULL) 

+	node = tree->root;

+    

+    l = node->left != tree->null ? pj_rbtree_max_height(tree,node->left)+1 : 0;

+    r = node->right != tree->null ? pj_rbtree_max_height(tree,node->right)+1 : 0;

+    return l > r ? l : r;

+}

+

+PJ_DEF(unsigned) pj_rbtree_min_height( pj_rbtree *tree,

+				       pj_rbtree_node *node )

+{

+    unsigned l, r;

+    

+    PJ_CHECK_STACK();

+

+    if (node==NULL) 

+	node=tree->root;

+    

+    l = (node->left != tree->null) ? pj_rbtree_max_height(tree,node->left)+1 : 0;

+    r = (node->right != tree->null) ? pj_rbtree_max_height(tree,node->right)+1 : 0;

+    return l > r ? r : l;

+}

+

+

diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c
index 8f1fa1d..1904a2e 100644
--- a/pjlib/src/pj/sock_bsd.c
+++ b/pjlib/src/pj/sock_bsd.c
@@ -1,568 +1,589 @@
-/* $Id$
- */
-#include <pj/sock.h>
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/string.h>
-#include <pj/compat/socket.h>
-#include <pj/addr_resolv.h>
-#include <pj/errno.h>
-
-/*
- * Address families conversion.
- * The values here are indexed based on pj_addr_family-0xFF00.
- */
-const pj_uint16_t PJ_AF_UNIX	= AF_UNIX;
-const pj_uint16_t PJ_AF_INET	= AF_INET;
-const pj_uint16_t PJ_AF_INET6	= AF_INET6;
-#ifdef AF_PACKET
-const pj_uint16_t PJ_AF_PACKET	= AF_PACKET;
-#else
-const pj_uint16_t PJ_AF_PACKET	= 0xFFFF;
-#endif
-#ifdef AF_IRDA
-const pj_uint16_t PJ_AF_IRDA	= AF_IRDA;
-#else
-const pj_uint16_t PJ_AF_IRDA	= 0xFFFF;
-#endif
-
-/*
- * Socket types conversion.
- * The values here are indexed based on pj_sock_type-0xFF00
- */
-const pj_uint16_t PJ_SOCK_STREAM	= SOCK_STREAM;
-const pj_uint16_t PJ_SOCK_DGRAM	= SOCK_DGRAM;
-const pj_uint16_t PJ_SOCK_RAW	= SOCK_RAW;
-const pj_uint16_t PJ_SOCK_RDM	= SOCK_RDM;
-
-/*
- * Socket level values.
- */
-const pj_uint16_t PJ_SOL_SOCKET	= SOL_SOCKET;
-#ifdef SOL_IP
-const pj_uint16_t PJ_SOL_IP	= SOL_IP;
-#else
-const pj_uint16_t PJ_SOL_IP	= 0xFFFF;
-#endif /* SOL_IP */
-#if defined(SOL_TCP)
-const pj_uint16_t PJ_SOL_TCP	= SOL_TCP;
-#elif defined(IPPROTO_TCP)
-const pj_uint16_t PJ_SOL_TCP	= IPPROTO_TCP;
-#endif /* SOL_TCP */
-#ifdef SOL_UDP
-const pj_uint16_t PJ_SOL_UDP	= SOL_UDP;
-#else
-const pj_uint16_t PJ_SOL_UDP	= 0xFFFF;
-#endif
-#ifdef SOL_IPV6
-const pj_uint16_t PJ_SOL_IPV6	= SOL_IPV6;
-#else
-const pj_uint16_t PJ_SOL_IPV6	= 0xFFFF;
-#endif
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/sock.h>

+#include <pj/os.h>

+#include <pj/assert.h>

+#include <pj/string.h>

+#include <pj/compat/socket.h>

+#include <pj/addr_resolv.h>

+#include <pj/errno.h>

 

-/* optname values. */
+/*

+ * Address families conversion.

+ * The values here are indexed based on pj_addr_family-0xFF00.

+ */

+const pj_uint16_t PJ_AF_UNIX	= AF_UNIX;

+const pj_uint16_t PJ_AF_INET	= AF_INET;

+const pj_uint16_t PJ_AF_INET6	= AF_INET6;

+#ifdef AF_PACKET

+const pj_uint16_t PJ_AF_PACKET	= AF_PACKET;

+#else

+const pj_uint16_t PJ_AF_PACKET	= 0xFFFF;

+#endif

+#ifdef AF_IRDA

+const pj_uint16_t PJ_AF_IRDA	= AF_IRDA;

+#else

+const pj_uint16_t PJ_AF_IRDA	= 0xFFFF;

+#endif

+

+/*

+ * Socket types conversion.

+ * The values here are indexed based on pj_sock_type-0xFF00

+ */

+const pj_uint16_t PJ_SOCK_STREAM	= SOCK_STREAM;

+const pj_uint16_t PJ_SOCK_DGRAM	= SOCK_DGRAM;

+const pj_uint16_t PJ_SOCK_RAW	= SOCK_RAW;

+const pj_uint16_t PJ_SOCK_RDM	= SOCK_RDM;

+

+/*

+ * Socket level values.

+ */

+const pj_uint16_t PJ_SOL_SOCKET	= SOL_SOCKET;

+#ifdef SOL_IP

+const pj_uint16_t PJ_SOL_IP	= SOL_IP;

+#else

+const pj_uint16_t PJ_SOL_IP	= 0xFFFF;

+#endif /* SOL_IP */

+#if defined(SOL_TCP)

+const pj_uint16_t PJ_SOL_TCP	= SOL_TCP;

+#elif defined(IPPROTO_TCP)

+const pj_uint16_t PJ_SOL_TCP	= IPPROTO_TCP;

+#endif /* SOL_TCP */

+#ifdef SOL_UDP

+const pj_uint16_t PJ_SOL_UDP	= SOL_UDP;

+#else

+const pj_uint16_t PJ_SOL_UDP	= 0xFFFF;

+#endif

+#ifdef SOL_IPV6

+const pj_uint16_t PJ_SOL_IPV6	= SOL_IPV6;

+#else

+const pj_uint16_t PJ_SOL_IPV6	= 0xFFFF;

+#endif

+

+/* optname values. */

 const pj_uint16_t PJ_SO_TYPE    = SO_TYPE;

 const pj_uint16_t PJ_SO_RCVBUF  = SO_RCVBUF;

 const pj_uint16_t PJ_SO_SNDBUF  = SO_SNDBUF;

 

-
-/*
- * Convert 16-bit value from network byte order to host byte order.
- */
-PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
-{
-    return ntohs(netshort);
-}
-
-/*
- * Convert 16-bit value from host byte order to network byte order.
- */
-PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
-{
-    return htons(hostshort);
-}
-
-/*
- * Convert 32-bit value from network byte order to host byte order.
- */
-PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
-{
-    return ntohl(netlong);
-}
-
-/*
- * Convert 32-bit value from host byte order to network byte order.
- */
-PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
-{
-    return htonl(hostlong);
-}
-
-/*
- * Convert an Internet host address given in network byte order
- * to string in standard numbers and dots notation.
- */
-PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)
+

+/*

+ * Convert 16-bit value from network byte order to host byte order.

+ */

+PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)

+{

+    return ntohs(netshort);

+}

+

+/*

+ * Convert 16-bit value from host byte order to network byte order.

+ */

+PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)

+{

+    return htons(hostshort);

+}

+

+/*

+ * Convert 32-bit value from network byte order to host byte order.

+ */

+PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)

+{

+    return ntohl(netlong);

+}

+

+/*

+ * Convert 32-bit value from host byte order to network byte order.

+ */

+PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)

+{

+    return htonl(hostlong);

+}

+

+/*

+ * Convert an Internet host address given in network byte order

+ * to string in standard numbers and dots notation.

+ */

+PJ_DEF(char*) pj_inet_ntoa(pj_in_addr inaddr)

 {

 #if !defined(PJ_LINUX) && !defined(PJ_LINUX_KERNEL)

     return inet_ntoa(*(struct in_addr*)&inaddr);

-#else
-    struct in_addr addr;
-    addr.s_addr = inaddr.s_addr;
+#else

+    struct in_addr addr;

+    addr.s_addr = inaddr.s_addr;

     return inet_ntoa(addr);

-#endif
-}
-
-/*
- * This function converts the Internet host address cp from the standard
- * numbers-and-dots notation into binary data and stores it in the structure
- * that inp points to. 
- */
-PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
-{
-    char tempaddr[16];
-
-    /* Initialize output with PJ_INADDR_NONE.
-     * Some apps relies on this instead of the return value
-     * (and anyway the return value is quite confusing!)
-     */
-    inp->s_addr = PJ_INADDR_NONE;
-
-    /* Caution:
-     *	this function might be called with cp->slen >= 16
-     *  (i.e. when called with hostname to check if it's an IP addr).
-     */
-    PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
-    if (cp->slen >= 16) {
-	return 0;
-    }
-
-    pj_memcpy(tempaddr, cp->ptr, cp->slen);
-    tempaddr[cp->slen] = '\0';
-
-#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0
-    return inet_aton(tempaddr, (struct in_addr*)inp);
-#else
-    inp->s_addr = inet_addr(tempaddr);
-    return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;
-#endif
-}
-
-/*
- * Convert address string with numbers and dots to binary IP address.
- */ 
-PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
-{
-    pj_in_addr addr;
-
-    pj_inet_aton(cp, &addr);
-    return addr;
-}
-
-/*
- * Set the IP address of an IP socket address from string address, 
- * with resolving the host if necessary. The string address may be in a
- * standard numbers and dots notation or may be a hostname. If hostname
- * is specified, then the function will resolve the host into the IP
- * address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
-					         const pj_str_t *str_addr)
-{
-    PJ_CHECK_STACK();
-
-    PJ_ASSERT_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME, 
-                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
-
-    addr->sin_family = AF_INET;
-
-    if (str_addr && str_addr->slen) {
-	addr->sin_addr = pj_inet_addr(str_addr);
-	if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
-    	    pj_hostent he;
-	    pj_status_t rc;
-
-	    rc = pj_gethostbyname(str_addr, &he);
-	    if (rc == 0) {
-		addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
-	    } else {
-		addr->sin_addr.s_addr = PJ_INADDR_NONE;
-		return rc;
-	    }
-	}
-
-    } else {
-	addr->sin_addr.s_addr = 0;
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Set the IP address and port of an IP socket address.
- * The string address may be in a standard numbers and dots notation or 
- * may be a hostname. If hostname is specified, then the function will 
- * resolve the host into the IP address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
-				         const pj_str_t *str_addr,
-					 pj_uint16_t port)
-{
-    PJ_ASSERT_RETURN(addr && str_addr, 
-                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));
-
-    addr->sin_family = PJ_AF_INET;
-    pj_sockaddr_in_set_port(addr, port);
-    return pj_sockaddr_in_set_str_addr(addr, str_addr);
-}
-
-
-/*
- * Get hostname.
- */
-PJ_DEF(const pj_str_t*) pj_gethostname(void)
-{
-    static char buf[PJ_MAX_HOSTNAME];
-    static pj_str_t hostname;
-
-    PJ_CHECK_STACK();
-
-    if (hostname.ptr == NULL) {
-	hostname.ptr = buf;
-	if (gethostname(buf, sizeof(buf)) != 0) {
-	    hostname.ptr[0] = '\0';
-	    hostname.slen = 0;
-	} else {
-	   hostname.slen = strlen(buf);
-	}
-    }
-    return &hostname;
-}
-
-/*
- * Get first IP address associated with the hostname.
- */
-PJ_DEF(pj_in_addr) pj_gethostaddr(void)
-{
-    pj_sockaddr_in addr;
-    const pj_str_t *hostname = pj_gethostname();
-
-    pj_sockaddr_in_set_str_addr(&addr, hostname);
-    return addr.sin_addr;
-}
-
-
-#if defined(PJ_WIN32)
-/*
- * Create new socket/endpoint for communication and returns a descriptor.
- */
-PJ_DEF(pj_status_t) pj_sock_socket(int af, 
-				   int type, 
-				   int proto,
-				   pj_sock_t *sock)
-{
-    PJ_CHECK_STACK();
-
-    /* Sanity checks. */
-    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
-    PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET, 
-                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
-
-    *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);
-
-    if (*sock == PJ_INVALID_SOCKET) 
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-#else
-/*
- * Create new socket/endpoint for communication and returns a descriptor.
- */
-PJ_DEF(pj_status_t) pj_sock_socket(int af, 
-				   int type, 
-				   int proto, 
-				   pj_sock_t *sock)
-{
-
-    PJ_CHECK_STACK();
-
-    /* Sanity checks. */
-    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);
-    PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1, 
-                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));
-
-    *sock = socket(af, type, proto);
-    if (*sock == PJ_INVALID_SOCKET)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else 
-	return PJ_SUCCESS;
-}
-#endif
-
-
-/*
- * Bind socket.
- */
-PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, 
-				  const pj_sockaddr_t *addr,
-				  int len)
-{
-    PJ_CHECK_STACK();
-
-    PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL);
-
-    if (bind(sock, (struct sockaddr*)addr, len) != 0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-
-/*
- * Bind socket.
- */
-PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock, 
-				     pj_uint32_t addr32,
-				     pj_uint16_t port)
-{
-    pj_sockaddr_in addr;
-
-    PJ_CHECK_STACK();
-
-    addr.sin_family = PJ_AF_INET;
-    addr.sin_addr.s_addr = pj_htonl(addr32);
-    addr.sin_port = pj_htons(port);
-
-    return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));
-}
-
-
-/*
- * Close socket.
- */
-PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)
-{
-    int rc;
-
-    PJ_CHECK_STACK();
-#if defined(PJ_WIN32) && PJ_WIN32==1
-    rc = closesocket(sock);
-#else
-    rc = close(sock);
-#endif
-
-    if (rc != 0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Get remote's name.
- */
-PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,
-					 pj_sockaddr_t *addr,
-					 int *namelen)
-{
-    PJ_CHECK_STACK();
-    if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Get socket name.
- */
-PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,
-					 pj_sockaddr_t *addr,
-					 int *namelen)
-{
-    PJ_CHECK_STACK();
-    if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Send data
- */
-PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,
-				 const void *buf,
-				 pj_ssize_t *len,
-				 unsigned flags)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(len, PJ_EINVAL);
-
-    *len = send(sock, (const char*)buf, *len, flags);
-
-    if (*len < 0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-
-/*
- * Send data.
- */
-PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,
-				   const void *buf,
-				   pj_ssize_t *len,
-				   unsigned flags,
-				   const pj_sockaddr_t *to,
-				   int tolen)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(len, PJ_EINVAL);
-
-    *len = sendto(sock, (const char*)buf, *len, flags, 
-		  (const struct sockaddr*)to, tolen);
-
-    if (*len < 0) 
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else 
-	return PJ_SUCCESS;
-}
-
-/*
- * Receive data.
- */
-PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,
-				 void *buf,
-				 pj_ssize_t *len,
-				 unsigned flags)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
-
-    *len = recv(sock, (char*)buf, *len, flags);
-
-    if (*len < 0) 
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Receive data.
- */
-PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,
-				     void *buf,
-				     pj_ssize_t *len,
-				     unsigned flags,
-				     pj_sockaddr_t *from,
-				     int *fromlen)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);
-    PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));
-
-    *len = recvfrom(sock, (char*)buf, *len, flags, 
-		    (struct sockaddr*)from, (socklen_t*)fromlen);
-
-    if (*len < 0) 
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Get socket option.
- */
-PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,
-					pj_uint16_t level,
-					pj_uint16_t optname,
-					void *optval,
-					int *optlen)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);
-
-    if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Set socket option.
- */
-PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,
-					pj_uint16_t level,
-					pj_uint16_t optname,
-					const void *optval,
-					int optlen)
-{
-    PJ_CHECK_STACK();
-    if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Shutdown socket.
- */
-#if PJ_HAS_TCP
-PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,
-				      int how)
-{
-    PJ_CHECK_STACK();
-    if (shutdown(sock, how) != 0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Start listening to incoming connections.
- */
-PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,
-				    int backlog)
-{
-    PJ_CHECK_STACK();
-    if (listen(sock, backlog) != 0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Connect socket.
- */
-PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,
-				     const pj_sockaddr_t *addr,
-				     int namelen)
-{
-    PJ_CHECK_STACK();
-    if (connect(sock, (struct sockaddr*)addr, namelen) != 0)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Accept incoming connections
- */
-PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,
-				    pj_sock_t *newsock,
-				    pj_sockaddr_t *addr,
-				    int *addrlen)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);
-
-    *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);
-    if (*newsock==PJ_INVALID_SOCKET)
-	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());
-    else
-	return PJ_SUCCESS;
-}
-#endif	/* PJ_HAS_TCP */
-
-
+#endif

+}

+

+/*

+ * This function converts the Internet host address cp from the standard

+ * numbers-and-dots notation into binary data and stores it in the structure

+ * that inp points to. 

+ */

+PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)

+{

+    char tempaddr[16];

+

+    /* Initialize output with PJ_INADDR_NONE.

+     * Some apps relies on this instead of the return value

+     * (and anyway the return value is quite confusing!)

+     */

+    inp->s_addr = PJ_INADDR_NONE;

+

+    /* Caution:

+     *	this function might be called with cp->slen >= 16

+     *  (i.e. when called with hostname to check if it's an IP addr).

+     */

+    PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);

+    if (cp->slen >= 16) {

+	return 0;

+    }

+

+    pj_memcpy(tempaddr, cp->ptr, cp->slen);

+    tempaddr[cp->slen] = '\0';

+

+#if defined(PJ_SOCK_HAS_INET_ATON) && PJ_SOCK_HAS_INET_ATON != 0

+    return inet_aton(tempaddr, (struct in_addr*)inp);

+#else

+    inp->s_addr = inet_addr(tempaddr);

+    return inp->s_addr == PJ_INADDR_NONE ? 0 : 1;

+#endif

+}

+

+/*

+ * Convert address string with numbers and dots to binary IP address.

+ */ 

+PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)

+{

+    pj_in_addr addr;

+

+    pj_inet_aton(cp, &addr);

+    return addr;

+}

+

+/*

+ * Set the IP address of an IP socket address from string address, 

+ * with resolving the host if necessary. The string address may be in a

+ * standard numbers and dots notation or may be a hostname. If hostname

+ * is specified, then the function will resolve the host into the IP

+ * address.

+ */

+PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,

+					         const pj_str_t *str_addr)

+{

+    PJ_CHECK_STACK();

+

+    PJ_ASSERT_RETURN(str_addr && str_addr->slen < PJ_MAX_HOSTNAME, 

+                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));

+

+    addr->sin_family = AF_INET;

+

+    if (str_addr && str_addr->slen) {

+	addr->sin_addr = pj_inet_addr(str_addr);

+	if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {

+    	    pj_hostent he;

+	    pj_status_t rc;

+

+	    rc = pj_gethostbyname(str_addr, &he);

+	    if (rc == 0) {

+		addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;

+	    } else {

+		addr->sin_addr.s_addr = PJ_INADDR_NONE;

+		return rc;

+	    }

+	}

+

+    } else {

+	addr->sin_addr.s_addr = 0;

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Set the IP address and port of an IP socket address.

+ * The string address may be in a standard numbers and dots notation or 

+ * may be a hostname. If hostname is specified, then the function will 

+ * resolve the host into the IP address.

+ */

+PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,

+				         const pj_str_t *str_addr,

+					 pj_uint16_t port)

+{

+    PJ_ASSERT_RETURN(addr && str_addr, 

+                     (addr->sin_addr.s_addr=PJ_INADDR_NONE, PJ_EINVAL));

+

+    addr->sin_family = PJ_AF_INET;

+    pj_sockaddr_in_set_port(addr, port);

+    return pj_sockaddr_in_set_str_addr(addr, str_addr);

+}

+

+

+/*

+ * Get hostname.

+ */

+PJ_DEF(const pj_str_t*) pj_gethostname(void)

+{

+    static char buf[PJ_MAX_HOSTNAME];

+    static pj_str_t hostname;

+

+    PJ_CHECK_STACK();

+

+    if (hostname.ptr == NULL) {

+	hostname.ptr = buf;

+	if (gethostname(buf, sizeof(buf)) != 0) {

+	    hostname.ptr[0] = '\0';

+	    hostname.slen = 0;

+	} else {

+	   hostname.slen = strlen(buf);

+	}

+    }

+    return &hostname;

+}

+

+/*

+ * Get first IP address associated with the hostname.

+ */

+PJ_DEF(pj_in_addr) pj_gethostaddr(void)

+{

+    pj_sockaddr_in addr;

+    const pj_str_t *hostname = pj_gethostname();

+

+    pj_sockaddr_in_set_str_addr(&addr, hostname);

+    return addr.sin_addr;

+}

+

+

+#if defined(PJ_WIN32)

+/*

+ * Create new socket/endpoint for communication and returns a descriptor.

+ */

+PJ_DEF(pj_status_t) pj_sock_socket(int af, 

+				   int type, 

+				   int proto,

+				   pj_sock_t *sock)

+{

+    PJ_CHECK_STACK();

+

+    /* Sanity checks. */

+    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);

+    PJ_ASSERT_RETURN((unsigned)PJ_INVALID_SOCKET==INVALID_SOCKET, 

+                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));

+

+    *sock = WSASocket(af, type, proto, NULL, 0, WSA_FLAG_OVERLAPPED);

+

+    if (*sock == PJ_INVALID_SOCKET) 

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+#else

+/*

+ * Create new socket/endpoint for communication and returns a descriptor.

+ */

+PJ_DEF(pj_status_t) pj_sock_socket(int af, 

+				   int type, 

+				   int proto, 

+				   pj_sock_t *sock)

+{

+

+    PJ_CHECK_STACK();

+

+    /* Sanity checks. */

+    PJ_ASSERT_RETURN(sock!=NULL, PJ_EINVAL);

+    PJ_ASSERT_RETURN(PJ_INVALID_SOCKET==-1, 

+                     (*sock=PJ_INVALID_SOCKET, PJ_EINVAL));

+

+    *sock = socket(af, type, proto);

+    if (*sock == PJ_INVALID_SOCKET)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else 

+	return PJ_SUCCESS;

+}

+#endif

+

+

+/*

+ * Bind socket.

+ */

+PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sock, 

+				  const pj_sockaddr_t *addr,

+				  int len)

+{

+    PJ_CHECK_STACK();

+

+    PJ_ASSERT_RETURN(addr && len > 0, PJ_EINVAL);

+

+    if (bind(sock, (struct sockaddr*)addr, len) != 0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+

+/*

+ * Bind socket.

+ */

+PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sock, 

+				     pj_uint32_t addr32,

+				     pj_uint16_t port)

+{

+    pj_sockaddr_in addr;

+

+    PJ_CHECK_STACK();

+

+    addr.sin_family = PJ_AF_INET;

+    addr.sin_addr.s_addr = pj_htonl(addr32);

+    addr.sin_port = pj_htons(port);

+

+    return pj_sock_bind(sock, &addr, sizeof(pj_sockaddr_in));

+}

+

+

+/*

+ * Close socket.

+ */

+PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sock)

+{

+    int rc;

+

+    PJ_CHECK_STACK();

+#if defined(PJ_WIN32) && PJ_WIN32==1

+    rc = closesocket(sock);

+#else

+    rc = close(sock);

+#endif

+

+    if (rc != 0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Get remote's name.

+ */

+PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sock,

+					 pj_sockaddr_t *addr,

+					 int *namelen)

+{

+    PJ_CHECK_STACK();

+    if (getpeername(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Get socket name.

+ */

+PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sock,

+					 pj_sockaddr_t *addr,

+					 int *namelen)

+{

+    PJ_CHECK_STACK();

+    if (getsockname(sock, (struct sockaddr*)addr, (socklen_t*)namelen) != 0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Send data

+ */

+PJ_DEF(pj_status_t) pj_sock_send(pj_sock_t sock,

+				 const void *buf,

+				 pj_ssize_t *len,

+				 unsigned flags)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(len, PJ_EINVAL);

+

+    *len = send(sock, (const char*)buf, *len, flags);

+

+    if (*len < 0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+

+/*

+ * Send data.

+ */

+PJ_DEF(pj_status_t) pj_sock_sendto(pj_sock_t sock,

+				   const void *buf,

+				   pj_ssize_t *len,

+				   unsigned flags,

+				   const pj_sockaddr_t *to,

+				   int tolen)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(len, PJ_EINVAL);

+

+    *len = sendto(sock, (const char*)buf, *len, flags, 

+		  (const struct sockaddr*)to, tolen);

+

+    if (*len < 0) 

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else 

+	return PJ_SUCCESS;

+}

+

+/*

+ * Receive data.

+ */

+PJ_DEF(pj_status_t) pj_sock_recv(pj_sock_t sock,

+				 void *buf,

+				 pj_ssize_t *len,

+				 unsigned flags)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);

+

+    *len = recv(sock, (char*)buf, *len, flags);

+

+    if (*len < 0) 

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Receive data.

+ */

+PJ_DEF(pj_status_t) pj_sock_recvfrom(pj_sock_t sock,

+				     void *buf,

+				     pj_ssize_t *len,

+				     unsigned flags,

+				     pj_sockaddr_t *from,

+				     int *fromlen)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(buf && len, PJ_EINVAL);

+    PJ_ASSERT_RETURN(from && fromlen, (*len=-1, PJ_EINVAL));

+

+    *len = recvfrom(sock, (char*)buf, *len, flags, 

+		    (struct sockaddr*)from, (socklen_t*)fromlen);

+

+    if (*len < 0) 

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Get socket option.

+ */

+PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sock,

+					pj_uint16_t level,

+					pj_uint16_t optname,

+					void *optval,

+					int *optlen)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(optval && optlen, PJ_EINVAL);

+

+    if (getsockopt(sock, level, optname, (char*)optval, (socklen_t*)optlen)!=0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Set socket option.

+ */

+PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sock,

+					pj_uint16_t level,

+					pj_uint16_t optname,

+					const void *optval,

+					int optlen)

+{

+    PJ_CHECK_STACK();

+    if (setsockopt(sock, level, optname, (const char*)optval, optlen) != 0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Shutdown socket.

+ */

+#if PJ_HAS_TCP

+PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sock,

+				      int how)

+{

+    PJ_CHECK_STACK();

+    if (shutdown(sock, how) != 0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Start listening to incoming connections.

+ */

+PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sock,

+				    int backlog)

+{

+    PJ_CHECK_STACK();

+    if (listen(sock, backlog) != 0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Connect socket.

+ */

+PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sock,

+				     const pj_sockaddr_t *addr,

+				     int namelen)

+{

+    PJ_CHECK_STACK();

+    if (connect(sock, (struct sockaddr*)addr, namelen) != 0)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Accept incoming connections

+ */

+PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t serverfd,

+				    pj_sock_t *newsock,

+				    pj_sockaddr_t *addr,

+				    int *addrlen)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(newsock != NULL, PJ_EINVAL);

+

+    *newsock = accept(serverfd, (struct sockaddr*)addr, (socklen_t*)addrlen);

+    if (*newsock==PJ_INVALID_SOCKET)

+	return PJ_RETURN_OS_ERROR(pj_get_native_netos_error());

+    else

+	return PJ_SUCCESS;

+}

+#endif	/* PJ_HAS_TCP */

+

+

diff --git a/pjlib/src/pj/sock_linux_kernel.c b/pjlib/src/pj/sock_linux_kernel.c
index d7924f9..75e272d 100644
--- a/pjlib/src/pj/sock_linux_kernel.c
+++ b/pjlib/src/pj/sock_linux_kernel.c
@@ -1,739 +1,760 @@
-/* $Id$
- *
- */
-#include <pj/sock.h>
-#include <pj/assert.h>
-#include <pj/string.h>	    /* pj_memcpy()	    */
-#include <pj/os.h>	    /* PJ_CHECK_STACK()	    */
-#include <pj/addr_resolv.h> /* pj_gethostbyname()   */
-#include <pj/ctype.h>
-#include <pj/compat/sprintf.h>
-#include <pj/log.h>
-#include <pj/errno.h>
-
-/* Linux kernel specific. */
-#include <linux/socket.h>
-#include <linux/net.h>
-//#include <net/sock.h>
-#include <linux/security.h>
-#include <linux/syscalls.h>	/* sys_xxx()	*/
-#include <asm/ioctls.h>		/* FIONBIO	*/
-#include <linux/utsname.h>	/* for pj_gethostname() */
-
-/*
- * Address families conversion.
- * The values here are indexed based on pj_addr_family-0xFF00.
- */
-const pj_uint16_t PJ_AF_UNIX	= AF_UNIX;
-const pj_uint16_t PJ_AF_INET	= AF_INET;
-const pj_uint16_t PJ_AF_INET6	= AF_INET6;
-#ifdef AF_PACKET
-const pj_uint16_t PJ_AF_PACKET	= AF_PACKET;
-#else
-#  error "AF_PACKET undeclared!"
-#endif
-#ifdef AF_IRDA
-const pj_uint16_t PJ_AF_IRDA	= AF_IRDA;
-#else
-#  error "AF_IRDA undeclared!"
-#endif
-
-/*
- * Socket types conversion.
- * The values here are indexed based on pj_sock_type-0xFF00
- */
-const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;
-const pj_uint16_t PJ_SOCK_DGRAM	= SOCK_DGRAM;
-const pj_uint16_t PJ_SOCK_RAW	= SOCK_RAW;
-const pj_uint16_t PJ_SOCK_RDM	= SOCK_RDM;
-
-/*
- * Socket level values.
- */
-const pj_uint16_t PJ_SOL_SOCKET	= SOL_SOCKET;
-#ifdef SOL_IP
-const pj_uint16_t PJ_SOL_IP	= SOL_IP;
-#else
-#  error "SOL_IP undeclared!"
-#endif /* SOL_IP */
-#if defined(SOL_TCP)
-const pj_uint16_t PJ_SOL_TCP	= SOL_TCP;
-#else
-#  error "SOL_TCP undeclared!"
-#endif /* SOL_TCP */
-#ifdef SOL_UDP
-const pj_uint16_t PJ_SOL_UDP	= SOL_UDP;
-#else
-#  error "SOL_UDP undeclared!"
-#endif
-#ifdef SOL_IPV6
-const pj_uint16_t PJ_SOL_IPV6	= SOL_IPV6;
-#else
-#  error "SOL_IPV6 undeclared!"
-#endif
+/* $Id$

+ *

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/sock.h>

+#include <pj/assert.h>

+#include <pj/string.h>	    /* pj_memcpy()	    */

+#include <pj/os.h>	    /* PJ_CHECK_STACK()	    */

+#include <pj/addr_resolv.h> /* pj_gethostbyname()   */

+#include <pj/ctype.h>

+#include <pj/compat/sprintf.h>

+#include <pj/log.h>

+#include <pj/errno.h>

+

+/* Linux kernel specific. */

+#include <linux/socket.h>

+#include <linux/net.h>

+//#include <net/sock.h>

+#include <linux/security.h>

+#include <linux/syscalls.h>	/* sys_xxx()	*/

+#include <asm/ioctls.h>		/* FIONBIO	*/

+#include <linux/utsname.h>	/* for pj_gethostname() */

+

+/*

+ * Address families conversion.

+ * The values here are indexed based on pj_addr_family-0xFF00.

+ */

+const pj_uint16_t PJ_AF_UNIX	= AF_UNIX;

+const pj_uint16_t PJ_AF_INET	= AF_INET;

+const pj_uint16_t PJ_AF_INET6	= AF_INET6;

+#ifdef AF_PACKET

+const pj_uint16_t PJ_AF_PACKET	= AF_PACKET;

+#else

+#  error "AF_PACKET undeclared!"

+#endif

+#ifdef AF_IRDA

+const pj_uint16_t PJ_AF_IRDA	= AF_IRDA;

+#else

+#  error "AF_IRDA undeclared!"

+#endif

+

+/*

+ * Socket types conversion.

+ * The values here are indexed based on pj_sock_type-0xFF00

+ */

+const pj_uint16_t PJ_SOCK_STREAM= SOCK_STREAM;

+const pj_uint16_t PJ_SOCK_DGRAM	= SOCK_DGRAM;

+const pj_uint16_t PJ_SOCK_RAW	= SOCK_RAW;

+const pj_uint16_t PJ_SOCK_RDM	= SOCK_RDM;

+

+/*

+ * Socket level values.

+ */

+const pj_uint16_t PJ_SOL_SOCKET	= SOL_SOCKET;

+#ifdef SOL_IP

+const pj_uint16_t PJ_SOL_IP	= SOL_IP;

+#else

+#  error "SOL_IP undeclared!"

+#endif /* SOL_IP */

+#if defined(SOL_TCP)

+const pj_uint16_t PJ_SOL_TCP	= SOL_TCP;

+#else

+#  error "SOL_TCP undeclared!"

+#endif /* SOL_TCP */

+#ifdef SOL_UDP

+const pj_uint16_t PJ_SOL_UDP	= SOL_UDP;

+#else

+#  error "SOL_UDP undeclared!"

+#endif

+#ifdef SOL_IPV6

+const pj_uint16_t PJ_SOL_IPV6	= SOL_IPV6;

+#else

+#  error "SOL_IPV6 undeclared!"

+#endif

 

 /* optname values. */

 const pj_uint16_t PJ_SO_TYPE    = SO_TYPE;

 const pj_uint16_t PJ_SO_RCVBUF  = SO_RCVBUF;

 const pj_uint16_t PJ_SO_SNDBUF  = SO_SNDBUF;

-
-/*
- * Convert 16-bit value from network byte order to host byte order.
- */
-PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)
-{
-    return ntohs(netshort);
-}
-
-/*
- * Convert 16-bit value from host byte order to network byte order.
- */
-PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)
-{
-    return htons(hostshort);
-}
-
-/*
- * Convert 32-bit value from network byte order to host byte order.
- */
-PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)
-{
-    return ntohl(netlong);
-}
-
-/*
- * Convert 32-bit value from host byte order to network byte order.
- */
-PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)
-{
-    return htonl(hostlong);
-}
-
-/*
- * Convert an Internet host address given in network byte order
- * to string in standard numbers and dots notation.
- */
-PJ_DEF(char*) pj_inet_ntoa(pj_in_addr in)
-{
-#define	UC(b)	(((int)b)&0xff)
-    static char b[18];
-    char *p;
-
-    p = (char *)&in;
-    pj_snprintf(b, sizeof(b), "%d.%d.%d.%d", 
-	       UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
-
-    return b;
-}
-
-/*
- * This function converts the Internet host address ccp from the standard
- * numbers-and-dots notation into binary data and stores it in the structure
- * that inp points to. 
- */
-PJ_DEF(int) pj_inet_aton(const pj_str_t *ccp, struct pj_in_addr *addr)
-{
-    pj_uint32_t val;
-    int base, n;
-    char c;
-    unsigned parts[4];
-    unsigned *pp = parts;
-    char cp_copy[18];
-    char *cp = cp_copy;
-    
-    addr->s_addr = PJ_INADDR_NONE;
-
-    if (ccp->slen > 15) return 0;
-
-    pj_memcpy(cp, ccp->ptr, ccp->slen);
-    cp[ccp->slen] = '\0';
-
-    c = *cp;
-    for (;;) {
-	/*
-	 * Collect number up to ``.''.
-	 * Values are specified as for C:
-	 * 0x=hex, 0=octal, isdigit=decimal.
-	 */
-	if (!pj_isdigit((int)c))
-	    return (0);
-	val = 0; base = 10;
-	if (c == '0') {
-	    c = *++cp;
-	    if (c == 'x' || c == 'X')
-		base = 16, c = *++cp;
-	    else
-		base = 8;
-	}
-
-	for (;;) {
-	    if (pj_isascii((int)c) && pj_isdigit((int)c)) {
-		val = (val * base) + (c - '0');
-		c = *++cp;
-	    } else if (base==16 && pj_isascii((int)c) && pj_isxdigit((int)c)) {
-		val = (val << 4) |
-		      (c + 10 - (pj_islower((int)c) ? 'a' : 'A'));
-		c = *++cp;
-	    } else
-		break;
-	}
-
-	if (c == '.') {
-	    /*
-	     * Internet format:
-	     *  a.b.c.d
-	     *  a.b.c   (with c treated as 16 bits)
-	     *  a.b	(with b treated as 24 bits)
-	     */
-	    if (pp >= parts + 3)
-		return (0);
-	    *pp++ = val;
-	    c = *++cp;
-	} else
-	    break;
-    }
-
-    /*
-     * Check for trailing characters.
-     */
-    if (c != '\0' && (!pj_isascii((int)c) || !pj_isspace((int)c)))
-        return (0);
-    /*
-     * Concoct the address according to
-     * the number of parts specified.
-     */
-    n = pp - parts + 1;
-    switch (n) {
-    case 0:
-	return (0);	    /* initial nondigit */
-    case 1:		/* a -- 32 bits */
-	break;
-    case 2:		/* a.b -- 8.24 bits */
-	if (val > 0xffffff)
-	    return (0);
-	val |= parts[0] << 24;
-	break;
-    case 3:		/* a.b.c -- 8.8.16 bits */
-	if (val > 0xffff)
-	    return (0);
-	val |= (parts[0] << 24) | (parts[1] << 16);
-	break;
-    case 4:		/* a.b.c.d -- 8.8.8.8 bits */
-	if (val > 0xff)
-	    return (0);
-	val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
-	break;
-    }
-
-    if (addr)
-	addr->s_addr = pj_htonl(val);
-    return (1);
-}
-
-/*
- * Convert address string with numbers and dots to binary IP address.
- */ 
-PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)
-{
-    pj_in_addr addr;
-    pj_inet_aton(cp, &addr);
-    return addr;
-}
-
-/*
- * Set the IP address of an IP socket address from string address, 
- * with resolving the host if necessary. The string address may be in a
- * standard numbers and dots notation or may be a hostname. If hostname
- * is specified, then the function will resolve the host into the IP
- * address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,
-					         const pj_str_t *str_addr)
-{
-    PJ_CHECK_STACK();
-
-    pj_assert(str_addr && str_addr->slen < PJ_MAX_HOSTNAME);
-
-    addr->sin_family = AF_INET;
-
-    if (str_addr && str_addr->slen) {
-	addr->sin_addr = pj_inet_addr(str_addr);
-	if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {
-    	    pj_hostent he;
-	    if (pj_gethostbyname(str_addr, &he) == 0) {
-		addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;
-	    } else {
-		addr->sin_addr.s_addr = PJ_INADDR_NONE;
-		return -1;
-	    }
-	}
-
-    } else {
-	addr->sin_addr.s_addr = 0;
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Set the IP address and port of an IP socket address.
- * The string address may be in a standard numbers and dots notation or 
- * may be a hostname. If hostname is specified, then the function will 
- * resolve the host into the IP address.
- */
-PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,
-				         const pj_str_t *str_addr,
-					 pj_uint16_t port)
-{
-    pj_assert(addr && str_addr);
-
-    addr->sin_family = PJ_AF_INET;
-    pj_sockaddr_in_set_port(addr, port);
-    return pj_sockaddr_in_set_str_addr(addr, str_addr);
-}
-
-
-/*
- * Get hostname.
- */
-PJ_DEF(const pj_str_t*) pj_gethostname(void)
-{
-    static char buf[PJ_MAX_HOSTNAME];
-    static pj_str_t hostname;
-
-    PJ_CHECK_STACK();
-
-    if (hostname.ptr == NULL) {
-	hostname.ptr = buf;
-	down_read(&uts_sem);
-	hostname.slen = strlen(system_utsname.nodename);
-	if (hostname.slen > PJ_MAX_HOSTNAME) {
-	    hostname.ptr[0] = '\0';
-	    hostname.slen = 0;
-	} else {
-	    pj_memcpy(hostname.ptr, system_utsname.nodename, hostname.slen);
-	}
-	up_read(&uts_sem);
-    }
-    return &hostname;
-}
-
-/*
- * Get first IP address associated with the hostname.
- */
-PJ_DEF(pj_in_addr) pj_gethostaddr(void)
-{
-    pj_sockaddr_in addr;
-    const pj_str_t *hostname = pj_gethostname();
-
-    pj_sockaddr_in_set_str_addr(&addr, hostname);
-    return addr.sin_addr;
-}
-
-
-/*
- * Create new socket/endpoint for communication and returns a descriptor.
- */
-PJ_DEF(pj_status_t) pj_sock_socket(int af, int type, int proto, 
-				   pj_sock_t *sock_fd)
-{
-    long result;
-
-    PJ_CHECK_STACK();
-
-    /* Sanity checks. */
-    PJ_ASSERT_RETURN(PJ_INVALID_SOCKET == -1 && sock_fd != NULL, PJ_EINVAL);
-
-    /* Initialize returned socket */
-    *sock_fd = PJ_INVALID_SOCKET;
-
-    /* Create socket. */
-    result = sys_socket(af, type, proto);
-    if (result < 0) {
-	return PJ_RETURN_OS_ERROR((-result));
-    }
-
-    *sock_fd = result;
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Bind socket.
- */
-PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sockfd, 
-				  const pj_sockaddr_t *addr,
-				  int len)
-{
-    long err;
-    mm_segment_t oldfs;
-
-    PJ_CHECK_STACK();
-
-    PJ_ASSERT_RETURN(addr!=NULL && len >= sizeof(struct pj_sockaddr),
-		     PJ_EINVAL);
-
-    oldfs = get_fs();
-    set_fs(KERNEL_DS);
-    
-    err = sys_bind(sockfd, (struct sockaddr*)addr, len);
-
-    set_fs(oldfs);
-
-    if (err)
-	return PJ_RETURN_OS_ERROR(-err);
-    else
-	return PJ_SUCCESS;
-}
-
-
-/*
- * Bind socket.
- */
-PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, 
-				     pj_uint32_t addr32,
-				     pj_uint16_t port)
-{
-    pj_sockaddr_in addr;
-
-    PJ_CHECK_STACK();
-
-    addr.sin_family = PJ_AF_INET;
-    addr.sin_addr.s_addr = pj_htonl(addr32);
-    addr.sin_port = pj_htons(port);
-
-    return pj_sock_bind(sockfd, &addr, sizeof(pj_sockaddr_in));
-}
-
-/*
- * Close socket.
- */
-PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sockfd)
-{
-    long err;
-
-    err = sys_close(sockfd);
-
-    if (err != 0)
-	return PJ_RETURN_OS_ERROR(-err);
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Get remote's name.
- */
-PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sockfd,
-					 pj_sockaddr_t *addr,
-					 int *namelen)
-{
-    mm_segment_t oldfs;
-    long err;
-
-    PJ_CHECK_STACK();
-
-    oldfs = get_fs();
-    set_fs(KERNEL_DS);
-
-    err = sys_getpeername( sockfd, addr, namelen);
-
-    set_fs(oldfs);
-
-    if (err)
-	return PJ_RETURN_OS_ERROR(-err);
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Get socket name.
- */
-PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,
-					 pj_sockaddr_t *addr,
-					 int *namelen)
-{
-    mm_segment_t oldfs;
-    int err;
-
-    PJ_CHECK_STACK();
-
-    oldfs = get_fs();
-    set_fs(KERNEL_DS);
-    
-    err = sys_getsockname( sockfd, addr, namelen );
-
-    set_fs(oldfs);
-
-    if (err)
-	return PJ_RETURN_OS_ERROR(-err);
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Send data
- */
-PJ_DEF(pj_status_t) pj_sock_send( pj_sock_t sockfd,
-				  const void *buf,
-				  pj_ssize_t *len,
-				  unsigned flags)
-{
-    return pj_sock_sendto(sockfd, buf, len, flags, NULL, 0);
-}
-
-
-/*
- * Send data.
- */
-PJ_DEF(pj_status_t) pj_sock_sendto( pj_sock_t sockfd,
-				    const void *buff,
-				    pj_ssize_t *len,
-				    unsigned flags,
-				    const pj_sockaddr_t *addr,
-				    int addr_len)
-{
-    long err;
-    mm_segment_t oldfs;
-
-    PJ_CHECK_STACK();
-
-    oldfs = get_fs();
-    set_fs(KERNEL_DS);
-    
-    err = *len = sys_sendto( sockfd, (void*)buff, *len, flags, 
-			     (void*)addr, addr_len );
-
-    set_fs(oldfs);
-    
-    if (err >= 0) {
-	return PJ_SUCCESS;
-    }
-    else {
-	return PJ_RETURN_OS_ERROR(-err);
-    }
-}
-
-/*
- * Receive data.
- */
-PJ_DEF(pj_status_t) pj_sock_recv( pj_sock_t sockfd,
-				  void *buf,
-				  pj_ssize_t *len,
-				  unsigned flags)
-{
-    return pj_sock_recvfrom(sockfd, buf, len, flags, NULL, NULL);
-}
-
-/*
- * Receive data.
- */
-PJ_DEF(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,
-				      void *buff,
-				      pj_ssize_t *size,
-				      unsigned flags,
-				      pj_sockaddr_t *from,
-				      int *fromlen)
-{
-    mm_segment_t oldfs;
-    long err;
-
-    PJ_CHECK_STACK();
-
-    oldfs = get_fs();
-    set_fs(KERNEL_DS);
-
-    err = *size = sys_recvfrom( sockfd, buff, *size, flags, from, fromlen);
-
-    set_fs(oldfs);
-
-    if (err >= 0) {
-	return PJ_SUCCESS;
-    }
-    else {
-	return PJ_RETURN_OS_ERROR(-err);
-    }
-}
-
-/*
- * Get socket option.
- */
-PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,
-					pj_uint16_t level,
-					pj_uint16_t optname,
-					void *optval,
-					int *optlen)
-{
-    mm_segment_t oldfs;
-    long err;
-
-    PJ_CHECK_STACK();
-
-    oldfs = get_fs();
-    set_fs(KERNEL_DS);
-
-    err = sys_getsockopt( sockfd, level, optname, optval, optlen);
-
-    set_fs(oldfs);
-
-    if (err)
-	return PJ_RETURN_OS_ERROR(-err);
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Set socket option.
- */
-PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,
-					pj_uint16_t level,
-					pj_uint16_t optname,
-					const void *optval,
-					int optlen)
-{
-    long err;
-    mm_segment_t oldfs;
-
-    PJ_CHECK_STACK();
-
-
-    oldfs = get_fs();
-    set_fs(KERNEL_DS);
-
-    err = sys_setsockopt( sockfd, level, optname, (void*)optval, optlen);
-
-    set_fs(oldfs);
-
-    if (err)
-	return PJ_RETURN_OS_ERROR(-err);
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Shutdown socket.
- */
-#if PJ_HAS_TCP
-PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,
-				      int how)
-{
-    long err;
-
-    PJ_CHECK_STACK();
-
-    err = sys_shutdown(sockfd, how);
-
-    if (err)
-	return PJ_RETURN_OS_ERROR(-err);
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Start listening to incoming connections.
- */
-PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sockfd,
-				    int backlog)
-{
-    long err;
-
-    PJ_CHECK_STACK();
-
-    err = sys_listen( sockfd, backlog );
-
-    if (err)
-	return PJ_RETURN_OS_ERROR(-err);
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Connect socket.
- */
-PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sockfd,
-				     const pj_sockaddr_t *addr,
-				     int namelen)
-{
-    long err;
-    mm_segment_t oldfs;
-    
-    PJ_CHECK_STACK();
-
-    oldfs = get_fs();
-    set_fs(KERNEL_DS);
-
-    err = sys_connect( sockfd, (void*)addr, namelen );
-
-    set_fs(oldfs);
-
-    if (err)
-	return PJ_RETURN_OS_ERROR(-err);
-    else
-	return PJ_SUCCESS;
-}
-
-/*
- * Accept incoming connections
- */
-PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t sockfd,
-				    pj_sock_t *newsockfd,
-				    pj_sockaddr_t *addr,
-				    int *addrlen)
-{
-    long err;
-
-    PJ_CHECK_STACK();
-
-    PJ_ASSERT_RETURN(newsockfd != NULL, PJ_EINVAL);
-
-    err = sys_accept( sockfd, addr, addrlen);
-
-    if (err < 0) {
-	*newsockfd = PJ_INVALID_SOCKET;
-	return PJ_RETURN_OS_ERROR(-err);
-    }
-    else {
-	*newsockfd = err;
-	return PJ_SUCCESS;
-    }
-}
-#endif	/* PJ_HAS_TCP */
-
-
-
-/*
- * Permission to steal inet_ntoa() and inet_aton() as long as this notice below
- * is included:
- */
-/*
- * Copyright (c) 1983, 1993
- *  The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *  This product includes software developed by the University of
- *  California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
+

+/*

+ * Convert 16-bit value from network byte order to host byte order.

+ */

+PJ_DEF(pj_uint16_t) pj_ntohs(pj_uint16_t netshort)

+{

+    return ntohs(netshort);

+}

+

+/*

+ * Convert 16-bit value from host byte order to network byte order.

+ */

+PJ_DEF(pj_uint16_t) pj_htons(pj_uint16_t hostshort)

+{

+    return htons(hostshort);

+}

+

+/*

+ * Convert 32-bit value from network byte order to host byte order.

+ */

+PJ_DEF(pj_uint32_t) pj_ntohl(pj_uint32_t netlong)

+{

+    return ntohl(netlong);

+}

+

+/*

+ * Convert 32-bit value from host byte order to network byte order.

+ */

+PJ_DEF(pj_uint32_t) pj_htonl(pj_uint32_t hostlong)

+{

+    return htonl(hostlong);

+}

+

+/*

+ * Convert an Internet host address given in network byte order

+ * to string in standard numbers and dots notation.

+ */

+PJ_DEF(char*) pj_inet_ntoa(pj_in_addr in)

+{

+#define	UC(b)	(((int)b)&0xff)

+    static char b[18];

+    char *p;

+

+    p = (char *)&in;

+    pj_snprintf(b, sizeof(b), "%d.%d.%d.%d", 

+	       UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));

+

+    return b;

+}

+

+/*

+ * This function converts the Internet host address ccp from the standard

+ * numbers-and-dots notation into binary data and stores it in the structure

+ * that inp points to. 

+ */

+PJ_DEF(int) pj_inet_aton(const pj_str_t *ccp, struct pj_in_addr *addr)

+{

+    pj_uint32_t val;

+    int base, n;

+    char c;

+    unsigned parts[4];

+    unsigned *pp = parts;

+    char cp_copy[18];

+    char *cp = cp_copy;

+    

+    addr->s_addr = PJ_INADDR_NONE;

+

+    if (ccp->slen > 15) return 0;

+

+    pj_memcpy(cp, ccp->ptr, ccp->slen);

+    cp[ccp->slen] = '\0';

+

+    c = *cp;

+    for (;;) {

+	/*

+	 * Collect number up to ``.''.

+	 * Values are specified as for C:

+	 * 0x=hex, 0=octal, isdigit=decimal.

+	 */

+	if (!pj_isdigit((int)c))

+	    return (0);

+	val = 0; base = 10;

+	if (c == '0') {

+	    c = *++cp;

+	    if (c == 'x' || c == 'X')

+		base = 16, c = *++cp;

+	    else

+		base = 8;

+	}

+

+	for (;;) {

+	    if (pj_isascii((int)c) && pj_isdigit((int)c)) {

+		val = (val * base) + (c - '0');

+		c = *++cp;

+	    } else if (base==16 && pj_isascii((int)c) && pj_isxdigit((int)c)) {

+		val = (val << 4) |

+		      (c + 10 - (pj_islower((int)c) ? 'a' : 'A'));

+		c = *++cp;

+	    } else

+		break;

+	}

+

+	if (c == '.') {

+	    /*

+	     * Internet format:

+	     *  a.b.c.d

+	     *  a.b.c   (with c treated as 16 bits)

+	     *  a.b	(with b treated as 24 bits)

+	     */

+	    if (pp >= parts + 3)

+		return (0);

+	    *pp++ = val;

+	    c = *++cp;

+	} else

+	    break;

+    }

+

+    /*

+     * Check for trailing characters.

+     */

+    if (c != '\0' && (!pj_isascii((int)c) || !pj_isspace((int)c)))

+        return (0);

+    /*

+     * Concoct the address according to

+     * the number of parts specified.

+     */

+    n = pp - parts + 1;

+    switch (n) {

+    case 0:

+	return (0);	    /* initial nondigit */

+    case 1:		/* a -- 32 bits */

+	break;

+    case 2:		/* a.b -- 8.24 bits */

+	if (val > 0xffffff)

+	    return (0);

+	val |= parts[0] << 24;

+	break;

+    case 3:		/* a.b.c -- 8.8.16 bits */

+	if (val > 0xffff)

+	    return (0);

+	val |= (parts[0] << 24) | (parts[1] << 16);

+	break;

+    case 4:		/* a.b.c.d -- 8.8.8.8 bits */

+	if (val > 0xff)

+	    return (0);

+	val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);

+	break;

+    }

+

+    if (addr)

+	addr->s_addr = pj_htonl(val);

+    return (1);

+}

+

+/*

+ * Convert address string with numbers and dots to binary IP address.

+ */ 

+PJ_DEF(pj_in_addr) pj_inet_addr(const pj_str_t *cp)

+{

+    pj_in_addr addr;

+    pj_inet_aton(cp, &addr);

+    return addr;

+}

+

+/*

+ * Set the IP address of an IP socket address from string address, 

+ * with resolving the host if necessary. The string address may be in a

+ * standard numbers and dots notation or may be a hostname. If hostname

+ * is specified, then the function will resolve the host into the IP

+ * address.

+ */

+PJ_DEF(pj_status_t) pj_sockaddr_in_set_str_addr( pj_sockaddr_in *addr,

+					         const pj_str_t *str_addr)

+{

+    PJ_CHECK_STACK();

+

+    pj_assert(str_addr && str_addr->slen < PJ_MAX_HOSTNAME);

+

+    addr->sin_family = AF_INET;

+

+    if (str_addr && str_addr->slen) {

+	addr->sin_addr = pj_inet_addr(str_addr);

+	if (addr->sin_addr.s_addr == PJ_INADDR_NONE) {

+    	    pj_hostent he;

+	    if (pj_gethostbyname(str_addr, &he) == 0) {

+		addr->sin_addr.s_addr = *(pj_uint32_t*)he.h_addr;

+	    } else {

+		addr->sin_addr.s_addr = PJ_INADDR_NONE;

+		return -1;

+	    }

+	}

+

+    } else {

+	addr->sin_addr.s_addr = 0;

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Set the IP address and port of an IP socket address.

+ * The string address may be in a standard numbers and dots notation or 

+ * may be a hostname. If hostname is specified, then the function will 

+ * resolve the host into the IP address.

+ */

+PJ_DEF(pj_status_t) pj_sockaddr_in_init( pj_sockaddr_in *addr,

+				         const pj_str_t *str_addr,

+					 pj_uint16_t port)

+{

+    pj_assert(addr && str_addr);

+

+    addr->sin_family = PJ_AF_INET;

+    pj_sockaddr_in_set_port(addr, port);

+    return pj_sockaddr_in_set_str_addr(addr, str_addr);

+}

+

+

+/*

+ * Get hostname.

+ */

+PJ_DEF(const pj_str_t*) pj_gethostname(void)

+{

+    static char buf[PJ_MAX_HOSTNAME];

+    static pj_str_t hostname;

+

+    PJ_CHECK_STACK();

+

+    if (hostname.ptr == NULL) {

+	hostname.ptr = buf;

+	down_read(&uts_sem);

+	hostname.slen = strlen(system_utsname.nodename);

+	if (hostname.slen > PJ_MAX_HOSTNAME) {

+	    hostname.ptr[0] = '\0';

+	    hostname.slen = 0;

+	} else {

+	    pj_memcpy(hostname.ptr, system_utsname.nodename, hostname.slen);

+	}

+	up_read(&uts_sem);

+    }

+    return &hostname;

+}

+

+/*

+ * Get first IP address associated with the hostname.

+ */

+PJ_DEF(pj_in_addr) pj_gethostaddr(void)

+{

+    pj_sockaddr_in addr;

+    const pj_str_t *hostname = pj_gethostname();

+

+    pj_sockaddr_in_set_str_addr(&addr, hostname);

+    return addr.sin_addr;

+}

+

+

+/*

+ * Create new socket/endpoint for communication and returns a descriptor.

+ */

+PJ_DEF(pj_status_t) pj_sock_socket(int af, int type, int proto, 

+				   pj_sock_t *sock_fd)

+{

+    long result;

+

+    PJ_CHECK_STACK();

+

+    /* Sanity checks. */

+    PJ_ASSERT_RETURN(PJ_INVALID_SOCKET == -1 && sock_fd != NULL, PJ_EINVAL);

+

+    /* Initialize returned socket */

+    *sock_fd = PJ_INVALID_SOCKET;

+

+    /* Create socket. */

+    result = sys_socket(af, type, proto);

+    if (result < 0) {

+	return PJ_RETURN_OS_ERROR((-result));

+    }

+

+    *sock_fd = result;

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Bind socket.

+ */

+PJ_DEF(pj_status_t) pj_sock_bind( pj_sock_t sockfd, 

+				  const pj_sockaddr_t *addr,

+				  int len)

+{

+    long err;

+    mm_segment_t oldfs;

+

+    PJ_CHECK_STACK();

+

+    PJ_ASSERT_RETURN(addr!=NULL && len >= sizeof(struct pj_sockaddr),

+		     PJ_EINVAL);

+

+    oldfs = get_fs();

+    set_fs(KERNEL_DS);

+    

+    err = sys_bind(sockfd, (struct sockaddr*)addr, len);

+

+    set_fs(oldfs);

+

+    if (err)

+	return PJ_RETURN_OS_ERROR(-err);

+    else

+	return PJ_SUCCESS;

+}

+

+

+/*

+ * Bind socket.

+ */

+PJ_DEF(pj_status_t) pj_sock_bind_in( pj_sock_t sockfd, 

+				     pj_uint32_t addr32,

+				     pj_uint16_t port)

+{

+    pj_sockaddr_in addr;

+

+    PJ_CHECK_STACK();

+

+    addr.sin_family = PJ_AF_INET;

+    addr.sin_addr.s_addr = pj_htonl(addr32);

+    addr.sin_port = pj_htons(port);

+

+    return pj_sock_bind(sockfd, &addr, sizeof(pj_sockaddr_in));

+}

+

+/*

+ * Close socket.

+ */

+PJ_DEF(pj_status_t) pj_sock_close(pj_sock_t sockfd)

+{

+    long err;

+

+    err = sys_close(sockfd);

+

+    if (err != 0)

+	return PJ_RETURN_OS_ERROR(-err);

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Get remote's name.

+ */

+PJ_DEF(pj_status_t) pj_sock_getpeername( pj_sock_t sockfd,

+					 pj_sockaddr_t *addr,

+					 int *namelen)

+{

+    mm_segment_t oldfs;

+    long err;

+

+    PJ_CHECK_STACK();

+

+    oldfs = get_fs();

+    set_fs(KERNEL_DS);

+

+    err = sys_getpeername( sockfd, addr, namelen);

+

+    set_fs(oldfs);

+

+    if (err)

+	return PJ_RETURN_OS_ERROR(-err);

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Get socket name.

+ */

+PJ_DEF(pj_status_t) pj_sock_getsockname( pj_sock_t sockfd,

+					 pj_sockaddr_t *addr,

+					 int *namelen)

+{

+    mm_segment_t oldfs;

+    int err;

+

+    PJ_CHECK_STACK();

+

+    oldfs = get_fs();

+    set_fs(KERNEL_DS);

+    

+    err = sys_getsockname( sockfd, addr, namelen );

+

+    set_fs(oldfs);

+

+    if (err)

+	return PJ_RETURN_OS_ERROR(-err);

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Send data

+ */

+PJ_DEF(pj_status_t) pj_sock_send( pj_sock_t sockfd,

+				  const void *buf,

+				  pj_ssize_t *len,

+				  unsigned flags)

+{

+    return pj_sock_sendto(sockfd, buf, len, flags, NULL, 0);

+}

+

+

+/*

+ * Send data.

+ */

+PJ_DEF(pj_status_t) pj_sock_sendto( pj_sock_t sockfd,

+				    const void *buff,

+				    pj_ssize_t *len,

+				    unsigned flags,

+				    const pj_sockaddr_t *addr,

+				    int addr_len)

+{

+    long err;

+    mm_segment_t oldfs;

+

+    PJ_CHECK_STACK();

+

+    oldfs = get_fs();

+    set_fs(KERNEL_DS);

+    

+    err = *len = sys_sendto( sockfd, (void*)buff, *len, flags, 

+			     (void*)addr, addr_len );

+

+    set_fs(oldfs);

+    

+    if (err >= 0) {

+	return PJ_SUCCESS;

+    }

+    else {

+	return PJ_RETURN_OS_ERROR(-err);

+    }

+}

+

+/*

+ * Receive data.

+ */

+PJ_DEF(pj_status_t) pj_sock_recv( pj_sock_t sockfd,

+				  void *buf,

+				  pj_ssize_t *len,

+				  unsigned flags)

+{

+    return pj_sock_recvfrom(sockfd, buf, len, flags, NULL, NULL);

+}

+

+/*

+ * Receive data.

+ */

+PJ_DEF(pj_status_t) pj_sock_recvfrom( pj_sock_t sockfd,

+				      void *buff,

+				      pj_ssize_t *size,

+				      unsigned flags,

+				      pj_sockaddr_t *from,

+				      int *fromlen)

+{

+    mm_segment_t oldfs;

+    long err;

+

+    PJ_CHECK_STACK();

+

+    oldfs = get_fs();

+    set_fs(KERNEL_DS);

+

+    err = *size = sys_recvfrom( sockfd, buff, *size, flags, from, fromlen);

+

+    set_fs(oldfs);

+

+    if (err >= 0) {

+	return PJ_SUCCESS;

+    }

+    else {

+	return PJ_RETURN_OS_ERROR(-err);

+    }

+}

+

+/*

+ * Get socket option.

+ */

+PJ_DEF(pj_status_t) pj_sock_getsockopt( pj_sock_t sockfd,

+					pj_uint16_t level,

+					pj_uint16_t optname,

+					void *optval,

+					int *optlen)

+{

+    mm_segment_t oldfs;

+    long err;

+

+    PJ_CHECK_STACK();

+

+    oldfs = get_fs();

+    set_fs(KERNEL_DS);

+

+    err = sys_getsockopt( sockfd, level, optname, optval, optlen);

+

+    set_fs(oldfs);

+

+    if (err)

+	return PJ_RETURN_OS_ERROR(-err);

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Set socket option.

+ */

+PJ_DEF(pj_status_t) pj_sock_setsockopt( pj_sock_t sockfd,

+					pj_uint16_t level,

+					pj_uint16_t optname,

+					const void *optval,

+					int optlen)

+{

+    long err;

+    mm_segment_t oldfs;

+

+    PJ_CHECK_STACK();

+

+

+    oldfs = get_fs();

+    set_fs(KERNEL_DS);

+

+    err = sys_setsockopt( sockfd, level, optname, (void*)optval, optlen);

+

+    set_fs(oldfs);

+

+    if (err)

+	return PJ_RETURN_OS_ERROR(-err);

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Shutdown socket.

+ */

+#if PJ_HAS_TCP

+PJ_DEF(pj_status_t) pj_sock_shutdown( pj_sock_t sockfd,

+				      int how)

+{

+    long err;

+

+    PJ_CHECK_STACK();

+

+    err = sys_shutdown(sockfd, how);

+

+    if (err)

+	return PJ_RETURN_OS_ERROR(-err);

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Start listening to incoming connections.

+ */

+PJ_DEF(pj_status_t) pj_sock_listen( pj_sock_t sockfd,

+				    int backlog)

+{

+    long err;

+

+    PJ_CHECK_STACK();

+

+    err = sys_listen( sockfd, backlog );

+

+    if (err)

+	return PJ_RETURN_OS_ERROR(-err);

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Connect socket.

+ */

+PJ_DEF(pj_status_t) pj_sock_connect( pj_sock_t sockfd,

+				     const pj_sockaddr_t *addr,

+				     int namelen)

+{

+    long err;

+    mm_segment_t oldfs;

+    

+    PJ_CHECK_STACK();

+

+    oldfs = get_fs();

+    set_fs(KERNEL_DS);

+

+    err = sys_connect( sockfd, (void*)addr, namelen );

+

+    set_fs(oldfs);

+

+    if (err)

+	return PJ_RETURN_OS_ERROR(-err);

+    else

+	return PJ_SUCCESS;

+}

+

+/*

+ * Accept incoming connections

+ */

+PJ_DEF(pj_status_t) pj_sock_accept( pj_sock_t sockfd,

+				    pj_sock_t *newsockfd,

+				    pj_sockaddr_t *addr,

+				    int *addrlen)

+{

+    long err;

+

+    PJ_CHECK_STACK();

+

+    PJ_ASSERT_RETURN(newsockfd != NULL, PJ_EINVAL);

+

+    err = sys_accept( sockfd, addr, addrlen);

+

+    if (err < 0) {

+	*newsockfd = PJ_INVALID_SOCKET;

+	return PJ_RETURN_OS_ERROR(-err);

+    }

+    else {

+	*newsockfd = err;

+	return PJ_SUCCESS;

+    }

+}

+#endif	/* PJ_HAS_TCP */

+

+

+

+/*

+ * Permission to steal inet_ntoa() and inet_aton() as long as this notice below

+ * is included:

+ */

+/*

+ * Copyright (c) 1983, 1993

+ *  The Regents of the University of California.  All rights reserved.

+ *

+ * Redistribution and use in source and binary forms, with or without

+ * modification, are permitted provided that the following conditions

+ * are met:

+ * 1. Redistributions of source code must retain the above copyright

+ *    notice, this list of conditions and the following disclaimer.

+ * 2. Redistributions in binary form must reproduce the above copyright

+ *    notice, this list of conditions and the following disclaimer in the

+ *    documentation and/or other materials provided with the distribution.

+ * 3. All advertising materials mentioning features or use of this software

+ *    must display the following acknowledgement:

+ *  This product includes software developed by the University of

+ *  California, Berkeley and its contributors.

+ * 4. Neither the name of the University nor the names of its contributors

+ *    may be used to endorse or promote products derived from this software

+ *    without specific prior written permission.

+ *

+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND

+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE

+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS

+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)

+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT

+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY

+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF

+ * SUCH DAMAGE.

+ */

+

diff --git a/pjlib/src/pj/sock_select.c b/pjlib/src/pj/sock_select.c
index 5b3d0a6..57d2f8e 100644
--- a/pjlib/src/pj/sock_select.c
+++ b/pjlib/src/pj/sock_select.c
@@ -1,92 +1,113 @@
-/* $Id$
- */
-#include <pj/sock_select.h>
-#include <pj/compat/socket.h>
-#include <pj/os.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
-
-#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H!=0
-#   include <string.h>
-#endif
-
-#ifdef _MSC_VER
-#   pragma warning(disable: 4018)    // Signed/unsigned mismatch in FD_*
-#   pragma warning(disable: 4389)    // Signed/unsigned mismatch in FD_*
-#endif
-
-#define PART_FDSET(ps)		((fd_set*)&ps->data[1])
-#define PART_FDSET_OR_NULL(ps)	(ps ? PART_FDSET(ps) : NULL)
-#define PART_COUNT(ps)		(ps->data[0])
-
-PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp)
-{
-    PJ_CHECK_STACK();
-    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
-
-    FD_ZERO(PART_FDSET(fdsetp));
-    PART_COUNT(fdsetp) = 0;
-}
-
-
-PJ_DEF(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp)
-{
-    PJ_CHECK_STACK();
-    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
-
-    if (!PJ_FD_ISSET(fd, fdsetp))
-        ++PART_COUNT(fdsetp);
-    FD_SET(fd, PART_FDSET(fdsetp));
-}
-
-
-PJ_DEF(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp)
-{
-    PJ_CHECK_STACK();
-    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));
-
-    if (PJ_FD_ISSET(fd, fdsetp))
-        --PART_COUNT(fdsetp);
-    FD_CLR(fd, PART_FDSET(fdsetp));
-}
-
-
-PJ_DEF(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp)
-{
-    PJ_CHECK_STACK();
-    PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),
-                     0);
-
-    return FD_ISSET(fd, PART_FDSET(fdsetp));
-}
-
-PJ_DEF(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp)
-{
-    return PART_COUNT(fdsetp);
-}
-
-PJ_DEF(int) pj_sock_select( int n, 
-			    pj_fd_set_t *readfds, 
-			    pj_fd_set_t *writefds,
-			    pj_fd_set_t *exceptfds, 
-			    const pj_time_val *timeout)
-{
-    struct timeval os_timeout, *p_os_timeout;
-
-    PJ_CHECK_STACK();
-
-    PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),
-                     PJ_EBUG);
-
-    if (timeout) {
-	os_timeout.tv_sec = timeout->sec;
-	os_timeout.tv_usec = timeout->msec * 1000;
-	p_os_timeout = &os_timeout;
-    } else {
-	p_os_timeout = NULL;
-    }
-
-    return select(n, PART_FDSET_OR_NULL(readfds), PART_FDSET_OR_NULL(writefds),
-		  PART_FDSET_OR_NULL(exceptfds), p_os_timeout);
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/sock_select.h>

+#include <pj/compat/socket.h>

+#include <pj/os.h>

+#include <pj/assert.h>

+#include <pj/errno.h>

+

+#if defined(PJ_HAS_STRING_H) && PJ_HAS_STRING_H!=0

+#   include <string.h>

+#endif

+

+#ifdef _MSC_VER

+#   pragma warning(disable: 4018)    // Signed/unsigned mismatch in FD_*

+#   pragma warning(disable: 4389)    // Signed/unsigned mismatch in FD_*

+#endif

+

+#define PART_FDSET(ps)		((fd_set*)&ps->data[1])

+#define PART_FDSET_OR_NULL(ps)	(ps ? PART_FDSET(ps) : NULL)

+#define PART_COUNT(ps)		(ps->data[0])

+

+PJ_DEF(void) PJ_FD_ZERO(pj_fd_set_t *fdsetp)

+{

+    PJ_CHECK_STACK();

+    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));

+

+    FD_ZERO(PART_FDSET(fdsetp));

+    PART_COUNT(fdsetp) = 0;

+}

+

+

+PJ_DEF(void) PJ_FD_SET(pj_sock_t fd, pj_fd_set_t *fdsetp)

+{

+    PJ_CHECK_STACK();

+    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));

+

+    if (!PJ_FD_ISSET(fd, fdsetp))

+        ++PART_COUNT(fdsetp);

+    FD_SET(fd, PART_FDSET(fdsetp));

+}

+

+

+PJ_DEF(void) PJ_FD_CLR(pj_sock_t fd, pj_fd_set_t *fdsetp)

+{

+    PJ_CHECK_STACK();

+    pj_assert(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set));

+

+    if (PJ_FD_ISSET(fd, fdsetp))

+        --PART_COUNT(fdsetp);

+    FD_CLR(fd, PART_FDSET(fdsetp));

+}

+

+

+PJ_DEF(pj_bool_t) PJ_FD_ISSET(pj_sock_t fd, const pj_fd_set_t *fdsetp)

+{

+    PJ_CHECK_STACK();

+    PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),

+                     0);

+

+    return FD_ISSET(fd, PART_FDSET(fdsetp));

+}

+

+PJ_DEF(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp)

+{

+    return PART_COUNT(fdsetp);

+}

+

+PJ_DEF(int) pj_sock_select( int n, 

+			    pj_fd_set_t *readfds, 

+			    pj_fd_set_t *writefds,

+			    pj_fd_set_t *exceptfds, 

+			    const pj_time_val *timeout)

+{

+    struct timeval os_timeout, *p_os_timeout;

+

+    PJ_CHECK_STACK();

+

+    PJ_ASSERT_RETURN(sizeof(pj_fd_set_t)-sizeof(pj_sock_t) >= sizeof(fd_set),

+                     PJ_EBUG);

+

+    if (timeout) {

+	os_timeout.tv_sec = timeout->sec;

+	os_timeout.tv_usec = timeout->msec * 1000;

+	p_os_timeout = &os_timeout;

+    } else {

+	p_os_timeout = NULL;

+    }

+

+    return select(n, PART_FDSET_OR_NULL(readfds), PART_FDSET_OR_NULL(writefds),

+		  PART_FDSET_OR_NULL(exceptfds), p_os_timeout);

+}

+

diff --git a/pjlib/src/pj/string.c b/pjlib/src/pj/string.c
index 73313f9..9c87d15 100644
--- a/pjlib/src/pj/string.c
+++ b/pjlib/src/pj/string.c
@@ -1,115 +1,136 @@
-/* $Id$
- */
-#include <pj/string.h>
-#include <pj/pool.h>
-#include <pj/ctype.h>
-#include <pj/rand.h>
-#include <pj/os.h>
-
-#if PJ_FUNCTIONS_ARE_INLINED==0
-#  include <pj/string_i.h>
-#endif
-
-
-static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
-		     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
-PJ_DEF(pj_str_t*) pj_strltrim( pj_str_t *str )
-{
-    register char *p = str->ptr;
-    while (pj_isspace(*p))
-	++p;
-    str->slen -= (p - str->ptr);
-    str->ptr = p;
-    return str;
-}
-
-PJ_DEF(pj_str_t*) pj_strrtrim( pj_str_t *str )
-{
-    char *end = str->ptr + str->slen;
-    register char *p = end - 1;
-    while (p >= str->ptr && pj_isspace(*p))
-        --p;
-    str->slen -= ((end - p) - 1);
-    return str;
-}
-
-PJ_INLINE(void) pj_val_to_hex_digit(unsigned value, char *p)
-{
-    *p++ = hex[ (value & 0xF0) >> 4 ];
-    *p++ = hex[ (value & 0x0F) ];
-}
-
-PJ_DEF(char*) pj_create_random_string(char *str, pj_size_t len)
-{
-    unsigned i;
-    char *p = str;
-
-    PJ_CHECK_STACK();
-
-    for (i=0; i<len/8; ++i) {
-	unsigned val = pj_rand();
-	pj_val_to_hex_digit( (val & 0xFF000000) >> 24, p+0 );
-	pj_val_to_hex_digit( (val & 0x00FF0000) >> 16, p+2 );
-	pj_val_to_hex_digit( (val & 0x0000FF00) >>  8, p+4 );
-	pj_val_to_hex_digit( (val & 0x000000FF) >>  0, p+6 );
-	p += 8;
-    }
-    for (i=i * 8; i<len; ++i) {
-	*p++ = hex[ pj_rand() & 0x0F ];
-    }
-    return str;
-}
-
-
-PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str)
-{
-    unsigned long value;
-    unsigned i;
-
-    PJ_CHECK_STACK();
-
-    value = 0;
-    for (i=0; i<(unsigned)str->slen; ++i) {
-	value = value * 10 + (str->ptr[i] - '0');
-    }
-    return value;
-}
-
-PJ_DEF(int) pj_utoa(unsigned long val, char *buf)
-{
-    return pj_utoa_pad(val, buf, 0, 0);
-}
-
-PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)
-{
-    char *p;
-    int len;
-
-    PJ_CHECK_STACK();
-
-    p = buf;
-    do {
-        unsigned long digval = (unsigned long) (val % 10);
-        val /= 10;
-        *p++ = (char) (digval + '0');
-    } while (val > 0);
-
-    len = p-buf;
-    while (len < min_dig) {
-	*p++ = (char)pad;
-	++len;
-    }
-    *p-- = '\0';
-
-    do {
-        char temp = *p;
-        *p = *buf;
-        *buf = temp;
-        --p;
-        ++buf;
-    } while (buf < p);
-
-    return len;
-}
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/string.h>

+#include <pj/pool.h>

+#include <pj/ctype.h>

+#include <pj/rand.h>

+#include <pj/os.h>

+

+#if PJ_FUNCTIONS_ARE_INLINED==0

+#  include <pj/string_i.h>

+#endif

+

+

+static char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',

+		     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

+

+PJ_DEF(pj_str_t*) pj_strltrim( pj_str_t *str )

+{

+    register char *p = str->ptr;

+    while (pj_isspace(*p))

+	++p;

+    str->slen -= (p - str->ptr);

+    str->ptr = p;

+    return str;

+}

+

+PJ_DEF(pj_str_t*) pj_strrtrim( pj_str_t *str )

+{

+    char *end = str->ptr + str->slen;

+    register char *p = end - 1;

+    while (p >= str->ptr && pj_isspace(*p))

+        --p;

+    str->slen -= ((end - p) - 1);

+    return str;

+}

+

+PJ_INLINE(void) pj_val_to_hex_digit(unsigned value, char *p)

+{

+    *p++ = hex[ (value & 0xF0) >> 4 ];

+    *p++ = hex[ (value & 0x0F) ];

+}

+

+PJ_DEF(char*) pj_create_random_string(char *str, pj_size_t len)

+{

+    unsigned i;

+    char *p = str;

+

+    PJ_CHECK_STACK();

+

+    for (i=0; i<len/8; ++i) {

+	unsigned val = pj_rand();

+	pj_val_to_hex_digit( (val & 0xFF000000) >> 24, p+0 );

+	pj_val_to_hex_digit( (val & 0x00FF0000) >> 16, p+2 );

+	pj_val_to_hex_digit( (val & 0x0000FF00) >>  8, p+4 );

+	pj_val_to_hex_digit( (val & 0x000000FF) >>  0, p+6 );

+	p += 8;

+    }

+    for (i=i * 8; i<len; ++i) {

+	*p++ = hex[ pj_rand() & 0x0F ];

+    }

+    return str;

+}

+

+

+PJ_DEF(unsigned long) pj_strtoul(const pj_str_t *str)

+{

+    unsigned long value;

+    unsigned i;

+

+    PJ_CHECK_STACK();

+

+    value = 0;

+    for (i=0; i<(unsigned)str->slen; ++i) {

+	value = value * 10 + (str->ptr[i] - '0');

+    }

+    return value;

+}

+

+PJ_DEF(int) pj_utoa(unsigned long val, char *buf)

+{

+    return pj_utoa_pad(val, buf, 0, 0);

+}

+

+PJ_DEF(int) pj_utoa_pad( unsigned long val, char *buf, int min_dig, int pad)

+{

+    char *p;

+    int len;

+

+    PJ_CHECK_STACK();

+

+    p = buf;

+    do {

+        unsigned long digval = (unsigned long) (val % 10);

+        val /= 10;

+        *p++ = (char) (digval + '0');

+    } while (val > 0);

+

+    len = p-buf;

+    while (len < min_dig) {

+	*p++ = (char)pad;

+	++len;

+    }

+    *p-- = '\0';

+

+    do {

+        char temp = *p;

+        *p = *buf;

+        *buf = temp;

+        --p;

+        ++buf;

+    } while (buf < p);

+

+    return len;

+}

+

diff --git a/pjlib/src/pj/symbols.c b/pjlib/src/pj/symbols.c
index fc434ad..8d0ba55 100644
--- a/pjlib/src/pj/symbols.c
+++ b/pjlib/src/pj/symbols.c
@@ -1,330 +1,351 @@
-/* $Id$
- */
-#include <pjlib.h>
-
-/*
- * addr_resolv.h
- */
-PJ_EXPORT_SYMBOL(pj_gethostbyname)
-
-/*
- * array.h
- */
-PJ_EXPORT_SYMBOL(pj_array_insert)
-PJ_EXPORT_SYMBOL(pj_array_erase)
-PJ_EXPORT_SYMBOL(pj_array_find)
-
-/*
- * config.h
- */
-PJ_EXPORT_SYMBOL(pj_dump_config)
-	
-/*
- * errno.h
- */
-PJ_EXPORT_SYMBOL(pj_get_os_error)
-PJ_EXPORT_SYMBOL(pj_set_os_error)
-PJ_EXPORT_SYMBOL(pj_get_netos_error)
-PJ_EXPORT_SYMBOL(pj_set_netos_error)
-PJ_EXPORT_SYMBOL(pj_strerror)
-
-/*
- * except.h
- */
-PJ_EXPORT_SYMBOL(pj_throw_exception_)
-PJ_EXPORT_SYMBOL(pj_push_exception_handler_)
-PJ_EXPORT_SYMBOL(pj_pop_exception_handler_)
-PJ_EXPORT_SYMBOL(pj_setjmp)
-PJ_EXPORT_SYMBOL(pj_longjmp)
-PJ_EXPORT_SYMBOL(pj_exception_id_alloc)
-PJ_EXPORT_SYMBOL(pj_exception_id_free)
-PJ_EXPORT_SYMBOL(pj_exception_id_name)
-
-
-/*
- * fifobuf.h
- */
-PJ_EXPORT_SYMBOL(pj_fifobuf_init)
-PJ_EXPORT_SYMBOL(pj_fifobuf_max_size)
-PJ_EXPORT_SYMBOL(pj_fifobuf_alloc)
-PJ_EXPORT_SYMBOL(pj_fifobuf_unalloc)
-PJ_EXPORT_SYMBOL(pj_fifobuf_free)
-
-/*
- * guid.h
- */
-PJ_EXPORT_SYMBOL(pj_generate_unique_string)
-PJ_EXPORT_SYMBOL(pj_create_unique_string)
-
-/*
- * hash.h
- */
-PJ_EXPORT_SYMBOL(pj_hash_calc)
-PJ_EXPORT_SYMBOL(pj_hash_create)
-PJ_EXPORT_SYMBOL(pj_hash_get)
-PJ_EXPORT_SYMBOL(pj_hash_set)
-PJ_EXPORT_SYMBOL(pj_hash_count)
-PJ_EXPORT_SYMBOL(pj_hash_first)
-PJ_EXPORT_SYMBOL(pj_hash_next)
-PJ_EXPORT_SYMBOL(pj_hash_this)
-
-/*
- * ioqueue.h
- */
-PJ_EXPORT_SYMBOL(pj_ioqueue_create)
-PJ_EXPORT_SYMBOL(pj_ioqueue_destroy)
-PJ_EXPORT_SYMBOL(pj_ioqueue_set_lock)
-PJ_EXPORT_SYMBOL(pj_ioqueue_register_sock)
-PJ_EXPORT_SYMBOL(pj_ioqueue_unregister)
-PJ_EXPORT_SYMBOL(pj_ioqueue_get_user_data)
-PJ_EXPORT_SYMBOL(pj_ioqueue_poll)
-PJ_EXPORT_SYMBOL(pj_ioqueue_read)
-PJ_EXPORT_SYMBOL(pj_ioqueue_recv)
-PJ_EXPORT_SYMBOL(pj_ioqueue_recvfrom)
-PJ_EXPORT_SYMBOL(pj_ioqueue_write)
-PJ_EXPORT_SYMBOL(pj_ioqueue_send)
-PJ_EXPORT_SYMBOL(pj_ioqueue_sendto)
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-PJ_EXPORT_SYMBOL(pj_ioqueue_accept)
-PJ_EXPORT_SYMBOL(pj_ioqueue_connect)
-#endif
-
-/*
- * list.h
- */
-PJ_EXPORT_SYMBOL(pj_list_insert_before)
-PJ_EXPORT_SYMBOL(pj_list_insert_nodes_before)
-PJ_EXPORT_SYMBOL(pj_list_insert_after)
-PJ_EXPORT_SYMBOL(pj_list_insert_nodes_after)
-PJ_EXPORT_SYMBOL(pj_list_merge_first)
-PJ_EXPORT_SYMBOL(pj_list_merge_last)
-PJ_EXPORT_SYMBOL(pj_list_erase)
-PJ_EXPORT_SYMBOL(pj_list_find_node)
-PJ_EXPORT_SYMBOL(pj_list_search)
-
-
-/*
- * log.h
- */
-PJ_EXPORT_SYMBOL(pj_log_write)
-#if PJ_LOG_MAX_LEVEL >= 1
-PJ_EXPORT_SYMBOL(pj_log_set_log_func)
-PJ_EXPORT_SYMBOL(pj_log_get_log_func)
-PJ_EXPORT_SYMBOL(pj_log_set_level)
-PJ_EXPORT_SYMBOL(pj_log_get_level)
-PJ_EXPORT_SYMBOL(pj_log_set_decor)
-PJ_EXPORT_SYMBOL(pj_log_get_decor)
-PJ_EXPORT_SYMBOL(pj_log_1)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 2
-PJ_EXPORT_SYMBOL(pj_log_2)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 3
-PJ_EXPORT_SYMBOL(pj_log_3)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 4
-PJ_EXPORT_SYMBOL(pj_log_4)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 5
-PJ_EXPORT_SYMBOL(pj_log_5)
-#endif
-#if PJ_LOG_MAX_LEVEL >= 6
-PJ_EXPORT_SYMBOL(pj_log_6)
-#endif
-
-/*
- * os.h
- */
-PJ_EXPORT_SYMBOL(pj_init)
-PJ_EXPORT_SYMBOL(pj_getpid)
-PJ_EXPORT_SYMBOL(pj_thread_register)
-PJ_EXPORT_SYMBOL(pj_thread_create)
-PJ_EXPORT_SYMBOL(pj_thread_get_name)
-PJ_EXPORT_SYMBOL(pj_thread_resume)
-PJ_EXPORT_SYMBOL(pj_thread_this)
-PJ_EXPORT_SYMBOL(pj_thread_join)
-PJ_EXPORT_SYMBOL(pj_thread_destroy)
-PJ_EXPORT_SYMBOL(pj_thread_sleep)
-#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0
-PJ_EXPORT_SYMBOL(pj_thread_check_stack)
-PJ_EXPORT_SYMBOL(pj_thread_get_stack_max_usage)
-PJ_EXPORT_SYMBOL(pj_thread_get_stack_info)
-#endif
-PJ_EXPORT_SYMBOL(pj_atomic_create)
-PJ_EXPORT_SYMBOL(pj_atomic_destroy)
-PJ_EXPORT_SYMBOL(pj_atomic_set)
-PJ_EXPORT_SYMBOL(pj_atomic_get)
-PJ_EXPORT_SYMBOL(pj_atomic_inc)
-PJ_EXPORT_SYMBOL(pj_atomic_dec)
-PJ_EXPORT_SYMBOL(pj_thread_local_alloc)
-PJ_EXPORT_SYMBOL(pj_thread_local_free)
-PJ_EXPORT_SYMBOL(pj_thread_local_set)
-PJ_EXPORT_SYMBOL(pj_thread_local_get)
-PJ_EXPORT_SYMBOL(pj_enter_critical_section)
-PJ_EXPORT_SYMBOL(pj_leave_critical_section)
-PJ_EXPORT_SYMBOL(pj_mutex_create)
-PJ_EXPORT_SYMBOL(pj_mutex_lock)
-PJ_EXPORT_SYMBOL(pj_mutex_unlock)
-PJ_EXPORT_SYMBOL(pj_mutex_trylock)
-PJ_EXPORT_SYMBOL(pj_mutex_destroy)
-#if defined(PJ_DEBUG) && PJ_DEBUG != 0
-PJ_EXPORT_SYMBOL(pj_mutex_is_locked)
-#endif
-#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0
-PJ_EXPORT_SYMBOL(pj_sem_create)
-PJ_EXPORT_SYMBOL(pj_sem_wait)
-PJ_EXPORT_SYMBOL(pj_sem_trywait)
-PJ_EXPORT_SYMBOL(pj_sem_post)
-PJ_EXPORT_SYMBOL(pj_sem_destroy)
-#endif
-PJ_EXPORT_SYMBOL(pj_gettimeofday)
-PJ_EXPORT_SYMBOL(pj_time_decode)
-#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0
-PJ_EXPORT_SYMBOL(pj_get_timestamp)
-PJ_EXPORT_SYMBOL(pj_get_timestamp_freq)
-PJ_EXPORT_SYMBOL(pj_elapsed_time)
-PJ_EXPORT_SYMBOL(pj_elapsed_usec)
-PJ_EXPORT_SYMBOL(pj_elapsed_nanosec)
-PJ_EXPORT_SYMBOL(pj_elapsed_cycle)
-#endif
-
-	
-/*
- * pool.h
- */
-PJ_EXPORT_SYMBOL(pj_pool_create)
-PJ_EXPORT_SYMBOL(pj_pool_release)
-PJ_EXPORT_SYMBOL(pj_pool_getobjname)
-PJ_EXPORT_SYMBOL(pj_pool_reset)
-PJ_EXPORT_SYMBOL(pj_pool_get_capacity)
-PJ_EXPORT_SYMBOL(pj_pool_get_used_size)
-PJ_EXPORT_SYMBOL(pj_pool_alloc)
-PJ_EXPORT_SYMBOL(pj_pool_calloc)
-PJ_EXPORT_SYMBOL(pj_pool_factory_default_policy)
-PJ_EXPORT_SYMBOL(pj_pool_create_int)
-PJ_EXPORT_SYMBOL(pj_pool_init_int)
-PJ_EXPORT_SYMBOL(pj_pool_destroy_int)
-PJ_EXPORT_SYMBOL(pj_caching_pool_init)
-PJ_EXPORT_SYMBOL(pj_caching_pool_destroy)
-
-/*
- * rand.h
- */
-PJ_EXPORT_SYMBOL(pj_rand)
-PJ_EXPORT_SYMBOL(pj_srand)
-
-/*
- * rbtree.h
- */
-PJ_EXPORT_SYMBOL(pj_rbtree_init)
-PJ_EXPORT_SYMBOL(pj_rbtree_first)
-PJ_EXPORT_SYMBOL(pj_rbtree_last)
-PJ_EXPORT_SYMBOL(pj_rbtree_next)
-PJ_EXPORT_SYMBOL(pj_rbtree_prev)
-PJ_EXPORT_SYMBOL(pj_rbtree_insert)
-PJ_EXPORT_SYMBOL(pj_rbtree_find)
-PJ_EXPORT_SYMBOL(pj_rbtree_erase)
-PJ_EXPORT_SYMBOL(pj_rbtree_max_height)
-PJ_EXPORT_SYMBOL(pj_rbtree_min_height)
-
-/*
- * sock.h
- */
-PJ_EXPORT_SYMBOL(PJ_AF_UNIX)
-PJ_EXPORT_SYMBOL(PJ_AF_INET)
-PJ_EXPORT_SYMBOL(PJ_AF_INET6)
-PJ_EXPORT_SYMBOL(PJ_AF_PACKET)
-PJ_EXPORT_SYMBOL(PJ_AF_IRDA)
-PJ_EXPORT_SYMBOL(PJ_SOCK_STREAM)
-PJ_EXPORT_SYMBOL(PJ_SOCK_DGRAM)
-PJ_EXPORT_SYMBOL(PJ_SOCK_RAW)
-PJ_EXPORT_SYMBOL(PJ_SOCK_RDM)
-PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET)
-PJ_EXPORT_SYMBOL(PJ_SOL_IP)
-PJ_EXPORT_SYMBOL(PJ_SOL_TCP)
-PJ_EXPORT_SYMBOL(PJ_SOL_UDP)
-PJ_EXPORT_SYMBOL(PJ_SOL_IPV6)
-PJ_EXPORT_SYMBOL(pj_ntohs)
-PJ_EXPORT_SYMBOL(pj_htons)
-PJ_EXPORT_SYMBOL(pj_ntohl)
-PJ_EXPORT_SYMBOL(pj_htonl)
-PJ_EXPORT_SYMBOL(pj_inet_ntoa)
-PJ_EXPORT_SYMBOL(pj_inet_aton)
-PJ_EXPORT_SYMBOL(pj_inet_addr)
-PJ_EXPORT_SYMBOL(pj_sockaddr_in_set_str_addr)
-PJ_EXPORT_SYMBOL(pj_sockaddr_in_init)
-PJ_EXPORT_SYMBOL(pj_gethostname)
-PJ_EXPORT_SYMBOL(pj_gethostaddr)
-PJ_EXPORT_SYMBOL(pj_sock_socket)
-PJ_EXPORT_SYMBOL(pj_sock_close)
-PJ_EXPORT_SYMBOL(pj_sock_bind)
-PJ_EXPORT_SYMBOL(pj_sock_bind_in)
-#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
-PJ_EXPORT_SYMBOL(pj_sock_listen)
-PJ_EXPORT_SYMBOL(pj_sock_accept)
-PJ_EXPORT_SYMBOL(pj_sock_shutdown)
-#endif
-PJ_EXPORT_SYMBOL(pj_sock_connect)
-PJ_EXPORT_SYMBOL(pj_sock_getpeername)
-PJ_EXPORT_SYMBOL(pj_sock_getsockname)
-PJ_EXPORT_SYMBOL(pj_sock_getsockopt)
-PJ_EXPORT_SYMBOL(pj_sock_setsockopt)
-PJ_EXPORT_SYMBOL(pj_sock_recv)
-PJ_EXPORT_SYMBOL(pj_sock_recvfrom)
-PJ_EXPORT_SYMBOL(pj_sock_send)
-PJ_EXPORT_SYMBOL(pj_sock_sendto)
-
-/*
- * sock_select.h
- */
-PJ_EXPORT_SYMBOL(PJ_FD_ZERO)
-PJ_EXPORT_SYMBOL(PJ_FD_SET)
-PJ_EXPORT_SYMBOL(PJ_FD_CLR)
-PJ_EXPORT_SYMBOL(PJ_FD_ISSET)
-PJ_EXPORT_SYMBOL(pj_sock_select)
-
-/*
- * string.h
- */
-PJ_EXPORT_SYMBOL(pj_str)
-PJ_EXPORT_SYMBOL(pj_strassign)
-PJ_EXPORT_SYMBOL(pj_strcpy)
-PJ_EXPORT_SYMBOL(pj_strcpy2)
-PJ_EXPORT_SYMBOL(pj_strdup)
-PJ_EXPORT_SYMBOL(pj_strdup_with_null)
-PJ_EXPORT_SYMBOL(pj_strdup2)
-PJ_EXPORT_SYMBOL(pj_strdup3)
-PJ_EXPORT_SYMBOL(pj_strcmp)
-PJ_EXPORT_SYMBOL(pj_strcmp2)
-PJ_EXPORT_SYMBOL(pj_strncmp)
-PJ_EXPORT_SYMBOL(pj_strncmp2)
-PJ_EXPORT_SYMBOL(pj_stricmp)
-PJ_EXPORT_SYMBOL(pj_stricmp2)
-PJ_EXPORT_SYMBOL(pj_strnicmp)
-PJ_EXPORT_SYMBOL(pj_strnicmp2)
-PJ_EXPORT_SYMBOL(pj_strcat)
-PJ_EXPORT_SYMBOL(pj_strltrim)
-PJ_EXPORT_SYMBOL(pj_strrtrim)
-PJ_EXPORT_SYMBOL(pj_strtrim)
-PJ_EXPORT_SYMBOL(pj_create_random_string)
-PJ_EXPORT_SYMBOL(pj_strtoul)
-PJ_EXPORT_SYMBOL(pj_utoa)
-PJ_EXPORT_SYMBOL(pj_utoa_pad)
-
-/*
- * timer.h
- */
-PJ_EXPORT_SYMBOL(pj_timer_heap_mem_size)
-PJ_EXPORT_SYMBOL(pj_timer_heap_create)
-PJ_EXPORT_SYMBOL(pj_timer_entry_init)
-PJ_EXPORT_SYMBOL(pj_timer_heap_schedule)
-PJ_EXPORT_SYMBOL(pj_timer_heap_cancel)
-PJ_EXPORT_SYMBOL(pj_timer_heap_count)
-PJ_EXPORT_SYMBOL(pj_timer_heap_earliest_time)
-PJ_EXPORT_SYMBOL(pj_timer_heap_poll)
-
-/*
- * types.h
- */
-PJ_EXPORT_SYMBOL(pj_time_val_normalize)
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjlib.h>

+

+/*

+ * addr_resolv.h

+ */

+PJ_EXPORT_SYMBOL(pj_gethostbyname)

+

+/*

+ * array.h

+ */

+PJ_EXPORT_SYMBOL(pj_array_insert)

+PJ_EXPORT_SYMBOL(pj_array_erase)

+PJ_EXPORT_SYMBOL(pj_array_find)

+

+/*

+ * config.h

+ */

+PJ_EXPORT_SYMBOL(pj_dump_config)

+	

+/*

+ * errno.h

+ */

+PJ_EXPORT_SYMBOL(pj_get_os_error)

+PJ_EXPORT_SYMBOL(pj_set_os_error)

+PJ_EXPORT_SYMBOL(pj_get_netos_error)

+PJ_EXPORT_SYMBOL(pj_set_netos_error)

+PJ_EXPORT_SYMBOL(pj_strerror)

+

+/*

+ * except.h

+ */

+PJ_EXPORT_SYMBOL(pj_throw_exception_)

+PJ_EXPORT_SYMBOL(pj_push_exception_handler_)

+PJ_EXPORT_SYMBOL(pj_pop_exception_handler_)

+PJ_EXPORT_SYMBOL(pj_setjmp)

+PJ_EXPORT_SYMBOL(pj_longjmp)

+PJ_EXPORT_SYMBOL(pj_exception_id_alloc)

+PJ_EXPORT_SYMBOL(pj_exception_id_free)

+PJ_EXPORT_SYMBOL(pj_exception_id_name)

+

+

+/*

+ * fifobuf.h

+ */

+PJ_EXPORT_SYMBOL(pj_fifobuf_init)

+PJ_EXPORT_SYMBOL(pj_fifobuf_max_size)

+PJ_EXPORT_SYMBOL(pj_fifobuf_alloc)

+PJ_EXPORT_SYMBOL(pj_fifobuf_unalloc)

+PJ_EXPORT_SYMBOL(pj_fifobuf_free)

+

+/*

+ * guid.h

+ */

+PJ_EXPORT_SYMBOL(pj_generate_unique_string)

+PJ_EXPORT_SYMBOL(pj_create_unique_string)

+

+/*

+ * hash.h

+ */

+PJ_EXPORT_SYMBOL(pj_hash_calc)

+PJ_EXPORT_SYMBOL(pj_hash_create)

+PJ_EXPORT_SYMBOL(pj_hash_get)

+PJ_EXPORT_SYMBOL(pj_hash_set)

+PJ_EXPORT_SYMBOL(pj_hash_count)

+PJ_EXPORT_SYMBOL(pj_hash_first)

+PJ_EXPORT_SYMBOL(pj_hash_next)

+PJ_EXPORT_SYMBOL(pj_hash_this)

+

+/*

+ * ioqueue.h

+ */

+PJ_EXPORT_SYMBOL(pj_ioqueue_create)

+PJ_EXPORT_SYMBOL(pj_ioqueue_destroy)

+PJ_EXPORT_SYMBOL(pj_ioqueue_set_lock)

+PJ_EXPORT_SYMBOL(pj_ioqueue_register_sock)

+PJ_EXPORT_SYMBOL(pj_ioqueue_unregister)

+PJ_EXPORT_SYMBOL(pj_ioqueue_get_user_data)

+PJ_EXPORT_SYMBOL(pj_ioqueue_poll)

+PJ_EXPORT_SYMBOL(pj_ioqueue_read)

+PJ_EXPORT_SYMBOL(pj_ioqueue_recv)

+PJ_EXPORT_SYMBOL(pj_ioqueue_recvfrom)

+PJ_EXPORT_SYMBOL(pj_ioqueue_write)

+PJ_EXPORT_SYMBOL(pj_ioqueue_send)

+PJ_EXPORT_SYMBOL(pj_ioqueue_sendto)

+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

+PJ_EXPORT_SYMBOL(pj_ioqueue_accept)

+PJ_EXPORT_SYMBOL(pj_ioqueue_connect)

+#endif

+

+/*

+ * list.h

+ */

+PJ_EXPORT_SYMBOL(pj_list_insert_before)

+PJ_EXPORT_SYMBOL(pj_list_insert_nodes_before)

+PJ_EXPORT_SYMBOL(pj_list_insert_after)

+PJ_EXPORT_SYMBOL(pj_list_insert_nodes_after)

+PJ_EXPORT_SYMBOL(pj_list_merge_first)

+PJ_EXPORT_SYMBOL(pj_list_merge_last)

+PJ_EXPORT_SYMBOL(pj_list_erase)

+PJ_EXPORT_SYMBOL(pj_list_find_node)

+PJ_EXPORT_SYMBOL(pj_list_search)

+

+

+/*

+ * log.h

+ */

+PJ_EXPORT_SYMBOL(pj_log_write)

+#if PJ_LOG_MAX_LEVEL >= 1

+PJ_EXPORT_SYMBOL(pj_log_set_log_func)

+PJ_EXPORT_SYMBOL(pj_log_get_log_func)

+PJ_EXPORT_SYMBOL(pj_log_set_level)

+PJ_EXPORT_SYMBOL(pj_log_get_level)

+PJ_EXPORT_SYMBOL(pj_log_set_decor)

+PJ_EXPORT_SYMBOL(pj_log_get_decor)

+PJ_EXPORT_SYMBOL(pj_log_1)

+#endif

+#if PJ_LOG_MAX_LEVEL >= 2

+PJ_EXPORT_SYMBOL(pj_log_2)

+#endif

+#if PJ_LOG_MAX_LEVEL >= 3

+PJ_EXPORT_SYMBOL(pj_log_3)

+#endif

+#if PJ_LOG_MAX_LEVEL >= 4

+PJ_EXPORT_SYMBOL(pj_log_4)

+#endif

+#if PJ_LOG_MAX_LEVEL >= 5

+PJ_EXPORT_SYMBOL(pj_log_5)

+#endif

+#if PJ_LOG_MAX_LEVEL >= 6

+PJ_EXPORT_SYMBOL(pj_log_6)

+#endif

+

+/*

+ * os.h

+ */

+PJ_EXPORT_SYMBOL(pj_init)

+PJ_EXPORT_SYMBOL(pj_getpid)

+PJ_EXPORT_SYMBOL(pj_thread_register)

+PJ_EXPORT_SYMBOL(pj_thread_create)

+PJ_EXPORT_SYMBOL(pj_thread_get_name)

+PJ_EXPORT_SYMBOL(pj_thread_resume)

+PJ_EXPORT_SYMBOL(pj_thread_this)

+PJ_EXPORT_SYMBOL(pj_thread_join)

+PJ_EXPORT_SYMBOL(pj_thread_destroy)

+PJ_EXPORT_SYMBOL(pj_thread_sleep)

+#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK != 0

+PJ_EXPORT_SYMBOL(pj_thread_check_stack)

+PJ_EXPORT_SYMBOL(pj_thread_get_stack_max_usage)

+PJ_EXPORT_SYMBOL(pj_thread_get_stack_info)

+#endif

+PJ_EXPORT_SYMBOL(pj_atomic_create)

+PJ_EXPORT_SYMBOL(pj_atomic_destroy)

+PJ_EXPORT_SYMBOL(pj_atomic_set)

+PJ_EXPORT_SYMBOL(pj_atomic_get)

+PJ_EXPORT_SYMBOL(pj_atomic_inc)

+PJ_EXPORT_SYMBOL(pj_atomic_dec)

+PJ_EXPORT_SYMBOL(pj_thread_local_alloc)

+PJ_EXPORT_SYMBOL(pj_thread_local_free)

+PJ_EXPORT_SYMBOL(pj_thread_local_set)

+PJ_EXPORT_SYMBOL(pj_thread_local_get)

+PJ_EXPORT_SYMBOL(pj_enter_critical_section)

+PJ_EXPORT_SYMBOL(pj_leave_critical_section)

+PJ_EXPORT_SYMBOL(pj_mutex_create)

+PJ_EXPORT_SYMBOL(pj_mutex_lock)

+PJ_EXPORT_SYMBOL(pj_mutex_unlock)

+PJ_EXPORT_SYMBOL(pj_mutex_trylock)

+PJ_EXPORT_SYMBOL(pj_mutex_destroy)

+#if defined(PJ_DEBUG) && PJ_DEBUG != 0

+PJ_EXPORT_SYMBOL(pj_mutex_is_locked)

+#endif

+#if defined(PJ_HAS_SEMAPHORE) && PJ_HAS_SEMAPHORE != 0

+PJ_EXPORT_SYMBOL(pj_sem_create)

+PJ_EXPORT_SYMBOL(pj_sem_wait)

+PJ_EXPORT_SYMBOL(pj_sem_trywait)

+PJ_EXPORT_SYMBOL(pj_sem_post)

+PJ_EXPORT_SYMBOL(pj_sem_destroy)

+#endif

+PJ_EXPORT_SYMBOL(pj_gettimeofday)

+PJ_EXPORT_SYMBOL(pj_time_decode)

+#if defined(PJ_HAS_HIGH_RES_TIMER) && PJ_HAS_HIGH_RES_TIMER != 0

+PJ_EXPORT_SYMBOL(pj_get_timestamp)

+PJ_EXPORT_SYMBOL(pj_get_timestamp_freq)

+PJ_EXPORT_SYMBOL(pj_elapsed_time)

+PJ_EXPORT_SYMBOL(pj_elapsed_usec)

+PJ_EXPORT_SYMBOL(pj_elapsed_nanosec)

+PJ_EXPORT_SYMBOL(pj_elapsed_cycle)

+#endif

+

+	

+/*

+ * pool.h

+ */

+PJ_EXPORT_SYMBOL(pj_pool_create)

+PJ_EXPORT_SYMBOL(pj_pool_release)

+PJ_EXPORT_SYMBOL(pj_pool_getobjname)

+PJ_EXPORT_SYMBOL(pj_pool_reset)

+PJ_EXPORT_SYMBOL(pj_pool_get_capacity)

+PJ_EXPORT_SYMBOL(pj_pool_get_used_size)

+PJ_EXPORT_SYMBOL(pj_pool_alloc)

+PJ_EXPORT_SYMBOL(pj_pool_calloc)

+PJ_EXPORT_SYMBOL(pj_pool_factory_default_policy)

+PJ_EXPORT_SYMBOL(pj_pool_create_int)

+PJ_EXPORT_SYMBOL(pj_pool_init_int)

+PJ_EXPORT_SYMBOL(pj_pool_destroy_int)

+PJ_EXPORT_SYMBOL(pj_caching_pool_init)

+PJ_EXPORT_SYMBOL(pj_caching_pool_destroy)

+

+/*

+ * rand.h

+ */

+PJ_EXPORT_SYMBOL(pj_rand)

+PJ_EXPORT_SYMBOL(pj_srand)

+

+/*

+ * rbtree.h

+ */

+PJ_EXPORT_SYMBOL(pj_rbtree_init)

+PJ_EXPORT_SYMBOL(pj_rbtree_first)

+PJ_EXPORT_SYMBOL(pj_rbtree_last)

+PJ_EXPORT_SYMBOL(pj_rbtree_next)

+PJ_EXPORT_SYMBOL(pj_rbtree_prev)

+PJ_EXPORT_SYMBOL(pj_rbtree_insert)

+PJ_EXPORT_SYMBOL(pj_rbtree_find)

+PJ_EXPORT_SYMBOL(pj_rbtree_erase)

+PJ_EXPORT_SYMBOL(pj_rbtree_max_height)

+PJ_EXPORT_SYMBOL(pj_rbtree_min_height)

+

+/*

+ * sock.h

+ */

+PJ_EXPORT_SYMBOL(PJ_AF_UNIX)

+PJ_EXPORT_SYMBOL(PJ_AF_INET)

+PJ_EXPORT_SYMBOL(PJ_AF_INET6)

+PJ_EXPORT_SYMBOL(PJ_AF_PACKET)

+PJ_EXPORT_SYMBOL(PJ_AF_IRDA)

+PJ_EXPORT_SYMBOL(PJ_SOCK_STREAM)

+PJ_EXPORT_SYMBOL(PJ_SOCK_DGRAM)

+PJ_EXPORT_SYMBOL(PJ_SOCK_RAW)

+PJ_EXPORT_SYMBOL(PJ_SOCK_RDM)

+PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET)

+PJ_EXPORT_SYMBOL(PJ_SOL_IP)

+PJ_EXPORT_SYMBOL(PJ_SOL_TCP)

+PJ_EXPORT_SYMBOL(PJ_SOL_UDP)

+PJ_EXPORT_SYMBOL(PJ_SOL_IPV6)

+PJ_EXPORT_SYMBOL(pj_ntohs)

+PJ_EXPORT_SYMBOL(pj_htons)

+PJ_EXPORT_SYMBOL(pj_ntohl)

+PJ_EXPORT_SYMBOL(pj_htonl)

+PJ_EXPORT_SYMBOL(pj_inet_ntoa)

+PJ_EXPORT_SYMBOL(pj_inet_aton)

+PJ_EXPORT_SYMBOL(pj_inet_addr)

+PJ_EXPORT_SYMBOL(pj_sockaddr_in_set_str_addr)

+PJ_EXPORT_SYMBOL(pj_sockaddr_in_init)

+PJ_EXPORT_SYMBOL(pj_gethostname)

+PJ_EXPORT_SYMBOL(pj_gethostaddr)

+PJ_EXPORT_SYMBOL(pj_sock_socket)

+PJ_EXPORT_SYMBOL(pj_sock_close)

+PJ_EXPORT_SYMBOL(pj_sock_bind)

+PJ_EXPORT_SYMBOL(pj_sock_bind_in)

+#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0

+PJ_EXPORT_SYMBOL(pj_sock_listen)

+PJ_EXPORT_SYMBOL(pj_sock_accept)

+PJ_EXPORT_SYMBOL(pj_sock_shutdown)

+#endif

+PJ_EXPORT_SYMBOL(pj_sock_connect)

+PJ_EXPORT_SYMBOL(pj_sock_getpeername)

+PJ_EXPORT_SYMBOL(pj_sock_getsockname)

+PJ_EXPORT_SYMBOL(pj_sock_getsockopt)

+PJ_EXPORT_SYMBOL(pj_sock_setsockopt)

+PJ_EXPORT_SYMBOL(pj_sock_recv)

+PJ_EXPORT_SYMBOL(pj_sock_recvfrom)

+PJ_EXPORT_SYMBOL(pj_sock_send)

+PJ_EXPORT_SYMBOL(pj_sock_sendto)

+

+/*

+ * sock_select.h

+ */

+PJ_EXPORT_SYMBOL(PJ_FD_ZERO)

+PJ_EXPORT_SYMBOL(PJ_FD_SET)

+PJ_EXPORT_SYMBOL(PJ_FD_CLR)

+PJ_EXPORT_SYMBOL(PJ_FD_ISSET)

+PJ_EXPORT_SYMBOL(pj_sock_select)

+

+/*

+ * string.h

+ */

+PJ_EXPORT_SYMBOL(pj_str)

+PJ_EXPORT_SYMBOL(pj_strassign)

+PJ_EXPORT_SYMBOL(pj_strcpy)

+PJ_EXPORT_SYMBOL(pj_strcpy2)

+PJ_EXPORT_SYMBOL(pj_strdup)

+PJ_EXPORT_SYMBOL(pj_strdup_with_null)

+PJ_EXPORT_SYMBOL(pj_strdup2)

+PJ_EXPORT_SYMBOL(pj_strdup3)

+PJ_EXPORT_SYMBOL(pj_strcmp)

+PJ_EXPORT_SYMBOL(pj_strcmp2)

+PJ_EXPORT_SYMBOL(pj_strncmp)

+PJ_EXPORT_SYMBOL(pj_strncmp2)

+PJ_EXPORT_SYMBOL(pj_stricmp)

+PJ_EXPORT_SYMBOL(pj_stricmp2)

+PJ_EXPORT_SYMBOL(pj_strnicmp)

+PJ_EXPORT_SYMBOL(pj_strnicmp2)

+PJ_EXPORT_SYMBOL(pj_strcat)

+PJ_EXPORT_SYMBOL(pj_strltrim)

+PJ_EXPORT_SYMBOL(pj_strrtrim)

+PJ_EXPORT_SYMBOL(pj_strtrim)

+PJ_EXPORT_SYMBOL(pj_create_random_string)

+PJ_EXPORT_SYMBOL(pj_strtoul)

+PJ_EXPORT_SYMBOL(pj_utoa)

+PJ_EXPORT_SYMBOL(pj_utoa_pad)

+

+/*

+ * timer.h

+ */

+PJ_EXPORT_SYMBOL(pj_timer_heap_mem_size)

+PJ_EXPORT_SYMBOL(pj_timer_heap_create)

+PJ_EXPORT_SYMBOL(pj_timer_entry_init)

+PJ_EXPORT_SYMBOL(pj_timer_heap_schedule)

+PJ_EXPORT_SYMBOL(pj_timer_heap_cancel)

+PJ_EXPORT_SYMBOL(pj_timer_heap_count)

+PJ_EXPORT_SYMBOL(pj_timer_heap_earliest_time)

+PJ_EXPORT_SYMBOL(pj_timer_heap_poll)

+

+/*

+ * types.h

+ */

+PJ_EXPORT_SYMBOL(pj_time_val_normalize)

+

diff --git a/pjlib/src/pj/timer.c b/pjlib/src/pj/timer.c
index ffec1f4..c3e4f95 100644
--- a/pjlib/src/pj/timer.c
+++ b/pjlib/src/pj/timer.c
@@ -1,390 +1,411 @@
-/* $Id$
- */
-/* (C)1993-2003 Douglas C. Schmidt
- *
- * This file is originaly from ACE library by Doug Schmidt
- * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and 
- * his research group at Washington University, University of California, 
- * Irvine, and Vanderbilt University Copyright 
- * (c) 1993-2003, all rights reserved.
- */
-#include <pj/timer.h>
-#include <pj/pool.h>
-#include <pj/os.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/errno.h>
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* (C)1993-2003 Douglas C. Schmidt

+ *

+ * This file is originaly from ACE library by Doug Schmidt

+ * ACE(TM), TAO(TM) and CIAO(TM) are copyrighted by Douglas C. Schmidt and 

+ * his research group at Washington University, University of California, 

+ * Irvine, and Vanderbilt University Copyright 

+ * (c) 1993-2003, all rights reserved.

+ */

+#include <pj/timer.h>

+#include <pj/pool.h>

+#include <pj/os.h>

+#include <pj/string.h>

+#include <pj/assert.h>

+#include <pj/errno.h>

 #include <pj/lock.h>

-
-#define HEAP_PARENT(X)	(X == 0 ? 0 : (((X) - 1) / 2))
-#define HEAP_LEFT(X)	(((X)+(X))+1)
+

+#define HEAP_PARENT(X)	(X == 0 ? 0 : (((X) - 1) / 2))

+#define HEAP_LEFT(X)	(((X)+(X))+1)

 

 

 #define DEFAULT_MAX_TIMED_OUT_PER_POLL  (64)

-
-
-/**
- * The implementation of timer heap.
- */
-struct pj_timer_heap_t
-{
-    /** Pool from which the timer heap resize will get the storage from */
-    pj_pool_t *pool;
-
-    /** Maximum size of the heap. */
-    pj_size_t max_size;
-
-    /** Current size of the heap. */
-    pj_size_t cur_size;
+

+

+/**

+ * The implementation of timer heap.

+ */

+struct pj_timer_heap_t

+{

+    /** Pool from which the timer heap resize will get the storage from */

+    pj_pool_t *pool;

+

+    /** Maximum size of the heap. */

+    pj_size_t max_size;

+

+    /** Current size of the heap. */

+    pj_size_t cur_size;

 

     /** Max timed out entries to process per poll. */

     unsigned max_entries_per_poll;

-
-    /** Lock object. */
-    pj_lock_t *lock;
+

+    /** Lock object. */

+    pj_lock_t *lock;

 

     /** Autodelete lock. */

     pj_bool_t auto_delete_lock;

-
-    /**
-     * Current contents of the Heap, which is organized as a "heap" of
-     * pj_timer_entry *'s.  In this context, a heap is a "partially
-     * ordered, almost complete" binary tree, which is stored in an
-     * array.
-     */
-    pj_timer_entry **heap;
-
-    /**
-     * An array of "pointers" that allows each pj_timer_entry in the
-     * <heap_> to be located in O(1) time.  Basically, <timer_id_[i]>
-     * contains the slot in the <heap_> array where an pj_timer_entry
-     * with timer id <i> resides.  Thus, the timer id passed back from
-     * <schedule_entry> is really an slot into the <timer_ids> array.  The
-     * <timer_ids_> array serves two purposes: negative values are
-     * treated as "pointers" for the <freelist_>, whereas positive
-     * values are treated as "pointers" into the <heap_> array.
-     */
-    pj_timer_id_t *timer_ids;
-
-    /**
-     * "Pointer" to the first element in the freelist contained within
-     * the <timer_ids_> array, which is organized as a stack.
-     */
-    pj_timer_id_t timer_ids_freelist;
-
-    /** Callback to be called when a timer expires. */
-    pj_timer_heap_callback *callback;
-
-};
-
-
-
-PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht )
-{
-    if (ht->lock) {
-	pj_lock_acquire(ht->lock);
-    }
-}
-
-PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht )
-{
-    if (ht->lock) {
-	pj_lock_release(ht->lock);
-    }
-}
-
-
-static void copy_node( pj_timer_heap_t *ht, int slot, pj_timer_entry *moved_node )
-{
-    PJ_CHECK_STACK();
-
-    // Insert <moved_node> into its new location in the heap.
-    ht->heap[slot] = moved_node;
-    
-    // Update the corresponding slot in the parallel <timer_ids_> array.
-    ht->timer_ids[moved_node->_timer_id] = slot;
-}
-
-static pj_timer_id_t pop_freelist( pj_timer_heap_t *ht )
-{
-    // We need to truncate this to <int> for backwards compatibility.
-    pj_timer_id_t new_id = ht->timer_ids_freelist;
-    
-    PJ_CHECK_STACK();
-
-    // The freelist values in the <timer_ids_> are negative, so we need
-    // to negate them to get the next freelist "pointer."
-    ht->timer_ids_freelist =
-	-ht->timer_ids[ht->timer_ids_freelist];
-    
-    return new_id;
-    
-}
-
-static void push_freelist (pj_timer_heap_t *ht, pj_timer_id_t old_id)
-{
-    PJ_CHECK_STACK();
-
-    // The freelist values in the <timer_ids_> are negative, so we need
-    // to negate them to get the next freelist "pointer."
-    ht->timer_ids[old_id] = -ht->timer_ids_freelist;
-    ht->timer_ids_freelist = old_id;
-}
-
-
-static void reheap_down(pj_timer_heap_t *ht, pj_timer_entry *moved_node,
-                        size_t slot, size_t child)
-{
-    PJ_CHECK_STACK();
-
-    // Restore the heap property after a deletion.
-    
-    while (child < ht->cur_size)
-    {
-	// Choose the smaller of the two children.
-	if (child + 1 < ht->cur_size
-	    && PJ_TIME_VAL_LT(ht->heap[child + 1]->_timer_value, ht->heap[child]->_timer_value))
-	    child++;
-	
-	// Perform a <copy> if the child has a larger timeout value than
-	// the <moved_node>.
-	if (PJ_TIME_VAL_LT(ht->heap[child]->_timer_value, moved_node->_timer_value))
-        {
-	    copy_node( ht, slot, ht->heap[child]);
-	    slot = child;
-	    child = HEAP_LEFT(child);
-        }
-	else
-	    // We've found our location in the heap.
-	    break;
-    }
-    
-    copy_node( ht, slot, moved_node);
-}
-
-static void reheap_up( pj_timer_heap_t *ht, pj_timer_entry *moved_node,
-		       size_t slot, size_t parent)
-{
-    // Restore the heap property after an insertion.
-    
-    while (slot > 0)
-    {
-	// If the parent node is greater than the <moved_node> we need
-	// to copy it down.
-	if (PJ_TIME_VAL_LT(moved_node->_timer_value, ht->heap[parent]->_timer_value))
-        {
-	    copy_node(ht, slot, ht->heap[parent]);
-	    slot = parent;
-	    parent = HEAP_PARENT(slot);
-        }
-	else
-	    break;
-    }
-    
-    // Insert the new node into its proper resting place in the heap and
-    // update the corresponding slot in the parallel <timer_ids> array.
-    copy_node(ht, slot, moved_node);
-}
-
-
-static pj_timer_entry * remove_node( pj_timer_heap_t *ht, size_t slot)
-{
-    pj_timer_entry *removed_node = ht->heap[slot];
-    
-    // Return this timer id to the freelist.
-    push_freelist( ht, removed_node->_timer_id );
-    
-    // Decrement the size of the heap by one since we're removing the
-    // "slot"th node.
-    ht->cur_size--;
-    
-    // Set the ID
-    removed_node->_timer_id = -1;
-
-    // Only try to reheapify if we're not deleting the last entry.
-    
-    if (slot < ht->cur_size)
-    {
-	int parent;
-	pj_timer_entry *moved_node = ht->heap[ht->cur_size];
-	
-	// Move the end node to the location being removed and update
-	// the corresponding slot in the parallel <timer_ids> array.
-	copy_node( ht, slot, moved_node);
-	
-	// If the <moved_node->time_value_> is great than or equal its
-	// parent it needs be moved down the heap.
-	parent = HEAP_PARENT (slot);
-	
-	if (PJ_TIME_VAL_GTE(moved_node->_timer_value, ht->heap[parent]->_timer_value))
-	    reheap_down( ht, moved_node, slot, HEAP_LEFT(slot));
-	else
-	    reheap_up( ht, moved_node, slot, parent);
-    }
-    
-    return removed_node;
-}
-
-static void grow_heap(pj_timer_heap_t *ht)
-{
-    // All the containers will double in size from max_size_
-    size_t new_size = ht->max_size * 2;
-    pj_timer_id_t *new_timer_ids;
-    pj_size_t i;
-    
-    // First grow the heap itself.
-    
-    pj_timer_entry **new_heap = 0;
-    
-    new_heap = pj_pool_alloc(ht->pool, sizeof(pj_timer_entry*) * new_size);
-    memcpy(new_heap, ht->heap, ht->max_size * sizeof(pj_timer_entry*));
-    //delete [] this->heap_;
-    ht->heap = new_heap;
-    
-    // Grow the array of timer ids.
-    
-    new_timer_ids = 0;
-    new_timer_ids = pj_pool_alloc(ht->pool, new_size * sizeof(pj_timer_id_t));
-    
-    memcpy( new_timer_ids, ht->timer_ids, ht->max_size * sizeof(pj_timer_id_t));
-    
-    //delete [] timer_ids_;
-    ht->timer_ids = new_timer_ids;
-    
-    // And add the new elements to the end of the "freelist".
-    for (i = ht->max_size; i < new_size; i++)
-	ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));
-    
-    ht->max_size = new_size;
-}
-
-static void insert_node(pj_timer_heap_t *ht, pj_timer_entry *new_node)
-{
-    if (ht->cur_size + 2 >= ht->max_size)
-	grow_heap(ht);
-    
-    reheap_up( ht, new_node, ht->cur_size, HEAP_PARENT(ht->cur_size));
-    ht->cur_size++;
-}
-
-
-static pj_status_t schedule_entry( pj_timer_heap_t *ht,
-				   pj_timer_entry *entry, 
-				   const pj_time_val *future_time )
-{
-    if (ht->cur_size < ht->max_size)
-    {
-	// Obtain the next unique sequence number.
-	// Set the entry
-	entry->_timer_id = pop_freelist(ht);
-	entry->_timer_value = *future_time;
-	insert_node( ht, entry);
-	return 0;
-    }
-    else
-	return -1;
-}
-
-
-static int cancel( pj_timer_heap_t *ht, 
-		   pj_timer_entry *entry, 
-		   int dont_call)
-{
-  long timer_node_slot;
-
-  PJ_CHECK_STACK();
-
-  // Check to see if the timer_id is out of range
-  if (entry->_timer_id < 0 || (pj_size_t)entry->_timer_id > ht->max_size)
-    return 0;
-
-  timer_node_slot = ht->timer_ids[entry->_timer_id];
-
-  if (timer_node_slot < 0) // Check to see if timer_id is still valid.
-    return 0;
-
-  if (entry != ht->heap[timer_node_slot])
-    {
-      pj_assert(entry == ht->heap[timer_node_slot]);
-      return 0;
-    }
-  else
-    {
-      remove_node( ht, timer_node_slot);
-
-      if (dont_call == 0)
-        // Call the close hook.
-	(*ht->callback)(ht, entry);
-      return 1;
-    }
-}
-
-
-/*
- * Calculate memory size required to create a timer heap.
- */
-PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)
-{
-    return /* size of the timer heap itself: */
-           sizeof(pj_timer_heap_t) + 
-           /* size of each entry: */
-           (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) +
-           /* lock, pool etc: */
-           132;
-}
-
-/*
- * Create a new timer heap.
- */
-PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,
-					  pj_size_t size,
-                                          pj_timer_heap_t **p_heap)
-{
-    pj_timer_heap_t *ht;
-    pj_size_t i;
-
-    PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);
-
-    *p_heap = NULL;
-
-    /* Magic? */
-    size += 2;
-
-    /* Allocate timer heap data structure from the pool */
-    ht = pj_pool_alloc(pool, sizeof(pj_timer_heap_t));
-    if (!ht)
-        return PJ_ENOMEM;
-
-    /* Initialize timer heap sizes */
-    ht->max_size = size;
+

+    /**

+     * Current contents of the Heap, which is organized as a "heap" of

+     * pj_timer_entry *'s.  In this context, a heap is a "partially

+     * ordered, almost complete" binary tree, which is stored in an

+     * array.

+     */

+    pj_timer_entry **heap;

+

+    /**

+     * An array of "pointers" that allows each pj_timer_entry in the

+     * <heap_> to be located in O(1) time.  Basically, <timer_id_[i]>

+     * contains the slot in the <heap_> array where an pj_timer_entry

+     * with timer id <i> resides.  Thus, the timer id passed back from

+     * <schedule_entry> is really an slot into the <timer_ids> array.  The

+     * <timer_ids_> array serves two purposes: negative values are

+     * treated as "pointers" for the <freelist_>, whereas positive

+     * values are treated as "pointers" into the <heap_> array.

+     */

+    pj_timer_id_t *timer_ids;

+

+    /**

+     * "Pointer" to the first element in the freelist contained within

+     * the <timer_ids_> array, which is organized as a stack.

+     */

+    pj_timer_id_t timer_ids_freelist;

+

+    /** Callback to be called when a timer expires. */

+    pj_timer_heap_callback *callback;

+

+};

+

+

+

+PJ_INLINE(void) lock_timer_heap( pj_timer_heap_t *ht )

+{

+    if (ht->lock) {

+	pj_lock_acquire(ht->lock);

+    }

+}

+

+PJ_INLINE(void) unlock_timer_heap( pj_timer_heap_t *ht )

+{

+    if (ht->lock) {

+	pj_lock_release(ht->lock);

+    }

+}

+

+

+static void copy_node( pj_timer_heap_t *ht, int slot, pj_timer_entry *moved_node )

+{

+    PJ_CHECK_STACK();

+

+    // Insert <moved_node> into its new location in the heap.

+    ht->heap[slot] = moved_node;

+    

+    // Update the corresponding slot in the parallel <timer_ids_> array.

+    ht->timer_ids[moved_node->_timer_id] = slot;

+}

+

+static pj_timer_id_t pop_freelist( pj_timer_heap_t *ht )

+{

+    // We need to truncate this to <int> for backwards compatibility.

+    pj_timer_id_t new_id = ht->timer_ids_freelist;

+    

+    PJ_CHECK_STACK();

+

+    // The freelist values in the <timer_ids_> are negative, so we need

+    // to negate them to get the next freelist "pointer."

+    ht->timer_ids_freelist =

+	-ht->timer_ids[ht->timer_ids_freelist];

+    

+    return new_id;

+    

+}

+

+static void push_freelist (pj_timer_heap_t *ht, pj_timer_id_t old_id)

+{

+    PJ_CHECK_STACK();

+

+    // The freelist values in the <timer_ids_> are negative, so we need

+    // to negate them to get the next freelist "pointer."

+    ht->timer_ids[old_id] = -ht->timer_ids_freelist;

+    ht->timer_ids_freelist = old_id;

+}

+

+

+static void reheap_down(pj_timer_heap_t *ht, pj_timer_entry *moved_node,

+                        size_t slot, size_t child)

+{

+    PJ_CHECK_STACK();

+

+    // Restore the heap property after a deletion.

+    

+    while (child < ht->cur_size)

+    {

+	// Choose the smaller of the two children.

+	if (child + 1 < ht->cur_size

+	    && PJ_TIME_VAL_LT(ht->heap[child + 1]->_timer_value, ht->heap[child]->_timer_value))

+	    child++;

+	

+	// Perform a <copy> if the child has a larger timeout value than

+	// the <moved_node>.

+	if (PJ_TIME_VAL_LT(ht->heap[child]->_timer_value, moved_node->_timer_value))

+        {

+	    copy_node( ht, slot, ht->heap[child]);

+	    slot = child;

+	    child = HEAP_LEFT(child);

+        }

+	else

+	    // We've found our location in the heap.

+	    break;

+    }

+    

+    copy_node( ht, slot, moved_node);

+}

+

+static void reheap_up( pj_timer_heap_t *ht, pj_timer_entry *moved_node,

+		       size_t slot, size_t parent)

+{

+    // Restore the heap property after an insertion.

+    

+    while (slot > 0)

+    {

+	// If the parent node is greater than the <moved_node> we need

+	// to copy it down.

+	if (PJ_TIME_VAL_LT(moved_node->_timer_value, ht->heap[parent]->_timer_value))

+        {

+	    copy_node(ht, slot, ht->heap[parent]);

+	    slot = parent;

+	    parent = HEAP_PARENT(slot);

+        }

+	else

+	    break;

+    }

+    

+    // Insert the new node into its proper resting place in the heap and

+    // update the corresponding slot in the parallel <timer_ids> array.

+    copy_node(ht, slot, moved_node);

+}

+

+

+static pj_timer_entry * remove_node( pj_timer_heap_t *ht, size_t slot)

+{

+    pj_timer_entry *removed_node = ht->heap[slot];

+    

+    // Return this timer id to the freelist.

+    push_freelist( ht, removed_node->_timer_id );

+    

+    // Decrement the size of the heap by one since we're removing the

+    // "slot"th node.

+    ht->cur_size--;

+    

+    // Set the ID

+    removed_node->_timer_id = -1;

+

+    // Only try to reheapify if we're not deleting the last entry.

+    

+    if (slot < ht->cur_size)

+    {

+	int parent;

+	pj_timer_entry *moved_node = ht->heap[ht->cur_size];

+	

+	// Move the end node to the location being removed and update

+	// the corresponding slot in the parallel <timer_ids> array.

+	copy_node( ht, slot, moved_node);

+	

+	// If the <moved_node->time_value_> is great than or equal its

+	// parent it needs be moved down the heap.

+	parent = HEAP_PARENT (slot);

+	

+	if (PJ_TIME_VAL_GTE(moved_node->_timer_value, ht->heap[parent]->_timer_value))

+	    reheap_down( ht, moved_node, slot, HEAP_LEFT(slot));

+	else

+	    reheap_up( ht, moved_node, slot, parent);

+    }

+    

+    return removed_node;

+}

+

+static void grow_heap(pj_timer_heap_t *ht)

+{

+    // All the containers will double in size from max_size_

+    size_t new_size = ht->max_size * 2;

+    pj_timer_id_t *new_timer_ids;

+    pj_size_t i;

+    

+    // First grow the heap itself.

+    

+    pj_timer_entry **new_heap = 0;

+    

+    new_heap = pj_pool_alloc(ht->pool, sizeof(pj_timer_entry*) * new_size);

+    memcpy(new_heap, ht->heap, ht->max_size * sizeof(pj_timer_entry*));

+    //delete [] this->heap_;

+    ht->heap = new_heap;

+    

+    // Grow the array of timer ids.

+    

+    new_timer_ids = 0;

+    new_timer_ids = pj_pool_alloc(ht->pool, new_size * sizeof(pj_timer_id_t));

+    

+    memcpy( new_timer_ids, ht->timer_ids, ht->max_size * sizeof(pj_timer_id_t));

+    

+    //delete [] timer_ids_;

+    ht->timer_ids = new_timer_ids;

+    

+    // And add the new elements to the end of the "freelist".

+    for (i = ht->max_size; i < new_size; i++)

+	ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));

+    

+    ht->max_size = new_size;

+}

+

+static void insert_node(pj_timer_heap_t *ht, pj_timer_entry *new_node)

+{

+    if (ht->cur_size + 2 >= ht->max_size)

+	grow_heap(ht);

+    

+    reheap_up( ht, new_node, ht->cur_size, HEAP_PARENT(ht->cur_size));

+    ht->cur_size++;

+}

+

+

+static pj_status_t schedule_entry( pj_timer_heap_t *ht,

+				   pj_timer_entry *entry, 

+				   const pj_time_val *future_time )

+{

+    if (ht->cur_size < ht->max_size)

+    {

+	// Obtain the next unique sequence number.

+	// Set the entry

+	entry->_timer_id = pop_freelist(ht);

+	entry->_timer_value = *future_time;

+	insert_node( ht, entry);

+	return 0;

+    }

+    else

+	return -1;

+}

+

+

+static int cancel( pj_timer_heap_t *ht, 

+		   pj_timer_entry *entry, 

+		   int dont_call)

+{

+  long timer_node_slot;

+

+  PJ_CHECK_STACK();

+

+  // Check to see if the timer_id is out of range

+  if (entry->_timer_id < 0 || (pj_size_t)entry->_timer_id > ht->max_size)

+    return 0;

+

+  timer_node_slot = ht->timer_ids[entry->_timer_id];

+

+  if (timer_node_slot < 0) // Check to see if timer_id is still valid.

+    return 0;

+

+  if (entry != ht->heap[timer_node_slot])

+    {

+      pj_assert(entry == ht->heap[timer_node_slot]);

+      return 0;

+    }

+  else

+    {

+      remove_node( ht, timer_node_slot);

+

+      if (dont_call == 0)

+        // Call the close hook.

+	(*ht->callback)(ht, entry);

+      return 1;

+    }

+}

+

+

+/*

+ * Calculate memory size required to create a timer heap.

+ */

+PJ_DEF(pj_size_t) pj_timer_heap_mem_size(pj_size_t count)

+{

+    return /* size of the timer heap itself: */

+           sizeof(pj_timer_heap_t) + 

+           /* size of each entry: */

+           (count+2) * (sizeof(pj_timer_entry*)+sizeof(pj_timer_id_t)) +

+           /* lock, pool etc: */

+           132;

+}

+

+/*

+ * Create a new timer heap.

+ */

+PJ_DEF(pj_status_t) pj_timer_heap_create( pj_pool_t *pool,

+					  pj_size_t size,

+                                          pj_timer_heap_t **p_heap)

+{

+    pj_timer_heap_t *ht;

+    pj_size_t i;

+

+    PJ_ASSERT_RETURN(pool && p_heap, PJ_EINVAL);

+

+    *p_heap = NULL;

+

+    /* Magic? */

+    size += 2;

+

+    /* Allocate timer heap data structure from the pool */

+    ht = pj_pool_alloc(pool, sizeof(pj_timer_heap_t));

+    if (!ht)

+        return PJ_ENOMEM;

+

+    /* Initialize timer heap sizes */

+    ht->max_size = size;

     ht->cur_size = 0;

-    ht->max_entries_per_poll = DEFAULT_MAX_TIMED_OUT_PER_POLL;
-    ht->timer_ids_freelist = 1;
+    ht->max_entries_per_poll = DEFAULT_MAX_TIMED_OUT_PER_POLL;

+    ht->timer_ids_freelist = 1;

     ht->pool = pool;

-
-    /* Lock. */
+

+    /* Lock. */

     ht->lock = NULL;

     ht->auto_delete_lock = 0;

-
-    // Create the heap array.
-    ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size);
-    if (!ht->heap)
-        return PJ_ENOMEM;
-
-    // Create the parallel
-    ht->timer_ids = pj_pool_alloc( pool, sizeof(pj_timer_id_t) * size);
-    if (!ht->timer_ids)
-        return PJ_ENOMEM;
-
-    // Initialize the "freelist," which uses negative values to
-    // distinguish freelist elements from "pointers" into the <heap_>
-    // array.
-    for (i=0; i<size; ++i)
-	ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));
-
-    *p_heap = ht;
-    return PJ_SUCCESS;
-}
+

+    // Create the heap array.

+    ht->heap = pj_pool_alloc(pool, sizeof(pj_timer_entry*) * size);

+    if (!ht->heap)

+        return PJ_ENOMEM;

+

+    // Create the parallel

+    ht->timer_ids = pj_pool_alloc( pool, sizeof(pj_timer_id_t) * size);

+    if (!ht->timer_ids)

+        return PJ_ENOMEM;

+

+    // Initialize the "freelist," which uses negative values to

+    // distinguish freelist elements from "pointers" into the <heap_>

+    // array.

+    for (i=0; i<size; ++i)

+	ht->timer_ids[i] = -((pj_timer_id_t) (i + 1));

+

+    *p_heap = ht;

+    return PJ_SUCCESS;

+}

 

 PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht )

 {

@@ -413,111 +434,111 @@
     ht->max_entries_per_poll = count;

     return old_count;

 }

-
-PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,
-                                             int id,
-                                             void *user_data,
-                                             pj_timer_heap_callback *cb )
-{
-    pj_assert(entry && cb);
-
-    entry->id = id;
-    entry->user_data = user_data;
-    entry->cb = cb;
-
-    return entry;
-}
-
-PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
-					    pj_timer_entry *entry, 
-					    const pj_time_val *delay)
-{
-    pj_status_t status;
-    pj_time_val expires;
-
-    PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
-
-    pj_gettimeofday(&expires);
-    PJ_TIME_VAL_ADD(expires, *delay);
-    
-    lock_timer_heap(ht);
-    status = schedule_entry(ht, entry, &expires);
-    unlock_timer_heap(ht);
-
-    return status;
-}
-
-PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,
-				  pj_timer_entry *entry)
-{
-    int count;
-
-    PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
-
-    lock_timer_heap(ht);
-    count = cancel(ht, entry, 1);
-    unlock_timer_heap(ht);
-
-    return count;
-}
-
+

+PJ_DEF(pj_timer_entry*) pj_timer_entry_init( pj_timer_entry *entry,

+                                             int id,

+                                             void *user_data,

+                                             pj_timer_heap_callback *cb )

+{

+    pj_assert(entry && cb);

+

+    entry->id = id;

+    entry->user_data = user_data;

+    entry->cb = cb;

+

+    return entry;

+}

+

+PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,

+					    pj_timer_entry *entry, 

+					    const pj_time_val *delay)

+{

+    pj_status_t status;

+    pj_time_val expires;

+

+    PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);

+

+    pj_gettimeofday(&expires);

+    PJ_TIME_VAL_ADD(expires, *delay);

+    

+    lock_timer_heap(ht);

+    status = schedule_entry(ht, entry, &expires);

+    unlock_timer_heap(ht);

+

+    return status;

+}

+

+PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht,

+				  pj_timer_entry *entry)

+{

+    int count;

+

+    PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);

+

+    lock_timer_heap(ht);

+    count = cancel(ht, entry, 1);

+    unlock_timer_heap(ht);

+

+    return count;

+}

+

 PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, 

-                                     pj_time_val *next_delay )
-{
-    pj_time_val now;
-    unsigned count;
-
-    PJ_ASSERT_RETURN(ht, 0);
-
-    if (!ht->cur_size && next_delay) {
-	next_delay->sec = next_delay->msec = PJ_MAXINT32;
-	return 0;
-    }
-
-    count = 0;
-    pj_gettimeofday(&now);
-
-    lock_timer_heap(ht);
-    while ( ht->cur_size && 
+                                     pj_time_val *next_delay )

+{

+    pj_time_val now;

+    unsigned count;

+

+    PJ_ASSERT_RETURN(ht, 0);

+

+    if (!ht->cur_size && next_delay) {

+	next_delay->sec = next_delay->msec = PJ_MAXINT32;

+	return 0;

+    }

+

+    count = 0;

+    pj_gettimeofday(&now);

+

+    lock_timer_heap(ht);

+    while ( ht->cur_size && 

 	    PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) &&

-            count < ht->max_entries_per_poll ) 
-    {
-	pj_timer_entry *node = remove_node(ht, 0);
-	++count;
-
-	unlock_timer_heap(ht);
-	(*node->cb)(ht, node);
-	lock_timer_heap(ht);
-    }
-    if (ht->cur_size && next_delay) {
-	*next_delay = ht->heap[0]->_timer_value;
-	PJ_TIME_VAL_SUB(*next_delay, now);
-    } else if (next_delay) {
-	next_delay->sec = next_delay->msec = PJ_MAXINT32;
-    }
-    unlock_timer_heap(ht);
-
-    return count;
-}
-
-PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )
+            count < ht->max_entries_per_poll ) 

+    {

+	pj_timer_entry *node = remove_node(ht, 0);

+	++count;

+

+	unlock_timer_heap(ht);

+	(*node->cb)(ht, node);

+	lock_timer_heap(ht);

+    }

+    if (ht->cur_size && next_delay) {

+	*next_delay = ht->heap[0]->_timer_value;

+	PJ_TIME_VAL_SUB(*next_delay, now);

+    } else if (next_delay) {

+	next_delay->sec = next_delay->msec = PJ_MAXINT32;

+    }

+    unlock_timer_heap(ht);

+

+    return count;

+}

+

+PJ_DEF(pj_size_t) pj_timer_heap_count( pj_timer_heap_t *ht )

 {

     PJ_ASSERT_RETURN(ht, 0);

-
-    return ht->cur_size;
-}
-
-PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,
-					         pj_time_val *timeval)
-{
-    pj_assert(ht->cur_size != 0);
-    if (ht->cur_size == 0)
-        return PJ_ENOTFOUND;
-
-    lock_timer_heap(ht);
-    *timeval = ht->heap[0]->_timer_value;
-    unlock_timer_heap(ht);
-
-    return PJ_SUCCESS;
-}
-
+

+    return ht->cur_size;

+}

+

+PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht,

+					         pj_time_val *timeval)

+{

+    pj_assert(ht->cur_size != 0);

+    if (ht->cur_size == 0)

+        return PJ_ENOTFOUND;

+

+    lock_timer_heap(ht);

+    *timeval = ht->heap[0]->_timer_value;

+    unlock_timer_heap(ht);

+

+    return PJ_SUCCESS;

+}

+

diff --git a/pjlib/src/pj/types.c b/pjlib/src/pj/types.c
index c45e740..7ca146e 100644
--- a/pjlib/src/pj/types.c
+++ b/pjlib/src/pj/types.c
@@ -1,31 +1,52 @@
-/* $Id$
- */
-#include <pj/types.h>
-#include <pj/os.h>
-
-void pj_time_val_normalize(pj_time_val *t)
-{
-    PJ_CHECK_STACK();
-
-    if (t->msec >= 1000) {
-	do {
-	    t->sec++;
-	    t->msec -= 1000;
-        } while (t->msec >= 1000);
-    }
-    else if (t->msec <= -1000) {
-	do {
-	    t->sec--;
-	    t->msec += 1000;
-        } while (t->msec <= -1000);
-    }
-
-    if (t->sec >= 1 && t->msec < 0) {
-	t->sec--;
-	t->msec += 1000;
-
-    } else if (t->sec < 0 && t->msec > 0) {
-	t->sec++;
-	t->msec -= 1000;
-    }
-}
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/types.h>

+#include <pj/os.h>

+

+void pj_time_val_normalize(pj_time_val *t)

+{

+    PJ_CHECK_STACK();

+

+    if (t->msec >= 1000) {

+	do {

+	    t->sec++;

+	    t->msec -= 1000;

+        } while (t->msec >= 1000);

+    }

+    else if (t->msec <= -1000) {

+	do {

+	    t->sec--;

+	    t->msec += 1000;

+        } while (t->msec <= -1000);

+    }

+

+    if (t->sec >= 1 && t->msec < 0) {

+	t->sec--;

+	t->msec += 1000;

+

+    } else if (t->sec < 0 && t->msec > 0) {

+	t->sec++;

+	t->msec -= 1000;

+    }

+}

diff --git a/pjlib/src/pjlib++-test/main.cpp b/pjlib/src/pjlib++-test/main.cpp
index 99b7f8d..1b41dbe 100644
--- a/pjlib/src/pjlib++-test/main.cpp
+++ b/pjlib/src/pjlib++-test/main.cpp
@@ -1,3 +1,24 @@
+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #include <pj++/file.hpp>

 #include <pj++/list.hpp>

 #include <pj++/lock.hpp>

diff --git a/pjlib/src/pjlib-samples/except.c b/pjlib/src/pjlib-samples/except.c
index ab936c3..36509e4 100644
--- a/pjlib/src/pjlib-samples/except.c
+++ b/pjlib/src/pjlib-samples/except.c
@@ -1,69 +1,89 @@
-/* $Id$
- */
-#include <pj/except.h>
-#include <pj/rand.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-/**
- * \page page_pjlib_samples_except_c Example: Exception Handling
- *
- * Below is sample program to demonstrate how to use exception handling.
- *
- * \includelineno pjlib-samples/except.c
- */
-
-static pj_exception_id_t NO_MEMORY, OTHER_EXCEPTION;
-
-static void randomly_throw_exception()
-{
-    if (pj_rand() % 2)
-        PJ_THROW(OTHER_EXCEPTION);
-}
-
-static void *my_malloc(size_t size)
-{
-    void *ptr = malloc(size);
-    if (!ptr)
-        PJ_THROW(NO_MEMORY);
-    return ptr;
-}
-
-static int test_exception()
-{
-    PJ_USE_EXCEPTION;
-    
-    PJ_TRY {
-        void *data = my_malloc(200);
-        free(data);
-        randomly_throw_exception();
-    }
-    PJ_CATCH( NO_MEMORY ) {
-        puts("Can't allocate memory");
-        return 0;
-    }
-    PJ_DEFAULT {
-        pj_exception_id_t x_id;
-        
-        x_id = PJ_GET_EXCEPTION();
-        printf("Caught exception %d (%s)\n", 
-            x_id, pj_exception_id_name(x_id));
-    }
-    PJ_END
-        return 1;
-}
-
-int main()
-{
-    pj_status_t rc;
-    
-    // Error handling is omited for clarity.
-    
-    rc = pj_init();
-
-    rc = pj_exception_id_alloc("No Memory", &NO_MEMORY);
-    rc = pj_exception_id_alloc("Other Exception", &OTHER_EXCEPTION);
-    
-    return test_exception();
-}
-
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/except.h>

+#include <pj/rand.h>

+#include <stdio.h>

+#include <stdlib.h>

+

+/**

+ * \page page_pjlib_samples_except_c Example: Exception Handling

+ *

+ * Below is sample program to demonstrate how to use exception handling.

+ *

+ * \includelineno pjlib-samples/except.c

+ */

+

+static pj_exception_id_t NO_MEMORY, OTHER_EXCEPTION;

+

+static void randomly_throw_exception()

+{

+    if (pj_rand() % 2)

+        PJ_THROW(OTHER_EXCEPTION);

+}

+

+static void *my_malloc(size_t size)

+{

+    void *ptr = malloc(size);

+    if (!ptr)

+        PJ_THROW(NO_MEMORY);

+    return ptr;

+}

+

+static int test_exception()

+{

+    PJ_USE_EXCEPTION;

+    

+    PJ_TRY {

+        void *data = my_malloc(200);

+        free(data);

+        randomly_throw_exception();

+    }

+    PJ_CATCH( NO_MEMORY ) {

+        puts("Can't allocate memory");

+        return 0;

+    }

+    PJ_DEFAULT {

+        pj_exception_id_t x_id;

+        

+        x_id = PJ_GET_EXCEPTION();

+        printf("Caught exception %d (%s)\n", 

+            x_id, pj_exception_id_name(x_id));

+    }

+    PJ_END

+        return 1;

+}

+

+int main()

+{

+    pj_status_t rc;

+    

+    // Error handling is omited for clarity.

+    

+    rc = pj_init();

+

+    rc = pj_exception_id_alloc("No Memory", &NO_MEMORY);

+    rc = pj_exception_id_alloc("Other Exception", &OTHER_EXCEPTION);

+    

+    return test_exception();

+}

+

diff --git a/pjlib/src/pjlib-samples/list.c b/pjlib/src/pjlib-samples/list.c
index 127d8dd..e478d22 100644
--- a/pjlib/src/pjlib-samples/list.c
+++ b/pjlib/src/pjlib-samples/list.c
@@ -1,55 +1,75 @@
-/* $Id$
- */
-#include <pj/list.h>
-#include <pj/assert.h>
-#include <pj/log.h>
-
-/**
- * \page page_pjlib_samples_list_c Example: List Manipulation
- *
- * Below is sample program to demonstrate how to manipulate linked list.
- *
- * \includelineno pjlib-samples/list.c
- */
-
-struct my_node
-{
-    // This must be the first member declared in the struct!
-    PJ_DECL_LIST_MEMBER(struct my_node);
-    int value;
-};
-
-
-int main()
-{
-    struct my_node nodes[10];
-    struct my_node list;
-    struct my_node *it;
-    int i;
-    
-    // Initialize the list as empty.
-    pj_list_init(&list);
-    
-    // Insert nodes.
-    for (i=0; i<10; ++i) {
-        nodes[i].value = i;
-        pj_list_insert_before(&list, &nodes[i]);
-    }
-    
-    // Iterate list nodes.
-    it = list.next;
-    while (it != &list) {
-        PJ_LOG(3,("list", "value = %d", it->value));
-        it = it->next;
-    }
-    
-    // Erase all nodes.
-    for (i=0; i<10; ++i) {
-        pj_list_erase(&nodes[i]);
-    }
-    
-    // List must be empty by now.
-    pj_assert( pj_list_empty(&list) );
-    
-    return 0;
-};
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/list.h>

+#include <pj/assert.h>

+#include <pj/log.h>

+

+/**

+ * \page page_pjlib_samples_list_c Example: List Manipulation

+ *

+ * Below is sample program to demonstrate how to manipulate linked list.

+ *

+ * \includelineno pjlib-samples/list.c

+ */

+

+struct my_node

+{

+    // This must be the first member declared in the struct!

+    PJ_DECL_LIST_MEMBER(struct my_node);

+    int value;

+};

+

+

+int main()

+{

+    struct my_node nodes[10];

+    struct my_node list;

+    struct my_node *it;

+    int i;

+    

+    // Initialize the list as empty.

+    pj_list_init(&list);

+    

+    // Insert nodes.

+    for (i=0; i<10; ++i) {

+        nodes[i].value = i;

+        pj_list_insert_before(&list, &nodes[i]);

+    }

+    

+    // Iterate list nodes.

+    it = list.next;

+    while (it != &list) {

+        PJ_LOG(3,("list", "value = %d", it->value));

+        it = it->next;

+    }

+    

+    // Erase all nodes.

+    for (i=0; i<10; ++i) {

+        pj_list_erase(&nodes[i]);

+    }

+    

+    // List must be empty by now.

+    pj_assert( pj_list_empty(&list) );

+    

+    return 0;

+};

diff --git a/pjlib/src/pjlib-samples/log.c b/pjlib/src/pjlib-samples/log.c
index 2e28976..cf1b7c8 100644
--- a/pjlib/src/pjlib-samples/log.c
+++ b/pjlib/src/pjlib-samples/log.c
@@ -1,26 +1,46 @@
-/* $Id$
- */
-#include <pj/log.h>
-
-/**
- * \page page_pjlib_samples_log_c Example: Log, Hello World
- *
- * Very simple program to write log.
- *
- * \includelineno pjlib-samples/log.c
- */
-
-int main()
-{
-    pj_status_t rc;
-
-    // Error handling omited for clarity
-    
-    // Must initialize PJLIB first!
-    rc = pj_init();
-
-    PJ_LOG(3, ("main.c", "Hello world!"));
-
-    return 0;
-}
-
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/log.h>

+

+/**

+ * \page page_pjlib_samples_log_c Example: Log, Hello World

+ *

+ * Very simple program to write log.

+ *

+ * \includelineno pjlib-samples/log.c

+ */

+

+int main()

+{

+    pj_status_t rc;

+

+    // Error handling omited for clarity

+    

+    // Must initialize PJLIB first!

+    rc = pj_init();

+

+    PJ_LOG(3, ("main.c", "Hello world!"));

+

+    return 0;

+}

+

diff --git a/pjlib/src/pjlib-test/atomic.c b/pjlib/src/pjlib-test/atomic.c
index 09bdfdb..a6d55d2 100644
--- a/pjlib/src/pjlib-test/atomic.c
+++ b/pjlib/src/pjlib-test/atomic.c
@@ -1,92 +1,113 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-/**
- * \page page_pjlib_atomic_test Test: Atomic Variable
- *
- * This file provides implementation of \b atomic_test(). It tests the
- * functionality of the atomic variable API.
- *
- * \section atomic_test_sec Scope of the Test
- *
- * API tested:
- *  - pj_atomic_create()
- *  - pj_atomic_get()
- *  - pj_atomic_inc()
- *  - pj_atomic_dec()
- *  - pj_atomic_set()
- *  - pj_atomic_destroy()
- *
- *
- * This file is <b>pjlib-test/atomic.c</b>
- *
- * \include pjlib-test/atomic.c
- */
-
-
-#if INCLUDE_ATOMIC_TEST
-
-int atomic_test(void)
-{
-    pj_pool_t *pool;
-    pj_atomic_t *atomic_var;
-    pj_status_t rc;
-
-    pool = pj_pool_create(mem, NULL, 4096, 0, NULL);
-    if (!pool)
-        return -10;
-
-    /* create() */
-    rc = pj_atomic_create(pool, 111, &atomic_var);
-    if (rc != 0) {
-        return -20;
-    }
-
-    /* get: check the value. */
-    if (pj_atomic_get(atomic_var) != 111)
-        return -30;
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pjlib.h>

+

+/**

+ * \page page_pjlib_atomic_test Test: Atomic Variable

+ *

+ * This file provides implementation of \b atomic_test(). It tests the

+ * functionality of the atomic variable API.

+ *

+ * \section atomic_test_sec Scope of the Test

+ *

+ * API tested:

+ *  - pj_atomic_create()

+ *  - pj_atomic_get()

+ *  - pj_atomic_inc()

+ *  - pj_atomic_dec()

+ *  - pj_atomic_set()

+ *  - pj_atomic_destroy()

+ *

+ *

+ * This file is <b>pjlib-test/atomic.c</b>

+ *

+ * \include pjlib-test/atomic.c

+ */

+

+

+#if INCLUDE_ATOMIC_TEST

+

+int atomic_test(void)

+{

+    pj_pool_t *pool;

+    pj_atomic_t *atomic_var;

+    pj_status_t rc;

+

+    pool = pj_pool_create(mem, NULL, 4096, 0, NULL);

+    if (!pool)

+        return -10;

+

+    /* create() */

+    rc = pj_atomic_create(pool, 111, &atomic_var);

+    if (rc != 0) {

+        return -20;

+    }

+

+    /* get: check the value. */

+    if (pj_atomic_get(atomic_var) != 111)

+        return -30;

 

     /* increment. */

-    pj_atomic_inc(atomic_var);
-    if (pj_atomic_get(atomic_var) != 112)
-        return -40;
-
+    pj_atomic_inc(atomic_var);

+    if (pj_atomic_get(atomic_var) != 112)

+        return -40;

+

     /* decrement. */

-    pj_atomic_dec(atomic_var);
-    if (pj_atomic_get(atomic_var) != 111)
-        return -50;
-
+    pj_atomic_dec(atomic_var);

+    if (pj_atomic_get(atomic_var) != 111)

+        return -50;

+

     /* set */

-    pj_atomic_set(atomic_var, 211);
-    if (pj_atomic_get(atomic_var) != 211)
-        return -60;
+    pj_atomic_set(atomic_var, 211);

+    if (pj_atomic_get(atomic_var) != 211)

+        return -60;

 

     /* add */

     pj_atomic_add(atomic_var, 10);

     if (pj_atomic_get(atomic_var) != 221)

         return -60;

-
-    /* check the value again. */
-    if (pj_atomic_get(atomic_var) != 221)
-        return -70;
-
-    /* destroy */
-    rc = pj_atomic_destroy(atomic_var);
-    if (rc != 0)
-        return -80;
-
-    pj_pool_release(pool);
-
-    return 0;
-}
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_atomic_test;
-#endif  /* INCLUDE_ATOMIC_TEST */
-
+

+    /* check the value again. */

+    if (pj_atomic_get(atomic_var) != 221)

+        return -70;

+

+    /* destroy */

+    rc = pj_atomic_destroy(atomic_var);

+    if (rc != 0)

+        return -80;

+

+    pj_pool_release(pool);

+

+    return 0;

+}

+

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_atomic_test;

+#endif  /* INCLUDE_ATOMIC_TEST */

+

diff --git a/pjlib/src/pjlib-test/echo_clt.c b/pjlib/src/pjlib-test/echo_clt.c
index afded4f..ae84b1f 100644
--- a/pjlib/src/pjlib-test/echo_clt.c
+++ b/pjlib/src/pjlib-test/echo_clt.c
@@ -1,252 +1,273 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-#if INCLUDE_ECHO_CLIENT
-
-enum { BUF_SIZE = 512 };
-
-struct client
-{
-    int sock_type;
-    const char *server;
-    int port;
-};
-
-static pj_atomic_t *totalBytes;
-static pj_atomic_t *timeout_counter;
-static pj_atomic_t *invalid_counter;
-
-#define MSEC_PRINT_DURATION 1000
-
-static int wait_socket(pj_sock_t sock, unsigned msec_timeout)
-{
-    pj_fd_set_t fdset;
-    pj_time_val timeout;
-
-    timeout.sec = 0;
-    timeout.msec = msec_timeout;
-    pj_time_val_normalize(&timeout);
-
-    PJ_FD_ZERO(&fdset);
-    PJ_FD_SET(sock, &fdset);
-    
-    return pj_sock_select(FD_SETSIZE, &fdset, NULL, NULL, &timeout);
-}
-
-static int echo_client_thread(void *arg)
-{
-    pj_sock_t sock;
-    char send_buf[BUF_SIZE];
-    char recv_buf[BUF_SIZE];
-    pj_sockaddr_in addr;
-    pj_str_t s;
-    pj_status_t rc;
-    pj_uint32_t buffer_id;
-    pj_uint32_t buffer_counter;
-    struct client *client = arg;
-    pj_status_t last_recv_err = PJ_SUCCESS, last_send_err = PJ_SUCCESS;
-    unsigned counter = 0;
-
-    rc = app_socket(PJ_AF_INET, client->sock_type, 0, -1, &sock);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...unable to create socket", rc);
-        return -10;
-    }
-
-    rc = pj_sockaddr_in_init( &addr, pj_cstr(&s, client->server), 
-                              (pj_uint16_t)client->port);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...unable to resolve server", rc);
-        return -15;
-    }
-
-    rc = pj_sock_connect(sock, &addr, sizeof(addr));
-    if (rc != PJ_SUCCESS) {
-        app_perror("...connect() error", rc);
-        pj_sock_close(sock);
-        return -20;
-    }
-
-    PJ_LOG(3,("", "...socket connected to %s:%d", 
-		  pj_inet_ntoa(addr.sin_addr),
-		  pj_ntohs(addr.sin_port)));
-
-    pj_memset(send_buf, 'A', BUF_SIZE);
-    send_buf[BUF_SIZE-1]='\0';
-
-    /* Give other thread chance to initialize themselves! */
-    pj_thread_sleep(200);
-
-    //PJ_LOG(3,("", "...thread %p running", pj_thread_this()));
-
-    buffer_id = (pj_uint32_t) pj_thread_this();
-    buffer_counter = 0;
-
-    *(pj_uint32_t*)send_buf = buffer_id;
-
-    for (;;) {
-        int rc;
-        pj_ssize_t bytes;
-
-	++counter;
-
-	//while (wait_socket(sock,0) > 0)
-	//    ;
-
-        /* Send a packet. */
-        bytes = BUF_SIZE;
-	*(pj_uint32_t*)(send_buf+4) = ++buffer_counter;
-        rc = pj_sock_send(sock, send_buf, &bytes, 0);
-        if (rc != PJ_SUCCESS || bytes != BUF_SIZE) {
-            if (rc != last_send_err) {
-                app_perror("...send() error", rc);
-                PJ_LOG(3,("", "...ignoring subsequent error.."));
-                last_send_err = rc;
-                pj_thread_sleep(100);
-            }
-            continue;
-        }
-
-        rc = wait_socket(sock, 500);
-        if (rc == 0) {
-            PJ_LOG(3,("", "...timeout"));
-	    bytes = 0;
-	    pj_atomic_inc(timeout_counter);
-	} else if (rc < 0) {
-	    rc = pj_get_netos_error();
-	    app_perror("...select() error", rc);
-	    break;
-        } else {
-            /* Receive back the original packet. */
-            bytes = 0;
-            do {
-                pj_ssize_t received = BUF_SIZE - bytes;
-                rc = pj_sock_recv(sock, recv_buf+bytes, &received, 0);
-                if (rc != PJ_SUCCESS || received == 0) {
-                    if (rc != last_recv_err) {
-                        app_perror("...recv() error", rc);
-                        PJ_LOG(3,("", "...ignoring subsequent error.."));
-                        last_recv_err = rc;
-                        pj_thread_sleep(100);
-                    }
-                    bytes = 0;
-		    received = 0;
-                    break;
-                }
-                bytes += received;
-            } while (bytes != BUF_SIZE && bytes != 0);
-        }
-
-        if (bytes == 0)
-            continue;
-
-        if (pj_memcmp(send_buf, recv_buf, BUF_SIZE) != 0) {
-	    recv_buf[BUF_SIZE-1] = '\0';
-            PJ_LOG(3,("", "...error: buffer %u has changed!\n"
-			  "send_buf=%s\n"
-			  "recv_buf=%s\n", 
-			  counter, send_buf, recv_buf));
-	    pj_atomic_inc(invalid_counter);
-        }
-
-        /* Accumulate total received. */
-	pj_atomic_add(totalBytes, bytes);
-    }
-
-    pj_sock_close(sock);
-    return 0;
-}
-
-int echo_client(int sock_type, const char *server, int port)
-{
-    pj_pool_t *pool;
-    pj_thread_t *thread[ECHO_CLIENT_MAX_THREADS];
-    pj_status_t rc;
-    struct client client;
-    int i;
-    pj_atomic_value_t last_received;
-    pj_timestamp last_report;
-
-    client.sock_type = sock_type;
-    client.server = server;
-    client.port = port;
-
-    pool = pj_pool_create( mem, NULL, 4000, 4000, NULL );
-
-    rc = pj_atomic_create(pool, 0, &totalBytes);
-    if (rc != PJ_SUCCESS) {
-        PJ_LOG(3,("", "...error: unable to create atomic variable", rc));
-        return -30;
-    }
-    rc = pj_atomic_create(pool, 0, &invalid_counter);
-    rc = pj_atomic_create(pool, 0, &timeout_counter);
-
-    PJ_LOG(3,("", "Echo client started"));
-    PJ_LOG(3,("", "  Destination: %s:%d", 
-                  ECHO_SERVER_ADDRESS, ECHO_SERVER_START_PORT));
-    PJ_LOG(3,("", "  Press Ctrl-C to exit"));
-
-    for (i=0; i<ECHO_CLIENT_MAX_THREADS; ++i) {
-        rc = pj_thread_create( pool, NULL, &echo_client_thread, &client, 
-                               PJ_THREAD_DEFAULT_STACK_SIZE, 0,
-                               &thread[i]);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error: unable to create thread", rc);
-            return -10;
-        }
-    }
-
-    last_received = 0;
-    pj_get_timestamp(&last_report);
-
-    for (;;) {
-	pj_timestamp now;
-	unsigned long received, cur_received;
-	unsigned msec;
-	pj_highprec_t bw;
-	pj_time_val elapsed;
-	unsigned bw32;
-	pj_uint32_t timeout, invalid;
-
-	pj_thread_sleep(1000);
-
-	pj_get_timestamp(&now);
-	elapsed = pj_elapsed_time(&last_report, &now);
-	msec = PJ_TIME_VAL_MSEC(elapsed);
-
-	received = pj_atomic_get(totalBytes);
-	cur_received = received - last_received;
-	
-	bw = cur_received;
-	pj_highprec_mul(bw, 1000);
-	pj_highprec_div(bw, msec);
-
-	bw32 = (unsigned)bw;
-	
-	last_report = now;
-	last_received = received;
-
-	timeout = pj_atomic_get(timeout_counter);
-	invalid = pj_atomic_get(invalid_counter);
-
-        PJ_LOG(3,("", 
-	          "...%d threads, total bandwidth: %d KB/s, "
-		  "timeout=%d, invalid=%d", 
-                  ECHO_CLIENT_MAX_THREADS, bw32/1000,
-		  timeout, invalid));
-    }
-
-    for (i=0; i<ECHO_CLIENT_MAX_THREADS; ++i) {
-        pj_thread_join( thread[i] );
-    }
-
-    pj_pool_release(pool);
-    return 0;
-}
-
-
-#else
-int dummy_echo_client;
-#endif  /* INCLUDE_ECHO_CLIENT */
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pjlib.h>

+

+#if INCLUDE_ECHO_CLIENT

+

+enum { BUF_SIZE = 512 };

+

+struct client

+{

+    int sock_type;

+    const char *server;

+    int port;

+};

+

+static pj_atomic_t *totalBytes;

+static pj_atomic_t *timeout_counter;

+static pj_atomic_t *invalid_counter;

+

+#define MSEC_PRINT_DURATION 1000

+

+static int wait_socket(pj_sock_t sock, unsigned msec_timeout)

+{

+    pj_fd_set_t fdset;

+    pj_time_val timeout;

+

+    timeout.sec = 0;

+    timeout.msec = msec_timeout;

+    pj_time_val_normalize(&timeout);

+

+    PJ_FD_ZERO(&fdset);

+    PJ_FD_SET(sock, &fdset);

+    

+    return pj_sock_select(FD_SETSIZE, &fdset, NULL, NULL, &timeout);

+}

+

+static int echo_client_thread(void *arg)

+{

+    pj_sock_t sock;

+    char send_buf[BUF_SIZE];

+    char recv_buf[BUF_SIZE];

+    pj_sockaddr_in addr;

+    pj_str_t s;

+    pj_status_t rc;

+    pj_uint32_t buffer_id;

+    pj_uint32_t buffer_counter;

+    struct client *client = arg;

+    pj_status_t last_recv_err = PJ_SUCCESS, last_send_err = PJ_SUCCESS;

+    unsigned counter = 0;

+

+    rc = app_socket(PJ_AF_INET, client->sock_type, 0, -1, &sock);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...unable to create socket", rc);

+        return -10;

+    }

+

+    rc = pj_sockaddr_in_init( &addr, pj_cstr(&s, client->server), 

+                              (pj_uint16_t)client->port);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...unable to resolve server", rc);

+        return -15;

+    }

+

+    rc = pj_sock_connect(sock, &addr, sizeof(addr));

+    if (rc != PJ_SUCCESS) {

+        app_perror("...connect() error", rc);

+        pj_sock_close(sock);

+        return -20;

+    }

+

+    PJ_LOG(3,("", "...socket connected to %s:%d", 

+		  pj_inet_ntoa(addr.sin_addr),

+		  pj_ntohs(addr.sin_port)));

+

+    pj_memset(send_buf, 'A', BUF_SIZE);

+    send_buf[BUF_SIZE-1]='\0';

+

+    /* Give other thread chance to initialize themselves! */

+    pj_thread_sleep(200);

+

+    //PJ_LOG(3,("", "...thread %p running", pj_thread_this()));

+

+    buffer_id = (pj_uint32_t) pj_thread_this();

+    buffer_counter = 0;

+

+    *(pj_uint32_t*)send_buf = buffer_id;

+

+    for (;;) {

+        int rc;

+        pj_ssize_t bytes;

+

+	++counter;

+

+	//while (wait_socket(sock,0) > 0)

+	//    ;

+

+        /* Send a packet. */

+        bytes = BUF_SIZE;

+	*(pj_uint32_t*)(send_buf+4) = ++buffer_counter;

+        rc = pj_sock_send(sock, send_buf, &bytes, 0);

+        if (rc != PJ_SUCCESS || bytes != BUF_SIZE) {

+            if (rc != last_send_err) {

+                app_perror("...send() error", rc);

+                PJ_LOG(3,("", "...ignoring subsequent error.."));

+                last_send_err = rc;

+                pj_thread_sleep(100);

+            }

+            continue;

+        }

+

+        rc = wait_socket(sock, 500);

+        if (rc == 0) {

+            PJ_LOG(3,("", "...timeout"));

+	    bytes = 0;

+	    pj_atomic_inc(timeout_counter);

+	} else if (rc < 0) {

+	    rc = pj_get_netos_error();

+	    app_perror("...select() error", rc);

+	    break;

+        } else {

+            /* Receive back the original packet. */

+            bytes = 0;

+            do {

+                pj_ssize_t received = BUF_SIZE - bytes;

+                rc = pj_sock_recv(sock, recv_buf+bytes, &received, 0);

+                if (rc != PJ_SUCCESS || received == 0) {

+                    if (rc != last_recv_err) {

+                        app_perror("...recv() error", rc);

+                        PJ_LOG(3,("", "...ignoring subsequent error.."));

+                        last_recv_err = rc;

+                        pj_thread_sleep(100);

+                    }

+                    bytes = 0;

+		    received = 0;

+                    break;

+                }

+                bytes += received;

+            } while (bytes != BUF_SIZE && bytes != 0);

+        }

+

+        if (bytes == 0)

+            continue;

+

+        if (pj_memcmp(send_buf, recv_buf, BUF_SIZE) != 0) {

+	    recv_buf[BUF_SIZE-1] = '\0';

+            PJ_LOG(3,("", "...error: buffer %u has changed!\n"

+			  "send_buf=%s\n"

+			  "recv_buf=%s\n", 

+			  counter, send_buf, recv_buf));

+	    pj_atomic_inc(invalid_counter);

+        }

+

+        /* Accumulate total received. */

+	pj_atomic_add(totalBytes, bytes);

+    }

+

+    pj_sock_close(sock);

+    return 0;

+}

+

+int echo_client(int sock_type, const char *server, int port)

+{

+    pj_pool_t *pool;

+    pj_thread_t *thread[ECHO_CLIENT_MAX_THREADS];

+    pj_status_t rc;

+    struct client client;

+    int i;

+    pj_atomic_value_t last_received;

+    pj_timestamp last_report;

+

+    client.sock_type = sock_type;

+    client.server = server;

+    client.port = port;

+

+    pool = pj_pool_create( mem, NULL, 4000, 4000, NULL );

+

+    rc = pj_atomic_create(pool, 0, &totalBytes);

+    if (rc != PJ_SUCCESS) {

+        PJ_LOG(3,("", "...error: unable to create atomic variable", rc));

+        return -30;

+    }

+    rc = pj_atomic_create(pool, 0, &invalid_counter);

+    rc = pj_atomic_create(pool, 0, &timeout_counter);

+

+    PJ_LOG(3,("", "Echo client started"));

+    PJ_LOG(3,("", "  Destination: %s:%d", 

+                  ECHO_SERVER_ADDRESS, ECHO_SERVER_START_PORT));

+    PJ_LOG(3,("", "  Press Ctrl-C to exit"));

+

+    for (i=0; i<ECHO_CLIENT_MAX_THREADS; ++i) {

+        rc = pj_thread_create( pool, NULL, &echo_client_thread, &client, 

+                               PJ_THREAD_DEFAULT_STACK_SIZE, 0,

+                               &thread[i]);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error: unable to create thread", rc);

+            return -10;

+        }

+    }

+

+    last_received = 0;

+    pj_get_timestamp(&last_report);

+

+    for (;;) {

+	pj_timestamp now;

+	unsigned long received, cur_received;

+	unsigned msec;

+	pj_highprec_t bw;

+	pj_time_val elapsed;

+	unsigned bw32;

+	pj_uint32_t timeout, invalid;

+

+	pj_thread_sleep(1000);

+

+	pj_get_timestamp(&now);

+	elapsed = pj_elapsed_time(&last_report, &now);

+	msec = PJ_TIME_VAL_MSEC(elapsed);

+

+	received = pj_atomic_get(totalBytes);

+	cur_received = received - last_received;

+	

+	bw = cur_received;

+	pj_highprec_mul(bw, 1000);

+	pj_highprec_div(bw, msec);

+

+	bw32 = (unsigned)bw;

+	

+	last_report = now;

+	last_received = received;

+

+	timeout = pj_atomic_get(timeout_counter);

+	invalid = pj_atomic_get(invalid_counter);

+

+        PJ_LOG(3,("", 

+	          "...%d threads, total bandwidth: %d KB/s, "

+		  "timeout=%d, invalid=%d", 

+                  ECHO_CLIENT_MAX_THREADS, bw32/1000,

+		  timeout, invalid));

+    }

+

+    for (i=0; i<ECHO_CLIENT_MAX_THREADS; ++i) {

+        pj_thread_join( thread[i] );

+    }

+

+    pj_pool_release(pool);

+    return 0;

+}

+

+

+#else

+int dummy_echo_client;

+#endif  /* INCLUDE_ECHO_CLIENT */

diff --git a/pjlib/src/pjlib-test/errno.c b/pjlib/src/pjlib-test/errno.c
index 7bf2887..6fa3e93 100644
--- a/pjlib/src/pjlib-test/errno.c
+++ b/pjlib/src/pjlib-test/errno.c
@@ -1,146 +1,166 @@
-/* $Id$
- */
-#include "test.h"
-#include <pj/errno.h>
-#include <pj/log.h>
-#include <pj/ctype.h>
-#include <pj/compat/socket.h>
-#include <pj/string.h>
-
-#if INCLUDE_ERRNO_TEST
-
-#define THIS_FILE   "errno"
-
-#if defined(PJ_WIN32) && PJ_WIN32 != 0
-#   include <windows.h>
-#endif
-
-#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0
-#   include <errno.h>
-#endif
-
-static void trim_newlines(char *s)
-{
-    while (*s) {
-        if (*s == '\r' || *s == '\n')
-            *s = ' ';
-        ++s;
-    }
-}
-
-int my_strncasecmp(const char *s1, const char *s2, int max_len)
-{
-    while (*s1 && *s2 && max_len > 0) {
-        if (pj_tolower(*s1) != pj_tolower(*s2))
-            return -1;
-        ++s1;
-        ++s2;
-        --max_len;
-    }
-    return 0;
-}
-
-const char *my_stristr(const char *whole, const char *part)
-{
-    int part_len = strlen(part);
-    while (*whole) {
-        if (my_strncasecmp(whole, part, part_len) == 0)
-            return whole;
-        ++whole;
-    }
-    return NULL;
-}
-
-int errno_test(void)
-{
-    enum { CUT = 6 };
-    pj_status_t rc;
-    char errbuf[256];
-
-    PJ_LOG(3,(THIS_FILE, "...errno test: check the msg carefully"));
-
-    /* 
-     * Windows platform error. 
-     */
-#   ifdef ERROR_INVALID_DATA
-    rc = PJ_STATUS_FROM_OS(ERROR_INVALID_DATA);
-    pj_set_os_error(rc);
-
-    /* Whole */
-    pj_strerror(rc, errbuf, sizeof(errbuf));
-    trim_newlines(errbuf);
-    PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA: '%s'", errbuf));
-    if (my_stristr(errbuf, "invalid") == NULL) {
-        PJ_LOG(3, (THIS_FILE, 
-                   "...error: expecting \"invalid\" string in the msg"));
-        return -20;
-    }
-
-    /* Cut version. */
-    pj_strerror(rc, errbuf, CUT);
-    PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA (cut): '%s'", errbuf));
-#   endif
-
-    /*
-     * Unix errors
-     */
-#   ifdef EINVAL
-    rc = PJ_STATUS_FROM_OS(EINVAL);
-    pj_set_os_error(rc);
-
-    /* Whole */
-    pj_strerror(rc, errbuf, sizeof(errbuf));
-    trim_newlines(errbuf);
-    PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL: '%s'", errbuf));
-    if (my_stristr(errbuf, "invalid") == NULL) {
-        PJ_LOG(3, (THIS_FILE, 
-                   "...error: expecting \"invalid\" string in the msg"));
-        return -30;
-    }
-
-    /* Cut */
-    pj_strerror(rc, errbuf, CUT);
-    PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL (cut): '%s'", errbuf));
-#   endif
-
-    /* 
-     * Windows WSA errors
-     */
-#   ifdef WSAEINVAL
-    rc = PJ_STATUS_FROM_OS(WSAEINVAL);
-    pj_set_os_error(rc);
-
-    /* Whole */
-    pj_strerror(rc, errbuf, sizeof(errbuf));
-    trim_newlines(errbuf);
-    PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL: '%s'", errbuf));
-    if (my_stristr(errbuf, "invalid") == NULL) {
-        PJ_LOG(3, (THIS_FILE, 
-                   "...error: expecting \"invalid\" string in the msg"));
-        return -40;
-    }
-
-    /* Cut */
-    pj_strerror(rc, errbuf, CUT);
-    PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL (cut): '%s'", errbuf));
-#   endif
-
-    pj_strerror(PJ_EBUG, errbuf, sizeof(errbuf));
-    PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG: '%s'", errbuf));
-    if (my_stristr(errbuf, "BUG") == NULL) {
-        PJ_LOG(3, (THIS_FILE, 
-                   "...error: expecting \"BUG\" string in the msg"));
-        return -20;
-    }
-
-    pj_strerror(PJ_EBUG, errbuf, CUT);
-    PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG, cut at %d chars: '%s'", 
-              CUT, errbuf));
-
-    return 0;
-}
-
-
-#endif	/* INCLUDE_ERRNO_TEST */
-
-
+/* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pj/errno.h>

+#include <pj/log.h>

+#include <pj/ctype.h>

+#include <pj/compat/socket.h>

+#include <pj/string.h>

+

+#if INCLUDE_ERRNO_TEST

+

+#define THIS_FILE   "errno"

+

+#if defined(PJ_WIN32) && PJ_WIN32 != 0

+#   include <windows.h>

+#endif

+

+#if defined(PJ_HAS_ERRNO_H) && PJ_HAS_ERRNO_H != 0

+#   include <errno.h>

+#endif

+

+static void trim_newlines(char *s)

+{

+    while (*s) {

+        if (*s == '\r' || *s == '\n')

+            *s = ' ';

+        ++s;

+    }

+}

+

+int my_strncasecmp(const char *s1, const char *s2, int max_len)

+{

+    while (*s1 && *s2 && max_len > 0) {

+        if (pj_tolower(*s1) != pj_tolower(*s2))

+            return -1;

+        ++s1;

+        ++s2;

+        --max_len;

+    }

+    return 0;

+}

+

+const char *my_stristr(const char *whole, const char *part)

+{

+    int part_len = strlen(part);

+    while (*whole) {

+        if (my_strncasecmp(whole, part, part_len) == 0)

+            return whole;

+        ++whole;

+    }

+    return NULL;

+}

+

+int errno_test(void)

+{

+    enum { CUT = 6 };

+    pj_status_t rc;

+    char errbuf[256];

+

+    PJ_LOG(3,(THIS_FILE, "...errno test: check the msg carefully"));

+

+    /* 

+     * Windows platform error. 

+     */

+#   ifdef ERROR_INVALID_DATA

+    rc = PJ_STATUS_FROM_OS(ERROR_INVALID_DATA);

+    pj_set_os_error(rc);

+

+    /* Whole */

+    pj_strerror(rc, errbuf, sizeof(errbuf));

+    trim_newlines(errbuf);

+    PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA: '%s'", errbuf));

+    if (my_stristr(errbuf, "invalid") == NULL) {

+        PJ_LOG(3, (THIS_FILE, 

+                   "...error: expecting \"invalid\" string in the msg"));

+        return -20;

+    }

+

+    /* Cut version. */

+    pj_strerror(rc, errbuf, CUT);

+    PJ_LOG(3,(THIS_FILE, "...msg for rc=ERROR_INVALID_DATA (cut): '%s'", errbuf));

+#   endif

+

+    /*

+     * Unix errors

+     */

+#   ifdef EINVAL

+    rc = PJ_STATUS_FROM_OS(EINVAL);

+    pj_set_os_error(rc);

+

+    /* Whole */

+    pj_strerror(rc, errbuf, sizeof(errbuf));

+    trim_newlines(errbuf);

+    PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL: '%s'", errbuf));

+    if (my_stristr(errbuf, "invalid") == NULL) {

+        PJ_LOG(3, (THIS_FILE, 

+                   "...error: expecting \"invalid\" string in the msg"));

+        return -30;

+    }

+

+    /* Cut */

+    pj_strerror(rc, errbuf, CUT);

+    PJ_LOG(3,(THIS_FILE, "...msg for rc=EINVAL (cut): '%s'", errbuf));

+#   endif

+

+    /* 

+     * Windows WSA errors

+     */

+#   ifdef WSAEINVAL

+    rc = PJ_STATUS_FROM_OS(WSAEINVAL);

+    pj_set_os_error(rc);

+

+    /* Whole */

+    pj_strerror(rc, errbuf, sizeof(errbuf));

+    trim_newlines(errbuf);

+    PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL: '%s'", errbuf));

+    if (my_stristr(errbuf, "invalid") == NULL) {

+        PJ_LOG(3, (THIS_FILE, 

+                   "...error: expecting \"invalid\" string in the msg"));

+        return -40;

+    }

+

+    /* Cut */

+    pj_strerror(rc, errbuf, CUT);

+    PJ_LOG(3,(THIS_FILE, "...msg for rc=WSAEINVAL (cut): '%s'", errbuf));

+#   endif

+

+    pj_strerror(PJ_EBUG, errbuf, sizeof(errbuf));

+    PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG: '%s'", errbuf));

+    if (my_stristr(errbuf, "BUG") == NULL) {

+        PJ_LOG(3, (THIS_FILE, 

+                   "...error: expecting \"BUG\" string in the msg"));

+        return -20;

+    }

+

+    pj_strerror(PJ_EBUG, errbuf, CUT);

+    PJ_LOG(3,(THIS_FILE, "...msg for rc=PJ_EBUG, cut at %d chars: '%s'", 

+              CUT, errbuf));

+

+    return 0;

+}

+

+

+#endif	/* INCLUDE_ERRNO_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/exception.c b/pjlib/src/pjlib-test/exception.c
index 31a4a54..be0886e 100644
--- a/pjlib/src/pjlib-test/exception.c
+++ b/pjlib/src/pjlib-test/exception.c
@@ -1,161 +1,182 @@
-/* $Id$
- */
-#include "test.h"
-
-
-/**
- * \page page_pjlib_exception_test Test: Exception Handling
- *
- * This file provides implementation of \b exception_test(). It tests the
- * functionality of the exception handling API.
- *
- * @note This test use static ID not acquired through proper registration.
- * This is not recommended, since it may create ID collissions.
- *
- * \section exception_test_sec Scope of the Test
- *
- * Some scenarios tested:
- *  - no exception situation
- *  - basic TRY/CATCH
- *  - multiple exception handlers
- *  - default handlers
- *
- *
- * This file is <b>pjlib-test/exception.c</b>
- *
- * \include pjlib-test/exception.c
- */
-
-
-#if INCLUDE_EXCEPTION_TEST
-
-#include <pjlib.h>
-
-#define	ID_1	1
-#define ID_2	2
-
-static int throw_id_1(void)
-{
-    PJ_THROW( ID_1 );
-    return -1;
-}
-
-static int throw_id_2(void)
-{
-    PJ_THROW( ID_2 );
-    return -1;
-}
-
-
-static int test(void)
-{
-    PJ_USE_EXCEPTION;
-    int rc = 0;
-
-    /*
-     * No exception situation.
-     */
-    PJ_TRY {
-        rc = rc;
-    }
-    PJ_CATCH( ID_1 ) {
-        rc = -2;
-    }
-    PJ_DEFAULT {
-        rc = -3;
-    }
-    PJ_END;
-
-    if (rc != 0)
-	return rc;
-
-
-    /*
-     * Basic TRY/CATCH
-     */ 
-    PJ_TRY {
-	rc = throw_id_1();
-
-	// should not reach here.
-	rc = -10;
-    }
-    PJ_CATCH( ID_1 ) {
-	if (!rc) rc = 0;
-    }
-    PJ_DEFAULT {
-        int id = PJ_GET_EXCEPTION();
-        PJ_LOG(3,("", "...error: got unexpected exception %d (%s)", 
-                  id, pj_exception_id_name(id)));
-	if (!rc) rc = -20;
-    }
-    PJ_END;
-
-    if (rc != 0)
-	return rc;
-
-    /*
-     * Multiple exceptions handlers
-     */
-    PJ_TRY {
-	rc = throw_id_2();
-	// should not reach here.
-	rc = -25;
-    }
-    PJ_CATCH( ID_1 ) {
-	if (!rc) rc = -30;
-    }
-    PJ_CATCH( ID_2 ) {
-	if (!rc) rc = 0;
-    }
-    PJ_DEFAULT {
-	if (!rc) rc = -40;
-    }
-    PJ_END;
-
-    if (rc != 0)
-	return rc;
-
-    /*
-     * Test default handler.
-     */
-    PJ_TRY {
-	rc = throw_id_1();
-	// should not reach here
-	rc = -50;
-    }
-    PJ_CATCH( ID_2 ) {
-	if (!rc) rc = -60;
-    }
-    PJ_DEFAULT {
-	if (!rc) rc = 0;
-    }
-    PJ_END;
-
-    if (rc != 0)
-	return rc;
-
-    return 0;
-}
-
-int exception_test(void)
-{
-    int i, rc;
-    enum { LOOP = 10 };
-
-    for (i=0; i<LOOP; ++i) {
-	if ((rc=test()) != 0) {
-	    PJ_LOG(3,("", "...failed at i=%d (rc=%d)", i, rc));
-	    return rc;
-	}
-    }
-    return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_exception_test;
-#endif	/* INCLUDE_EXCEPTION_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+

+/**

+ * \page page_pjlib_exception_test Test: Exception Handling

+ *

+ * This file provides implementation of \b exception_test(). It tests the

+ * functionality of the exception handling API.

+ *

+ * @note This test use static ID not acquired through proper registration.

+ * This is not recommended, since it may create ID collissions.

+ *

+ * \section exception_test_sec Scope of the Test

+ *

+ * Some scenarios tested:

+ *  - no exception situation

+ *  - basic TRY/CATCH

+ *  - multiple exception handlers

+ *  - default handlers

+ *

+ *

+ * This file is <b>pjlib-test/exception.c</b>

+ *

+ * \include pjlib-test/exception.c

+ */

+

+

+#if INCLUDE_EXCEPTION_TEST

+

+#include <pjlib.h>

+

+#define	ID_1	1

+#define ID_2	2

+

+static int throw_id_1(void)

+{

+    PJ_THROW( ID_1 );

+    return -1;

+}

+

+static int throw_id_2(void)

+{

+    PJ_THROW( ID_2 );

+    return -1;

+}

+

+

+static int test(void)

+{

+    PJ_USE_EXCEPTION;

+    int rc = 0;

+

+    /*

+     * No exception situation.

+     */

+    PJ_TRY {

+        rc = rc;

+    }

+    PJ_CATCH( ID_1 ) {

+        rc = -2;

+    }

+    PJ_DEFAULT {

+        rc = -3;

+    }

+    PJ_END;

+

+    if (rc != 0)

+	return rc;

+

+

+    /*

+     * Basic TRY/CATCH

+     */ 

+    PJ_TRY {

+	rc = throw_id_1();

+

+	// should not reach here.

+	rc = -10;

+    }

+    PJ_CATCH( ID_1 ) {

+	if (!rc) rc = 0;

+    }

+    PJ_DEFAULT {

+        int id = PJ_GET_EXCEPTION();

+        PJ_LOG(3,("", "...error: got unexpected exception %d (%s)", 

+                  id, pj_exception_id_name(id)));

+	if (!rc) rc = -20;

+    }

+    PJ_END;

+

+    if (rc != 0)

+	return rc;

+

+    /*

+     * Multiple exceptions handlers

+     */

+    PJ_TRY {

+	rc = throw_id_2();

+	// should not reach here.

+	rc = -25;

+    }

+    PJ_CATCH( ID_1 ) {

+	if (!rc) rc = -30;

+    }

+    PJ_CATCH( ID_2 ) {

+	if (!rc) rc = 0;

+    }

+    PJ_DEFAULT {

+	if (!rc) rc = -40;

+    }

+    PJ_END;

+

+    if (rc != 0)

+	return rc;

+

+    /*

+     * Test default handler.

+     */

+    PJ_TRY {

+	rc = throw_id_1();

+	// should not reach here

+	rc = -50;

+    }

+    PJ_CATCH( ID_2 ) {

+	if (!rc) rc = -60;

+    }

+    PJ_DEFAULT {

+	if (!rc) rc = 0;

+    }

+    PJ_END;

+

+    if (rc != 0)

+	return rc;

+

+    return 0;

+}

+

+int exception_test(void)

+{

+    int i, rc;

+    enum { LOOP = 10 };

+

+    for (i=0; i<LOOP; ++i) {

+	if ((rc=test()) != 0) {

+	    PJ_LOG(3,("", "...failed at i=%d (rc=%d)", i, rc));

+	    return rc;

+	}

+    }

+    return 0;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_exception_test;

+#endif	/* INCLUDE_EXCEPTION_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/fifobuf.c b/pjlib/src/pjlib-test/fifobuf.c
index 2f59473..55d4c5a 100644
--- a/pjlib/src/pjlib-test/fifobuf.c
+++ b/pjlib/src/pjlib-test/fifobuf.c
@@ -1,100 +1,121 @@
-/* $Id$
- */
-#include "test.h"
-
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_fifobuf_test;
-
-#if INCLUDE_FIFOBUF_TEST
-
-#include <pjlib.h>
-
-int fifobuf_test()
-{
-    enum { SIZE = 1024, MAX_ENTRIES = 128, 
-	   MIN_SIZE = 4, MAX_SIZE = 64, 
-	   LOOP=10000 };
-    pj_pool_t *pool;
-    pj_fifobuf_t fifo;
-    unsigned available = SIZE;
-    void *entries[MAX_ENTRIES];
-    void *buffer;
-    int i;
-
-    pool = pj_pool_create(mem, NULL, SIZE+256, 0, NULL);
-    if (!pool)
-	return -10;
-
-    buffer = pj_pool_alloc(pool, SIZE);
-    if (!buffer)
-	return -20;
-
-    pj_fifobuf_init (&fifo, buffer, SIZE);
-    
-    // Test 1
-    for (i=0; i<LOOP*MAX_ENTRIES; ++i) {
-	int size;
-	int c, f;
-	c = i%2;
-	f = (i+1)%2;
-	do {
-	    size = MIN_SIZE+(pj_rand() % MAX_SIZE);
-	    entries[c] = pj_fifobuf_alloc (&fifo, size);
-	} while (entries[c] == 0);
-	if ( i!=0) {
-	    pj_fifobuf_free(&fifo, entries[f]);
-	}
-    }
-    if (entries[(i+1)%2])
-	pj_fifobuf_free(&fifo, entries[(i+1)%2]);
-
-    if (pj_fifobuf_max_size(&fifo) < SIZE-4) {
-	pj_assert(0);
-	return -1;
-    }
-
-    // Test 2
-    entries[0] = pj_fifobuf_alloc (&fifo, MIN_SIZE);
-    if (!entries[0]) return -1;
-    for (i=0; i<LOOP*MAX_ENTRIES; ++i) {
-	int size = MIN_SIZE+(pj_rand() % MAX_SIZE);
-	entries[1] = pj_fifobuf_alloc (&fifo, size);
-	if (entries[1])
-	    pj_fifobuf_unalloc(&fifo, entries[1]);
-    }
-    pj_fifobuf_unalloc(&fifo, entries[0]);
-    if (pj_fifobuf_max_size(&fifo) < SIZE-4) {
-	pj_assert(0);
-	return -2;
-    }
-
-    // Test 3
-    for (i=0; i<LOOP; ++i) {
-	int count, j;
-	for (count=0; available>=MIN_SIZE+4 && count < MAX_ENTRIES;) {
-	    int size = MIN_SIZE+(pj_rand() % MAX_SIZE);
-	    entries[count] = pj_fifobuf_alloc (&fifo, size);
-	    if (entries[count]) {
-		available -= (size+4);
-		++count;
-	    }
-	}
-	for (j=0; j<count; ++j) {
-	    pj_fifobuf_free (&fifo, entries[j]);
-	}
-	available = SIZE;
-    }
-
-    if (pj_fifobuf_max_size(&fifo) < SIZE-4) {
-	pj_assert(0);
-	return -3;
-    }
-    pj_pool_release(pool);
-    return 0;
-}
-
-#endif	/* INCLUDE_FIFOBUF_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_fifobuf_test;

+

+#if INCLUDE_FIFOBUF_TEST

+

+#include <pjlib.h>

+

+int fifobuf_test()

+{

+    enum { SIZE = 1024, MAX_ENTRIES = 128, 

+	   MIN_SIZE = 4, MAX_SIZE = 64, 

+	   LOOP=10000 };

+    pj_pool_t *pool;

+    pj_fifobuf_t fifo;

+    unsigned available = SIZE;

+    void *entries[MAX_ENTRIES];

+    void *buffer;

+    int i;

+

+    pool = pj_pool_create(mem, NULL, SIZE+256, 0, NULL);

+    if (!pool)

+	return -10;

+

+    buffer = pj_pool_alloc(pool, SIZE);

+    if (!buffer)

+	return -20;

+

+    pj_fifobuf_init (&fifo, buffer, SIZE);

+    

+    // Test 1

+    for (i=0; i<LOOP*MAX_ENTRIES; ++i) {

+	int size;

+	int c, f;

+	c = i%2;

+	f = (i+1)%2;

+	do {

+	    size = MIN_SIZE+(pj_rand() % MAX_SIZE);

+	    entries[c] = pj_fifobuf_alloc (&fifo, size);

+	} while (entries[c] == 0);

+	if ( i!=0) {

+	    pj_fifobuf_free(&fifo, entries[f]);

+	}

+    }

+    if (entries[(i+1)%2])

+	pj_fifobuf_free(&fifo, entries[(i+1)%2]);

+

+    if (pj_fifobuf_max_size(&fifo) < SIZE-4) {

+	pj_assert(0);

+	return -1;

+    }

+

+    // Test 2

+    entries[0] = pj_fifobuf_alloc (&fifo, MIN_SIZE);

+    if (!entries[0]) return -1;

+    for (i=0; i<LOOP*MAX_ENTRIES; ++i) {

+	int size = MIN_SIZE+(pj_rand() % MAX_SIZE);

+	entries[1] = pj_fifobuf_alloc (&fifo, size);

+	if (entries[1])

+	    pj_fifobuf_unalloc(&fifo, entries[1]);

+    }

+    pj_fifobuf_unalloc(&fifo, entries[0]);

+    if (pj_fifobuf_max_size(&fifo) < SIZE-4) {

+	pj_assert(0);

+	return -2;

+    }

+

+    // Test 3

+    for (i=0; i<LOOP; ++i) {

+	int count, j;

+	for (count=0; available>=MIN_SIZE+4 && count < MAX_ENTRIES;) {

+	    int size = MIN_SIZE+(pj_rand() % MAX_SIZE);

+	    entries[count] = pj_fifobuf_alloc (&fifo, size);

+	    if (entries[count]) {

+		available -= (size+4);

+		++count;

+	    }

+	}

+	for (j=0; j<count; ++j) {

+	    pj_fifobuf_free (&fifo, entries[j]);

+	}

+	available = SIZE;

+    }

+

+    if (pj_fifobuf_max_size(&fifo) < SIZE-4) {

+	pj_assert(0);

+	return -3;

+    }

+    pj_pool_release(pool);

+    return 0;

+}

+

+#endif	/* INCLUDE_FIFOBUF_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/file.c b/pjlib/src/pjlib-test/file.c
index b3ab6e3..6e5611a 100644
--- a/pjlib/src/pjlib-test/file.c
+++ b/pjlib/src/pjlib-test/file.c
@@ -1,4 +1,25 @@
 /* $Id$ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #include "test.h"

 #include <pjlib.h>

 

diff --git a/pjlib/src/pjlib-test/ioq_perf.c b/pjlib/src/pjlib-test/ioq_perf.c
index cfeaab7..2d76a01 100644
--- a/pjlib/src/pjlib-test/ioq_perf.c
+++ b/pjlib/src/pjlib-test/ioq_perf.c
@@ -1,486 +1,507 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-#include <pj/compat/high_precision.h>
-
-/**
- * \page page_pjlib_ioqueue_perf_test Test: I/O Queue Performance
- *
- * Test the performance of the I/O queue, using typical producer
- * consumer test. The test should examine the effect of using multiple
- * threads on the performance.
- *
- * This file is <b>pjlib-test/ioq_perf.c</b>
- *
- * \include pjlib-test/ioq_perf.c
- */
-
-#if INCLUDE_IOQUEUE_PERF_TEST
-
-#ifdef _MSC_VER
-#   pragma warning ( disable: 4204)     // non-constant aggregate initializer
-#endif
-
-#define THIS_FILE	"ioq_perf"
-//#define TRACE_(expr)	PJ_LOG(3,expr)
-#define TRACE_(expr)
-
-
-static pj_bool_t thread_quit_flag;
-static pj_status_t last_error;
-static unsigned last_error_counter;
-
-/* Descriptor for each producer/consumer pair. */
-typedef struct test_item
-{
-    pj_sock_t            server_fd, 
-                         client_fd;
-    pj_ioqueue_t        *ioqueue;
-    pj_ioqueue_key_t    *server_key,
-                        *client_key;
-    pj_ioqueue_op_key_t  recv_op,
-                         send_op;
-    int                  has_pending_send;
-    pj_size_t            buffer_size;
-    char                *outgoing_buffer;
-    char                *incoming_buffer;
-    pj_size_t            bytes_sent, 
-                         bytes_recv;
-} test_item;
-
-/* Callback when data has been read.
- * Increment item->bytes_recv and ready to read the next data.
- */
-static void on_read_complete(pj_ioqueue_key_t *key, 
-                             pj_ioqueue_op_key_t *op_key,
-                             pj_ssize_t bytes_read)
-{
-    test_item *item = pj_ioqueue_get_user_data(key);
-    pj_status_t rc;
-    int data_is_available = 1;
-
-    //TRACE_((THIS_FILE, "     read complete, bytes_read=%d", bytes_read));
-
-    do {
-        if (thread_quit_flag)
-            return;
-
-        if (bytes_read < 0) {
-            pj_status_t rc = -bytes_read;
-            char errmsg[128];
-
-	    if (rc != last_error) {
-	        //last_error = rc;
-	        pj_strerror(rc, errmsg, sizeof(errmsg));
-	        PJ_LOG(3,(THIS_FILE, "...error: read error, bytes_read=%d (%s)", 
-		          bytes_read, errmsg));
-	        PJ_LOG(3,(THIS_FILE, 
-		          ".....additional info: total read=%u, total sent=%u",
-		          item->bytes_recv, item->bytes_sent));
-	    } else {
-	        last_error_counter++;
-	    }
-            bytes_read = 0;
-
-        } else if (bytes_read == 0) {
-            PJ_LOG(3,(THIS_FILE, "...socket has closed!"));
-        }
-
-        item->bytes_recv += bytes_read;
-    
-        /* To assure that the test quits, even if main thread
-         * doesn't have time to run.
-         */
-        if (item->bytes_recv > item->buffer_size * 10000) 
-	    thread_quit_flag = 1;
-
-        bytes_read = item->buffer_size;
-        rc = pj_ioqueue_recv( key, op_key,
-                              item->incoming_buffer, &bytes_read, 0 );
-
-        if (rc == PJ_SUCCESS) {
-            data_is_available = 1;
-        } else if (rc == PJ_EPENDING) {
-            data_is_available = 0;
-        } else {
-            data_is_available = 0;
-	    if (rc != last_error) {
-	        last_error = rc;
-	        app_perror("...error: read error(1)", rc);
-	    } else {
-	        last_error_counter++;
-	    }
-        }
-
-        if (!item->has_pending_send) {
-            pj_ssize_t sent = item->buffer_size;
-            rc = pj_ioqueue_send(item->client_key, &item->send_op,
-                                 item->outgoing_buffer, &sent, 0);
-            if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
-                app_perror("...error: write error", rc);
-            }
-
-            item->has_pending_send = (rc==PJ_EPENDING);
-        }
-
-    } while (data_is_available);
-}
-
-/* Callback when data has been written.
- * Increment item->bytes_sent and write the next data.
- */
-static void on_write_complete(pj_ioqueue_key_t *key, 
-                              pj_ioqueue_op_key_t *op_key,
-                              pj_ssize_t bytes_sent)
-{
-    test_item *item = pj_ioqueue_get_user_data(key);
-    
-    //TRACE_((THIS_FILE, "     write complete: sent = %d", bytes_sent));
-
-    if (thread_quit_flag)
-        return;
-
-    item->has_pending_send = 0;
-    item->bytes_sent += bytes_sent;
-
-    if (bytes_sent <= 0) {
-        PJ_LOG(3,(THIS_FILE, "...error: sending stopped. bytes_sent=%d", 
-                  bytes_sent));
-    } 
-    else {
-        pj_status_t rc;
-
-        bytes_sent = item->buffer_size;
-        rc = pj_ioqueue_send( item->client_key, op_key,
-                              item->outgoing_buffer, &bytes_sent, 0);
-        if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
-            app_perror("...error: write error", rc);
-        }
-
-        item->has_pending_send = (rc==PJ_EPENDING);
-    }
-}
-
-/* The worker thread. */
-static int worker_thread(void *arg)
-{
-    pj_ioqueue_t *ioqueue = arg;
-    const pj_time_val timeout = {0, 100};
-    int rc;
-
-    while (!thread_quit_flag) {
-        rc = pj_ioqueue_poll(ioqueue, &timeout);
-	//TRACE_((THIS_FILE, "     thread: poll returned rc=%d", rc));
-        if (rc < 0) {
-            app_perror("...error in pj_ioqueue_poll()", pj_get_netos_error());
-            return -1;
-        }
-    }
-    return 0;
-}
-
-/* Calculate the bandwidth for the specific test configuration.
- * The test is simple:
- *  - create sockpair_cnt number of producer-consumer socket pair.
- *  - create thread_cnt number of worker threads.
- *  - each producer will send buffer_size bytes data as fast and
- *    as soon as it can.
- *  - each consumer will read buffer_size bytes of data as fast 
- *    as it could.
- *  - measure the total bytes received by all consumers during a
- *    period of time.
- */
-static int perform_test(int sock_type, const char *type_name,
-                        unsigned thread_cnt, unsigned sockpair_cnt,
-                        pj_size_t buffer_size, 
-                        pj_size_t *p_bandwidth)
-{
-    enum { MSEC_DURATION = 5000 };
-    pj_pool_t *pool;
-    test_item *items;
-    pj_thread_t **thread;
-    pj_ioqueue_t *ioqueue;
-    pj_status_t rc;
-    pj_ioqueue_callback ioqueue_callback;
-    pj_uint32_t total_elapsed_usec, total_received;
-    pj_highprec_t bandwidth;
-    pj_timestamp start, stop;
-    unsigned i;
-
-    TRACE_((THIS_FILE, "    starting test.."));
-
-    ioqueue_callback.on_read_complete = &on_read_complete;
-    ioqueue_callback.on_write_complete = &on_write_complete;
-
-    thread_quit_flag = 0;
-
-    pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
-    if (!pool)
-        return -10;
-
-    items = pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item));
-    thread = pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*));
-
-    TRACE_((THIS_FILE, "     creating ioqueue.."));
-    rc = pj_ioqueue_create(pool, sockpair_cnt*2, &ioqueue);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error: unable to create ioqueue", rc);
-        return -15;
-    }
-
-    /* Initialize each producer-consumer pair. */
-    for (i=0; i<sockpair_cnt; ++i) {
-        pj_ssize_t bytes;
-
-        items[i].ioqueue = ioqueue;
-        items[i].buffer_size = buffer_size;
-        items[i].outgoing_buffer = pj_pool_alloc(pool, buffer_size);
-        items[i].incoming_buffer = pj_pool_alloc(pool, buffer_size);
-        items[i].bytes_recv = items[i].bytes_sent = 0;
-
-        /* randomize outgoing buffer. */
-        pj_create_random_string(items[i].outgoing_buffer, buffer_size);
-
-        /* Create socket pair. */
-	TRACE_((THIS_FILE, "      calling socketpair.."));
-        rc = app_socketpair(PJ_AF_INET, sock_type, 0, 
-                            &items[i].server_fd, &items[i].client_fd);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error: unable to create socket pair", rc);
-            return -20;
-        }
-
-        /* Register server socket to ioqueue. */
-	TRACE_((THIS_FILE, "      register(1).."));
-        rc = pj_ioqueue_register_sock(pool, ioqueue, 
-                                      items[i].server_fd,
-                                      &items[i], &ioqueue_callback,
-                                      &items[i].server_key);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error: registering server socket to ioqueue", rc);
-            return -60;
-        }
-
-        /* Register client socket to ioqueue. */
-	TRACE_((THIS_FILE, "      register(2).."));
-        rc = pj_ioqueue_register_sock(pool, ioqueue, 
-                                      items[i].client_fd,
-                                      &items[i],  &ioqueue_callback,
-                                      &items[i].client_key);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error: registering server socket to ioqueue", rc);
-            return -70;
-        }
-
-        /* Start reading. */
-	TRACE_((THIS_FILE, "      pj_ioqueue_recv.."));
-        bytes = items[i].buffer_size;
-        rc = pj_ioqueue_recv(items[i].server_key, &items[i].recv_op,
-                             items[i].incoming_buffer, &bytes,
-			     0);
-        if (rc != PJ_EPENDING) {
-            app_perror("...error: pj_ioqueue_recv", rc);
-            return -73;
-        }
-
-        /* Start writing. */
-	TRACE_((THIS_FILE, "      pj_ioqueue_write.."));
-        bytes = items[i].buffer_size;
-        rc = pj_ioqueue_send(items[i].client_key, &items[i].recv_op,
-                             items[i].outgoing_buffer, &bytes, 0);
-        if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
-            app_perror("...error: pj_ioqueue_write", rc);
-            return -76;
-        }
-
-        items[i].has_pending_send = (rc==PJ_EPENDING);
-    }
-
-    /* Create the threads. */
-    for (i=0; i<thread_cnt; ++i) {
-        rc = pj_thread_create( pool, NULL, 
-                               &worker_thread, 
-                               ioqueue, 
-                               PJ_THREAD_DEFAULT_STACK_SIZE, 
-                               PJ_THREAD_SUSPENDED, &thread[i] );
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error: unable to create thread", rc);
-            return -80;
-        }
-    }
-
-    /* Mark start time. */
-    rc = pj_get_timestamp(&start);
-    if (rc != PJ_SUCCESS)
-        return -90;
-
-    /* Start the thread. */
-    TRACE_((THIS_FILE, "     resuming all threads.."));
-    for (i=0; i<thread_cnt; ++i) {
-        rc = pj_thread_resume(thread[i]);
-        if (rc != 0)
-            return -100;
-    }
-
-    /* Wait for MSEC_DURATION seconds. 
-     * This should be as simple as pj_thread_sleep(MSEC_DURATION) actually,
-     * but unfortunately it doesn't work when system doesn't employ
-     * timeslicing for threads.
-     */
-    TRACE_((THIS_FILE, "     wait for few seconds.."));
-    do {
-	pj_thread_sleep(1);
-
-	/* Mark end time. */
-	rc = pj_get_timestamp(&stop);
-
-	if (thread_quit_flag) {
-	    TRACE_((THIS_FILE, "      transfer limit reached.."));
-	    break;
-	}
-
-	if (pj_elapsed_usec(&start,&stop)<MSEC_DURATION * 1000) {
-	    TRACE_((THIS_FILE, "      time limit reached.."));
-	    break;
-	}
-
-    } while (1);
-
-    /* Terminate all threads. */
-    TRACE_((THIS_FILE, "     terminating all threads.."));
-    thread_quit_flag = 1;
-
-    for (i=0; i<thread_cnt; ++i) {
-	TRACE_((THIS_FILE, "      join thread %d..", i));
-        pj_thread_join(thread[i]);
-        pj_thread_destroy(thread[i]);
-    }
-
-    /* Close all sockets. */
-    TRACE_((THIS_FILE, "     closing all sockets.."));
-    for (i=0; i<sockpair_cnt; ++i) {
-        pj_ioqueue_unregister(items[i].server_key);
-        pj_ioqueue_unregister(items[i].client_key);
-        pj_sock_close(items[i].server_fd);
-        pj_sock_close(items[i].client_fd);
-    }
-
-    /* Destroy ioqueue. */
-    TRACE_((THIS_FILE, "     destroying ioqueue.."));
-    pj_ioqueue_destroy(ioqueue);
-
-    /* Calculate actual time in usec. */
-    total_elapsed_usec = pj_elapsed_usec(&start, &stop);
-
-    /* Calculate total bytes received. */
-    total_received = 0;
-    for (i=0; i<sockpair_cnt; ++i) {
-        total_received = items[i].bytes_recv;
-    }
-
-    /* bandwidth = total_received*1000/total_elapsed_usec */
-    bandwidth = total_received;
-    pj_highprec_mul(bandwidth, 1000);
-    pj_highprec_div(bandwidth, total_elapsed_usec);
-    
-    *p_bandwidth = (pj_uint32_t)bandwidth;
-
-    PJ_LOG(3,(THIS_FILE, "   %.4s    %d         %d        %3d us  %8d KB/s",
-              type_name, thread_cnt, sockpair_cnt,
-              -1 /*total_elapsed_usec/sockpair_cnt*/,
-              *p_bandwidth));
-
-    /* Done. */
-    pj_pool_release(pool);
-
-    TRACE_((THIS_FILE, "    done.."));
-    return 0;
-}
-
-/*
- * main test entry.
- */
-int ioqueue_perf_test(void)
-{
-    enum { BUF_SIZE = 512 };
-    int i, rc;
-    struct {
-        int         type;
-        const char *type_name;
-        int         thread_cnt;
-        int         sockpair_cnt;
-    } test_param[] = 
-    {
-        { PJ_SOCK_DGRAM, "udp", 1, 1},
-        { PJ_SOCK_DGRAM, "udp", 1, 2},
-        { PJ_SOCK_DGRAM, "udp", 1, 4},
-        { PJ_SOCK_DGRAM, "udp", 1, 8},
-        { PJ_SOCK_DGRAM, "udp", 2, 1},
-        { PJ_SOCK_DGRAM, "udp", 2, 2},
-        { PJ_SOCK_DGRAM, "udp", 2, 4},
-        { PJ_SOCK_DGRAM, "udp", 2, 8},
-        { PJ_SOCK_DGRAM, "udp", 4, 1},
-        { PJ_SOCK_DGRAM, "udp", 4, 2},
-        { PJ_SOCK_DGRAM, "udp", 4, 4},
-        { PJ_SOCK_DGRAM, "udp", 4, 8},
-        { PJ_SOCK_STREAM, "tcp", 1, 1},
-        { PJ_SOCK_STREAM, "tcp", 1, 2},
-        { PJ_SOCK_STREAM, "tcp", 1, 4},
-        { PJ_SOCK_STREAM, "tcp", 1, 8},
-        { PJ_SOCK_STREAM, "tcp", 2, 1},
-        { PJ_SOCK_STREAM, "tcp", 2, 2},
-        { PJ_SOCK_STREAM, "tcp", 2, 4},
-        { PJ_SOCK_STREAM, "tcp", 2, 8},
-        { PJ_SOCK_STREAM, "tcp", 4, 1},
-        { PJ_SOCK_STREAM, "tcp", 4, 2},
-        { PJ_SOCK_STREAM, "tcp", 4, 4},
-        { PJ_SOCK_STREAM, "tcp", 4, 8},
-    };
-    pj_size_t best_bandwidth;
-    int best_index = 0;
-
-    PJ_LOG(3,(THIS_FILE, "   Benchmarking %s ioqueue:", pj_ioqueue_name()));
-    PJ_LOG(3,(THIS_FILE, "   ==============================================="));
-    PJ_LOG(3,(THIS_FILE, "   Type  Threads  Skt.Pairs  Avg.Time    Bandwidth"));
-    PJ_LOG(3,(THIS_FILE, "   ==============================================="));
-
-    best_bandwidth = 0;
-    for (i=0; i<sizeof(test_param)/sizeof(test_param[0]); ++i) {
-        pj_size_t bandwidth;
-
-        rc = perform_test(test_param[i].type, 
-                          test_param[i].type_name,
-                          test_param[i].thread_cnt, 
-                          test_param[i].sockpair_cnt, 
-                          BUF_SIZE, 
-                          &bandwidth);
-        if (rc != 0)
-            return rc;
-
-        if (bandwidth > best_bandwidth)
-            best_bandwidth = bandwidth, best_index = i;
-
-        /* Give it a rest before next test. */
-        pj_thread_sleep(500);
-    }
-
-    PJ_LOG(3,(THIS_FILE, 
-              "   Best: Type=%s Threads=%d, Skt.Pairs=%d, Bandwidth=%u KB/s",
-              test_param[best_index].type_name,
-              test_param[best_index].thread_cnt,
-              test_param[best_index].sockpair_cnt,
-              best_bandwidth));
-    PJ_LOG(3,(THIS_FILE, "   (Note: packet size=%d, total errors=%u)", 
-			 BUF_SIZE, last_error_counter));
-    return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_uiq_perf_test;
-#endif  /* INCLUDE_IOQUEUE_PERF_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pjlib.h>

+#include <pj/compat/high_precision.h>

+

+/**

+ * \page page_pjlib_ioqueue_perf_test Test: I/O Queue Performance

+ *

+ * Test the performance of the I/O queue, using typical producer

+ * consumer test. The test should examine the effect of using multiple

+ * threads on the performance.

+ *

+ * This file is <b>pjlib-test/ioq_perf.c</b>

+ *

+ * \include pjlib-test/ioq_perf.c

+ */

+

+#if INCLUDE_IOQUEUE_PERF_TEST

+

+#ifdef _MSC_VER

+#   pragma warning ( disable: 4204)     // non-constant aggregate initializer

+#endif

+

+#define THIS_FILE	"ioq_perf"

+//#define TRACE_(expr)	PJ_LOG(3,expr)

+#define TRACE_(expr)

+

+

+static pj_bool_t thread_quit_flag;

+static pj_status_t last_error;

+static unsigned last_error_counter;

+

+/* Descriptor for each producer/consumer pair. */

+typedef struct test_item

+{

+    pj_sock_t            server_fd, 

+                         client_fd;

+    pj_ioqueue_t        *ioqueue;

+    pj_ioqueue_key_t    *server_key,

+                        *client_key;

+    pj_ioqueue_op_key_t  recv_op,

+                         send_op;

+    int                  has_pending_send;

+    pj_size_t            buffer_size;

+    char                *outgoing_buffer;

+    char                *incoming_buffer;

+    pj_size_t            bytes_sent, 

+                         bytes_recv;

+} test_item;

+

+/* Callback when data has been read.

+ * Increment item->bytes_recv and ready to read the next data.

+ */

+static void on_read_complete(pj_ioqueue_key_t *key, 

+                             pj_ioqueue_op_key_t *op_key,

+                             pj_ssize_t bytes_read)

+{

+    test_item *item = pj_ioqueue_get_user_data(key);

+    pj_status_t rc;

+    int data_is_available = 1;

+

+    //TRACE_((THIS_FILE, "     read complete, bytes_read=%d", bytes_read));

+

+    do {

+        if (thread_quit_flag)

+            return;

+

+        if (bytes_read < 0) {

+            pj_status_t rc = -bytes_read;

+            char errmsg[128];

+

+	    if (rc != last_error) {

+	        //last_error = rc;

+	        pj_strerror(rc, errmsg, sizeof(errmsg));

+	        PJ_LOG(3,(THIS_FILE, "...error: read error, bytes_read=%d (%s)", 

+		          bytes_read, errmsg));

+	        PJ_LOG(3,(THIS_FILE, 

+		          ".....additional info: total read=%u, total sent=%u",

+		          item->bytes_recv, item->bytes_sent));

+	    } else {

+	        last_error_counter++;

+	    }

+            bytes_read = 0;

+

+        } else if (bytes_read == 0) {

+            PJ_LOG(3,(THIS_FILE, "...socket has closed!"));

+        }

+

+        item->bytes_recv += bytes_read;

+    

+        /* To assure that the test quits, even if main thread

+         * doesn't have time to run.

+         */

+        if (item->bytes_recv > item->buffer_size * 10000) 

+	    thread_quit_flag = 1;

+

+        bytes_read = item->buffer_size;

+        rc = pj_ioqueue_recv( key, op_key,

+                              item->incoming_buffer, &bytes_read, 0 );

+

+        if (rc == PJ_SUCCESS) {

+            data_is_available = 1;

+        } else if (rc == PJ_EPENDING) {

+            data_is_available = 0;

+        } else {

+            data_is_available = 0;

+	    if (rc != last_error) {

+	        last_error = rc;

+	        app_perror("...error: read error(1)", rc);

+	    } else {

+	        last_error_counter++;

+	    }

+        }

+

+        if (!item->has_pending_send) {

+            pj_ssize_t sent = item->buffer_size;

+            rc = pj_ioqueue_send(item->client_key, &item->send_op,

+                                 item->outgoing_buffer, &sent, 0);

+            if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {

+                app_perror("...error: write error", rc);

+            }

+

+            item->has_pending_send = (rc==PJ_EPENDING);

+        }

+

+    } while (data_is_available);

+}

+

+/* Callback when data has been written.

+ * Increment item->bytes_sent and write the next data.

+ */

+static void on_write_complete(pj_ioqueue_key_t *key, 

+                              pj_ioqueue_op_key_t *op_key,

+                              pj_ssize_t bytes_sent)

+{

+    test_item *item = pj_ioqueue_get_user_data(key);

+    

+    //TRACE_((THIS_FILE, "     write complete: sent = %d", bytes_sent));

+

+    if (thread_quit_flag)

+        return;

+

+    item->has_pending_send = 0;

+    item->bytes_sent += bytes_sent;

+

+    if (bytes_sent <= 0) {

+        PJ_LOG(3,(THIS_FILE, "...error: sending stopped. bytes_sent=%d", 

+                  bytes_sent));

+    } 

+    else {

+        pj_status_t rc;

+

+        bytes_sent = item->buffer_size;

+        rc = pj_ioqueue_send( item->client_key, op_key,

+                              item->outgoing_buffer, &bytes_sent, 0);

+        if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {

+            app_perror("...error: write error", rc);

+        }

+

+        item->has_pending_send = (rc==PJ_EPENDING);

+    }

+}

+

+/* The worker thread. */

+static int worker_thread(void *arg)

+{

+    pj_ioqueue_t *ioqueue = arg;

+    const pj_time_val timeout = {0, 100};

+    int rc;

+

+    while (!thread_quit_flag) {

+        rc = pj_ioqueue_poll(ioqueue, &timeout);

+	//TRACE_((THIS_FILE, "     thread: poll returned rc=%d", rc));

+        if (rc < 0) {

+            app_perror("...error in pj_ioqueue_poll()", pj_get_netos_error());

+            return -1;

+        }

+    }

+    return 0;

+}

+

+/* Calculate the bandwidth for the specific test configuration.

+ * The test is simple:

+ *  - create sockpair_cnt number of producer-consumer socket pair.

+ *  - create thread_cnt number of worker threads.

+ *  - each producer will send buffer_size bytes data as fast and

+ *    as soon as it can.

+ *  - each consumer will read buffer_size bytes of data as fast 

+ *    as it could.

+ *  - measure the total bytes received by all consumers during a

+ *    period of time.

+ */

+static int perform_test(int sock_type, const char *type_name,

+                        unsigned thread_cnt, unsigned sockpair_cnt,

+                        pj_size_t buffer_size, 

+                        pj_size_t *p_bandwidth)

+{

+    enum { MSEC_DURATION = 5000 };

+    pj_pool_t *pool;

+    test_item *items;

+    pj_thread_t **thread;

+    pj_ioqueue_t *ioqueue;

+    pj_status_t rc;

+    pj_ioqueue_callback ioqueue_callback;

+    pj_uint32_t total_elapsed_usec, total_received;

+    pj_highprec_t bandwidth;

+    pj_timestamp start, stop;

+    unsigned i;

+

+    TRACE_((THIS_FILE, "    starting test.."));

+

+    ioqueue_callback.on_read_complete = &on_read_complete;

+    ioqueue_callback.on_write_complete = &on_write_complete;

+

+    thread_quit_flag = 0;

+

+    pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);

+    if (!pool)

+        return -10;

+

+    items = pj_pool_alloc(pool, sockpair_cnt*sizeof(test_item));

+    thread = pj_pool_alloc(pool, thread_cnt*sizeof(pj_thread_t*));

+

+    TRACE_((THIS_FILE, "     creating ioqueue.."));

+    rc = pj_ioqueue_create(pool, sockpair_cnt*2, &ioqueue);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error: unable to create ioqueue", rc);

+        return -15;

+    }

+

+    /* Initialize each producer-consumer pair. */

+    for (i=0; i<sockpair_cnt; ++i) {

+        pj_ssize_t bytes;

+

+        items[i].ioqueue = ioqueue;

+        items[i].buffer_size = buffer_size;

+        items[i].outgoing_buffer = pj_pool_alloc(pool, buffer_size);

+        items[i].incoming_buffer = pj_pool_alloc(pool, buffer_size);

+        items[i].bytes_recv = items[i].bytes_sent = 0;

+

+        /* randomize outgoing buffer. */

+        pj_create_random_string(items[i].outgoing_buffer, buffer_size);

+

+        /* Create socket pair. */

+	TRACE_((THIS_FILE, "      calling socketpair.."));

+        rc = app_socketpair(PJ_AF_INET, sock_type, 0, 

+                            &items[i].server_fd, &items[i].client_fd);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error: unable to create socket pair", rc);

+            return -20;

+        }

+

+        /* Register server socket to ioqueue. */

+	TRACE_((THIS_FILE, "      register(1).."));

+        rc = pj_ioqueue_register_sock(pool, ioqueue, 

+                                      items[i].server_fd,

+                                      &items[i], &ioqueue_callback,

+                                      &items[i].server_key);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error: registering server socket to ioqueue", rc);

+            return -60;

+        }

+

+        /* Register client socket to ioqueue. */

+	TRACE_((THIS_FILE, "      register(2).."));

+        rc = pj_ioqueue_register_sock(pool, ioqueue, 

+                                      items[i].client_fd,

+                                      &items[i],  &ioqueue_callback,

+                                      &items[i].client_key);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error: registering server socket to ioqueue", rc);

+            return -70;

+        }

+

+        /* Start reading. */

+	TRACE_((THIS_FILE, "      pj_ioqueue_recv.."));

+        bytes = items[i].buffer_size;

+        rc = pj_ioqueue_recv(items[i].server_key, &items[i].recv_op,

+                             items[i].incoming_buffer, &bytes,

+			     0);

+        if (rc != PJ_EPENDING) {

+            app_perror("...error: pj_ioqueue_recv", rc);

+            return -73;

+        }

+

+        /* Start writing. */

+	TRACE_((THIS_FILE, "      pj_ioqueue_write.."));

+        bytes = items[i].buffer_size;

+        rc = pj_ioqueue_send(items[i].client_key, &items[i].recv_op,

+                             items[i].outgoing_buffer, &bytes, 0);

+        if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {

+            app_perror("...error: pj_ioqueue_write", rc);

+            return -76;

+        }

+

+        items[i].has_pending_send = (rc==PJ_EPENDING);

+    }

+

+    /* Create the threads. */

+    for (i=0; i<thread_cnt; ++i) {

+        rc = pj_thread_create( pool, NULL, 

+                               &worker_thread, 

+                               ioqueue, 

+                               PJ_THREAD_DEFAULT_STACK_SIZE, 

+                               PJ_THREAD_SUSPENDED, &thread[i] );

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error: unable to create thread", rc);

+            return -80;

+        }

+    }

+

+    /* Mark start time. */

+    rc = pj_get_timestamp(&start);

+    if (rc != PJ_SUCCESS)

+        return -90;

+

+    /* Start the thread. */

+    TRACE_((THIS_FILE, "     resuming all threads.."));

+    for (i=0; i<thread_cnt; ++i) {

+        rc = pj_thread_resume(thread[i]);

+        if (rc != 0)

+            return -100;

+    }

+

+    /* Wait for MSEC_DURATION seconds. 

+     * This should be as simple as pj_thread_sleep(MSEC_DURATION) actually,

+     * but unfortunately it doesn't work when system doesn't employ

+     * timeslicing for threads.

+     */

+    TRACE_((THIS_FILE, "     wait for few seconds.."));

+    do {

+	pj_thread_sleep(1);

+

+	/* Mark end time. */

+	rc = pj_get_timestamp(&stop);

+

+	if (thread_quit_flag) {

+	    TRACE_((THIS_FILE, "      transfer limit reached.."));

+	    break;

+	}

+

+	if (pj_elapsed_usec(&start,&stop)<MSEC_DURATION * 1000) {

+	    TRACE_((THIS_FILE, "      time limit reached.."));

+	    break;

+	}

+

+    } while (1);

+

+    /* Terminate all threads. */

+    TRACE_((THIS_FILE, "     terminating all threads.."));

+    thread_quit_flag = 1;

+

+    for (i=0; i<thread_cnt; ++i) {

+	TRACE_((THIS_FILE, "      join thread %d..", i));

+        pj_thread_join(thread[i]);

+        pj_thread_destroy(thread[i]);

+    }

+

+    /* Close all sockets. */

+    TRACE_((THIS_FILE, "     closing all sockets.."));

+    for (i=0; i<sockpair_cnt; ++i) {

+        pj_ioqueue_unregister(items[i].server_key);

+        pj_ioqueue_unregister(items[i].client_key);

+        pj_sock_close(items[i].server_fd);

+        pj_sock_close(items[i].client_fd);

+    }

+

+    /* Destroy ioqueue. */

+    TRACE_((THIS_FILE, "     destroying ioqueue.."));

+    pj_ioqueue_destroy(ioqueue);

+

+    /* Calculate actual time in usec. */

+    total_elapsed_usec = pj_elapsed_usec(&start, &stop);

+

+    /* Calculate total bytes received. */

+    total_received = 0;

+    for (i=0; i<sockpair_cnt; ++i) {

+        total_received = items[i].bytes_recv;

+    }

+

+    /* bandwidth = total_received*1000/total_elapsed_usec */

+    bandwidth = total_received;

+    pj_highprec_mul(bandwidth, 1000);

+    pj_highprec_div(bandwidth, total_elapsed_usec);

+    

+    *p_bandwidth = (pj_uint32_t)bandwidth;

+

+    PJ_LOG(3,(THIS_FILE, "   %.4s    %d         %d        %3d us  %8d KB/s",

+              type_name, thread_cnt, sockpair_cnt,

+              -1 /*total_elapsed_usec/sockpair_cnt*/,

+              *p_bandwidth));

+

+    /* Done. */

+    pj_pool_release(pool);

+

+    TRACE_((THIS_FILE, "    done.."));

+    return 0;

+}

+

+/*

+ * main test entry.

+ */

+int ioqueue_perf_test(void)

+{

+    enum { BUF_SIZE = 512 };

+    int i, rc;

+    struct {

+        int         type;

+        const char *type_name;

+        int         thread_cnt;

+        int         sockpair_cnt;

+    } test_param[] = 

+    {

+        { PJ_SOCK_DGRAM, "udp", 1, 1},

+        { PJ_SOCK_DGRAM, "udp", 1, 2},

+        { PJ_SOCK_DGRAM, "udp", 1, 4},

+        { PJ_SOCK_DGRAM, "udp", 1, 8},

+        { PJ_SOCK_DGRAM, "udp", 2, 1},

+        { PJ_SOCK_DGRAM, "udp", 2, 2},

+        { PJ_SOCK_DGRAM, "udp", 2, 4},

+        { PJ_SOCK_DGRAM, "udp", 2, 8},

+        { PJ_SOCK_DGRAM, "udp", 4, 1},

+        { PJ_SOCK_DGRAM, "udp", 4, 2},

+        { PJ_SOCK_DGRAM, "udp", 4, 4},

+        { PJ_SOCK_DGRAM, "udp", 4, 8},

+        { PJ_SOCK_STREAM, "tcp", 1, 1},

+        { PJ_SOCK_STREAM, "tcp", 1, 2},

+        { PJ_SOCK_STREAM, "tcp", 1, 4},

+        { PJ_SOCK_STREAM, "tcp", 1, 8},

+        { PJ_SOCK_STREAM, "tcp", 2, 1},

+        { PJ_SOCK_STREAM, "tcp", 2, 2},

+        { PJ_SOCK_STREAM, "tcp", 2, 4},

+        { PJ_SOCK_STREAM, "tcp", 2, 8},

+        { PJ_SOCK_STREAM, "tcp", 4, 1},

+        { PJ_SOCK_STREAM, "tcp", 4, 2},

+        { PJ_SOCK_STREAM, "tcp", 4, 4},

+        { PJ_SOCK_STREAM, "tcp", 4, 8},

+    };

+    pj_size_t best_bandwidth;

+    int best_index = 0;

+

+    PJ_LOG(3,(THIS_FILE, "   Benchmarking %s ioqueue:", pj_ioqueue_name()));

+    PJ_LOG(3,(THIS_FILE, "   ==============================================="));

+    PJ_LOG(3,(THIS_FILE, "   Type  Threads  Skt.Pairs  Avg.Time    Bandwidth"));

+    PJ_LOG(3,(THIS_FILE, "   ==============================================="));

+

+    best_bandwidth = 0;

+    for (i=0; i<sizeof(test_param)/sizeof(test_param[0]); ++i) {

+        pj_size_t bandwidth;

+

+        rc = perform_test(test_param[i].type, 

+                          test_param[i].type_name,

+                          test_param[i].thread_cnt, 

+                          test_param[i].sockpair_cnt, 

+                          BUF_SIZE, 

+                          &bandwidth);

+        if (rc != 0)

+            return rc;

+

+        if (bandwidth > best_bandwidth)

+            best_bandwidth = bandwidth, best_index = i;

+

+        /* Give it a rest before next test. */

+        pj_thread_sleep(500);

+    }

+

+    PJ_LOG(3,(THIS_FILE, 

+              "   Best: Type=%s Threads=%d, Skt.Pairs=%d, Bandwidth=%u KB/s",

+              test_param[best_index].type_name,

+              test_param[best_index].thread_cnt,

+              test_param[best_index].sockpair_cnt,

+              best_bandwidth));

+    PJ_LOG(3,(THIS_FILE, "   (Note: packet size=%d, total errors=%u)", 

+			 BUF_SIZE, last_error_counter));

+    return 0;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_uiq_perf_test;

+#endif  /* INCLUDE_IOQUEUE_PERF_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/ioq_tcp.c b/pjlib/src/pjlib-test/ioq_tcp.c
index 2282794..30d594b 100644
--- a/pjlib/src/pjlib-test/ioq_tcp.c
+++ b/pjlib/src/pjlib-test/ioq_tcp.c
@@ -1,524 +1,545 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_ioqueue_tcp_test Test: I/O Queue (TCP)
- *
- * This file provides implementation to test the
- * functionality of the I/O queue when TCP socket is used.
- *
- *
- * This file is <b>pjlib-test/ioq_tcp.c</b>
- *
- * \include pjlib-test/ioq_tcp.c
- */
-
-
-#if INCLUDE_TCP_IOQUEUE_TEST
-
-#include <pjlib.h>
-
-#if PJ_HAS_TCP
-
-#define THIS_FILE	    "test_tcp"
-#define PORT		    50000
-#define NON_EXISTANT_PORT   50123
-#define LOOP		    100
-#define BUF_MIN_SIZE	    32
-#define BUF_MAX_SIZE	    2048
-#define SOCK_INACTIVE_MIN   (4-2)
-#define SOCK_INACTIVE_MAX   (PJ_IOQUEUE_MAX_HANDLES - 2)
-#define POOL_SIZE	    (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
-
-static pj_ssize_t	     callback_read_size,
-                             callback_write_size,
-                             callback_accept_status,
-                             callback_connect_status;
-static pj_ioqueue_key_t     *callback_read_key,
-                            *callback_write_key,
-                            *callback_accept_key,
-                            *callback_connect_key;
-static pj_ioqueue_op_key_t  *callback_read_op,
-                            *callback_write_op,
-                            *callback_accept_op;
-
-static void on_ioqueue_read(pj_ioqueue_key_t *key, 
-                            pj_ioqueue_op_key_t *op_key,
-                            pj_ssize_t bytes_read)
-{
-    callback_read_key = key;
-    callback_read_op = op_key;
-    callback_read_size = bytes_read;
-}
-
-static void on_ioqueue_write(pj_ioqueue_key_t *key, 
-                             pj_ioqueue_op_key_t *op_key,
-                             pj_ssize_t bytes_written)
-{
-    callback_write_key = key;
-    callback_write_op = op_key;
-    callback_write_size = bytes_written;
-}
-
-static void on_ioqueue_accept(pj_ioqueue_key_t *key, 
-                              pj_ioqueue_op_key_t *op_key,
-                              pj_sock_t sock, 
-                              int status)
-{
-    PJ_UNUSED_ARG(sock);
-
-    callback_accept_key = key;
-    callback_accept_op = op_key;
-    callback_accept_status = status;
-}
-
-static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
-{
-    callback_connect_key = key;
-    callback_connect_status = status;
-}
-
-static pj_ioqueue_callback test_cb = 
-{
-    &on_ioqueue_read,
-    &on_ioqueue_write,
-    &on_ioqueue_accept,
-    &on_ioqueue_connect,
-};
-
-static int send_recv_test(pj_ioqueue_t *ioque,
-			  pj_ioqueue_key_t *skey,
-			  pj_ioqueue_key_t *ckey,
-			  void *send_buf,
-			  void *recv_buf,
-			  pj_ssize_t bufsize,
-			  pj_timestamp *t_elapsed)
-{
-    pj_status_t status;
-    pj_ssize_t bytes;
-    pj_time_val timeout;
-    pj_timestamp t1, t2;
-    int pending_op = 0;
-    pj_ioqueue_op_key_t read_op, write_op;
-
-    // Start reading on the server side.
-    bytes = bufsize;
-    status = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
-    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
-        app_perror("...pj_ioqueue_recv error", status);
-	return -100;
-    }
-    
-    if (status == PJ_EPENDING)
-        ++pending_op;
-    else {
-        /* Does not expect to return error or immediate data. */
-        return -115;
-    }
-
-    // Randomize send buffer.
-    pj_create_random_string((char*)send_buf, bufsize);
-
-    // Starts send on the client side.
-    bytes = bufsize;
-    status = pj_ioqueue_send(ckey, &write_op, send_buf, &bytes, 0);
-    if (status != PJ_SUCCESS && bytes != PJ_EPENDING) {
-	return -120;
-    }
-    if (status == PJ_EPENDING) {
-	++pending_op;
-    }
-
-    // Begin time.
-    pj_get_timestamp(&t1);
-
-    // Reset indicators
-    callback_read_size = callback_write_size = 0;
-    callback_read_key = callback_write_key = NULL;
-    callback_read_op = callback_write_op = NULL;
-
-    // Poll the queue until we've got completion event in the server side.
-    status = 0;
-    while (pending_op > 0) {
-        timeout.sec = 1; timeout.msec = 0;
-	status = pj_ioqueue_poll(ioque, &timeout);
-	if (status > 0) {
-            if (callback_read_size) {
-                if (callback_read_size != bufsize)
-                    return -160;
-                if (callback_read_key != skey)
-                    return -161;
-                if (callback_read_op != &read_op)
-                    return -162;
-            }
-            if (callback_write_size) {
-                if (callback_write_key != ckey)
-                    return -163;
-                if (callback_write_op != &write_op)
-                    return -164;
-            }
-	    pending_op -= status;
-	}
-        if (status == 0) {
-            PJ_LOG(3,("", "...error: timed out"));
-        }
-	if (status < 0) {
-	    return -170;
-	}
-    }
-
-    // Pending op is zero.
-    // Subsequent poll should yield zero too.
-    timeout.sec = timeout.msec = 0;
-    status = pj_ioqueue_poll(ioque, &timeout);
-    if (status != 0)
-        return -173;
-
-    // End time.
-    pj_get_timestamp(&t2);
-    t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo);
-
-    // Compare recv buffer with send buffer.
-    if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {
-	return -180;
-    }
-
-    // Success
-    return 0;
-}
-
-
-/*
- * Compliance test for success scenario.
- */
-static int compliance_test_0(void)
-{
-    pj_sock_t ssock=-1, csock0=-1, csock1=-1;
-    pj_sockaddr_in addr, client_addr, rmt_addr;
-    int client_addr_len;
-    pj_pool_t *pool = NULL;
-    char *send_buf, *recv_buf;
-    pj_ioqueue_t *ioque = NULL;
-    pj_ioqueue_key_t *skey, *ckey0, *ckey1;
-    pj_ioqueue_op_key_t accept_op;
-    int bufsize = BUF_MIN_SIZE;
-    pj_ssize_t status = -1;
-    int pending_op = 0;
-    pj_timestamp t_elapsed;
-    pj_str_t s;
-    pj_status_t rc;
-
-    // Create pool.
-    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
-
-    // Allocate buffers for send and receive.
-    send_buf = (char*)pj_pool_alloc(pool, bufsize);
-    recv_buf = (char*)pj_pool_alloc(pool, bufsize);
-
-    // Create server socket and client socket for connecting
-    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ssock);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error creating socket", rc);
-        status=-1; goto on_error;
-    }
-
-    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error creating socket", rc);
-	status=-1; goto on_error;
-    }
-
-    // Bind server socket.
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = PJ_AF_INET;
-    addr.sin_port = pj_htons(PORT);
-    if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
-        app_perror("...bind error", rc);
-	status=-10; goto on_error;
-    }
-
-    // Create I/O Queue.
-    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...ERROR in pj_ioqueue_create()", rc);
-	status=-20; goto on_error;
-    }
-
-    // Register server socket and client socket.
-    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey);
-    if (rc == PJ_SUCCESS)
-        rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb, 
-                                      &ckey1);
-    else
-        ckey1 = NULL;
-    if (rc != PJ_SUCCESS) {
-        app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
-	status=-23; goto on_error;
-    }
-
-    // Server socket listen().
-    if (pj_sock_listen(ssock, 5)) {
-        app_perror("...ERROR in pj_sock_listen()", rc);
-	status=-25; goto on_error;
-    }
-
-    // Server socket accept()
-    client_addr_len = sizeof(pj_sockaddr_in);
-    status = pj_ioqueue_accept(skey, &accept_op, &csock0, 
-                               &client_addr, &rmt_addr, &client_addr_len);
-    if (status != PJ_EPENDING) {
-        app_perror("...ERROR in pj_ioqueue_accept()", rc);
-	status=-30; goto on_error;
-    }
-    if (status==PJ_EPENDING) {
-	++pending_op;
-    }
-
-    // Initialize remote address.
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = PJ_AF_INET;
-    addr.sin_port = pj_htons(PORT);
-    addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-
-    // Client socket connect()
-    status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
-    if (status!=PJ_SUCCESS && status != PJ_EPENDING) {
-        app_perror("...ERROR in pj_ioqueue_connect()", rc);
-	status=-40; goto on_error;
-    }
-    if (status==PJ_EPENDING) {
-	++pending_op;
-    }
-
-    // Poll until connected
-    callback_read_size = callback_write_size = 0;
-    callback_accept_status = callback_connect_status = -2;
-
-    callback_read_key = callback_write_key = 
-        callback_accept_key = callback_connect_key = NULL;
-    callback_accept_op = callback_read_op = callback_write_op = NULL;
-
-    while (pending_op) {
-	pj_time_val timeout = {1, 0};
-
-	status=pj_ioqueue_poll(ioque, &timeout);
-	if (status > 0) {
-            if (callback_accept_status != -2) {
-                if (callback_accept_status != 0) {
-                    status=-41; goto on_error;
-                }
-                if (callback_accept_key != skey) {
-                    status=-42; goto on_error;
-                }
-                if (callback_accept_op != &accept_op) {
-                    status=-43; goto on_error;
-                }
-                callback_accept_status = -2;
-            }
-
-            if (callback_connect_status != -2) {
-                if (callback_connect_status != 0) {
-                    status=-50; goto on_error;
-                }
-                if (callback_connect_key != ckey1) {
-                    status=-51; goto on_error;
-                }
-                callback_connect_status = -2;
-            }
-
-	    pending_op -= status;
-
-	    if (pending_op == 0) {
-		status = 0;
-	    }
-	}
-    }
-
-    // There's no pending operation.
-    // When we poll the ioqueue, there must not be events.
-    if (pending_op == 0) {
-        pj_time_val timeout = {1, 0};
-        status = pj_ioqueue_poll(ioque, &timeout);
-        if (status != 0) {
-            status=-60; goto on_error;
-        }
-    }
-
-    // Check accepted socket.
-    if (csock0 == PJ_INVALID_SOCKET) {
-	status = -69;
-        app_perror("...accept() error", pj_get_os_error());
-	goto on_error;
-    }
-
-    // Register newly accepted socket.
-    rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL, 
-                                  &test_cb, &ckey0);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...ERROR in pj_ioqueue_register_sock", rc);
-	status = -70;
-	goto on_error;
-    }
-
-    // Test send and receive.
-    t_elapsed.u32.lo = 0;
-    status = send_recv_test(ioque, ckey0, ckey1, send_buf, 
-                            recv_buf, bufsize, &t_elapsed);
-    if (status != 0) {
-	goto on_error;
-    }
-
-    // Success
-    status = 0;
-
-on_error:
-    if (ssock != PJ_INVALID_SOCKET)
-	pj_sock_close(ssock);
-    if (csock1 != PJ_INVALID_SOCKET)
-	pj_sock_close(csock1);
-    if (csock0 != PJ_INVALID_SOCKET)
-	pj_sock_close(csock0);
-    if (ioque != NULL)
-	pj_ioqueue_destroy(ioque);
-    pj_pool_release(pool);
-    return status;
-
-}
-
-/*
- * Compliance test for failed scenario.
- * In this case, the client connects to a non-existant service.
- */
-static int compliance_test_1(void)
-{
-    pj_sock_t csock1=-1;
-    pj_sockaddr_in addr;
-    pj_pool_t *pool = NULL;
-    pj_ioqueue_t *ioque = NULL;
-    pj_ioqueue_key_t *ckey1;
-    pj_ssize_t status = -1;
-    int pending_op = 0;
-    pj_str_t s;
-    pj_status_t rc;
-
-    // Create pool.
-    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
-
-    // Create I/O Queue.
-    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
-    if (!ioque) {
-	status=-20; goto on_error;
-    }
-
-    // Create client socket
-    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...ERROR in pj_sock_socket()", rc);
-	status=-1; goto on_error;
-    }
-
-    // Register client socket.
-    rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, 
-                                  &test_cb, &ckey1);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...ERROR in pj_ioqueue_register_sock()", rc);
-	status=-23; goto on_error;
-    }
-
-    // Initialize remote address.
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = PJ_AF_INET;
-    addr.sin_port = pj_htons(NON_EXISTANT_PORT);
-    addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-
-    // Client socket connect()
-    status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));
-    if (status==PJ_SUCCESS) {
-	// unexpectedly success!
-	status = -30;
-	goto on_error;
-    }
-    if (status != PJ_EPENDING) {
-	// success
-    } else {
-	++pending_op;
-    }
-
-    callback_connect_status = -2;
-    callback_connect_key = NULL;
-
-    // Poll until we've got result
-    while (pending_op) {
-	pj_time_val timeout = {1, 0};
-
-	status=pj_ioqueue_poll(ioque, &timeout);
-	if (status > 0) {
-            if (callback_connect_key==ckey1) {
-		if (callback_connect_status == 0) {
-		    // unexpectedly connected!
-		    status = -50;
-		    goto on_error;
-		}
-	    }
-
-	    pending_op -= status;
-	    if (pending_op == 0) {
-		status = 0;
-	    }
-	}
-    }
-
-    // There's no pending operation.
-    // When we poll the ioqueue, there must not be events.
-    if (pending_op == 0) {
-        pj_time_val timeout = {1, 0};
-        status = pj_ioqueue_poll(ioque, &timeout);
-        if (status != 0) {
-            status=-60; goto on_error;
-        }
-    }
-
-    // Success
-    status = 0;
-
-on_error:
-    if (csock1 != PJ_INVALID_SOCKET)
-	pj_sock_close(csock1);
-    if (ioque != NULL)
-	pj_ioqueue_destroy(ioque);
-    pj_pool_release(pool);
-    return status;
-}
-
-int tcp_ioqueue_test()
-{
-    int status;
-
-    PJ_LOG(3, (THIS_FILE, "..%s compliance test 0 (success scenario)",
-	       pj_ioqueue_name()));
-    if ((status=compliance_test_0()) != 0) {
-	PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
-	return status;
-    }
-    PJ_LOG(3, (THIS_FILE, "..%s compliance test 1 (failed scenario)",
-               pj_ioqueue_name()));
-    if ((status=compliance_test_1()) != 0) {
-	PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));
-	return status;
-    }
-
-    return 0;
-}
-
-#endif	/* PJ_HAS_TCP */
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_uiq_tcp;
-#endif	/* INCLUDE_TCP_IOQUEUE_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+/**

+ * \page page_pjlib_ioqueue_tcp_test Test: I/O Queue (TCP)

+ *

+ * This file provides implementation to test the

+ * functionality of the I/O queue when TCP socket is used.

+ *

+ *

+ * This file is <b>pjlib-test/ioq_tcp.c</b>

+ *

+ * \include pjlib-test/ioq_tcp.c

+ */

+

+

+#if INCLUDE_TCP_IOQUEUE_TEST

+

+#include <pjlib.h>

+

+#if PJ_HAS_TCP

+

+#define THIS_FILE	    "test_tcp"

+#define PORT		    50000

+#define NON_EXISTANT_PORT   50123

+#define LOOP		    100

+#define BUF_MIN_SIZE	    32

+#define BUF_MAX_SIZE	    2048

+#define SOCK_INACTIVE_MIN   (4-2)

+#define SOCK_INACTIVE_MAX   (PJ_IOQUEUE_MAX_HANDLES - 2)

+#define POOL_SIZE	    (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)

+

+static pj_ssize_t	     callback_read_size,

+                             callback_write_size,

+                             callback_accept_status,

+                             callback_connect_status;

+static pj_ioqueue_key_t     *callback_read_key,

+                            *callback_write_key,

+                            *callback_accept_key,

+                            *callback_connect_key;

+static pj_ioqueue_op_key_t  *callback_read_op,

+                            *callback_write_op,

+                            *callback_accept_op;

+

+static void on_ioqueue_read(pj_ioqueue_key_t *key, 

+                            pj_ioqueue_op_key_t *op_key,

+                            pj_ssize_t bytes_read)

+{

+    callback_read_key = key;

+    callback_read_op = op_key;

+    callback_read_size = bytes_read;

+}

+

+static void on_ioqueue_write(pj_ioqueue_key_t *key, 

+                             pj_ioqueue_op_key_t *op_key,

+                             pj_ssize_t bytes_written)

+{

+    callback_write_key = key;

+    callback_write_op = op_key;

+    callback_write_size = bytes_written;

+}

+

+static void on_ioqueue_accept(pj_ioqueue_key_t *key, 

+                              pj_ioqueue_op_key_t *op_key,

+                              pj_sock_t sock, 

+                              int status)

+{

+    PJ_UNUSED_ARG(sock);

+

+    callback_accept_key = key;

+    callback_accept_op = op_key;

+    callback_accept_status = status;

+}

+

+static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)

+{

+    callback_connect_key = key;

+    callback_connect_status = status;

+}

+

+static pj_ioqueue_callback test_cb = 

+{

+    &on_ioqueue_read,

+    &on_ioqueue_write,

+    &on_ioqueue_accept,

+    &on_ioqueue_connect,

+};

+

+static int send_recv_test(pj_ioqueue_t *ioque,

+			  pj_ioqueue_key_t *skey,

+			  pj_ioqueue_key_t *ckey,

+			  void *send_buf,

+			  void *recv_buf,

+			  pj_ssize_t bufsize,

+			  pj_timestamp *t_elapsed)

+{

+    pj_status_t status;

+    pj_ssize_t bytes;

+    pj_time_val timeout;

+    pj_timestamp t1, t2;

+    int pending_op = 0;

+    pj_ioqueue_op_key_t read_op, write_op;

+

+    // Start reading on the server side.

+    bytes = bufsize;

+    status = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);

+    if (status != PJ_SUCCESS && status != PJ_EPENDING) {

+        app_perror("...pj_ioqueue_recv error", status);

+	return -100;

+    }

+    

+    if (status == PJ_EPENDING)

+        ++pending_op;

+    else {

+        /* Does not expect to return error or immediate data. */

+        return -115;

+    }

+

+    // Randomize send buffer.

+    pj_create_random_string((char*)send_buf, bufsize);

+

+    // Starts send on the client side.

+    bytes = bufsize;

+    status = pj_ioqueue_send(ckey, &write_op, send_buf, &bytes, 0);

+    if (status != PJ_SUCCESS && bytes != PJ_EPENDING) {

+	return -120;

+    }

+    if (status == PJ_EPENDING) {

+	++pending_op;

+    }

+

+    // Begin time.

+    pj_get_timestamp(&t1);

+

+    // Reset indicators

+    callback_read_size = callback_write_size = 0;

+    callback_read_key = callback_write_key = NULL;

+    callback_read_op = callback_write_op = NULL;

+

+    // Poll the queue until we've got completion event in the server side.

+    status = 0;

+    while (pending_op > 0) {

+        timeout.sec = 1; timeout.msec = 0;

+	status = pj_ioqueue_poll(ioque, &timeout);

+	if (status > 0) {

+            if (callback_read_size) {

+                if (callback_read_size != bufsize)

+                    return -160;

+                if (callback_read_key != skey)

+                    return -161;

+                if (callback_read_op != &read_op)

+                    return -162;

+            }

+            if (callback_write_size) {

+                if (callback_write_key != ckey)

+                    return -163;

+                if (callback_write_op != &write_op)

+                    return -164;

+            }

+	    pending_op -= status;

+	}

+        if (status == 0) {

+            PJ_LOG(3,("", "...error: timed out"));

+        }

+	if (status < 0) {

+	    return -170;

+	}

+    }

+

+    // Pending op is zero.

+    // Subsequent poll should yield zero too.

+    timeout.sec = timeout.msec = 0;

+    status = pj_ioqueue_poll(ioque, &timeout);

+    if (status != 0)

+        return -173;

+

+    // End time.

+    pj_get_timestamp(&t2);

+    t_elapsed->u32.lo += (t2.u32.lo - t1.u32.lo);

+

+    // Compare recv buffer with send buffer.

+    if (pj_memcmp(send_buf, recv_buf, bufsize) != 0) {

+	return -180;

+    }

+

+    // Success

+    return 0;

+}

+

+

+/*

+ * Compliance test for success scenario.

+ */

+static int compliance_test_0(void)

+{

+    pj_sock_t ssock=-1, csock0=-1, csock1=-1;

+    pj_sockaddr_in addr, client_addr, rmt_addr;

+    int client_addr_len;

+    pj_pool_t *pool = NULL;

+    char *send_buf, *recv_buf;

+    pj_ioqueue_t *ioque = NULL;

+    pj_ioqueue_key_t *skey, *ckey0, *ckey1;

+    pj_ioqueue_op_key_t accept_op;

+    int bufsize = BUF_MIN_SIZE;

+    pj_ssize_t status = -1;

+    int pending_op = 0;

+    pj_timestamp t_elapsed;

+    pj_str_t s;

+    pj_status_t rc;

+

+    // Create pool.

+    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);

+

+    // Allocate buffers for send and receive.

+    send_buf = (char*)pj_pool_alloc(pool, bufsize);

+    recv_buf = (char*)pj_pool_alloc(pool, bufsize);

+

+    // Create server socket and client socket for connecting

+    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ssock);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error creating socket", rc);

+        status=-1; goto on_error;

+    }

+

+    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error creating socket", rc);

+	status=-1; goto on_error;

+    }

+

+    // Bind server socket.

+    memset(&addr, 0, sizeof(addr));

+    addr.sin_family = PJ_AF_INET;

+    addr.sin_port = pj_htons(PORT);

+    if (pj_sock_bind(ssock, &addr, sizeof(addr))) {

+        app_perror("...bind error", rc);

+	status=-10; goto on_error;

+    }

+

+    // Create I/O Queue.

+    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...ERROR in pj_ioqueue_create()", rc);

+	status=-20; goto on_error;

+    }

+

+    // Register server socket and client socket.

+    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, &test_cb, &skey);

+    if (rc == PJ_SUCCESS)

+        rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, &test_cb, 

+                                      &ckey1);

+    else

+        ckey1 = NULL;

+    if (rc != PJ_SUCCESS) {

+        app_perror("...ERROR in pj_ioqueue_register_sock()", rc);

+	status=-23; goto on_error;

+    }

+

+    // Server socket listen().

+    if (pj_sock_listen(ssock, 5)) {

+        app_perror("...ERROR in pj_sock_listen()", rc);

+	status=-25; goto on_error;

+    }

+

+    // Server socket accept()

+    client_addr_len = sizeof(pj_sockaddr_in);

+    status = pj_ioqueue_accept(skey, &accept_op, &csock0, 

+                               &client_addr, &rmt_addr, &client_addr_len);

+    if (status != PJ_EPENDING) {

+        app_perror("...ERROR in pj_ioqueue_accept()", rc);

+	status=-30; goto on_error;

+    }

+    if (status==PJ_EPENDING) {

+	++pending_op;

+    }

+

+    // Initialize remote address.

+    memset(&addr, 0, sizeof(addr));

+    addr.sin_family = PJ_AF_INET;

+    addr.sin_port = pj_htons(PORT);

+    addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));

+

+    // Client socket connect()

+    status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));

+    if (status!=PJ_SUCCESS && status != PJ_EPENDING) {

+        app_perror("...ERROR in pj_ioqueue_connect()", rc);

+	status=-40; goto on_error;

+    }

+    if (status==PJ_EPENDING) {

+	++pending_op;

+    }

+

+    // Poll until connected

+    callback_read_size = callback_write_size = 0;

+    callback_accept_status = callback_connect_status = -2;

+

+    callback_read_key = callback_write_key = 

+        callback_accept_key = callback_connect_key = NULL;

+    callback_accept_op = callback_read_op = callback_write_op = NULL;

+

+    while (pending_op) {

+	pj_time_val timeout = {1, 0};

+

+	status=pj_ioqueue_poll(ioque, &timeout);

+	if (status > 0) {

+            if (callback_accept_status != -2) {

+                if (callback_accept_status != 0) {

+                    status=-41; goto on_error;

+                }

+                if (callback_accept_key != skey) {

+                    status=-42; goto on_error;

+                }

+                if (callback_accept_op != &accept_op) {

+                    status=-43; goto on_error;

+                }

+                callback_accept_status = -2;

+            }

+

+            if (callback_connect_status != -2) {

+                if (callback_connect_status != 0) {

+                    status=-50; goto on_error;

+                }

+                if (callback_connect_key != ckey1) {

+                    status=-51; goto on_error;

+                }

+                callback_connect_status = -2;

+            }

+

+	    pending_op -= status;

+

+	    if (pending_op == 0) {

+		status = 0;

+	    }

+	}

+    }

+

+    // There's no pending operation.

+    // When we poll the ioqueue, there must not be events.

+    if (pending_op == 0) {

+        pj_time_val timeout = {1, 0};

+        status = pj_ioqueue_poll(ioque, &timeout);

+        if (status != 0) {

+            status=-60; goto on_error;

+        }

+    }

+

+    // Check accepted socket.

+    if (csock0 == PJ_INVALID_SOCKET) {

+	status = -69;

+        app_perror("...accept() error", pj_get_os_error());

+	goto on_error;

+    }

+

+    // Register newly accepted socket.

+    rc = pj_ioqueue_register_sock(pool, ioque, csock0, NULL, 

+                                  &test_cb, &ckey0);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...ERROR in pj_ioqueue_register_sock", rc);

+	status = -70;

+	goto on_error;

+    }

+

+    // Test send and receive.

+    t_elapsed.u32.lo = 0;

+    status = send_recv_test(ioque, ckey0, ckey1, send_buf, 

+                            recv_buf, bufsize, &t_elapsed);

+    if (status != 0) {

+	goto on_error;

+    }

+

+    // Success

+    status = 0;

+

+on_error:

+    if (ssock != PJ_INVALID_SOCKET)

+	pj_sock_close(ssock);

+    if (csock1 != PJ_INVALID_SOCKET)

+	pj_sock_close(csock1);

+    if (csock0 != PJ_INVALID_SOCKET)

+	pj_sock_close(csock0);

+    if (ioque != NULL)

+	pj_ioqueue_destroy(ioque);

+    pj_pool_release(pool);

+    return status;

+

+}

+

+/*

+ * Compliance test for failed scenario.

+ * In this case, the client connects to a non-existant service.

+ */

+static int compliance_test_1(void)

+{

+    pj_sock_t csock1=-1;

+    pj_sockaddr_in addr;

+    pj_pool_t *pool = NULL;

+    pj_ioqueue_t *ioque = NULL;

+    pj_ioqueue_key_t *ckey1;

+    pj_ssize_t status = -1;

+    int pending_op = 0;

+    pj_str_t s;

+    pj_status_t rc;

+

+    // Create pool.

+    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);

+

+    // Create I/O Queue.

+    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);

+    if (!ioque) {

+	status=-20; goto on_error;

+    }

+

+    // Create client socket

+    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_STREAM, 0, &csock1);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...ERROR in pj_sock_socket()", rc);

+	status=-1; goto on_error;

+    }

+

+    // Register client socket.

+    rc = pj_ioqueue_register_sock(pool, ioque, csock1, NULL, 

+                                  &test_cb, &ckey1);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...ERROR in pj_ioqueue_register_sock()", rc);

+	status=-23; goto on_error;

+    }

+

+    // Initialize remote address.

+    memset(&addr, 0, sizeof(addr));

+    addr.sin_family = PJ_AF_INET;

+    addr.sin_port = pj_htons(NON_EXISTANT_PORT);

+    addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));

+

+    // Client socket connect()

+    status = pj_ioqueue_connect(ckey1, &addr, sizeof(addr));

+    if (status==PJ_SUCCESS) {

+	// unexpectedly success!

+	status = -30;

+	goto on_error;

+    }

+    if (status != PJ_EPENDING) {

+	// success

+    } else {

+	++pending_op;

+    }

+

+    callback_connect_status = -2;

+    callback_connect_key = NULL;

+

+    // Poll until we've got result

+    while (pending_op) {

+	pj_time_val timeout = {1, 0};

+

+	status=pj_ioqueue_poll(ioque, &timeout);

+	if (status > 0) {

+            if (callback_connect_key==ckey1) {

+		if (callback_connect_status == 0) {

+		    // unexpectedly connected!

+		    status = -50;

+		    goto on_error;

+		}

+	    }

+

+	    pending_op -= status;

+	    if (pending_op == 0) {

+		status = 0;

+	    }

+	}

+    }

+

+    // There's no pending operation.

+    // When we poll the ioqueue, there must not be events.

+    if (pending_op == 0) {

+        pj_time_val timeout = {1, 0};

+        status = pj_ioqueue_poll(ioque, &timeout);

+        if (status != 0) {

+            status=-60; goto on_error;

+        }

+    }

+

+    // Success

+    status = 0;

+

+on_error:

+    if (csock1 != PJ_INVALID_SOCKET)

+	pj_sock_close(csock1);

+    if (ioque != NULL)

+	pj_ioqueue_destroy(ioque);

+    pj_pool_release(pool);

+    return status;

+}

+

+int tcp_ioqueue_test()

+{

+    int status;

+

+    PJ_LOG(3, (THIS_FILE, "..%s compliance test 0 (success scenario)",

+	       pj_ioqueue_name()));

+    if ((status=compliance_test_0()) != 0) {

+	PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));

+	return status;

+    }

+    PJ_LOG(3, (THIS_FILE, "..%s compliance test 1 (failed scenario)",

+               pj_ioqueue_name()));

+    if ((status=compliance_test_1()) != 0) {

+	PJ_LOG(1, (THIS_FILE, "....FAILED (status=%d)\n", status));

+	return status;

+    }

+

+    return 0;

+}

+

+#endif	/* PJ_HAS_TCP */

+

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_uiq_tcp;

+#endif	/* INCLUDE_TCP_IOQUEUE_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/ioq_udp.c b/pjlib/src/pjlib-test/ioq_udp.c
index c6a5c5f..8e8b6d1 100644
--- a/pjlib/src/pjlib-test/ioq_udp.c
+++ b/pjlib/src/pjlib-test/ioq_udp.c
@@ -1,647 +1,668 @@
-/* $Id$
- */
-#include "test.h"
-
-
-/**
- * \page page_pjlib_ioqueue_udp_test Test: I/O Queue (UDP)
- *
- * This file provides implementation to test the
- * functionality of the I/O queue when UDP socket is used.
- *
- *
- * This file is <b>pjlib-test/ioq_udp.c</b>
- *
- * \include pjlib-test/ioq_udp.c
- */
-
-
-#if INCLUDE_UDP_IOQUEUE_TEST
-
-#include <pjlib.h>
-
-#include <pj/compat/socket.h>
-
-#define THIS_FILE	    "test_udp"
-#define PORT		    51233
-#define LOOP		    100
-#define BUF_MIN_SIZE	    32
-#define BUF_MAX_SIZE	    2048
-#define SOCK_INACTIVE_MIN   (1)
-#define SOCK_INACTIVE_MAX   (PJ_IOQUEUE_MAX_HANDLES - 2)
-#define POOL_SIZE	    (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)
-
-#undef TRACE_
-#define TRACE_(msg)	    PJ_LOG(3,(THIS_FILE,"....." msg))
-
-static pj_ssize_t            callback_read_size,
-                             callback_write_size,
-                             callback_accept_status,
-                             callback_connect_status;
-static pj_ioqueue_key_t     *callback_read_key,
-                            *callback_write_key,
-                            *callback_accept_key,
-                            *callback_connect_key;
-static pj_ioqueue_op_key_t  *callback_read_op,
-                            *callback_write_op,
-                            *callback_accept_op;
-
-static void on_ioqueue_read(pj_ioqueue_key_t *key, 
-                            pj_ioqueue_op_key_t *op_key,
-                            pj_ssize_t bytes_read)
-{
-    callback_read_key = key;
-    callback_read_op = op_key;
-    callback_read_size = bytes_read;
-}
-
-static void on_ioqueue_write(pj_ioqueue_key_t *key, 
-                             pj_ioqueue_op_key_t *op_key,
-                             pj_ssize_t bytes_written)
-{
-    callback_write_key = key;
-    callback_write_op = op_key;
-    callback_write_size = bytes_written;
-}
-
-static void on_ioqueue_accept(pj_ioqueue_key_t *key, 
-                              pj_ioqueue_op_key_t *op_key,
-                              pj_sock_t sock, int status)
-{
-    PJ_UNUSED_ARG(sock);
-    callback_accept_key = key;
-    callback_accept_op = op_key;
-    callback_accept_status = status;
-}
-
-static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
-{
-    callback_connect_key = key;
-    callback_connect_status = status;
-}
-
-static pj_ioqueue_callback test_cb = 
-{
-    &on_ioqueue_read,
-    &on_ioqueue_write,
-    &on_ioqueue_accept,
-    &on_ioqueue_connect,
-};
-
-#ifdef PJ_WIN32
-#  define S_ADDR S_un.S_addr
-#else
-#  define S_ADDR s_addr
-#endif
-
-/*
- * compliance_test()
- * To test that the basic IOQueue functionality works. It will just exchange
- * data between two sockets.
- */ 
-static int compliance_test(void)
-{
-    pj_sock_t ssock=-1, csock=-1;
-    pj_sockaddr_in addr;
-    int addrlen;
-    pj_pool_t *pool = NULL;
-    char *send_buf, *recv_buf;
-    pj_ioqueue_t *ioque = NULL;
-    pj_ioqueue_key_t *skey, *ckey;
-    pj_ioqueue_op_key_t read_op, write_op;
-    int bufsize = BUF_MIN_SIZE;
-    pj_ssize_t bytes, status = -1;
-    pj_str_t temp;
-    pj_bool_t send_pending, recv_pending;
-    pj_status_t rc;
-
-    pj_set_os_error(PJ_SUCCESS);
-
-    // Create pool.
-    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
-
-    // Allocate buffers for send and receive.
-    send_buf = (char*)pj_pool_alloc(pool, bufsize);
-    recv_buf = (char*)pj_pool_alloc(pool, bufsize);
-
-    // Allocate sockets for sending and receiving.
-    TRACE_("creating sockets...");
-    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
-    if (rc==PJ_SUCCESS)
-        rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
-    else
-        csock = PJ_INVALID_SOCKET;
-    if (rc != PJ_SUCCESS) {
-        app_perror("...ERROR in pj_sock_socket()", rc);
-	status=-1; goto on_error;
-    }
-
-    // Bind server socket.
-    TRACE_("bind socket...");
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = PJ_AF_INET;
-    addr.sin_port = pj_htons(PORT);
-    if (pj_sock_bind(ssock, &addr, sizeof(addr))) {
-	status=-10; goto on_error;
-    }
-
-    // Create I/O Queue.
-    TRACE_("create ioqueue...");
-    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
-    if (rc != PJ_SUCCESS) {
-	status=-20; goto on_error;
-    }
-
-    // Register server and client socket.
-    // We put this after inactivity socket, hopefully this can represent the
-    // worst waiting time.
-    TRACE_("registering first sockets...");
-    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, 
-			          &test_cb, &skey);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error(10): ioqueue_register error", rc);
-	status=-25; goto on_error;
-    }
-    TRACE_("registering second sockets...");
-    rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL, 
-			           &test_cb, &ckey);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error(11): ioqueue_register error", rc);
-	status=-26; goto on_error;
-    }
-
-    // Set destination address to send the packet.
-    TRACE_("set destination address...");
-    temp = pj_str("127.0.0.1");
-    if ((rc=pj_sockaddr_in_init(&addr, &temp, PORT)) != 0) {
-	app_perror("...error: unable to resolve 127.0.0.1", rc);
-	status=-26; goto on_error;
-    }
-
-    // Randomize send_buf.
-    pj_create_random_string(send_buf, bufsize);
-
-    // Register reading from ioqueue.
-    TRACE_("start recvfrom...");
-    addrlen = sizeof(addr);
-    bytes = bufsize;
-    rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0,
-			     &addr, &addrlen);
-    if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
-        app_perror("...error: pj_ioqueue_recvfrom", rc);
-	status=-28; goto on_error;
-    } else if (rc == PJ_EPENDING) {
-	recv_pending = 1;
-	PJ_LOG(3, (THIS_FILE, 
-		   "......ok: recvfrom returned pending"));
-    } else {
-	PJ_LOG(3, (THIS_FILE, 
-		   "......error: recvfrom returned immediate ok!"));
-	status=-29; goto on_error;
-    }
-
-    // Write must return the number of bytes.
-    TRACE_("start sendto...");
-    bytes = bufsize;
-    rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &addr, 
-			   sizeof(addr));
-    if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
-        app_perror("...error: pj_ioqueue_sendto", rc);
-	status=-30; goto on_error;
-    } else if (rc == PJ_EPENDING) {
-	send_pending = 1;
-	PJ_LOG(3, (THIS_FILE, 
-		   "......ok: sendto returned pending"));
-    } else {
-	send_pending = 0;
-	PJ_LOG(3, (THIS_FILE, 
-		   "......ok: sendto returned immediate success"));
-    }
-
-    // reset callback variables.
-    callback_read_size = callback_write_size = 0;
-    callback_accept_status = callback_connect_status = -2;
-    callback_read_key = callback_write_key = 
-        callback_accept_key = callback_connect_key = NULL;
-    callback_read_op = callback_write_op = NULL;
-
-    // Poll if pending.
-    while (send_pending || recv_pending) {
-	int rc;
-	pj_time_val timeout = { 5, 0 };
-
-	TRACE_("poll...");
-	rc = pj_ioqueue_poll(ioque, &timeout);
-
-	if (rc == 0) {
-	    PJ_LOG(1,(THIS_FILE, "...ERROR: timed out..."));
-	    status=-45; goto on_error;
-        } else if (rc < 0) {
-            app_perror("...ERROR in ioqueue_poll()", rc);
-	    status=-50; goto on_error;
-	}
-
-	if (callback_read_key != NULL) {
-            if (callback_read_size != bufsize) {
-                status=-61; goto on_error;
-            }
-            if (callback_read_key != skey) {
-                status=-65; goto on_error;
-            }
-            if (callback_read_op != &read_op) {
-                status=-66; goto on_error;
-            }
-
-	    if (memcmp(send_buf, recv_buf, bufsize) != 0) {
-		status=-70; goto on_error;
-	    }
-
-
-	    recv_pending = 0;
-	} 
-
-        if (callback_write_key != NULL) {
-            if (callback_write_size != bufsize) {
-                status=-73; goto on_error;
-            }
-            if (callback_write_key != ckey) {
-                status=-75; goto on_error;
-            }
-            if (callback_write_op != &write_op) {
-                status=-76; goto on_error;
-            }
-
-            send_pending = 0;
-	}
-    } 
-    
-    // Success
-    status = 0;
-
-on_error:
-    if (status != 0) {
-	char errbuf[128];
-	PJ_LOG(1, (THIS_FILE, 
-		   "...compliance test error: status=%d, os_err=%d (%s)", 
-		   status, pj_get_netos_error(),
-	           pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
-    }
-    if (ssock)
-	pj_sock_close(ssock);
-    if (csock)
-	pj_sock_close(csock);
-    if (ioque != NULL)
-	pj_ioqueue_destroy(ioque);
-    pj_pool_release(pool);
-    return status;
-
-}
-
-/*
- * Testing with many handles.
- * This will just test registering PJ_IOQUEUE_MAX_HANDLES count
- * of sockets to the ioqueue.
- */
-static int many_handles_test(void)
-{
-    enum { MAX = PJ_IOQUEUE_MAX_HANDLES };
-    pj_pool_t *pool;
-    pj_ioqueue_t *ioqueue;
-    pj_sock_t *sock;
-    pj_ioqueue_key_t **key;
-    pj_status_t rc;
-    int count, i;
-
-    PJ_LOG(3,(THIS_FILE,"...testing with so many handles"));
-
-    pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
-    if (!pool)
-	return PJ_ENOMEM;
-
-    key = pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));
-    sock = pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));
-    
-    /* Create IOQueue */
-    rc = pj_ioqueue_create(pool, MAX, &ioqueue);
-    if (rc != PJ_SUCCESS || ioqueue == NULL) {
-	app_perror("...error in pj_ioqueue_create", rc);
-	return -10;
-    }
-
-    /* Register as many sockets. */
-    for (count=0; count<MAX; ++count) {
-	sock[count] = PJ_INVALID_SOCKET;
-	rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[count]);
-	if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) {
-	    PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d", 
-				 count, rc));
-	    break;
-	}
-	key[count] = NULL;
-	rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count],
-				      NULL, &test_cb, &key[count]);
-	if (rc != PJ_SUCCESS || key[count] == NULL) {
-	    PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d", 
-				 count, rc));
-	    return -30;
-	}
-    }
-
-    /* Test complete. */
-
-    /* Now deregister and close all handles. */ 
-
-    for (i=0; i<count; ++i) {
-	rc = pj_ioqueue_unregister(key[i]);
-	if (rc != PJ_SUCCESS) {
-	    app_perror("...error in pj_ioqueue_unregister", rc);
-	}
-	rc = pj_sock_close(sock[i]);
-	if (rc != PJ_SUCCESS) {
-	    app_perror("...error in pj_sock_close", rc);
-	}
-    }
-
-    rc = pj_ioqueue_destroy(ioqueue);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error in pj_ioqueue_destroy", rc);
-    }
-    
-    pj_pool_release(pool);
-
-    PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok"));
-
-    return 0;
-}
-
-/*
- * Multi-operation test.
- */
-
-/*
- * Benchmarking IOQueue
- */
-static int bench_test(int bufsize, int inactive_sock_count)
-{
-    pj_sock_t ssock=-1, csock=-1;
-    pj_sockaddr_in addr;
-    pj_pool_t *pool = NULL;
-    pj_sock_t *inactive_sock=NULL;
-    pj_ioqueue_op_key_t *inactive_read_op;
-    char *send_buf, *recv_buf;
-    pj_ioqueue_t *ioque = NULL;
-    pj_ioqueue_key_t *skey, *ckey, *key;
-    pj_timestamp t1, t2, t_elapsed;
-    int rc=0, i;
-    pj_str_t temp;
-    char errbuf[128];
-
-    // Create pool.
-    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);
-
-    // Allocate buffers for send and receive.
-    send_buf = (char*)pj_pool_alloc(pool, bufsize);
-    recv_buf = (char*)pj_pool_alloc(pool, bufsize);
-
-    // Allocate sockets for sending and receiving.
-    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);
-    if (rc == PJ_SUCCESS) {
-        rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);
-    } else
-        csock = PJ_INVALID_SOCKET;
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: pj_sock_socket()", rc);
-	goto on_error;
-    }
-
-    // Bind server socket.
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = PJ_AF_INET;
-    addr.sin_port = pj_htons(PORT);
-    if (pj_sock_bind(ssock, &addr, sizeof(addr)))
-	goto on_error;
-
-    pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);
-
-    // Create I/O Queue.
-    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: pj_ioqueue_create()", rc);
-	goto on_error;
-    }
-
-    // Allocate inactive sockets, and bind them to some arbitrary address.
-    // Then register them to the I/O queue, and start a read operation.
-    inactive_sock = (pj_sock_t*)pj_pool_alloc(pool, 
-				    inactive_sock_count*sizeof(pj_sock_t));
-    inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,
-                              inactive_sock_count*sizeof(pj_ioqueue_op_key_t));
-    memset(&addr, 0, sizeof(addr));
-    addr.sin_family = PJ_AF_INET;
-    for (i=0; i<inactive_sock_count; ++i) {
-        pj_ssize_t bytes;
-
-	rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &inactive_sock[i]);
-	if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {
-	    app_perror("...error: pj_sock_socket()", rc);
-	    goto on_error;
-	}
-	if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {
-	    pj_sock_close(inactive_sock[i]);
-	    inactive_sock[i] = PJ_INVALID_SOCKET;
-	    app_perror("...error: pj_sock_bind()", rc);
-	    goto on_error;
-	}
-	rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i], 
-			              NULL, &test_cb, &key);
-	if (rc != PJ_SUCCESS) {
-	    pj_sock_close(inactive_sock[i]);
-	    inactive_sock[i] = PJ_INVALID_SOCKET;
-	    app_perror("...error(1): pj_ioqueue_register_sock()", rc);
-	    PJ_LOG(3,(THIS_FILE, "....i=%d", i));
-	    goto on_error;
-	}
-        bytes = bufsize;
-	rc = pj_ioqueue_recv(key, &inactive_read_op[i], recv_buf, &bytes, 0);
-	if ( rc < 0 && rc != PJ_EPENDING) {
-	    pj_sock_close(inactive_sock[i]);
-	    inactive_sock[i] = PJ_INVALID_SOCKET;
-	    app_perror("...error: pj_ioqueue_read()", rc);
-	    goto on_error;
-	}
-    }
-
-    // Register server and client socket.
-    // We put this after inactivity socket, hopefully this can represent the
-    // worst waiting time.
-    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, 
-			          &test_cb, &skey);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error(2): pj_ioqueue_register_sock()", rc);
-	goto on_error;
-    }
-
-    rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL, 
-			          &test_cb, &ckey);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error(3): pj_ioqueue_register_sock()", rc);
-	goto on_error;
-    }
-
-    // Set destination address to send the packet.
-    pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);
-
-    // Test loop.
-    t_elapsed.u64 = 0;
-    for (i=0; i<LOOP; ++i) {
-	pj_ssize_t bytes;
-        pj_ioqueue_op_key_t read_op, write_op;
-
-	// Randomize send buffer.
-	pj_create_random_string(send_buf, bufsize);
-
-	// Start reading on the server side.
-        bytes = bufsize;
-	rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);
-	if (rc < 0 && rc != PJ_EPENDING) {
-	    app_perror("...error: pj_ioqueue_read()", rc);
-	    break;
-	}
-
-	// Starts send on the client side.
-        bytes = bufsize;
-	rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,
-			       &addr, sizeof(addr));
-	if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {
-	    app_perror("...error: pj_ioqueue_write()", bytes);
-	    rc = -1;
-	    break;
-	}
-
-	// Begin time.
-	pj_get_timestamp(&t1);
-
-	// Poll the queue until we've got completion event in the server side.
-        callback_read_key = NULL;
-        callback_read_size = 0;
-	do {
-	    rc = pj_ioqueue_poll(ioque, NULL);
-	} while (rc >= 0 && callback_read_key != skey);
-
-	// End time.
-	pj_get_timestamp(&t2);
-	t_elapsed.u64 += (t2.u64 - t1.u64);
-
-	if (rc < 0)
-	    break;
-
-	// Compare recv buffer with send buffer.
-	if (callback_read_size != bufsize || 
-	    memcmp(send_buf, recv_buf, bufsize)) 
-	{
-	    rc = -1;
-	    break;
-	}
-
-	// Poll until all events are exhausted, before we start the next loop.
-	do {
-	    pj_time_val timeout = { 0, 10 };
-	    rc = pj_ioqueue_poll(ioque, &timeout);
-	} while (rc>0);
-
-	rc = 0;
-    }
-
-    // Print results
-    if (rc == 0) {
-	pj_timestamp tzero;
-	pj_uint32_t usec_delay;
-
-	tzero.u32.hi = tzero.u32.lo = 0;
-	usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);
-
-	PJ_LOG(3, (THIS_FILE, "...%10d %15d  % 9d", 
-	           bufsize, inactive_sock_count, usec_delay));
-
-    } else {
-	PJ_LOG(2, (THIS_FILE, "...ERROR (buf:%d, fds:%d)", 
-			      bufsize, inactive_sock_count+2));
-    }
-
-    // Cleaning up.
-    for (i=0; i<inactive_sock_count; ++i)
-	pj_sock_close(inactive_sock[i]);
-    pj_sock_close(ssock);
-    pj_sock_close(csock);
-
-    pj_ioqueue_destroy(ioque);
-    pj_pool_release( pool);
-    return 0;
-
-on_error:
-    PJ_LOG(1,(THIS_FILE, "...ERROR: %s", 
-	      pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));
-    if (ssock)
-	pj_sock_close(ssock);
-    if (csock)
-	pj_sock_close(csock);
-    for (i=0; i<inactive_sock_count && inactive_sock && 
-	      inactive_sock[i]!=PJ_INVALID_SOCKET; ++i) 
-    {
-	pj_sock_close(inactive_sock[i]);
-    }
-    if (ioque != NULL)
-	pj_ioqueue_destroy(ioque);
-    pj_pool_release( pool);
-    return -1;
-}
-
-int udp_ioqueue_test()
-{
-    int status;
-    int bufsize, sock_count;
-
-    PJ_LOG(3, (THIS_FILE, "...compliance test (%s)", pj_ioqueue_name()));
-    if ((status=compliance_test()) != 0) {
-	return status;
-    }
-    PJ_LOG(3, (THIS_FILE, "....compliance test ok"));
-
-    if ((status=many_handles_test()) != 0) {
-	return status;
-    }
-    
-    PJ_LOG(4, (THIS_FILE, "...benchmarking different buffer size:"));
-    PJ_LOG(4, (THIS_FILE, "... note: buf=bytes sent, fds=# of fds, "
-			  "elapsed=in timer ticks"));
-
-    PJ_LOG(3, (THIS_FILE, "...Benchmarking poll times for %s:", pj_ioqueue_name()));
-    PJ_LOG(3, (THIS_FILE, "...====================================="));
-    PJ_LOG(3, (THIS_FILE, "...Buf.size   #inactive-socks  Time/poll"));
-    PJ_LOG(3, (THIS_FILE, "... (bytes)                    (nanosec)"));
-    PJ_LOG(3, (THIS_FILE, "...====================================="));
-
-    for (bufsize=BUF_MIN_SIZE; bufsize <= BUF_MAX_SIZE; bufsize *= 2) {
-	if (bench_test(bufsize, SOCK_INACTIVE_MIN))
-	    return -1;
-    }
-    bufsize = 512;
-    for (sock_count=SOCK_INACTIVE_MIN+2; 
-	 sock_count<=SOCK_INACTIVE_MAX+2; 
-	 sock_count *= 2) 
-    {
-	//PJ_LOG(3,(THIS_FILE, "...testing with %d fds", sock_count));
-	if (bench_test(bufsize, sock_count-2))
-	    return -1;
-    }
-    return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_uiq_udp;
-#endif	/* INCLUDE_UDP_IOQUEUE_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+

+/**

+ * \page page_pjlib_ioqueue_udp_test Test: I/O Queue (UDP)

+ *

+ * This file provides implementation to test the

+ * functionality of the I/O queue when UDP socket is used.

+ *

+ *

+ * This file is <b>pjlib-test/ioq_udp.c</b>

+ *

+ * \include pjlib-test/ioq_udp.c

+ */

+

+

+#if INCLUDE_UDP_IOQUEUE_TEST

+

+#include <pjlib.h>

+

+#include <pj/compat/socket.h>

+

+#define THIS_FILE	    "test_udp"

+#define PORT		    51233

+#define LOOP		    100

+#define BUF_MIN_SIZE	    32

+#define BUF_MAX_SIZE	    2048

+#define SOCK_INACTIVE_MIN   (1)

+#define SOCK_INACTIVE_MAX   (PJ_IOQUEUE_MAX_HANDLES - 2)

+#define POOL_SIZE	    (2*BUF_MAX_SIZE + SOCK_INACTIVE_MAX*128 + 2048)

+

+#undef TRACE_

+#define TRACE_(msg)	    PJ_LOG(3,(THIS_FILE,"....." msg))

+

+static pj_ssize_t            callback_read_size,

+                             callback_write_size,

+                             callback_accept_status,

+                             callback_connect_status;

+static pj_ioqueue_key_t     *callback_read_key,

+                            *callback_write_key,

+                            *callback_accept_key,

+                            *callback_connect_key;

+static pj_ioqueue_op_key_t  *callback_read_op,

+                            *callback_write_op,

+                            *callback_accept_op;

+

+static void on_ioqueue_read(pj_ioqueue_key_t *key, 

+                            pj_ioqueue_op_key_t *op_key,

+                            pj_ssize_t bytes_read)

+{

+    callback_read_key = key;

+    callback_read_op = op_key;

+    callback_read_size = bytes_read;

+}

+

+static void on_ioqueue_write(pj_ioqueue_key_t *key, 

+                             pj_ioqueue_op_key_t *op_key,

+                             pj_ssize_t bytes_written)

+{

+    callback_write_key = key;

+    callback_write_op = op_key;

+    callback_write_size = bytes_written;

+}

+

+static void on_ioqueue_accept(pj_ioqueue_key_t *key, 

+                              pj_ioqueue_op_key_t *op_key,

+                              pj_sock_t sock, int status)

+{

+    PJ_UNUSED_ARG(sock);

+    callback_accept_key = key;

+    callback_accept_op = op_key;

+    callback_accept_status = status;

+}

+

+static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)

+{

+    callback_connect_key = key;

+    callback_connect_status = status;

+}

+

+static pj_ioqueue_callback test_cb = 

+{

+    &on_ioqueue_read,

+    &on_ioqueue_write,

+    &on_ioqueue_accept,

+    &on_ioqueue_connect,

+};

+

+#ifdef PJ_WIN32

+#  define S_ADDR S_un.S_addr

+#else

+#  define S_ADDR s_addr

+#endif

+

+/*

+ * compliance_test()

+ * To test that the basic IOQueue functionality works. It will just exchange

+ * data between two sockets.

+ */ 

+static int compliance_test(void)

+{

+    pj_sock_t ssock=-1, csock=-1;

+    pj_sockaddr_in addr;

+    int addrlen;

+    pj_pool_t *pool = NULL;

+    char *send_buf, *recv_buf;

+    pj_ioqueue_t *ioque = NULL;

+    pj_ioqueue_key_t *skey, *ckey;

+    pj_ioqueue_op_key_t read_op, write_op;

+    int bufsize = BUF_MIN_SIZE;

+    pj_ssize_t bytes, status = -1;

+    pj_str_t temp;

+    pj_bool_t send_pending, recv_pending;

+    pj_status_t rc;

+

+    pj_set_os_error(PJ_SUCCESS);

+

+    // Create pool.

+    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);

+

+    // Allocate buffers for send and receive.

+    send_buf = (char*)pj_pool_alloc(pool, bufsize);

+    recv_buf = (char*)pj_pool_alloc(pool, bufsize);

+

+    // Allocate sockets for sending and receiving.

+    TRACE_("creating sockets...");

+    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);

+    if (rc==PJ_SUCCESS)

+        rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);

+    else

+        csock = PJ_INVALID_SOCKET;

+    if (rc != PJ_SUCCESS) {

+        app_perror("...ERROR in pj_sock_socket()", rc);

+	status=-1; goto on_error;

+    }

+

+    // Bind server socket.

+    TRACE_("bind socket...");

+    memset(&addr, 0, sizeof(addr));

+    addr.sin_family = PJ_AF_INET;

+    addr.sin_port = pj_htons(PORT);

+    if (pj_sock_bind(ssock, &addr, sizeof(addr))) {

+	status=-10; goto on_error;

+    }

+

+    // Create I/O Queue.

+    TRACE_("create ioqueue...");

+    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);

+    if (rc != PJ_SUCCESS) {

+	status=-20; goto on_error;

+    }

+

+    // Register server and client socket.

+    // We put this after inactivity socket, hopefully this can represent the

+    // worst waiting time.

+    TRACE_("registering first sockets...");

+    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, 

+			          &test_cb, &skey);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error(10): ioqueue_register error", rc);

+	status=-25; goto on_error;

+    }

+    TRACE_("registering second sockets...");

+    rc = pj_ioqueue_register_sock( pool, ioque, csock, NULL, 

+			           &test_cb, &ckey);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error(11): ioqueue_register error", rc);

+	status=-26; goto on_error;

+    }

+

+    // Set destination address to send the packet.

+    TRACE_("set destination address...");

+    temp = pj_str("127.0.0.1");

+    if ((rc=pj_sockaddr_in_init(&addr, &temp, PORT)) != 0) {

+	app_perror("...error: unable to resolve 127.0.0.1", rc);

+	status=-26; goto on_error;

+    }

+

+    // Randomize send_buf.

+    pj_create_random_string(send_buf, bufsize);

+

+    // Register reading from ioqueue.

+    TRACE_("start recvfrom...");

+    addrlen = sizeof(addr);

+    bytes = bufsize;

+    rc = pj_ioqueue_recvfrom(skey, &read_op, recv_buf, &bytes, 0,

+			     &addr, &addrlen);

+    if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {

+        app_perror("...error: pj_ioqueue_recvfrom", rc);

+	status=-28; goto on_error;

+    } else if (rc == PJ_EPENDING) {

+	recv_pending = 1;

+	PJ_LOG(3, (THIS_FILE, 

+		   "......ok: recvfrom returned pending"));

+    } else {

+	PJ_LOG(3, (THIS_FILE, 

+		   "......error: recvfrom returned immediate ok!"));

+	status=-29; goto on_error;

+    }

+

+    // Write must return the number of bytes.

+    TRACE_("start sendto...");

+    bytes = bufsize;

+    rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0, &addr, 

+			   sizeof(addr));

+    if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {

+        app_perror("...error: pj_ioqueue_sendto", rc);

+	status=-30; goto on_error;

+    } else if (rc == PJ_EPENDING) {

+	send_pending = 1;

+	PJ_LOG(3, (THIS_FILE, 

+		   "......ok: sendto returned pending"));

+    } else {

+	send_pending = 0;

+	PJ_LOG(3, (THIS_FILE, 

+		   "......ok: sendto returned immediate success"));

+    }

+

+    // reset callback variables.

+    callback_read_size = callback_write_size = 0;

+    callback_accept_status = callback_connect_status = -2;

+    callback_read_key = callback_write_key = 

+        callback_accept_key = callback_connect_key = NULL;

+    callback_read_op = callback_write_op = NULL;

+

+    // Poll if pending.

+    while (send_pending || recv_pending) {

+	int rc;

+	pj_time_val timeout = { 5, 0 };

+

+	TRACE_("poll...");

+	rc = pj_ioqueue_poll(ioque, &timeout);

+

+	if (rc == 0) {

+	    PJ_LOG(1,(THIS_FILE, "...ERROR: timed out..."));

+	    status=-45; goto on_error;

+        } else if (rc < 0) {

+            app_perror("...ERROR in ioqueue_poll()", rc);

+	    status=-50; goto on_error;

+	}

+

+	if (callback_read_key != NULL) {

+            if (callback_read_size != bufsize) {

+                status=-61; goto on_error;

+            }

+            if (callback_read_key != skey) {

+                status=-65; goto on_error;

+            }

+            if (callback_read_op != &read_op) {

+                status=-66; goto on_error;

+            }

+

+	    if (memcmp(send_buf, recv_buf, bufsize) != 0) {

+		status=-70; goto on_error;

+	    }

+

+

+	    recv_pending = 0;

+	} 

+

+        if (callback_write_key != NULL) {

+            if (callback_write_size != bufsize) {

+                status=-73; goto on_error;

+            }

+            if (callback_write_key != ckey) {

+                status=-75; goto on_error;

+            }

+            if (callback_write_op != &write_op) {

+                status=-76; goto on_error;

+            }

+

+            send_pending = 0;

+	}

+    } 

+    

+    // Success

+    status = 0;

+

+on_error:

+    if (status != 0) {

+	char errbuf[128];

+	PJ_LOG(1, (THIS_FILE, 

+		   "...compliance test error: status=%d, os_err=%d (%s)", 

+		   status, pj_get_netos_error(),

+	           pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));

+    }

+    if (ssock)

+	pj_sock_close(ssock);

+    if (csock)

+	pj_sock_close(csock);

+    if (ioque != NULL)

+	pj_ioqueue_destroy(ioque);

+    pj_pool_release(pool);

+    return status;

+

+}

+

+/*

+ * Testing with many handles.

+ * This will just test registering PJ_IOQUEUE_MAX_HANDLES count

+ * of sockets to the ioqueue.

+ */

+static int many_handles_test(void)

+{

+    enum { MAX = PJ_IOQUEUE_MAX_HANDLES };

+    pj_pool_t *pool;

+    pj_ioqueue_t *ioqueue;

+    pj_sock_t *sock;

+    pj_ioqueue_key_t **key;

+    pj_status_t rc;

+    int count, i;

+

+    PJ_LOG(3,(THIS_FILE,"...testing with so many handles"));

+

+    pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);

+    if (!pool)

+	return PJ_ENOMEM;

+

+    key = pj_pool_alloc(pool, MAX*sizeof(pj_ioqueue_key_t*));

+    sock = pj_pool_alloc(pool, MAX*sizeof(pj_sock_t));

+    

+    /* Create IOQueue */

+    rc = pj_ioqueue_create(pool, MAX, &ioqueue);

+    if (rc != PJ_SUCCESS || ioqueue == NULL) {

+	app_perror("...error in pj_ioqueue_create", rc);

+	return -10;

+    }

+

+    /* Register as many sockets. */

+    for (count=0; count<MAX; ++count) {

+	sock[count] = PJ_INVALID_SOCKET;

+	rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[count]);

+	if (rc != PJ_SUCCESS || sock[count] == PJ_INVALID_SOCKET) {

+	    PJ_LOG(3,(THIS_FILE, "....unable to create %d-th socket, rc=%d", 

+				 count, rc));

+	    break;

+	}

+	key[count] = NULL;

+	rc = pj_ioqueue_register_sock(pool, ioqueue, sock[count],

+				      NULL, &test_cb, &key[count]);

+	if (rc != PJ_SUCCESS || key[count] == NULL) {

+	    PJ_LOG(3,(THIS_FILE, "....unable to register %d-th socket, rc=%d", 

+				 count, rc));

+	    return -30;

+	}

+    }

+

+    /* Test complete. */

+

+    /* Now deregister and close all handles. */ 

+

+    for (i=0; i<count; ++i) {

+	rc = pj_ioqueue_unregister(key[i]);

+	if (rc != PJ_SUCCESS) {

+	    app_perror("...error in pj_ioqueue_unregister", rc);

+	}

+	rc = pj_sock_close(sock[i]);

+	if (rc != PJ_SUCCESS) {

+	    app_perror("...error in pj_sock_close", rc);

+	}

+    }

+

+    rc = pj_ioqueue_destroy(ioqueue);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error in pj_ioqueue_destroy", rc);

+    }

+    

+    pj_pool_release(pool);

+

+    PJ_LOG(3,(THIS_FILE,"....many_handles_test() ok"));

+

+    return 0;

+}

+

+/*

+ * Multi-operation test.

+ */

+

+/*

+ * Benchmarking IOQueue

+ */

+static int bench_test(int bufsize, int inactive_sock_count)

+{

+    pj_sock_t ssock=-1, csock=-1;

+    pj_sockaddr_in addr;

+    pj_pool_t *pool = NULL;

+    pj_sock_t *inactive_sock=NULL;

+    pj_ioqueue_op_key_t *inactive_read_op;

+    char *send_buf, *recv_buf;

+    pj_ioqueue_t *ioque = NULL;

+    pj_ioqueue_key_t *skey, *ckey, *key;

+    pj_timestamp t1, t2, t_elapsed;

+    int rc=0, i;

+    pj_str_t temp;

+    char errbuf[128];

+

+    // Create pool.

+    pool = pj_pool_create(mem, NULL, POOL_SIZE, 4000, NULL);

+

+    // Allocate buffers for send and receive.

+    send_buf = (char*)pj_pool_alloc(pool, bufsize);

+    recv_buf = (char*)pj_pool_alloc(pool, bufsize);

+

+    // Allocate sockets for sending and receiving.

+    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ssock);

+    if (rc == PJ_SUCCESS) {

+        rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &csock);

+    } else

+        csock = PJ_INVALID_SOCKET;

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: pj_sock_socket()", rc);

+	goto on_error;

+    }

+

+    // Bind server socket.

+    memset(&addr, 0, sizeof(addr));

+    addr.sin_family = PJ_AF_INET;

+    addr.sin_port = pj_htons(PORT);

+    if (pj_sock_bind(ssock, &addr, sizeof(addr)))

+	goto on_error;

+

+    pj_assert(inactive_sock_count+2 <= PJ_IOQUEUE_MAX_HANDLES);

+

+    // Create I/O Queue.

+    rc = pj_ioqueue_create(pool, PJ_IOQUEUE_MAX_HANDLES, &ioque);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: pj_ioqueue_create()", rc);

+	goto on_error;

+    }

+

+    // Allocate inactive sockets, and bind them to some arbitrary address.

+    // Then register them to the I/O queue, and start a read operation.

+    inactive_sock = (pj_sock_t*)pj_pool_alloc(pool, 

+				    inactive_sock_count*sizeof(pj_sock_t));

+    inactive_read_op = (pj_ioqueue_op_key_t*)pj_pool_alloc(pool,

+                              inactive_sock_count*sizeof(pj_ioqueue_op_key_t));

+    memset(&addr, 0, sizeof(addr));

+    addr.sin_family = PJ_AF_INET;

+    for (i=0; i<inactive_sock_count; ++i) {

+        pj_ssize_t bytes;

+

+	rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &inactive_sock[i]);

+	if (rc != PJ_SUCCESS || inactive_sock[i] < 0) {

+	    app_perror("...error: pj_sock_socket()", rc);

+	    goto on_error;

+	}

+	if ((rc=pj_sock_bind(inactive_sock[i], &addr, sizeof(addr))) != 0) {

+	    pj_sock_close(inactive_sock[i]);

+	    inactive_sock[i] = PJ_INVALID_SOCKET;

+	    app_perror("...error: pj_sock_bind()", rc);

+	    goto on_error;

+	}

+	rc = pj_ioqueue_register_sock(pool, ioque, inactive_sock[i], 

+			              NULL, &test_cb, &key);

+	if (rc != PJ_SUCCESS) {

+	    pj_sock_close(inactive_sock[i]);

+	    inactive_sock[i] = PJ_INVALID_SOCKET;

+	    app_perror("...error(1): pj_ioqueue_register_sock()", rc);

+	    PJ_LOG(3,(THIS_FILE, "....i=%d", i));

+	    goto on_error;

+	}

+        bytes = bufsize;

+	rc = pj_ioqueue_recv(key, &inactive_read_op[i], recv_buf, &bytes, 0);

+	if ( rc < 0 && rc != PJ_EPENDING) {

+	    pj_sock_close(inactive_sock[i]);

+	    inactive_sock[i] = PJ_INVALID_SOCKET;

+	    app_perror("...error: pj_ioqueue_read()", rc);

+	    goto on_error;

+	}

+    }

+

+    // Register server and client socket.

+    // We put this after inactivity socket, hopefully this can represent the

+    // worst waiting time.

+    rc = pj_ioqueue_register_sock(pool, ioque, ssock, NULL, 

+			          &test_cb, &skey);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error(2): pj_ioqueue_register_sock()", rc);

+	goto on_error;

+    }

+

+    rc = pj_ioqueue_register_sock(pool, ioque, csock, NULL, 

+			          &test_cb, &ckey);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error(3): pj_ioqueue_register_sock()", rc);

+	goto on_error;

+    }

+

+    // Set destination address to send the packet.

+    pj_sockaddr_in_init(&addr, pj_cstr(&temp, "127.0.0.1"), PORT);

+

+    // Test loop.

+    t_elapsed.u64 = 0;

+    for (i=0; i<LOOP; ++i) {

+	pj_ssize_t bytes;

+        pj_ioqueue_op_key_t read_op, write_op;

+

+	// Randomize send buffer.

+	pj_create_random_string(send_buf, bufsize);

+

+	// Start reading on the server side.

+        bytes = bufsize;

+	rc = pj_ioqueue_recv(skey, &read_op, recv_buf, &bytes, 0);

+	if (rc < 0 && rc != PJ_EPENDING) {

+	    app_perror("...error: pj_ioqueue_read()", rc);

+	    break;

+	}

+

+	// Starts send on the client side.

+        bytes = bufsize;

+	rc = pj_ioqueue_sendto(ckey, &write_op, send_buf, &bytes, 0,

+			       &addr, sizeof(addr));

+	if (rc != PJ_SUCCESS && rc != PJ_EPENDING) {

+	    app_perror("...error: pj_ioqueue_write()", bytes);

+	    rc = -1;

+	    break;

+	}

+

+	// Begin time.

+	pj_get_timestamp(&t1);

+

+	// Poll the queue until we've got completion event in the server side.

+        callback_read_key = NULL;

+        callback_read_size = 0;

+	do {

+	    rc = pj_ioqueue_poll(ioque, NULL);

+	} while (rc >= 0 && callback_read_key != skey);

+

+	// End time.

+	pj_get_timestamp(&t2);

+	t_elapsed.u64 += (t2.u64 - t1.u64);

+

+	if (rc < 0)

+	    break;

+

+	// Compare recv buffer with send buffer.

+	if (callback_read_size != bufsize || 

+	    memcmp(send_buf, recv_buf, bufsize)) 

+	{

+	    rc = -1;

+	    break;

+	}

+

+	// Poll until all events are exhausted, before we start the next loop.

+	do {

+	    pj_time_val timeout = { 0, 10 };

+	    rc = pj_ioqueue_poll(ioque, &timeout);

+	} while (rc>0);

+

+	rc = 0;

+    }

+

+    // Print results

+    if (rc == 0) {

+	pj_timestamp tzero;

+	pj_uint32_t usec_delay;

+

+	tzero.u32.hi = tzero.u32.lo = 0;

+	usec_delay = pj_elapsed_usec( &tzero, &t_elapsed);

+

+	PJ_LOG(3, (THIS_FILE, "...%10d %15d  % 9d", 

+	           bufsize, inactive_sock_count, usec_delay));

+

+    } else {

+	PJ_LOG(2, (THIS_FILE, "...ERROR (buf:%d, fds:%d)", 

+			      bufsize, inactive_sock_count+2));

+    }

+

+    // Cleaning up.

+    for (i=0; i<inactive_sock_count; ++i)

+	pj_sock_close(inactive_sock[i]);

+    pj_sock_close(ssock);

+    pj_sock_close(csock);

+

+    pj_ioqueue_destroy(ioque);

+    pj_pool_release( pool);

+    return 0;

+

+on_error:

+    PJ_LOG(1,(THIS_FILE, "...ERROR: %s", 

+	      pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf))));

+    if (ssock)

+	pj_sock_close(ssock);

+    if (csock)

+	pj_sock_close(csock);

+    for (i=0; i<inactive_sock_count && inactive_sock && 

+	      inactive_sock[i]!=PJ_INVALID_SOCKET; ++i) 

+    {

+	pj_sock_close(inactive_sock[i]);

+    }

+    if (ioque != NULL)

+	pj_ioqueue_destroy(ioque);

+    pj_pool_release( pool);

+    return -1;

+}

+

+int udp_ioqueue_test()

+{

+    int status;

+    int bufsize, sock_count;

+

+    PJ_LOG(3, (THIS_FILE, "...compliance test (%s)", pj_ioqueue_name()));

+    if ((status=compliance_test()) != 0) {

+	return status;

+    }

+    PJ_LOG(3, (THIS_FILE, "....compliance test ok"));

+

+    if ((status=many_handles_test()) != 0) {

+	return status;

+    }

+    

+    PJ_LOG(4, (THIS_FILE, "...benchmarking different buffer size:"));

+    PJ_LOG(4, (THIS_FILE, "... note: buf=bytes sent, fds=# of fds, "

+			  "elapsed=in timer ticks"));

+

+    PJ_LOG(3, (THIS_FILE, "...Benchmarking poll times for %s:", pj_ioqueue_name()));

+    PJ_LOG(3, (THIS_FILE, "...====================================="));

+    PJ_LOG(3, (THIS_FILE, "...Buf.size   #inactive-socks  Time/poll"));

+    PJ_LOG(3, (THIS_FILE, "... (bytes)                    (nanosec)"));

+    PJ_LOG(3, (THIS_FILE, "...====================================="));

+

+    for (bufsize=BUF_MIN_SIZE; bufsize <= BUF_MAX_SIZE; bufsize *= 2) {

+	if (bench_test(bufsize, SOCK_INACTIVE_MIN))

+	    return -1;

+    }

+    bufsize = 512;

+    for (sock_count=SOCK_INACTIVE_MIN+2; 

+	 sock_count<=SOCK_INACTIVE_MAX+2; 

+	 sock_count *= 2) 

+    {

+	//PJ_LOG(3,(THIS_FILE, "...testing with %d fds", sock_count));

+	if (bench_test(bufsize, sock_count-2))

+	    return -1;

+    }

+    return 0;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_uiq_udp;

+#endif	/* INCLUDE_UDP_IOQUEUE_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/list.c b/pjlib/src/pjlib-test/list.c
index 4184e80..2a2dafb 100644
--- a/pjlib/src/pjlib-test/list.c
+++ b/pjlib/src/pjlib-test/list.c
@@ -1,209 +1,230 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_list_test Test: Linked List
- *
- * This file provides implementation of \b list_test(). It tests the
- * functionality of the linked-list API.
- *
- * \section list_test_sec Scope of the Test
- *
- * API tested:
- *  - pj_list_init()
- *  - pj_list_insert_before()
- *  - pj_list_insert_after()
- *  - pj_list_merge_last()
- *  - pj_list_empty()
- *  - pj_list_insert_nodes_before()
- *  - pj_list_erase()
- *  - pj_list_find_node()
- *  - pj_list_search()
- *
- *
- * This file is <b>pjlib-test/list.c</b>
- *
- * \include pjlib-test/list.c
- */
-
-#if INCLUDE_LIST_TEST
-
-#include <pjlib.h>
-
-typedef struct list_node
-{
-    PJ_DECL_LIST_MEMBER(struct list_node);
-    int value;
-} list_node;
-
-static int compare_node(void *value, const pj_list_type *nd)
-{
-    list_node *node = (list_node*)nd;
-    return ((long)value == node->value) ? 0 : -1;
-}
-
-#define PJ_SIGNED_ARRAY_SIZE(a)	((int)PJ_ARRAY_SIZE(a))
-
-int list_test()
-{
-    list_node nodes[4];    // must be even number of nodes
-    list_node list;
-    list_node list2;
-    list_node *p;
-    int i; // don't change to unsigned!
-
-    //
-    // Test insert_before().
-    //
-    list.value = (unsigned)-1;
-    pj_list_init(&list);
-    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
-	nodes[i].value = i;
-	pj_list_insert_before(&list, &nodes[i]);
-    }
-    // check.
-    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
-	pj_assert(p->value == i);
-	if (p->value != i) {
-	    return -1;
-	}
-    }
-
-    //
-    // Test insert_after()
-    //
-    pj_list_init(&list);
-    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {
-	pj_list_insert_after(&list, &nodes[i]);
-    }
-    // check.
-    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
-	pj_assert(p->value == i);
-	if (p->value != i) {
-	    return -1;
-	}
-    }
-
-    //
-    // Test merge_last()
-    //
-    // Init lists
-    pj_list_init(&list);
-    pj_list_init(&list2);
-    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
-	pj_list_insert_before(&list, &nodes[i]);
-    }
-    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
-	pj_list_insert_before(&list2, &nodes[i]);
-    }
-    // merge
-    pj_list_merge_last(&list, &list2);
-    // check.
-    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
-	pj_assert(p->value == i);
-	if (p->value != i) {
-	    return -1;
-	}
-    }
-    // check list is empty
-    pj_assert( pj_list_empty(&list2) );
-    if (!pj_list_empty(&list2)) {
-	return -1;
-    }
-
-    // 
-    // Check merge_first()
-    //
-    pj_list_init(&list);
-    pj_list_init(&list2);
-    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
-	pj_list_insert_before(&list, &nodes[i]);
-    }
-    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
-	pj_list_insert_before(&list2, &nodes[i]);
-    }
-    // merge
-    pj_list_merge_first(&list2, &list);
-    // check (list2).
-    for (i=0, p=list2.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
-	pj_assert(p->value == i);
-	if (p->value != i) {
-	    return -1;
-	}
-    }
-    // check list is empty
-    pj_assert( pj_list_empty(&list) );
-    if (!pj_list_empty(&list)) {
-	return -1;
-    }
-
-    //
-    // Test insert_nodes_before()
-    //
-    // init list
-    pj_list_init(&list);
-    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {
-	pj_list_insert_before(&list, &nodes[i]);
-    }
-    // chain remaining nodes
-    pj_list_init(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);
-    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2+1; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
-	pj_list_insert_before(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2], &nodes[i]);
-    }
-    // insert nodes
-    pj_list_insert_nodes_before(&list, &nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);
-    // check
-    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {
-	pj_assert(p->value == i);
-	if (p->value != i) {
-	    return -1;
-	}
-    }
-
-    // erase test.
-    pj_list_init(&list);
-    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
-	nodes[i].value = i;
-	pj_list_insert_before(&list, &nodes[i]);
-    }
-    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {
-	int j;
-	pj_list_erase(&nodes[i]);
-	for (j=0, p=list.next; j<i; ++j, p=p->next) {
-	    pj_assert(p->value == j);
-	    if (p->value != j) {
-		return -1;
-	    }
-	}
-    }
-
-    // find and search
-    pj_list_init(&list);
-    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
-	nodes[i].value = i;
-	pj_list_insert_before(&list, &nodes[i]);
-    }
-    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {
-	p = (list_node*) pj_list_find_node(&list, &nodes[i]);
-	pj_assert( p == &nodes[i] );
-	if (p != &nodes[i]) {
-	    return -1;
-	}
-	p = (list_node*) pj_list_search(&list, (void*)(long)i, &compare_node);
-	pj_assert( p == &nodes[i] );
-	if (p != &nodes[i]) {
-	    return -1;
-	}
-    }
-    return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_list_test;
-#endif	/* INCLUDE_LIST_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+/**

+ * \page page_pjlib_list_test Test: Linked List

+ *

+ * This file provides implementation of \b list_test(). It tests the

+ * functionality of the linked-list API.

+ *

+ * \section list_test_sec Scope of the Test

+ *

+ * API tested:

+ *  - pj_list_init()

+ *  - pj_list_insert_before()

+ *  - pj_list_insert_after()

+ *  - pj_list_merge_last()

+ *  - pj_list_empty()

+ *  - pj_list_insert_nodes_before()

+ *  - pj_list_erase()

+ *  - pj_list_find_node()

+ *  - pj_list_search()

+ *

+ *

+ * This file is <b>pjlib-test/list.c</b>

+ *

+ * \include pjlib-test/list.c

+ */

+

+#if INCLUDE_LIST_TEST

+

+#include <pjlib.h>

+

+typedef struct list_node

+{

+    PJ_DECL_LIST_MEMBER(struct list_node);

+    int value;

+} list_node;

+

+static int compare_node(void *value, const pj_list_type *nd)

+{

+    list_node *node = (list_node*)nd;

+    return ((long)value == node->value) ? 0 : -1;

+}

+

+#define PJ_SIGNED_ARRAY_SIZE(a)	((int)PJ_ARRAY_SIZE(a))

+

+int list_test()

+{

+    list_node nodes[4];    // must be even number of nodes

+    list_node list;

+    list_node list2;

+    list_node *p;

+    int i; // don't change to unsigned!

+

+    //

+    // Test insert_before().

+    //

+    list.value = (unsigned)-1;

+    pj_list_init(&list);

+    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {

+	nodes[i].value = i;

+	pj_list_insert_before(&list, &nodes[i]);

+    }

+    // check.

+    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {

+	pj_assert(p->value == i);

+	if (p->value != i) {

+	    return -1;

+	}

+    }

+

+    //

+    // Test insert_after()

+    //

+    pj_list_init(&list);

+    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {

+	pj_list_insert_after(&list, &nodes[i]);

+    }

+    // check.

+    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {

+	pj_assert(p->value == i);

+	if (p->value != i) {

+	    return -1;

+	}

+    }

+

+    //

+    // Test merge_last()

+    //

+    // Init lists

+    pj_list_init(&list);

+    pj_list_init(&list2);

+    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {

+	pj_list_insert_before(&list, &nodes[i]);

+    }

+    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {

+	pj_list_insert_before(&list2, &nodes[i]);

+    }

+    // merge

+    pj_list_merge_last(&list, &list2);

+    // check.

+    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {

+	pj_assert(p->value == i);

+	if (p->value != i) {

+	    return -1;

+	}

+    }

+    // check list is empty

+    pj_assert( pj_list_empty(&list2) );

+    if (!pj_list_empty(&list2)) {

+	return -1;

+    }

+

+    // 

+    // Check merge_first()

+    //

+    pj_list_init(&list);

+    pj_list_init(&list2);

+    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {

+	pj_list_insert_before(&list, &nodes[i]);

+    }

+    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {

+	pj_list_insert_before(&list2, &nodes[i]);

+    }

+    // merge

+    pj_list_merge_first(&list2, &list);

+    // check (list2).

+    for (i=0, p=list2.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {

+	pj_assert(p->value == i);

+	if (p->value != i) {

+	    return -1;

+	}

+    }

+    // check list is empty

+    pj_assert( pj_list_empty(&list) );

+    if (!pj_list_empty(&list)) {

+	return -1;

+    }

+

+    //

+    // Test insert_nodes_before()

+    //

+    // init list

+    pj_list_init(&list);

+    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes)/2; ++i) {

+	pj_list_insert_before(&list, &nodes[i]);

+    }

+    // chain remaining nodes

+    pj_list_init(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);

+    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)/2+1; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {

+	pj_list_insert_before(&nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2], &nodes[i]);

+    }

+    // insert nodes

+    pj_list_insert_nodes_before(&list, &nodes[PJ_SIGNED_ARRAY_SIZE(nodes)/2]);

+    // check

+    for (i=0, p=list.next; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i, p=p->next) {

+	pj_assert(p->value == i);

+	if (p->value != i) {

+	    return -1;

+	}

+    }

+

+    // erase test.

+    pj_list_init(&list);

+    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {

+	nodes[i].value = i;

+	pj_list_insert_before(&list, &nodes[i]);

+    }

+    for (i=PJ_SIGNED_ARRAY_SIZE(nodes)-1; i>=0; --i) {

+	int j;

+	pj_list_erase(&nodes[i]);

+	for (j=0, p=list.next; j<i; ++j, p=p->next) {

+	    pj_assert(p->value == j);

+	    if (p->value != j) {

+		return -1;

+	    }

+	}

+    }

+

+    // find and search

+    pj_list_init(&list);

+    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {

+	nodes[i].value = i;

+	pj_list_insert_before(&list, &nodes[i]);

+    }

+    for (i=0; i<PJ_SIGNED_ARRAY_SIZE(nodes); ++i) {

+	p = (list_node*) pj_list_find_node(&list, &nodes[i]);

+	pj_assert( p == &nodes[i] );

+	if (p != &nodes[i]) {

+	    return -1;

+	}

+	p = (list_node*) pj_list_search(&list, (void*)(long)i, &compare_node);

+	pj_assert( p == &nodes[i] );

+	if (p != &nodes[i]) {

+	    return -1;

+	}

+    }

+    return 0;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_list_test;

+#endif	/* INCLUDE_LIST_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/main.c b/pjlib/src/pjlib-test/main.c
index 6a764e6..bf8e99c 100644
--- a/pjlib/src/pjlib-test/main.c
+++ b/pjlib/src/pjlib-test/main.c
@@ -1,77 +1,98 @@
-/* $Id$
- */
-#include "test.h"
-
-#include <pj/string.h>
-#include <pj/sock.h>
-#include <pj/log.h>
-
-extern int param_echo_sock_type;
-extern const char *param_echo_server;
-extern int param_echo_port;
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+#include <pj/string.h>

+#include <pj/sock.h>

+#include <pj/log.h>

+

+extern int param_echo_sock_type;

+extern const char *param_echo_server;

+extern int param_echo_port;

+

+

 //#if defined(PJ_WIN32) && PJ_WIN32!=0

-#if 0
-#include <windows.h>
-static void boost(void)
-{
-    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
-}
-#else
-#define boost()
-#endif
-
-#if defined(PJ_SUNOS) && PJ_SUNOS!=0
-#include <signal.h>
-static void init_signals()
-{
-    struct sigaction act;
-
-    memset(&act, 0, sizeof(act));
-    act.sa_handler = SIG_IGN;
-
-    sigaction(SIGALRM, &act, NULL);
-}
-
-#else
-#define init_signals()
-#endif
-
-int main(int argc, char *argv[])
-{
-    int rc;
-
-    boost();
-    init_signals();
-
-    while (argc > 1) {
-        char *arg = argv[--argc];
-
-        if (*arg=='-' && *(arg+1)=='p') {
-            pj_str_t port = pj_str(argv[--argc]);
-
-            param_echo_port = pj_strtoul(&port);
-
-        } else if (*arg=='-' && *(arg+1)=='s') {
-            param_echo_server = argv[--argc];
-
-        } else if (*arg=='-' && *(arg+1)=='t') {
-            pj_str_t type = pj_str(argv[--argc]);
-            
-            if (pj_stricmp2(&type, "tcp")==0)
-                param_echo_sock_type = PJ_SOCK_STREAM;
-            else if (pj_stricmp2(&type, "udp")==0)
-                param_echo_sock_type = PJ_SOCK_DGRAM;
-            else {
-                PJ_LOG(3,("", "error: unknown socket type %s", type.ptr));
-                return 1;
-            }
-        }
-    }
-
-    rc = test_main();
-
-    return rc;
-}
-
+#if 0

+#include <windows.h>

+static void boost(void)

+{

+    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);

+}

+#else

+#define boost()

+#endif

+

+#if defined(PJ_SUNOS) && PJ_SUNOS!=0

+#include <signal.h>

+static void init_signals()

+{

+    struct sigaction act;

+

+    memset(&act, 0, sizeof(act));

+    act.sa_handler = SIG_IGN;

+

+    sigaction(SIGALRM, &act, NULL);

+}

+

+#else

+#define init_signals()

+#endif

+

+int main(int argc, char *argv[])

+{

+    int rc;

+

+    boost();

+    init_signals();

+

+    while (argc > 1) {

+        char *arg = argv[--argc];

+

+        if (*arg=='-' && *(arg+1)=='p') {

+            pj_str_t port = pj_str(argv[--argc]);

+

+            param_echo_port = pj_strtoul(&port);

+

+        } else if (*arg=='-' && *(arg+1)=='s') {

+            param_echo_server = argv[--argc];

+

+        } else if (*arg=='-' && *(arg+1)=='t') {

+            pj_str_t type = pj_str(argv[--argc]);

+            

+            if (pj_stricmp2(&type, "tcp")==0)

+                param_echo_sock_type = PJ_SOCK_STREAM;

+            else if (pj_stricmp2(&type, "udp")==0)

+                param_echo_sock_type = PJ_SOCK_DGRAM;

+            else {

+                PJ_LOG(3,("", "error: unknown socket type %s", type.ptr));

+                return 1;

+            }

+        }

+    }

+

+    rc = test_main();

+

+    return rc;

+}

+

diff --git a/pjlib/src/pjlib-test/main_mod.c b/pjlib/src/pjlib-test/main_mod.c
index 7978e36..34dfc70 100644
--- a/pjlib/src/pjlib-test/main_mod.c
+++ b/pjlib/src/pjlib-test/main_mod.c
@@ -1,23 +1,44 @@
-/* $Id$
- */
-#include "test.h"
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-int init_module(void)
-{
-    printk(KERN_INFO "PJLIB test module loaded. Starting tests...\n");
-    
-    test_main();
-
-    /* Prevent module from loading. We've finished test anyway.. */
-    return 1;
-}
-
-void cleanup_module(void)
-{
-    printk(KERN_INFO "PJLIB test module unloading...\n");
-}
-
-MODULE_LICENSE("GPL");
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <linux/module.h>

+#include <linux/kernel.h>

+

+int init_module(void)

+{

+    printk(KERN_INFO "PJLIB test module loaded. Starting tests...\n");

+    

+    test_main();

+

+    /* Prevent module from loading. We've finished test anyway.. */

+    return 1;

+}

+

+void cleanup_module(void)

+{

+    printk(KERN_INFO "PJLIB test module unloading...\n");

+}

+

+MODULE_LICENSE("GPL");

+

diff --git a/pjlib/src/pjlib-test/mutex.c b/pjlib/src/pjlib-test/mutex.c
index c7af51b..f82987c 100644
--- a/pjlib/src/pjlib-test/mutex.c
+++ b/pjlib/src/pjlib-test/mutex.c
@@ -1,158 +1,179 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-#if INCLUDE_MUTEX_TEST
-
-#undef TRACE_
-//#define TRACE_(x)   PJ_LOG(3,x)
-#define TRACE_(x)
-
-/* Test witn non-recursive mutex. */
-static int simple_mutex_test(pj_pool_t *pool)
-{
-    pj_status_t rc;
-    pj_mutex_t *mutex;
-
-    PJ_LOG(3,("", "...testing simple mutex"));
-    
-    /* Create mutex. */
-    TRACE_(("", "....create mutex"));
-    rc = pj_mutex_create( pool, "", PJ_MUTEX_SIMPLE, &mutex);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: pj_mutex_create", rc);
-	return -10;
-    }
-
-    /* Normal lock/unlock cycle. */
-    TRACE_(("", "....lock mutex"));
-    rc = pj_mutex_lock(mutex);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: pj_mutex_lock", rc);
-	return -20;
-    }
-    TRACE_(("", "....unlock mutex"));
-    rc = pj_mutex_unlock(mutex);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: pj_mutex_unlock", rc);
-	return -30;
-    }
-    
-    /* Lock again. */
-    TRACE_(("", "....lock mutex"));
-    rc = pj_mutex_lock(mutex);
-    if (rc != PJ_SUCCESS) return -40;
-
-    /* Try-lock should fail. It should not deadlocked. */
-    TRACE_(("", "....trylock mutex"));
-    rc = pj_mutex_trylock(mutex);
-    if (rc == PJ_SUCCESS)
-	PJ_LOG(3,("", "...info: looks like simple mutex is recursive"));
-
-    /* Unlock and done. */
-    TRACE_(("", "....unlock mutex"));
-    rc = pj_mutex_unlock(mutex);
-    if (rc != PJ_SUCCESS) return -50;
-
-    TRACE_(("", "....destroy mutex"));
-    rc = pj_mutex_destroy(mutex);
-    if (rc != PJ_SUCCESS) return -60;
-
-    TRACE_(("", "....done"));
-    return PJ_SUCCESS;
-}
-
-
-/* Test with recursive mutex. */
-static int recursive_mutex_test(pj_pool_t *pool)
-{
-    pj_status_t rc;
-    pj_mutex_t *mutex;
-
-    PJ_LOG(3,("", "...testing recursive mutex"));
-
-    /* Create mutex. */
-    TRACE_(("", "....create mutex"));
-    rc = pj_mutex_create( pool, "", PJ_MUTEX_RECURSE, &mutex);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: pj_mutex_create", rc);
-	return -10;
-    }
-
-    /* Normal lock/unlock cycle. */
-    TRACE_(("", "....lock mutex"));
-    rc = pj_mutex_lock(mutex);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: pj_mutex_lock", rc);
-	return -20;
-    }
-    TRACE_(("", "....unlock mutex"));
-    rc = pj_mutex_unlock(mutex);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: pj_mutex_unlock", rc);
-	return -30;
-    }
-    
-    /* Lock again. */
-    TRACE_(("", "....lock mutex"));
-    rc = pj_mutex_lock(mutex);
-    if (rc != PJ_SUCCESS) return -40;
-
-    /* Try-lock should NOT fail. . */
-    TRACE_(("", "....trylock mutex"));
-    rc = pj_mutex_trylock(mutex);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: recursive mutex is not recursive!", rc);
-	return -40;
-    }
-
-    /* Locking again should not fail. */
-    TRACE_(("", "....lock mutex"));
-    rc = pj_mutex_lock(mutex);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: recursive mutex is not recursive!", rc);
-	return -45;
-    }
-
-    /* Unlock several times and done. */
-    TRACE_(("", "....unlock mutex 3x"));
-    rc = pj_mutex_unlock(mutex);
-    if (rc != PJ_SUCCESS) return -50;
-    rc = pj_mutex_unlock(mutex);
-    if (rc != PJ_SUCCESS) return -51;
-    rc = pj_mutex_unlock(mutex);
-    if (rc != PJ_SUCCESS) return -52;
-
-    TRACE_(("", "....destroy mutex"));
-    rc = pj_mutex_destroy(mutex);
-    if (rc != PJ_SUCCESS) return -60;
-
-    TRACE_(("", "....done"));
-    return PJ_SUCCESS;
-}
-
-int mutex_test(void)
-{
-    pj_pool_t *pool;
-    int rc;
-
-    pool = pj_pool_create(mem, "", 4000, 4000, NULL);
-
-    rc = simple_mutex_test(pool);
-    if (rc != 0)
-	return rc;
-
-    rc = recursive_mutex_test(pool);
-    if (rc != 0)
-	return rc;
-
-    pj_pool_release(pool);
-
-    return 0;
-}
-
-#else
-int dummy_mutex_test;
-#endif
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pjlib.h>

+

+#if INCLUDE_MUTEX_TEST

+

+#undef TRACE_

+//#define TRACE_(x)   PJ_LOG(3,x)

+#define TRACE_(x)

+

+/* Test witn non-recursive mutex. */

+static int simple_mutex_test(pj_pool_t *pool)

+{

+    pj_status_t rc;

+    pj_mutex_t *mutex;

+

+    PJ_LOG(3,("", "...testing simple mutex"));

+    

+    /* Create mutex. */

+    TRACE_(("", "....create mutex"));

+    rc = pj_mutex_create( pool, "", PJ_MUTEX_SIMPLE, &mutex);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: pj_mutex_create", rc);

+	return -10;

+    }

+

+    /* Normal lock/unlock cycle. */

+    TRACE_(("", "....lock mutex"));

+    rc = pj_mutex_lock(mutex);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: pj_mutex_lock", rc);

+	return -20;

+    }

+    TRACE_(("", "....unlock mutex"));

+    rc = pj_mutex_unlock(mutex);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: pj_mutex_unlock", rc);

+	return -30;

+    }

+    

+    /* Lock again. */

+    TRACE_(("", "....lock mutex"));

+    rc = pj_mutex_lock(mutex);

+    if (rc != PJ_SUCCESS) return -40;

+

+    /* Try-lock should fail. It should not deadlocked. */

+    TRACE_(("", "....trylock mutex"));

+    rc = pj_mutex_trylock(mutex);

+    if (rc == PJ_SUCCESS)

+	PJ_LOG(3,("", "...info: looks like simple mutex is recursive"));

+

+    /* Unlock and done. */

+    TRACE_(("", "....unlock mutex"));

+    rc = pj_mutex_unlock(mutex);

+    if (rc != PJ_SUCCESS) return -50;

+

+    TRACE_(("", "....destroy mutex"));

+    rc = pj_mutex_destroy(mutex);

+    if (rc != PJ_SUCCESS) return -60;

+

+    TRACE_(("", "....done"));

+    return PJ_SUCCESS;

+}

+

+

+/* Test with recursive mutex. */

+static int recursive_mutex_test(pj_pool_t *pool)

+{

+    pj_status_t rc;

+    pj_mutex_t *mutex;

+

+    PJ_LOG(3,("", "...testing recursive mutex"));

+

+    /* Create mutex. */

+    TRACE_(("", "....create mutex"));

+    rc = pj_mutex_create( pool, "", PJ_MUTEX_RECURSE, &mutex);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: pj_mutex_create", rc);

+	return -10;

+    }

+

+    /* Normal lock/unlock cycle. */

+    TRACE_(("", "....lock mutex"));

+    rc = pj_mutex_lock(mutex);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: pj_mutex_lock", rc);

+	return -20;

+    }

+    TRACE_(("", "....unlock mutex"));

+    rc = pj_mutex_unlock(mutex);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: pj_mutex_unlock", rc);

+	return -30;

+    }

+    

+    /* Lock again. */

+    TRACE_(("", "....lock mutex"));

+    rc = pj_mutex_lock(mutex);

+    if (rc != PJ_SUCCESS) return -40;

+

+    /* Try-lock should NOT fail. . */

+    TRACE_(("", "....trylock mutex"));

+    rc = pj_mutex_trylock(mutex);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: recursive mutex is not recursive!", rc);

+	return -40;

+    }

+

+    /* Locking again should not fail. */

+    TRACE_(("", "....lock mutex"));

+    rc = pj_mutex_lock(mutex);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: recursive mutex is not recursive!", rc);

+	return -45;

+    }

+

+    /* Unlock several times and done. */

+    TRACE_(("", "....unlock mutex 3x"));

+    rc = pj_mutex_unlock(mutex);

+    if (rc != PJ_SUCCESS) return -50;

+    rc = pj_mutex_unlock(mutex);

+    if (rc != PJ_SUCCESS) return -51;

+    rc = pj_mutex_unlock(mutex);

+    if (rc != PJ_SUCCESS) return -52;

+

+    TRACE_(("", "....destroy mutex"));

+    rc = pj_mutex_destroy(mutex);

+    if (rc != PJ_SUCCESS) return -60;

+

+    TRACE_(("", "....done"));

+    return PJ_SUCCESS;

+}

+

+int mutex_test(void)

+{

+    pj_pool_t *pool;

+    int rc;

+

+    pool = pj_pool_create(mem, "", 4000, 4000, NULL);

+

+    rc = simple_mutex_test(pool);

+    if (rc != 0)

+	return rc;

+

+    rc = recursive_mutex_test(pool);

+    if (rc != 0)

+	return rc;

+

+    pj_pool_release(pool);

+

+    return 0;

+}

+

+#else

+int dummy_mutex_test;

+#endif

+

diff --git a/pjlib/src/pjlib-test/os.c b/pjlib/src/pjlib-test/os.c
index 6ae733c..da46682 100644
--- a/pjlib/src/pjlib-test/os.c
+++ b/pjlib/src/pjlib-test/os.c
@@ -1,3 +1,24 @@
-/* $Id$
- */
-int dummy_os_var;
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+int dummy_os_var;

diff --git a/pjlib/src/pjlib-test/pool.c b/pjlib/src/pjlib-test/pool.c
index c07d6a7..7541475 100644
--- a/pjlib/src/pjlib-test/pool.c
+++ b/pjlib/src/pjlib-test/pool.c
@@ -1,156 +1,177 @@
-/* $Id$
- */
-#include <pj/pool.h>
-#include <pj/rand.h>
-#include <pj/log.h>
-#include "test.h"
-
-/**
- * \page page_pjlib_pool_test Test: Pool
- *
- * This file provides implementation of \b pool_test(). It tests the
- * functionality of the memory pool.
- *
- *
- * This file is <b>pjlib-test/pool.c</b>
- *
- * \include pjlib-test/pool.c
- */
-
-
-#if INCLUDE_POOL_TEST
-
-#define SIZE	4096
-
-/* Normally we should throw exception when memory alloc fails.
- * Here we do nothing so that the flow will go back to original caller,
- * which will test the result using NULL comparison. Normally caller will
- * catch the exception instead of checking for NULLs.
- */
-static void null_callback(pj_pool_t *pool, pj_size_t size)
-{
-    PJ_UNUSED_ARG(pool);
-    PJ_UNUSED_ARG(size);
-}
-
-#define GET_FREE(p)	(pj_pool_get_capacity(p)-pj_pool_get_used_size(p))
-
-/* Test that the capacity and used size reported by the pool is correct. 
- */
-static int capacity_test(void)
-{
-    pj_pool_t *pool = pj_pool_create(mem, NULL, SIZE, 0, &null_callback);
-    pj_size_t freesize;
-
-    PJ_LOG(3,("test", "...capacity_test()"));
-
-    if (!pool)
-	return -200;
-
-    freesize = GET_FREE(pool);
-
-    if (pj_pool_alloc(pool, freesize) == NULL) {
-	PJ_LOG(3,("test", "...error: wrong freesize %u reported",
-			  freesize));
-	pj_pool_release(pool);
-	return -210;
-    }
-
-    pj_pool_release(pool);
-    return 0;
-}
-
-/* Test function to drain the pool's space. 
- */
-static int drain_test(pj_size_t size, pj_size_t increment)
-{
-    pj_pool_t *pool = pj_pool_create(mem, NULL, size, increment, 
-				     &null_callback);
-    pj_size_t freesize;
-    void *p;
-    int status = 0;
-    
-    PJ_LOG(3,("test", "...drain_test(%d,%d)", size, increment));
-
-    if (!pool)
-	return -10;
-
-    /* Get free size */
-    freesize = GET_FREE(pool);
-    if (freesize < 1) {
-    	status=-15; 
-	goto on_error;
-    }
-
-    /* Drain the pool until there's nothing left. */
-    while (freesize > 0) {
-	int size;
-
-	if (freesize > 255)
-	    size = ((pj_rand() & 0x000000FF) + 4) & ~0x03L;
-	else
-	    size = freesize;
-
-	p = pj_pool_alloc(pool, size);
-	if (!p) {
-	    status=-20; goto on_error;
-	}
-
-	freesize -= size;
-    }
-
-    /* Check that capacity is zero. */
-    if (GET_FREE(pool) != 0) {
-	PJ_LOG(3,("test", "....error: returned free=%u (expecting 0)",
-		  GET_FREE(pool)));
-	status=-30; goto on_error;
-    }
-
-    /* Try to allocate once more */
-    p = pj_pool_alloc(pool, 257);
-    if (!p) {
-	status=-40; goto on_error;
-    }
-
-    /* Check that capacity is NOT zero. */
-    if (GET_FREE(pool) == 0) {
-	status=-50; goto on_error;
-    }
-
-
-on_error:
-    pj_pool_release(pool);
-    return status;
-}
-
-int pool_test(void)
-{
-    enum { LOOP = 2 };
-    int loop;
-    int rc;
-
-    rc = capacity_test();
-    if (rc) return rc;
-
-    for (loop=0; loop<LOOP; ++loop) {
-	/* Test that the pool should grow automaticly. */
-	rc = drain_test(SIZE, SIZE);
-	if (rc != 0) return rc;
-
-	/* Test situation where pool is not allowed to grow. 
- 	 * We expect the test to return correct error.
-	 */
-	rc = drain_test(SIZE, 0);
-	if (rc != -40) return rc;
-    }
-
-    return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_pool_test;
-#endif	/* INCLUDE_POOL_TEST */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/pool.h>

+#include <pj/rand.h>

+#include <pj/log.h>

+#include "test.h"

+

+/**

+ * \page page_pjlib_pool_test Test: Pool

+ *

+ * This file provides implementation of \b pool_test(). It tests the

+ * functionality of the memory pool.

+ *

+ *

+ * This file is <b>pjlib-test/pool.c</b>

+ *

+ * \include pjlib-test/pool.c

+ */

+

+

+#if INCLUDE_POOL_TEST

+

+#define SIZE	4096

+

+/* Normally we should throw exception when memory alloc fails.

+ * Here we do nothing so that the flow will go back to original caller,

+ * which will test the result using NULL comparison. Normally caller will

+ * catch the exception instead of checking for NULLs.

+ */

+static void null_callback(pj_pool_t *pool, pj_size_t size)

+{

+    PJ_UNUSED_ARG(pool);

+    PJ_UNUSED_ARG(size);

+}

+

+#define GET_FREE(p)	(pj_pool_get_capacity(p)-pj_pool_get_used_size(p))

+

+/* Test that the capacity and used size reported by the pool is correct. 

+ */

+static int capacity_test(void)

+{

+    pj_pool_t *pool = pj_pool_create(mem, NULL, SIZE, 0, &null_callback);

+    pj_size_t freesize;

+

+    PJ_LOG(3,("test", "...capacity_test()"));

+

+    if (!pool)

+	return -200;

+

+    freesize = GET_FREE(pool);

+

+    if (pj_pool_alloc(pool, freesize) == NULL) {

+	PJ_LOG(3,("test", "...error: wrong freesize %u reported",

+			  freesize));

+	pj_pool_release(pool);

+	return -210;

+    }

+

+    pj_pool_release(pool);

+    return 0;

+}

+

+/* Test function to drain the pool's space. 

+ */

+static int drain_test(pj_size_t size, pj_size_t increment)

+{

+    pj_pool_t *pool = pj_pool_create(mem, NULL, size, increment, 

+				     &null_callback);

+    pj_size_t freesize;

+    void *p;

+    int status = 0;

+    

+    PJ_LOG(3,("test", "...drain_test(%d,%d)", size, increment));

+

+    if (!pool)

+	return -10;

+

+    /* Get free size */

+    freesize = GET_FREE(pool);

+    if (freesize < 1) {

+    	status=-15; 

+	goto on_error;

+    }

+

+    /* Drain the pool until there's nothing left. */

+    while (freesize > 0) {

+	int size;

+

+	if (freesize > 255)

+	    size = ((pj_rand() & 0x000000FF) + 4) & ~0x03L;

+	else

+	    size = freesize;

+

+	p = pj_pool_alloc(pool, size);

+	if (!p) {

+	    status=-20; goto on_error;

+	}

+

+	freesize -= size;

+    }

+

+    /* Check that capacity is zero. */

+    if (GET_FREE(pool) != 0) {

+	PJ_LOG(3,("test", "....error: returned free=%u (expecting 0)",

+		  GET_FREE(pool)));

+	status=-30; goto on_error;

+    }

+

+    /* Try to allocate once more */

+    p = pj_pool_alloc(pool, 257);

+    if (!p) {

+	status=-40; goto on_error;

+    }

+

+    /* Check that capacity is NOT zero. */

+    if (GET_FREE(pool) == 0) {

+	status=-50; goto on_error;

+    }

+

+

+on_error:

+    pj_pool_release(pool);

+    return status;

+}

+

+int pool_test(void)

+{

+    enum { LOOP = 2 };

+    int loop;

+    int rc;

+

+    rc = capacity_test();

+    if (rc) return rc;

+

+    for (loop=0; loop<LOOP; ++loop) {

+	/* Test that the pool should grow automaticly. */

+	rc = drain_test(SIZE, SIZE);

+	if (rc != 0) return rc;

+

+	/* Test situation where pool is not allowed to grow. 

+ 	 * We expect the test to return correct error.

+	 */

+	rc = drain_test(SIZE, 0);

+	if (rc != -40) return rc;

+    }

+

+    return 0;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_pool_test;

+#endif	/* INCLUDE_POOL_TEST */

+

diff --git a/pjlib/src/pjlib-test/pool_perf.c b/pjlib/src/pjlib-test/pool_perf.c
index 7482710..d5c55a6 100644
--- a/pjlib/src/pjlib-test/pool_perf.c
+++ b/pjlib/src/pjlib-test/pool_perf.c
@@ -1,124 +1,145 @@
-/* $Id$
- */
-#include "test.h"
-
-#if INCLUDE_POOL_PERF_TEST
-
-#include <pjlib.h>
-#include <pj/compat/malloc.h>
-
-#if !PJ_HAS_HIGH_RES_TIMER
-# error Need high resolution timer for this test.
-#endif
-
-#define THIS_FILE   "test"
-
-#define LOOP	    10
-#define COUNT	    1024
-static unsigned	    sizes[COUNT];
-#define MIN_SIZE    4
-#define MAX_SIZE    512
-static unsigned total_size;
-
-static int pool_test_pool()
-{
-    int i;
-    pj_pool_t *pool = pj_pool_create(mem, NULL, total_size + 4*COUNT, 0, NULL);
-    if (!pool)
-	return -1;
-
-    for (i=0; i<COUNT; ++i) {
-	char *p;
-	if ( (p=(char*)pj_pool_alloc(pool, sizes[i])) == NULL)
-	    return -1;
-	*p = '\0';
-    }
-
-    pj_pool_release(pool);
-    return 0;
-}
-
-static int pool_test_malloc_free()
-{
-    char *p[COUNT];
-    int i;
-
-    for (i=0; i<COUNT; ++i) {
-	p[i] = (char*)malloc(sizes[i]);
-	if (!p[i]) {
-	    // Don't care for memory leak in this test
-	    return -1;
-	}
-	*p[i] = '\0';
-    }
-
-    for (i=0; i<COUNT; ++i) {
-	free(p[i]);
-    }
-
-    return 0;
-}
-
-int pool_perf_test()
-{
-    unsigned i;
-    pj_uint32_t pool_time=0, malloc_time=0, pool_time2=0;
-    pj_timestamp start, end;
-    pj_uint32_t best, worst;
-
-    // Initialize sizes.
-    for (i=0; i<COUNT; ++i) {
-	sizes[i] = MIN_SIZE + pj_rand() % MAX_SIZE;
-	total_size += sizes[i];
-    }
-
-    PJ_LOG(3, (THIS_FILE, "Benchmarking pool.."));
-
-    // Warmup
-    pool_test_pool();
-    pool_test_malloc_free();
-
-    for (i=0; i<LOOP; ++i) {
-	pj_get_timestamp(&start);
-	if (pool_test_pool()) {
-	    return 1;
-	}
-	pj_get_timestamp(&end);
-	pool_time += (end.u32.lo - start.u32.lo);
-
-	pj_get_timestamp(&start);
-	if (pool_test_malloc_free()) {
-	    return 2;
-	}
-	pj_get_timestamp(&end);
-	malloc_time += (end.u32.lo - start.u32.lo);
-
-	pj_get_timestamp(&start);
-	if (pool_test_pool()) {
-	    return 4;
-	}
-	pj_get_timestamp(&end);
-	pool_time2 += (end.u32.lo - start.u32.lo);
-    }
-
-    PJ_LOG(4, (THIS_FILE, "..LOOP count:                        %u", LOOP));
-    PJ_LOG(4, (THIS_FILE, "..number of alloc/dealloc per loop:  %u", COUNT));
-    PJ_LOG(4, (THIS_FILE, "..pool allocation/deallocation time: %u", pool_time));
-    PJ_LOG(4, (THIS_FILE, "..malloc/free time:                  %u", malloc_time));
-    PJ_LOG(4, (THIS_FILE, "..pool again, second invocation:     %u", pool_time2));
-
-    if (pool_time2==0) pool_time2=1;
-    if (pool_time < pool_time2)
-	best = pool_time, worst = pool_time2;
-    else
-	best = pool_time2, worst = pool_time;
-
-    PJ_LOG(3, (THIS_FILE, "..malloc Speedup best=%dx, worst=%dx", 
-			  (int)(malloc_time/best),
-			  (int)(malloc_time/worst)));
-    return 0;
-}
-
-
-#endif	/* INCLUDE_POOL_PERF_TEST */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+#if INCLUDE_POOL_PERF_TEST

+

+#include <pjlib.h>

+#include <pj/compat/malloc.h>

+

+#if !PJ_HAS_HIGH_RES_TIMER

+# error Need high resolution timer for this test.

+#endif

+

+#define THIS_FILE   "test"

+

+#define LOOP	    10

+#define COUNT	    1024

+static unsigned	    sizes[COUNT];

+#define MIN_SIZE    4

+#define MAX_SIZE    512

+static unsigned total_size;

+

+static int pool_test_pool()

+{

+    int i;

+    pj_pool_t *pool = pj_pool_create(mem, NULL, total_size + 4*COUNT, 0, NULL);

+    if (!pool)

+	return -1;

+

+    for (i=0; i<COUNT; ++i) {

+	char *p;

+	if ( (p=(char*)pj_pool_alloc(pool, sizes[i])) == NULL)

+	    return -1;

+	*p = '\0';

+    }

+

+    pj_pool_release(pool);

+    return 0;

+}

+

+static int pool_test_malloc_free()

+{

+    char *p[COUNT];

+    int i;

+

+    for (i=0; i<COUNT; ++i) {

+	p[i] = (char*)malloc(sizes[i]);

+	if (!p[i]) {

+	    // Don't care for memory leak in this test

+	    return -1;

+	}

+	*p[i] = '\0';

+    }

+

+    for (i=0; i<COUNT; ++i) {

+	free(p[i]);

+    }

+

+    return 0;

+}

+

+int pool_perf_test()

+{

+    unsigned i;

+    pj_uint32_t pool_time=0, malloc_time=0, pool_time2=0;

+    pj_timestamp start, end;

+    pj_uint32_t best, worst;

+

+    // Initialize sizes.

+    for (i=0; i<COUNT; ++i) {

+	sizes[i] = MIN_SIZE + pj_rand() % MAX_SIZE;

+	total_size += sizes[i];

+    }

+

+    PJ_LOG(3, (THIS_FILE, "Benchmarking pool.."));

+

+    // Warmup

+    pool_test_pool();

+    pool_test_malloc_free();

+

+    for (i=0; i<LOOP; ++i) {

+	pj_get_timestamp(&start);

+	if (pool_test_pool()) {

+	    return 1;

+	}

+	pj_get_timestamp(&end);

+	pool_time += (end.u32.lo - start.u32.lo);

+

+	pj_get_timestamp(&start);

+	if (pool_test_malloc_free()) {

+	    return 2;

+	}

+	pj_get_timestamp(&end);

+	malloc_time += (end.u32.lo - start.u32.lo);

+

+	pj_get_timestamp(&start);

+	if (pool_test_pool()) {

+	    return 4;

+	}

+	pj_get_timestamp(&end);

+	pool_time2 += (end.u32.lo - start.u32.lo);

+    }

+

+    PJ_LOG(4, (THIS_FILE, "..LOOP count:                        %u", LOOP));

+    PJ_LOG(4, (THIS_FILE, "..number of alloc/dealloc per loop:  %u", COUNT));

+    PJ_LOG(4, (THIS_FILE, "..pool allocation/deallocation time: %u", pool_time));

+    PJ_LOG(4, (THIS_FILE, "..malloc/free time:                  %u", malloc_time));

+    PJ_LOG(4, (THIS_FILE, "..pool again, second invocation:     %u", pool_time2));

+

+    if (pool_time2==0) pool_time2=1;

+    if (pool_time < pool_time2)

+	best = pool_time, worst = pool_time2;

+    else

+	best = pool_time2, worst = pool_time;

+

+    PJ_LOG(3, (THIS_FILE, "..malloc Speedup best=%dx, worst=%dx", 

+			  (int)(malloc_time/best),

+			  (int)(malloc_time/worst)));

+    return 0;

+}

+

+

+#endif	/* INCLUDE_POOL_PERF_TEST */

+

diff --git a/pjlib/src/pjlib-test/rand.c b/pjlib/src/pjlib-test/rand.c
index 55efa86..d39089d 100644
--- a/pjlib/src/pjlib-test/rand.c
+++ b/pjlib/src/pjlib-test/rand.c
@@ -1,37 +1,58 @@
-/* $Id$
- */
-#include <pj/rand.h>
-#include <pj/log.h>
-#include "test.h"
-
-#if INCLUDE_RAND_TEST
-
-#define COUNT  1024
-static int values[COUNT];
-
-/*
- * rand_test(), simply generates COUNT number of random number and
- * check that there's no duplicate numbers.
- */
-int rand_test(void)
-{
-    int i;
-
-    for (i=0; i<COUNT; ++i) {
-	int j;
-
-	values[i] = pj_rand();
-	for (j=0; j<i; ++j) {
-	    if (values[i] == values[j]) {
-		PJ_LOG(3,("test", "error: duplicate value %d at %d-th index",
-			 values[i], i));
-		return -10;
-	    }
-	}
-    }
-
-    return 0;
-}
-
-#endif	/* INCLUDE_RAND_TEST */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/rand.h>

+#include <pj/log.h>

+#include "test.h"

+

+#if INCLUDE_RAND_TEST

+

+#define COUNT  1024

+static int values[COUNT];

+

+/*

+ * rand_test(), simply generates COUNT number of random number and

+ * check that there's no duplicate numbers.

+ */

+int rand_test(void)

+{

+    int i;

+

+    for (i=0; i<COUNT; ++i) {

+	int j;

+

+	values[i] = pj_rand();

+	for (j=0; j<i; ++j) {

+	    if (values[i] == values[j]) {

+		PJ_LOG(3,("test", "error: duplicate value %d at %d-th index",

+			 values[i], i));

+		return -10;

+	    }

+	}

+    }

+

+    return 0;

+}

+

+#endif	/* INCLUDE_RAND_TEST */

+

diff --git a/pjlib/src/pjlib-test/rbtree.c b/pjlib/src/pjlib-test/rbtree.c
index 475ce0c..c7324ca 100644
--- a/pjlib/src/pjlib-test/rbtree.c
+++ b/pjlib/src/pjlib-test/rbtree.c
@@ -1,151 +1,172 @@
-/* $Id$
- */
-#include "test.h"
-
-#if INCLUDE_RBTREE_TEST
-
-#include <pjlib.h>
-
-#define LOOP	    32
-#define MIN_COUNT   64
-#define MAX_COUNT   (LOOP * MIN_COUNT)
-#define STRSIZE	    16
-#define THIS_FILE   "rbtree_test"
-
-typedef struct node_key
-{
-    pj_uint32_t hash;
-    char str[STRSIZE];
-} node_key;
-
-static int compare_node(const node_key *k1, const node_key *k2)
-{
-    if (k1->hash == k2->hash) {
-	return strcmp(k1->str, k2->str);
-    } else {
-	return k1->hash	< k2->hash ? -1 : 1;
-    }
-}
-
-void randomize_string(char *str, int len)
-{
-    int i;
-    for (i=0; i<len-1; ++i)
-	str[i] = (char)('a' + pj_rand() % 26);
-    str[len-1] = '\0';
-}
-
-static int test(void)
-{
-    pj_rbtree rb;
-    node_key *key;
-    pj_rbtree_node *node;
-    pj_pool_t *pool;
-    int err=0;
-    int count = MIN_COUNT;
-    int i;
-    unsigned size;
-
-    pj_rbtree_init(&rb, (pj_rbtree_comp*)&compare_node);
-    size = MAX_COUNT*(sizeof(*key)+PJ_RBTREE_NODE_SIZE) + 
-			   PJ_RBTREE_SIZE + PJ_POOL_SIZE;
-    pool = pj_pool_create( mem, "pool", size, 0, NULL);
-    if (!pool) {
-	PJ_LOG(3,("test", "...error: creating pool of %u bytes", size));
-	return -10;
-    }
-
-    key = (node_key *)pj_pool_alloc(pool, MAX_COUNT*sizeof(*key));
-    if (!key)
-	return -20;
-
-    node = (pj_rbtree_node*)pj_pool_alloc(pool, MAX_COUNT*sizeof(*node));
-    if (!node)
-	return -30;
-
-    for (i=0; i<LOOP; ++i) {
-	int j;
-	pj_rbtree_node *prev, *it;
-	pj_timestamp t1, t2, t_setup, t_insert, t_search, t_erase;
-
-	pj_assert(rb.size == 0);
-
-	t_setup.u32.lo = t_insert.u32.lo = t_search.u32.lo = t_erase.u32.lo = 0;
-
-	for (j=0; j<count; j++) {
-	    randomize_string(key[j].str, STRSIZE);
-
-	    pj_get_timestamp(&t1);
-	    node[j].key = &key[j];
-	    node[j].user_data = key[j].str;
-	    key[j].hash = pj_hash_calc(0, key[j].str, PJ_HASH_KEY_STRING);
-	    pj_get_timestamp(&t2);
-	    t_setup.u32.lo += (t2.u32.lo - t1.u32.lo);
-
-	    pj_get_timestamp(&t1);
-	    pj_rbtree_insert(&rb, &node[j]);
-	    pj_get_timestamp(&t2);
-	    t_insert.u32.lo += (t2.u32.lo - t1.u32.lo);
-	}
-
-	pj_assert(rb.size == (unsigned)count);
-
-	// Iterate key, make sure they're sorted.
-	prev = NULL;
-	it = pj_rbtree_first(&rb);
-	while (it) {
-	    if (prev) {
-		if (compare_node((node_key*)prev->key,(node_key*)it->key)>=0) {
-		    ++err;
-		    PJ_LOG(3, (THIS_FILE, "Error: %s >= %s", 
-			       (char*)prev->user_data, (char*)it->user_data));
-		}
-	    }
-	    prev = it;
-	    it = pj_rbtree_next(&rb, it);
-	}
-
-	// Search.
-	for (j=0; j<count; j++) {
-	    pj_get_timestamp(&t1);
-	    it = pj_rbtree_find(&rb, &key[j]);
-	    pj_get_timestamp(&t2);
-	    t_search.u32.lo += (t2.u32.lo - t1.u32.lo);
-
-	    pj_assert(it != NULL);
-	    if (it == NULL)
-		++err;
-	}
-
-	// Erase node.
-	for (j=0; j<count; j++) {
-	    pj_get_timestamp(&t1);
-	    it = pj_rbtree_erase(&rb, &node[j]);
-	    pj_get_timestamp(&t2);
-	    t_erase.u32.lo += (t2.u32.lo - t1.u32.lo);
-	}
-
-	PJ_LOG(4, (THIS_FILE, 
-		"...count:%d, setup:%d, insert:%d, search:%d, erase:%d",
-		count,
-		t_setup.u32.lo / count, t_insert.u32.lo / count,
-		t_search.u32.lo / count, t_erase.u32.lo / count));
-
-	count = 2 * count;
-	if (count > MAX_COUNT)
-	    break;
-    }
-
-    pj_pool_release(pool);
-    return err;
-}
-
-
-int rbtree_test()
-{
-    return test();
-}
-
-#endif	/* INCLUDE_RBTREE_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+#if INCLUDE_RBTREE_TEST

+

+#include <pjlib.h>

+

+#define LOOP	    32

+#define MIN_COUNT   64

+#define MAX_COUNT   (LOOP * MIN_COUNT)

+#define STRSIZE	    16

+#define THIS_FILE   "rbtree_test"

+

+typedef struct node_key

+{

+    pj_uint32_t hash;

+    char str[STRSIZE];

+} node_key;

+

+static int compare_node(const node_key *k1, const node_key *k2)

+{

+    if (k1->hash == k2->hash) {

+	return strcmp(k1->str, k2->str);

+    } else {

+	return k1->hash	< k2->hash ? -1 : 1;

+    }

+}

+

+void randomize_string(char *str, int len)

+{

+    int i;

+    for (i=0; i<len-1; ++i)

+	str[i] = (char)('a' + pj_rand() % 26);

+    str[len-1] = '\0';

+}

+

+static int test(void)

+{

+    pj_rbtree rb;

+    node_key *key;

+    pj_rbtree_node *node;

+    pj_pool_t *pool;

+    int err=0;

+    int count = MIN_COUNT;

+    int i;

+    unsigned size;

+

+    pj_rbtree_init(&rb, (pj_rbtree_comp*)&compare_node);

+    size = MAX_COUNT*(sizeof(*key)+PJ_RBTREE_NODE_SIZE) + 

+			   PJ_RBTREE_SIZE + PJ_POOL_SIZE;

+    pool = pj_pool_create( mem, "pool", size, 0, NULL);

+    if (!pool) {

+	PJ_LOG(3,("test", "...error: creating pool of %u bytes", size));

+	return -10;

+    }

+

+    key = (node_key *)pj_pool_alloc(pool, MAX_COUNT*sizeof(*key));

+    if (!key)

+	return -20;

+

+    node = (pj_rbtree_node*)pj_pool_alloc(pool, MAX_COUNT*sizeof(*node));

+    if (!node)

+	return -30;

+

+    for (i=0; i<LOOP; ++i) {

+	int j;

+	pj_rbtree_node *prev, *it;

+	pj_timestamp t1, t2, t_setup, t_insert, t_search, t_erase;

+

+	pj_assert(rb.size == 0);

+

+	t_setup.u32.lo = t_insert.u32.lo = t_search.u32.lo = t_erase.u32.lo = 0;

+

+	for (j=0; j<count; j++) {

+	    randomize_string(key[j].str, STRSIZE);

+

+	    pj_get_timestamp(&t1);

+	    node[j].key = &key[j];

+	    node[j].user_data = key[j].str;

+	    key[j].hash = pj_hash_calc(0, key[j].str, PJ_HASH_KEY_STRING);

+	    pj_get_timestamp(&t2);

+	    t_setup.u32.lo += (t2.u32.lo - t1.u32.lo);

+

+	    pj_get_timestamp(&t1);

+	    pj_rbtree_insert(&rb, &node[j]);

+	    pj_get_timestamp(&t2);

+	    t_insert.u32.lo += (t2.u32.lo - t1.u32.lo);

+	}

+

+	pj_assert(rb.size == (unsigned)count);

+

+	// Iterate key, make sure they're sorted.

+	prev = NULL;

+	it = pj_rbtree_first(&rb);

+	while (it) {

+	    if (prev) {

+		if (compare_node((node_key*)prev->key,(node_key*)it->key)>=0) {

+		    ++err;

+		    PJ_LOG(3, (THIS_FILE, "Error: %s >= %s", 

+			       (char*)prev->user_data, (char*)it->user_data));

+		}

+	    }

+	    prev = it;

+	    it = pj_rbtree_next(&rb, it);

+	}

+

+	// Search.

+	for (j=0; j<count; j++) {

+	    pj_get_timestamp(&t1);

+	    it = pj_rbtree_find(&rb, &key[j]);

+	    pj_get_timestamp(&t2);

+	    t_search.u32.lo += (t2.u32.lo - t1.u32.lo);

+

+	    pj_assert(it != NULL);

+	    if (it == NULL)

+		++err;

+	}

+

+	// Erase node.

+	for (j=0; j<count; j++) {

+	    pj_get_timestamp(&t1);

+	    it = pj_rbtree_erase(&rb, &node[j]);

+	    pj_get_timestamp(&t2);

+	    t_erase.u32.lo += (t2.u32.lo - t1.u32.lo);

+	}

+

+	PJ_LOG(4, (THIS_FILE, 

+		"...count:%d, setup:%d, insert:%d, search:%d, erase:%d",

+		count,

+		t_setup.u32.lo / count, t_insert.u32.lo / count,

+		t_search.u32.lo / count, t_erase.u32.lo / count));

+

+	count = 2 * count;

+	if (count > MAX_COUNT)

+	    break;

+    }

+

+    pj_pool_release(pool);

+    return err;

+}

+

+

+int rbtree_test()

+{

+    return test();

+}

+

+#endif	/* INCLUDE_RBTREE_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/select.c b/pjlib/src/pjlib-test/select.c
index 4d1fe1b..6ebc76a 100644
--- a/pjlib/src/pjlib-test/select.c
+++ b/pjlib/src/pjlib-test/select.c
@@ -1,201 +1,222 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_select_test Test: Socket Select()
- *
- * This file provides implementation of \b select_test(). It tests the
- * functionality of the pj_sock_select() API.
- *
- *
- * This file is <b>pjlib-test/select.c</b>
- *
- * \include pjlib-test/select.c
- */
-
-
-#if INCLUDE_SELECT_TEST
-
-#include <pj/sock.h>
-#include <pj/sock_select.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/assert.h>
-#include <pj/os.h>
-#include <pj/errno.h>
-
-enum
-{
-    READ_FDS,
-    WRITE_FDS,
-    EXCEPT_FDS
-};
-
-#define UDP_PORT    51232
-#define THIS_FILE   "select_test"
-
-/*
- * do_select()
- *
- * Perform pj_sock_select() and find out which sockets
- * are signalled.
- */    
-static int do_select( pj_sock_t sock1, pj_sock_t sock2,
-		      int setcount[])
-{
-    pj_fd_set_t fds[3];
-    pj_time_val timeout;
-    int i, n;
-    
-    for (i=0; i<3; ++i) {
-        PJ_FD_ZERO(&fds[i]);
-        PJ_FD_SET(sock1, &fds[i]);
-        PJ_FD_SET(sock2, &fds[i]);
-        setcount[i] = 0;
-    }
-
-    timeout.sec = 1;
-    timeout.msec = 0;
-
-    n = pj_sock_select(FD_SETSIZE, &fds[0], &fds[1], &fds[2],
-		       &timeout);
-    if (n < 0)
-        return n;
-    if (n == 0)
-        return 0;
-
-    for (i=0; i<3; ++i) {
-        if (PJ_FD_ISSET(sock1, &fds[i]))
-            setcount[i]++;
-        if (PJ_FD_ISSET(sock2, &fds[i]))
-	    setcount[i]++;
-    }
-
-    return n;
-}
-
-/*
- * select_test()
- *
- * Test main entry.
- */
-int select_test()
-{
-    pj_sock_t udp1=PJ_INVALID_SOCKET, udp2=PJ_INVALID_SOCKET;
-    pj_sockaddr_in udp_addr;
-    int status;
-    int setcount[3];
-    pj_str_t s;
-    const char data[] = "hello";
-    const int datalen = 5;
-    pj_ssize_t sent, received;
-    char buf[10];
-    pj_status_t rc;
-
-    PJ_LOG(3, (THIS_FILE, "...Testing simple UDP select()"));
-    
-    // Create two UDP sockets.
-    rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp1);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error: unable to create socket", rc);
-	status=-10; goto on_return;
-    }
-    rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp2);
-    if (udp2 == PJ_INVALID_SOCKET) {
-        app_perror("...error: unable to create socket", rc);
-	status=-20; goto on_return;
-    }
-
-    // Bind one of the UDP socket.
-    pj_memset(&udp_addr, 0, sizeof(udp_addr));
-    udp_addr.sin_family = PJ_AF_INET;
-    udp_addr.sin_port = UDP_PORT;
-    udp_addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-
-    if (pj_sock_bind(udp2, &udp_addr, sizeof(udp_addr))) {
-	status=-30; goto on_return;
-    }
-
-    // Send data.
-    sent = datalen;
-    rc = pj_sock_sendto(udp1, data, &sent, 0, &udp_addr, sizeof(udp_addr));
-    if (rc != PJ_SUCCESS || sent != datalen) {
-        app_perror("...error: sendto() error", rc);
-	status=-40; goto on_return;
-    }
-
-    // Check that socket is marked as reable.
-    // Note that select() may also report that sockets are writable.
-    status = do_select(udp1, udp2, setcount);
-    if (status < 0) {
-	char errbuf[128];
-        pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf));
-	PJ_LOG(1,(THIS_FILE, "...error: %s", errbuf));
-	status=-50; goto on_return;
-    }
-    if (status == 0) {
-	status=-60; goto on_return;
-    }
-
-    if (setcount[READ_FDS] != 1) {
-	status=-70; goto on_return;
-    }
-    if (setcount[WRITE_FDS] != 0) {
-	if (setcount[WRITE_FDS] == 2) {
-	    PJ_LOG(3,(THIS_FILE, "...info: system reports writable sockets"));
-	} else {
-	    status=-80; goto on_return;
-	}
-    } else {
-	PJ_LOG(3,(THIS_FILE, 
-		  "...info: system doesn't report writable sockets"));
-    }
-    if (setcount[EXCEPT_FDS] != 0) {
-	status=-90; goto on_return;
-    }
-
-    // Read the socket to clear readable sockets.
-    received = sizeof(buf);
-    rc = pj_sock_recv(udp2, buf, &received, 0);
-    if (rc != PJ_SUCCESS || received != 5) {
-	status=-100; goto on_return;
-    }
-    
-    status = 0;
-
-    // Test timeout on the read part.
-    // This won't necessarily return zero, as select() may report that
-    // sockets are writable.
-    setcount[0] = setcount[1] = setcount[2] = 0;
-    status = do_select(udp1, udp2, setcount);
-    if (status != 0 && status != setcount[WRITE_FDS]) {
-	PJ_LOG(3,(THIS_FILE, "...error: expecting timeout but got %d sks set",
-			     status));
-	PJ_LOG(3,(THIS_FILE, "          rdset: %d, wrset: %d, exset: %d",
-			     setcount[0], setcount[1], setcount[2]));
-	status = -110; goto on_return;
-    }
-    if (setcount[READ_FDS] != 0) {
-	PJ_LOG(3,(THIS_FILE, "...error: readable socket not expected"));
-	status = -120; goto on_return;
-    }
-
-    status = 0;
-
-on_return:
-    if (udp1 != PJ_INVALID_SOCKET)
-	pj_sock_close(udp1);
-    if (udp2 != PJ_INVALID_SOCKET)
-	pj_sock_close(udp2);
-    return status;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_select_test;
-#endif	/* INCLUDE_SELECT_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+/**

+ * \page page_pjlib_select_test Test: Socket Select()

+ *

+ * This file provides implementation of \b select_test(). It tests the

+ * functionality of the pj_sock_select() API.

+ *

+ *

+ * This file is <b>pjlib-test/select.c</b>

+ *

+ * \include pjlib-test/select.c

+ */

+

+

+#if INCLUDE_SELECT_TEST

+

+#include <pj/sock.h>

+#include <pj/sock_select.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/assert.h>

+#include <pj/os.h>

+#include <pj/errno.h>

+

+enum

+{

+    READ_FDS,

+    WRITE_FDS,

+    EXCEPT_FDS

+};

+

+#define UDP_PORT    51232

+#define THIS_FILE   "select_test"

+

+/*

+ * do_select()

+ *

+ * Perform pj_sock_select() and find out which sockets

+ * are signalled.

+ */    

+static int do_select( pj_sock_t sock1, pj_sock_t sock2,

+		      int setcount[])

+{

+    pj_fd_set_t fds[3];

+    pj_time_val timeout;

+    int i, n;

+    

+    for (i=0; i<3; ++i) {

+        PJ_FD_ZERO(&fds[i]);

+        PJ_FD_SET(sock1, &fds[i]);

+        PJ_FD_SET(sock2, &fds[i]);

+        setcount[i] = 0;

+    }

+

+    timeout.sec = 1;

+    timeout.msec = 0;

+

+    n = pj_sock_select(FD_SETSIZE, &fds[0], &fds[1], &fds[2],

+		       &timeout);

+    if (n < 0)

+        return n;

+    if (n == 0)

+        return 0;

+

+    for (i=0; i<3; ++i) {

+        if (PJ_FD_ISSET(sock1, &fds[i]))

+            setcount[i]++;

+        if (PJ_FD_ISSET(sock2, &fds[i]))

+	    setcount[i]++;

+    }

+

+    return n;

+}

+

+/*

+ * select_test()

+ *

+ * Test main entry.

+ */

+int select_test()

+{

+    pj_sock_t udp1=PJ_INVALID_SOCKET, udp2=PJ_INVALID_SOCKET;

+    pj_sockaddr_in udp_addr;

+    int status;

+    int setcount[3];

+    pj_str_t s;

+    const char data[] = "hello";

+    const int datalen = 5;

+    pj_ssize_t sent, received;

+    char buf[10];

+    pj_status_t rc;

+

+    PJ_LOG(3, (THIS_FILE, "...Testing simple UDP select()"));

+    

+    // Create two UDP sockets.

+    rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp1);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error: unable to create socket", rc);

+	status=-10; goto on_return;

+    }

+    rc = pj_sock_socket( PJ_AF_INET, PJ_SOCK_DGRAM, 0, &udp2);

+    if (udp2 == PJ_INVALID_SOCKET) {

+        app_perror("...error: unable to create socket", rc);

+	status=-20; goto on_return;

+    }

+

+    // Bind one of the UDP socket.

+    pj_memset(&udp_addr, 0, sizeof(udp_addr));

+    udp_addr.sin_family = PJ_AF_INET;

+    udp_addr.sin_port = UDP_PORT;

+    udp_addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));

+

+    if (pj_sock_bind(udp2, &udp_addr, sizeof(udp_addr))) {

+	status=-30; goto on_return;

+    }

+

+    // Send data.

+    sent = datalen;

+    rc = pj_sock_sendto(udp1, data, &sent, 0, &udp_addr, sizeof(udp_addr));

+    if (rc != PJ_SUCCESS || sent != datalen) {

+        app_perror("...error: sendto() error", rc);

+	status=-40; goto on_return;

+    }

+

+    // Check that socket is marked as reable.

+    // Note that select() may also report that sockets are writable.

+    status = do_select(udp1, udp2, setcount);

+    if (status < 0) {

+	char errbuf[128];

+        pj_strerror(pj_get_netos_error(), errbuf, sizeof(errbuf));

+	PJ_LOG(1,(THIS_FILE, "...error: %s", errbuf));

+	status=-50; goto on_return;

+    }

+    if (status == 0) {

+	status=-60; goto on_return;

+    }

+

+    if (setcount[READ_FDS] != 1) {

+	status=-70; goto on_return;

+    }

+    if (setcount[WRITE_FDS] != 0) {

+	if (setcount[WRITE_FDS] == 2) {

+	    PJ_LOG(3,(THIS_FILE, "...info: system reports writable sockets"));

+	} else {

+	    status=-80; goto on_return;

+	}

+    } else {

+	PJ_LOG(3,(THIS_FILE, 

+		  "...info: system doesn't report writable sockets"));

+    }

+    if (setcount[EXCEPT_FDS] != 0) {

+	status=-90; goto on_return;

+    }

+

+    // Read the socket to clear readable sockets.

+    received = sizeof(buf);

+    rc = pj_sock_recv(udp2, buf, &received, 0);

+    if (rc != PJ_SUCCESS || received != 5) {

+	status=-100; goto on_return;

+    }

+    

+    status = 0;

+

+    // Test timeout on the read part.

+    // This won't necessarily return zero, as select() may report that

+    // sockets are writable.

+    setcount[0] = setcount[1] = setcount[2] = 0;

+    status = do_select(udp1, udp2, setcount);

+    if (status != 0 && status != setcount[WRITE_FDS]) {

+	PJ_LOG(3,(THIS_FILE, "...error: expecting timeout but got %d sks set",

+			     status));

+	PJ_LOG(3,(THIS_FILE, "          rdset: %d, wrset: %d, exset: %d",

+			     setcount[0], setcount[1], setcount[2]));

+	status = -110; goto on_return;

+    }

+    if (setcount[READ_FDS] != 0) {

+	PJ_LOG(3,(THIS_FILE, "...error: readable socket not expected"));

+	status = -120; goto on_return;

+    }

+

+    status = 0;

+

+on_return:

+    if (udp1 != PJ_INVALID_SOCKET)

+	pj_sock_close(udp1);

+    if (udp2 != PJ_INVALID_SOCKET)

+	pj_sock_close(udp2);

+    return status;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_select_test;

+#endif	/* INCLUDE_SELECT_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/sleep.c b/pjlib/src/pjlib-test/sleep.c
index 6281e4d..07b5696 100644
--- a/pjlib/src/pjlib-test/sleep.c
+++ b/pjlib/src/pjlib-test/sleep.c
@@ -1,184 +1,205 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_sleep_test Test: Sleep, Time, and Timestamp
- *
- * This file provides implementation of \b sleep_test().
- *
- * \section sleep_test_sec Scope of the Test
- *
- * This tests:
- *  - whether pj_thread_sleep() works.
- *  - whether pj_gettimeofday() works.
- *  - whether pj_get_timestamp() and friends works.
- *
- * API tested:
- *  - pj_thread_sleep()
- *  - pj_gettimeofday()
- *  - PJ_TIME_VAL_SUB()
- *  - PJ_TIME_VAL_LTE()
- *  - pj_get_timestamp()
- *  - pj_get_timestamp_freq() (implicitly)
- *  - pj_elapsed_time()
- *  - pj_elapsed_usec()
- *
- *
- * This file is <b>pjlib-test/sleep.c</b>
- *
- * \include pjlib-test/sleep.c
- */
-
-#if INCLUDE_SLEEP_TEST
-
-#include <pjlib.h>
-
-#define THIS_FILE   "sleep_test"
-
-static int simple_sleep_test(void)
-{
-    enum { COUNT = 5 };
-    int i;
-    pj_status_t rc;
-    
-    PJ_LOG(3,(THIS_FILE, "..will write messages every 1 second:"));
-    
-    for (i=0; i<COUNT; ++i) {
-	rc = pj_thread_sleep(1000);
-	if (rc != PJ_SUCCESS) {
-	    app_perror("...error: pj_thread_sleep()", rc);
-	    return -10;
-	}
-	PJ_LOG(3,(THIS_FILE, "...wake up.."));
-    }
-
-    return 0;
-}
-
-static int sleep_duration_test(void)
-{
-    enum { MIS = 20, DURATION = 1000, DURATION2 = 500 };
-    pj_status_t rc;
-
-    PJ_LOG(3,(THIS_FILE, "..running sleep duration test"));
-
-    /* Test pj_thread_sleep() and pj_gettimeofday() */
-    {
-        pj_time_val start, stop;
-	pj_uint32_t msec;
-
-        /* Mark start of test. */
-        rc = pj_gettimeofday(&start);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error: pj_gettimeofday()", rc);
-            return -10;
-        }
-
-        /* Sleep */
-        rc = pj_thread_sleep(DURATION);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error: pj_thread_sleep()", rc);
-            return -20;
-        }
-
-        /* Mark end of test. */
-        rc = pj_gettimeofday(&stop);
-
-        /* Calculate duration (store in stop). */
-        PJ_TIME_VAL_SUB(stop, start);
-
-	/* Convert to msec. */
-	msec = PJ_TIME_VAL_MSEC(stop);
-
-	/* Check if it's within range. */
-	if (msec < DURATION * (100-MIS)/100 ||
-	    msec > DURATION * (100+MIS)/100)
-	{
-	    PJ_LOG(3,(THIS_FILE, 
-		      "...error: slept for %d ms instead of %d ms "
-		      "(outside %d%% err window)",
-		      msec, DURATION, MIS));
-	    return -30;
-	}
-    }
-
-
-    /* Test pj_thread_sleep() and pj_get_timestamp() and friends */
-    {
-	pj_time_val t1, t2;
-        pj_timestamp start, stop;
-        pj_time_val elapsed;
-	pj_uint32_t msec;
-
-        /* Mark start of test. */
-        rc = pj_get_timestamp(&start);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error: pj_get_timestamp()", rc);
-            return -60;
-        }
-
-	/* ..also with gettimeofday() */
-	pj_gettimeofday(&t1);
-
-        /* Sleep */
-        rc = pj_thread_sleep(DURATION2);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error: pj_thread_sleep()", rc);
-            return -70;
-        }
-
-        /* Mark end of test. */
-        pj_get_timestamp(&stop);
-
-	/* ..also with gettimeofday() */
-	pj_gettimeofday(&t2);
-
-	/* Compare t1 and t2. */
-	if (PJ_TIME_VAL_LTE(t2, t1)) {
-	    PJ_LOG(3,(THIS_FILE, "...error: t2 is less than t1!!"));
-	    return -75;
-	}
-
-        /* Get elapsed time in time_val */
-        elapsed = pj_elapsed_time(&start, &stop);
-
-	msec = PJ_TIME_VAL_MSEC(elapsed);
-
-	/* Check if it's within range. */
-	if (msec < DURATION2 * (100-MIS)/100 ||
-	    msec > DURATION2 * (100+MIS)/100)
-	{
-	    PJ_LOG(3,(THIS_FILE, 
-		      "...error: slept for %d ms instead of %d ms "
-		      "(outside %d%% err window)",
-		      msec, DURATION2, MIS));
-	    return -30;
-	}
-    }
-
-    /* All done. */
-    return 0;
-}
-
-int sleep_test()
-{
-    int rc;
-
-    rc = simple_sleep_test();
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    rc = sleep_duration_test();
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_sleep_test;
-#endif  /* INCLUDE_SLEEP_TEST */
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+/**

+ * \page page_pjlib_sleep_test Test: Sleep, Time, and Timestamp

+ *

+ * This file provides implementation of \b sleep_test().

+ *

+ * \section sleep_test_sec Scope of the Test

+ *

+ * This tests:

+ *  - whether pj_thread_sleep() works.

+ *  - whether pj_gettimeofday() works.

+ *  - whether pj_get_timestamp() and friends works.

+ *

+ * API tested:

+ *  - pj_thread_sleep()

+ *  - pj_gettimeofday()

+ *  - PJ_TIME_VAL_SUB()

+ *  - PJ_TIME_VAL_LTE()

+ *  - pj_get_timestamp()

+ *  - pj_get_timestamp_freq() (implicitly)

+ *  - pj_elapsed_time()

+ *  - pj_elapsed_usec()

+ *

+ *

+ * This file is <b>pjlib-test/sleep.c</b>

+ *

+ * \include pjlib-test/sleep.c

+ */

+

+#if INCLUDE_SLEEP_TEST

+

+#include <pjlib.h>

+

+#define THIS_FILE   "sleep_test"

+

+static int simple_sleep_test(void)

+{

+    enum { COUNT = 5 };

+    int i;

+    pj_status_t rc;

+    

+    PJ_LOG(3,(THIS_FILE, "..will write messages every 1 second:"));

+    

+    for (i=0; i<COUNT; ++i) {

+	rc = pj_thread_sleep(1000);

+	if (rc != PJ_SUCCESS) {

+	    app_perror("...error: pj_thread_sleep()", rc);

+	    return -10;

+	}

+	PJ_LOG(3,(THIS_FILE, "...wake up.."));

+    }

+

+    return 0;

+}

+

+static int sleep_duration_test(void)

+{

+    enum { MIS = 20, DURATION = 1000, DURATION2 = 500 };

+    pj_status_t rc;

+

+    PJ_LOG(3,(THIS_FILE, "..running sleep duration test"));

+

+    /* Test pj_thread_sleep() and pj_gettimeofday() */

+    {

+        pj_time_val start, stop;

+	pj_uint32_t msec;

+

+        /* Mark start of test. */

+        rc = pj_gettimeofday(&start);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error: pj_gettimeofday()", rc);

+            return -10;

+        }

+

+        /* Sleep */

+        rc = pj_thread_sleep(DURATION);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error: pj_thread_sleep()", rc);

+            return -20;

+        }

+

+        /* Mark end of test. */

+        rc = pj_gettimeofday(&stop);

+

+        /* Calculate duration (store in stop). */

+        PJ_TIME_VAL_SUB(stop, start);

+

+	/* Convert to msec. */

+	msec = PJ_TIME_VAL_MSEC(stop);

+

+	/* Check if it's within range. */

+	if (msec < DURATION * (100-MIS)/100 ||

+	    msec > DURATION * (100+MIS)/100)

+	{

+	    PJ_LOG(3,(THIS_FILE, 

+		      "...error: slept for %d ms instead of %d ms "

+		      "(outside %d%% err window)",

+		      msec, DURATION, MIS));

+	    return -30;

+	}

+    }

+

+

+    /* Test pj_thread_sleep() and pj_get_timestamp() and friends */

+    {

+	pj_time_val t1, t2;

+        pj_timestamp start, stop;

+        pj_time_val elapsed;

+	pj_uint32_t msec;

+

+        /* Mark start of test. */

+        rc = pj_get_timestamp(&start);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error: pj_get_timestamp()", rc);

+            return -60;

+        }

+

+	/* ..also with gettimeofday() */

+	pj_gettimeofday(&t1);

+

+        /* Sleep */

+        rc = pj_thread_sleep(DURATION2);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error: pj_thread_sleep()", rc);

+            return -70;

+        }

+

+        /* Mark end of test. */

+        pj_get_timestamp(&stop);

+

+	/* ..also with gettimeofday() */

+	pj_gettimeofday(&t2);

+

+	/* Compare t1 and t2. */

+	if (PJ_TIME_VAL_LTE(t2, t1)) {

+	    PJ_LOG(3,(THIS_FILE, "...error: t2 is less than t1!!"));

+	    return -75;

+	}

+

+        /* Get elapsed time in time_val */

+        elapsed = pj_elapsed_time(&start, &stop);

+

+	msec = PJ_TIME_VAL_MSEC(elapsed);

+

+	/* Check if it's within range. */

+	if (msec < DURATION2 * (100-MIS)/100 ||

+	    msec > DURATION2 * (100+MIS)/100)

+	{

+	    PJ_LOG(3,(THIS_FILE, 

+		      "...error: slept for %d ms instead of %d ms "

+		      "(outside %d%% err window)",

+		      msec, DURATION2, MIS));

+	    return -30;

+	}

+    }

+

+    /* All done. */

+    return 0;

+}

+

+int sleep_test()

+{

+    int rc;

+

+    rc = simple_sleep_test();

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    rc = sleep_duration_test();

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    return 0;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_sleep_test;

+#endif  /* INCLUDE_SLEEP_TEST */

diff --git a/pjlib/src/pjlib-test/sock.c b/pjlib/src/pjlib-test/sock.c
index 56da4be..3a635b1 100644
--- a/pjlib/src/pjlib-test/sock.c
+++ b/pjlib/src/pjlib-test/sock.c
@@ -1,440 +1,461 @@
-/* $Id$
- */
-#include <pjlib.h>
-#include "test.h"
-
-
-/**
- * \page page_pjlib_sock_test Test: Socket
- *
- * This file provides implementation of \b sock_test(). It tests the
- * various aspects of the socket API.
- *
- * \section sock_test_scope_sec Scope of the Test
- *
- * The scope of the test:
- *  - verify the validity of the address structs.
- *  - verify that address manipulation API works.
- *  - simple socket creation and destruction.
- *  - simple socket send/recv and sendto/recvfrom.
- *  - UDP connect()
- *  - send/recv big data.
- *  - all for both UDP and TCP.
- *
- * The APIs tested in this test:
- *  - pj_inet_aton()
- *  - pj_inet_ntoa()
- *  - pj_gethostname()
- *  - pj_sock_socket()
- *  - pj_sock_close()
- *  - pj_sock_send()
- *  - pj_sock_sendto()
- *  - pj_sock_recv()
- *  - pj_sock_recvfrom()
- *  - pj_sock_bind()
- *  - pj_sock_connect()
- *  - pj_sock_listen()
- *  - pj_sock_accept()
- *
- *
- * This file is <b>pjlib-test/sock.c</b>
- *
- * \include pjlib-test/sock.c
- */
-
-#if INCLUDE_SOCK_TEST
-
-#define UDP_PORT	51234
-#define TCP_PORT        (UDP_PORT+10)
-#define BIG_DATA_LEN	9000
-
-static char bigdata[BIG_DATA_LEN];
-static char bigbuffer[BIG_DATA_LEN];
-
-static int format_test(void)
-{
-    pj_str_t s = pj_str("127.0.0.1");
-    char *p;
-    pj_in_addr addr;
-    const pj_str_t *hostname;
-
-    PJ_LOG(3,("test", "...format_test()"));
-    
-    /* pj_inet_aton() */
-    if (pj_inet_aton(&s, &addr) != 1)
-	return -10;
-    
-    /* Check the result. */
-    p = (char*)&addr;
-    if (p[0]!=127 || p[1]!=0 || p[2]!=0 || p[3]!=1)
-	return -15;
-
-    /* pj_inet_ntoa() */
-    p = pj_inet_ntoa(addr);
-    if (!p)
-	return -20;
-
-    if (pj_strcmp2(&s, p) != 0)
-	return -30;
-
-    /* pj_gethostname() */
-    hostname = pj_gethostname();
-    if (!hostname || !hostname->ptr || !hostname->slen)
-	return -40;
-
-    /* pj_gethostaddr() */
-
-    return 0;
-}
-
-static int simple_sock_test(void)
-{
-    int types[2];
-    pj_sock_t sock;
-    int i;
-    pj_status_t rc = PJ_SUCCESS;
-
-    types[0] = PJ_SOCK_STREAM;
-    types[1] = PJ_SOCK_DGRAM;
-
-    PJ_LOG(3,("test", "...simple_sock_test()"));
-
-    for (i=0; i<sizeof(types)/sizeof(types[0]); ++i) {
-	
-	rc = pj_sock_socket(PJ_AF_INET, types[i], 0, &sock);
-	if (rc != PJ_SUCCESS) {
-	    app_perror("...error: unable to create socket type %d", rc);
-	    break;
-	} else {
-	    rc = pj_sock_close(sock);
-	    if (rc != 0) {
-		app_perror("...error: close socket", rc);
-		break;
-	    }
-	}
-    }
-    return rc;
-}
-
-
-static int send_recv_test(int sock_type,
-                          pj_sock_t ss, pj_sock_t cs,
-			  pj_sockaddr_in *dstaddr, pj_sockaddr_in *srcaddr, 
-			  int addrlen)
-{
-    enum { DATA_LEN = 16 };
-    char senddata[DATA_LEN+4], recvdata[DATA_LEN+4];
-    pj_ssize_t sent, received, total_received;
-    pj_status_t rc;
-
-    TRACE_(("test", "....create_random_string()"));
-    pj_create_random_string(senddata, DATA_LEN);
-    senddata[DATA_LEN-1] = '\0';
-
-    /*
-     * Test send/recv small data.
-     */
-    TRACE_(("test", "....sendto()"));
-    if (dstaddr) {
-        sent = DATA_LEN;
-	rc = pj_sock_sendto(cs, senddata, &sent, 0, dstaddr, addrlen);
-	if (rc != PJ_SUCCESS || sent != DATA_LEN) {
-	    app_perror("...sendto error", rc);
-	    rc = -140; goto on_error;
-	}
-    } else {
-        sent = DATA_LEN;
-	rc = pj_sock_send(cs, senddata, &sent, 0);
-	if (rc != PJ_SUCCESS || sent != DATA_LEN) {
-	    app_perror("...send error", rc);
-	    rc = -145; goto on_error;
-	}
-    }
-
-    TRACE_(("test", "....recv()"));
-    if (srcaddr) {
-	pj_sockaddr_in addr;
-	int srclen = sizeof(addr);
-	
-	pj_memset(&addr, 0, sizeof(addr));
-
-        received = DATA_LEN;
-	rc = pj_sock_recvfrom(ss, recvdata, &received, 0, &addr, &srclen);
-	if (rc != PJ_SUCCESS || received != DATA_LEN) {
-	    app_perror("...recvfrom error", rc);
-	    rc = -150; goto on_error;
-	}
-	if (srclen != addrlen)
-	    return -151;
-	if (pj_memcmp(&addr, srcaddr, srclen) != 0) {
-	    char srcaddr_str[32], addr_str[32];
-	    strcpy(srcaddr_str, pj_inet_ntoa(srcaddr->sin_addr));
-	    strcpy(addr_str, pj_inet_ntoa(addr.sin_addr));
-	    PJ_LOG(3,("test", "...error: src address mismatch (original=%s, "
-			      "recvfrom addr=%s)", 
-			      srcaddr_str, addr_str));
-	    return -152;
-	}
-	
-    } else {
-        /* Repeat recv() until all data is received.
-         * This applies only for non-UDP of course, since for UDP
-         * we would expect all data to be received in one packet.
-         */
-        total_received = 0;
-        do {
-            received = DATA_LEN-total_received;
-	    rc = pj_sock_recv(ss, recvdata+total_received, &received, 0);
-	    if (rc != PJ_SUCCESS) {
-	        app_perror("...recv error", rc);
-	        rc = -155; goto on_error;
-	    }
-            if (received <= 0) {
-                PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
-                          received));
-                rc = -156; goto on_error;
-            }
-	    if (received != DATA_LEN-total_received) {
-                if (sock_type != PJ_SOCK_STREAM) {
-	            PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
-                              DATA_LEN-total_received, received));
-	            rc = -157; goto on_error;
-                }
-	    }
-            total_received += received;
-        } while (total_received < DATA_LEN);
-    }
-
-    TRACE_(("test", "....memcmp()"));
-    if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) {
-	PJ_LOG(3,("","...error: received data mismatch "
-		     "(got:'%s' expecting:'%s'",
-		     recvdata, senddata));
-	rc = -160; goto on_error;
-    }
-
-    /*
-     * Test send/recv big data.
-     */
-    TRACE_(("test", "....sendto()"));
-    if (dstaddr) {
-        sent = BIG_DATA_LEN;
-	rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen);
-	if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
-	    app_perror("...sendto error", rc);
-	    rc = -161; goto on_error;
-	}
-    } else {
-        sent = BIG_DATA_LEN;
-	rc = pj_sock_send(cs, bigdata, &sent, 0);
-	if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {
-	    app_perror("...send error", rc);
-	    rc = -165; goto on_error;
-	}
-    }
-
-    TRACE_(("test", "....recv()"));
-
-    /* Repeat recv() until all data is received.
-     * This applies only for non-UDP of course, since for UDP
-     * we would expect all data to be received in one packet.
-     */
-    total_received = 0;
-    do {
-        received = BIG_DATA_LEN-total_received;
-	rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0);
-	if (rc != PJ_SUCCESS) {
-	    app_perror("...recv error", rc);
-	    rc = -170; goto on_error;
-	}
-        if (received <= 0) {
-            PJ_LOG(3,("", "...error: socket has closed! (received=%d)",
-                      received));
-            rc = -173; goto on_error;
-        }
-	if (received != BIG_DATA_LEN-total_received) {
-            if (sock_type != PJ_SOCK_STREAM) {
-	        PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
-                          BIG_DATA_LEN-total_received, received));
-	        rc = -176; goto on_error;
-            }
-	}
-        total_received += received;
-    } while (total_received < BIG_DATA_LEN);
-
-    TRACE_(("test", "....memcmp()"));
-    if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) {
-        PJ_LOG(3,("", "...error: received data has been altered!"));
-	rc = -180; goto on_error;
-    }
-    
-    rc = 0;
-
-on_error:
-    return rc;
-}
-
-static int udp_test(void)
-{
-    pj_sock_t cs = PJ_INVALID_SOCKET, ss = PJ_INVALID_SOCKET;
-    pj_sockaddr_in dstaddr, srcaddr;
-    pj_str_t s;
-    pj_status_t rc = 0, retval;
-
-    PJ_LOG(3,("test", "...udp_test()"));
-
-    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ss);
-    if (rc != 0) {
-	app_perror("...error: unable to create socket", rc);
-	return -100;
-    }
-
-    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &cs);
-    if (rc != 0)
-	return -110;
-
-    /* Bind server socket. */
-    pj_memset(&dstaddr, 0, sizeof(dstaddr));
-    dstaddr.sin_family = PJ_AF_INET;
-    dstaddr.sin_port = pj_htons(UDP_PORT);
-    dstaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-    
-    if ((rc=pj_sock_bind(ss, &dstaddr, sizeof(dstaddr))) != 0) {
-	app_perror("...bind error", rc);
-	rc = -120; goto on_error;
-    }
-
-    /* Bind client socket. */
-    pj_memset(&srcaddr, 0, sizeof(srcaddr));
-    srcaddr.sin_family = PJ_AF_INET;
-    srcaddr.sin_port = pj_htons(UDP_PORT-1);
-    srcaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-
-    if ((rc=pj_sock_bind(cs, &srcaddr, sizeof(srcaddr))) != 0) {
-	app_perror("...bind error", rc);
-	rc = -121; goto on_error;
-    }
-	    
-    /* Test send/recv, with sendto */
-    rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, NULL, 
-                        sizeof(dstaddr));
-    if (rc != 0)
-	goto on_error;
-
-    /* Test send/recv, with sendto and recvfrom */
-    rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, 
-                        &srcaddr, sizeof(dstaddr));
-    if (rc != 0)
-	goto on_error;
-
-    /* connect() the sockets. */
-    rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr));
-    if (rc != 0) {
-	app_perror("...connect() error", rc);
-	rc = -122; goto on_error;
-    }
-
-    /* Test send/recv with send() */
-    rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, NULL, 0);
-    if (rc != 0)
-	goto on_error;
-
-    /* Test send/recv with send() and recvfrom */
-    rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, &srcaddr, 
-                        sizeof(srcaddr));
-    if (rc != 0)
-	goto on_error;
-
-on_error:
-    retval = rc;
-    if (cs != PJ_INVALID_SOCKET) {
-        rc = pj_sock_close(cs);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error in closing socket", rc);
-            return -1000;
-        }
-    }
-    if (ss != PJ_INVALID_SOCKET) {
-        rc = pj_sock_close(ss);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...error in closing socket", rc);
-            return -1010;
-        }
-    }
-
-    return retval;
-}
-
-static int tcp_test(void)
-{
-    pj_sock_t cs, ss;
-    pj_status_t rc = 0, retval;
-
-    PJ_LOG(3,("test", "...tcp_test()"));
-
-    rc = app_socketpair(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ss, &cs);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error: app_socketpair():", rc);
-        return -2000;
-    }
-
-    /* Test send/recv with send() and recv() */
-    retval = send_recv_test(PJ_SOCK_STREAM, ss, cs, NULL, NULL, 0);
-
-    rc = pj_sock_close(cs);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error in closing socket", rc);
-        return -2000;
-    }
-
-    rc = pj_sock_close(ss);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error in closing socket", rc);
-        return -2010;
-    }
-
-    return retval;
-}
-
-static int ioctl_test(void)
-{
-    return 0;
-}
-
-int sock_test()
-{
-    int rc;
-    
-    pj_create_random_string(bigdata, BIG_DATA_LEN);
-
-    rc = format_test();
-    if (rc != 0)
-	return rc;
-
-    rc = simple_sock_test();
-    if (rc != 0)
-	return rc;
-
-    rc = ioctl_test();
-    if (rc != 0)
-	return rc;
-
-    rc = udp_test();
-    if (rc != 0)
-	return rc;
-
-    rc = tcp_test();
-    if (rc != 0)
-	return rc;
-
-    return 0;
-}
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_sock_test;
-#endif	/* INCLUDE_SOCK_TEST */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjlib.h>

+#include "test.h"

+

+

+/**

+ * \page page_pjlib_sock_test Test: Socket

+ *

+ * This file provides implementation of \b sock_test(). It tests the

+ * various aspects of the socket API.

+ *

+ * \section sock_test_scope_sec Scope of the Test

+ *

+ * The scope of the test:

+ *  - verify the validity of the address structs.

+ *  - verify that address manipulation API works.

+ *  - simple socket creation and destruction.

+ *  - simple socket send/recv and sendto/recvfrom.

+ *  - UDP connect()

+ *  - send/recv big data.

+ *  - all for both UDP and TCP.

+ *

+ * The APIs tested in this test:

+ *  - pj_inet_aton()

+ *  - pj_inet_ntoa()

+ *  - pj_gethostname()

+ *  - pj_sock_socket()

+ *  - pj_sock_close()

+ *  - pj_sock_send()

+ *  - pj_sock_sendto()

+ *  - pj_sock_recv()

+ *  - pj_sock_recvfrom()

+ *  - pj_sock_bind()

+ *  - pj_sock_connect()

+ *  - pj_sock_listen()

+ *  - pj_sock_accept()

+ *

+ *

+ * This file is <b>pjlib-test/sock.c</b>

+ *

+ * \include pjlib-test/sock.c

+ */

+

+#if INCLUDE_SOCK_TEST

+

+#define UDP_PORT	51234

+#define TCP_PORT        (UDP_PORT+10)

+#define BIG_DATA_LEN	9000

+

+static char bigdata[BIG_DATA_LEN];

+static char bigbuffer[BIG_DATA_LEN];

+

+static int format_test(void)

+{

+    pj_str_t s = pj_str("127.0.0.1");

+    char *p;

+    pj_in_addr addr;

+    const pj_str_t *hostname;

+

+    PJ_LOG(3,("test", "...format_test()"));

+    

+    /* pj_inet_aton() */

+    if (pj_inet_aton(&s, &addr) != 1)

+	return -10;

+    

+    /* Check the result. */

+    p = (char*)&addr;

+    if (p[0]!=127 || p[1]!=0 || p[2]!=0 || p[3]!=1)

+	return -15;

+

+    /* pj_inet_ntoa() */

+    p = pj_inet_ntoa(addr);

+    if (!p)

+	return -20;

+

+    if (pj_strcmp2(&s, p) != 0)

+	return -30;

+

+    /* pj_gethostname() */

+    hostname = pj_gethostname();

+    if (!hostname || !hostname->ptr || !hostname->slen)

+	return -40;

+

+    /* pj_gethostaddr() */

+

+    return 0;

+}

+

+static int simple_sock_test(void)

+{

+    int types[2];

+    pj_sock_t sock;

+    int i;

+    pj_status_t rc = PJ_SUCCESS;

+

+    types[0] = PJ_SOCK_STREAM;

+    types[1] = PJ_SOCK_DGRAM;

+

+    PJ_LOG(3,("test", "...simple_sock_test()"));

+

+    for (i=0; i<sizeof(types)/sizeof(types[0]); ++i) {

+	

+	rc = pj_sock_socket(PJ_AF_INET, types[i], 0, &sock);

+	if (rc != PJ_SUCCESS) {

+	    app_perror("...error: unable to create socket type %d", rc);

+	    break;

+	} else {

+	    rc = pj_sock_close(sock);

+	    if (rc != 0) {

+		app_perror("...error: close socket", rc);

+		break;

+	    }

+	}

+    }

+    return rc;

+}

+

+

+static int send_recv_test(int sock_type,

+                          pj_sock_t ss, pj_sock_t cs,

+			  pj_sockaddr_in *dstaddr, pj_sockaddr_in *srcaddr, 

+			  int addrlen)

+{

+    enum { DATA_LEN = 16 };

+    char senddata[DATA_LEN+4], recvdata[DATA_LEN+4];

+    pj_ssize_t sent, received, total_received;

+    pj_status_t rc;

+

+    TRACE_(("test", "....create_random_string()"));

+    pj_create_random_string(senddata, DATA_LEN);

+    senddata[DATA_LEN-1] = '\0';

+

+    /*

+     * Test send/recv small data.

+     */

+    TRACE_(("test", "....sendto()"));

+    if (dstaddr) {

+        sent = DATA_LEN;

+	rc = pj_sock_sendto(cs, senddata, &sent, 0, dstaddr, addrlen);

+	if (rc != PJ_SUCCESS || sent != DATA_LEN) {

+	    app_perror("...sendto error", rc);

+	    rc = -140; goto on_error;

+	}

+    } else {

+        sent = DATA_LEN;

+	rc = pj_sock_send(cs, senddata, &sent, 0);

+	if (rc != PJ_SUCCESS || sent != DATA_LEN) {

+	    app_perror("...send error", rc);

+	    rc = -145; goto on_error;

+	}

+    }

+

+    TRACE_(("test", "....recv()"));

+    if (srcaddr) {

+	pj_sockaddr_in addr;

+	int srclen = sizeof(addr);

+	

+	pj_memset(&addr, 0, sizeof(addr));

+

+        received = DATA_LEN;

+	rc = pj_sock_recvfrom(ss, recvdata, &received, 0, &addr, &srclen);

+	if (rc != PJ_SUCCESS || received != DATA_LEN) {

+	    app_perror("...recvfrom error", rc);

+	    rc = -150; goto on_error;

+	}

+	if (srclen != addrlen)

+	    return -151;

+	if (pj_memcmp(&addr, srcaddr, srclen) != 0) {

+	    char srcaddr_str[32], addr_str[32];

+	    strcpy(srcaddr_str, pj_inet_ntoa(srcaddr->sin_addr));

+	    strcpy(addr_str, pj_inet_ntoa(addr.sin_addr));

+	    PJ_LOG(3,("test", "...error: src address mismatch (original=%s, "

+			      "recvfrom addr=%s)", 

+			      srcaddr_str, addr_str));

+	    return -152;

+	}

+	

+    } else {

+        /* Repeat recv() until all data is received.

+         * This applies only for non-UDP of course, since for UDP

+         * we would expect all data to be received in one packet.

+         */

+        total_received = 0;

+        do {

+            received = DATA_LEN-total_received;

+	    rc = pj_sock_recv(ss, recvdata+total_received, &received, 0);

+	    if (rc != PJ_SUCCESS) {

+	        app_perror("...recv error", rc);

+	        rc = -155; goto on_error;

+	    }

+            if (received <= 0) {

+                PJ_LOG(3,("", "...error: socket has closed! (received=%d)",

+                          received));

+                rc = -156; goto on_error;

+            }

+	    if (received != DATA_LEN-total_received) {

+                if (sock_type != PJ_SOCK_STREAM) {

+	            PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",

+                              DATA_LEN-total_received, received));

+	            rc = -157; goto on_error;

+                }

+	    }

+            total_received += received;

+        } while (total_received < DATA_LEN);

+    }

+

+    TRACE_(("test", "....memcmp()"));

+    if (pj_memcmp(senddata, recvdata, DATA_LEN) != 0) {

+	PJ_LOG(3,("","...error: received data mismatch "

+		     "(got:'%s' expecting:'%s'",

+		     recvdata, senddata));

+	rc = -160; goto on_error;

+    }

+

+    /*

+     * Test send/recv big data.

+     */

+    TRACE_(("test", "....sendto()"));

+    if (dstaddr) {

+        sent = BIG_DATA_LEN;

+	rc = pj_sock_sendto(cs, bigdata, &sent, 0, dstaddr, addrlen);

+	if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {

+	    app_perror("...sendto error", rc);

+	    rc = -161; goto on_error;

+	}

+    } else {

+        sent = BIG_DATA_LEN;

+	rc = pj_sock_send(cs, bigdata, &sent, 0);

+	if (rc != PJ_SUCCESS || sent != BIG_DATA_LEN) {

+	    app_perror("...send error", rc);

+	    rc = -165; goto on_error;

+	}

+    }

+

+    TRACE_(("test", "....recv()"));

+

+    /* Repeat recv() until all data is received.

+     * This applies only for non-UDP of course, since for UDP

+     * we would expect all data to be received in one packet.

+     */

+    total_received = 0;

+    do {

+        received = BIG_DATA_LEN-total_received;

+	rc = pj_sock_recv(ss, bigbuffer+total_received, &received, 0);

+	if (rc != PJ_SUCCESS) {

+	    app_perror("...recv error", rc);

+	    rc = -170; goto on_error;

+	}

+        if (received <= 0) {

+            PJ_LOG(3,("", "...error: socket has closed! (received=%d)",

+                      received));

+            rc = -173; goto on_error;

+        }

+	if (received != BIG_DATA_LEN-total_received) {

+            if (sock_type != PJ_SOCK_STREAM) {

+	        PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",

+                          BIG_DATA_LEN-total_received, received));

+	        rc = -176; goto on_error;

+            }

+	}

+        total_received += received;

+    } while (total_received < BIG_DATA_LEN);

+

+    TRACE_(("test", "....memcmp()"));

+    if (pj_memcmp(bigdata, bigbuffer, BIG_DATA_LEN) != 0) {

+        PJ_LOG(3,("", "...error: received data has been altered!"));

+	rc = -180; goto on_error;

+    }

+    

+    rc = 0;

+

+on_error:

+    return rc;

+}

+

+static int udp_test(void)

+{

+    pj_sock_t cs = PJ_INVALID_SOCKET, ss = PJ_INVALID_SOCKET;

+    pj_sockaddr_in dstaddr, srcaddr;

+    pj_str_t s;

+    pj_status_t rc = 0, retval;

+

+    PJ_LOG(3,("test", "...udp_test()"));

+

+    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &ss);

+    if (rc != 0) {

+	app_perror("...error: unable to create socket", rc);

+	return -100;

+    }

+

+    rc = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &cs);

+    if (rc != 0)

+	return -110;

+

+    /* Bind server socket. */

+    pj_memset(&dstaddr, 0, sizeof(dstaddr));

+    dstaddr.sin_family = PJ_AF_INET;

+    dstaddr.sin_port = pj_htons(UDP_PORT);

+    dstaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));

+    

+    if ((rc=pj_sock_bind(ss, &dstaddr, sizeof(dstaddr))) != 0) {

+	app_perror("...bind error", rc);

+	rc = -120; goto on_error;

+    }

+

+    /* Bind client socket. */

+    pj_memset(&srcaddr, 0, sizeof(srcaddr));

+    srcaddr.sin_family = PJ_AF_INET;

+    srcaddr.sin_port = pj_htons(UDP_PORT-1);

+    srcaddr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));

+

+    if ((rc=pj_sock_bind(cs, &srcaddr, sizeof(srcaddr))) != 0) {

+	app_perror("...bind error", rc);

+	rc = -121; goto on_error;

+    }

+	    

+    /* Test send/recv, with sendto */

+    rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, NULL, 

+                        sizeof(dstaddr));

+    if (rc != 0)

+	goto on_error;

+

+    /* Test send/recv, with sendto and recvfrom */

+    rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, &dstaddr, 

+                        &srcaddr, sizeof(dstaddr));

+    if (rc != 0)

+	goto on_error;

+

+    /* connect() the sockets. */

+    rc = pj_sock_connect(cs, &dstaddr, sizeof(dstaddr));

+    if (rc != 0) {

+	app_perror("...connect() error", rc);

+	rc = -122; goto on_error;

+    }

+

+    /* Test send/recv with send() */

+    rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, NULL, 0);

+    if (rc != 0)

+	goto on_error;

+

+    /* Test send/recv with send() and recvfrom */

+    rc = send_recv_test(PJ_SOCK_DGRAM, ss, cs, NULL, &srcaddr, 

+                        sizeof(srcaddr));

+    if (rc != 0)

+	goto on_error;

+

+on_error:

+    retval = rc;

+    if (cs != PJ_INVALID_SOCKET) {

+        rc = pj_sock_close(cs);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error in closing socket", rc);

+            return -1000;

+        }

+    }

+    if (ss != PJ_INVALID_SOCKET) {

+        rc = pj_sock_close(ss);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...error in closing socket", rc);

+            return -1010;

+        }

+    }

+

+    return retval;

+}

+

+static int tcp_test(void)

+{

+    pj_sock_t cs, ss;

+    pj_status_t rc = 0, retval;

+

+    PJ_LOG(3,("test", "...tcp_test()"));

+

+    rc = app_socketpair(PJ_AF_INET, PJ_SOCK_STREAM, 0, &ss, &cs);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error: app_socketpair():", rc);

+        return -2000;

+    }

+

+    /* Test send/recv with send() and recv() */

+    retval = send_recv_test(PJ_SOCK_STREAM, ss, cs, NULL, NULL, 0);

+

+    rc = pj_sock_close(cs);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error in closing socket", rc);

+        return -2000;

+    }

+

+    rc = pj_sock_close(ss);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error in closing socket", rc);

+        return -2010;

+    }

+

+    return retval;

+}

+

+static int ioctl_test(void)

+{

+    return 0;

+}

+

+int sock_test()

+{

+    int rc;

+    

+    pj_create_random_string(bigdata, BIG_DATA_LEN);

+

+    rc = format_test();

+    if (rc != 0)

+	return rc;

+

+    rc = simple_sock_test();

+    if (rc != 0)

+	return rc;

+

+    rc = ioctl_test();

+    if (rc != 0)

+	return rc;

+

+    rc = udp_test();

+    if (rc != 0)

+	return rc;

+

+    rc = tcp_test();

+    if (rc != 0)

+	return rc;

+

+    return 0;

+}

+

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_sock_test;

+#endif	/* INCLUDE_SOCK_TEST */

+

diff --git a/pjlib/src/pjlib-test/sock_perf.c b/pjlib/src/pjlib-test/sock_perf.c
index dfc480c..c19b8ab 100644
--- a/pjlib/src/pjlib-test/sock_perf.c
+++ b/pjlib/src/pjlib-test/sock_perf.c
@@ -1,167 +1,188 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-#include <pj/compat/high_precision.h>
-
-
-/**
- * \page page_pjlib_sock_perf_test Test: Socket Performance
- *
- * Test the performance of the socket communication. This will perform
- * simple producer-consumer type of test, where we calculate how long
- * does it take to send certain number of packets from producer to
- * consumer.
- *
- * This file is <b>pjlib-test/sock_perf.c</b>
- *
- * \include pjlib-test/sock_perf.c
- */
-
-#if INCLUDE_SOCK_PERF_TEST
-
-/*
- * sock_producer_consumer()
- *
- * Simple producer-consumer benchmarking. Send loop number of
- * buf_size size packets as fast as possible.
- */
-static int sock_producer_consumer(int sock_type,
-                                  unsigned buf_size,
-                                  unsigned loop, 
-                                  unsigned *p_bandwidth)
-{
-    pj_sock_t consumer, producer;
-    pj_pool_t *pool;
-    char *outgoing_buffer, *incoming_buffer;
-    pj_timestamp start, stop;
-    unsigned i;
-    pj_highprec_t elapsed, bandwidth;
-    pj_size_t total_received;
-    pj_status_t rc;
-
-    /* Create pool. */
-    pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);
-    if (!pool)
-        return -10;
-
-    /* Create producer-consumer pair. */
-    rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error: create socket pair", rc);
-        return -20;
-    }
-
-    /* Create buffers. */
-    outgoing_buffer = pj_pool_alloc(pool, buf_size);
-    incoming_buffer = pj_pool_alloc(pool, buf_size);
-
-    /* Start loop. */
-    pj_get_timestamp(&start);
-    total_received = 0;
-    for (i=0; i<loop; ++i) {
-        pj_ssize_t sent, part_received, received;
-	pj_time_val delay;
-
-        sent = buf_size;
-        rc = pj_sock_send(producer, outgoing_buffer, &sent, 0);
-        if (rc != PJ_SUCCESS || sent != (pj_ssize_t)buf_size) {
-            app_perror("...error: send()", rc);
-            return -61;
-        }
-
-        /* Repeat recv() until all data is part_received.
-         * This applies only for non-UDP of course, since for UDP
-         * we would expect all data to be part_received in one packet.
-         */
-        received = 0;
-        do {
-            part_received = buf_size-received;
-	    rc = pj_sock_recv(consumer, incoming_buffer+received, 
-			      &part_received, 0);
-	    if (rc != PJ_SUCCESS) {
-	        app_perror("...recv error", rc);
-	        return -70;
-	    }
-            if (part_received <= 0) {
-                PJ_LOG(3,("", "...error: socket has closed (part_received=%d)!",
-                          part_received));
-                return -73;
-            }
-	    if ((pj_size_t)part_received != buf_size-received) {
-                if (sock_type != PJ_SOCK_STREAM) {
-	            PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",
-                              buf_size-received, part_received));
-	            return -76;
-                }
-	    }
-            received += part_received;
-        } while ((pj_size_t)received < buf_size);
-
-	total_received += received;
-
-	/* Stop test if it's been runnign for more than 10 secs. */
-	pj_get_timestamp(&stop);
-	delay = pj_elapsed_time(&start, &stop);
-	if (delay.sec > 10)
-	    break;
-    }
-
-    /* Stop timer. */
-    pj_get_timestamp(&stop);
-
-    elapsed = pj_elapsed_usec(&start, &stop);
-
-    /* bandwidth = total_received * 1000 / elapsed */
-    bandwidth = total_received;
-    pj_highprec_mul(bandwidth, 1000);
-    pj_highprec_div(bandwidth, elapsed);
-    
-    *p_bandwidth = (pj_uint32_t)bandwidth;
-
-    /* Close sockets. */
-    pj_sock_close(consumer);
-    pj_sock_close(producer);
-
-    /* Done */
-    pj_pool_release(pool);
-
-    return 0;
-}
-
-/*
- * sock_perf_test()
- *
- * Main test entry.
- */
-int sock_perf_test(void)
-{
-    enum { LOOP = 64 * 1024 };
-    int rc;
-    unsigned bandwidth;
-
-    PJ_LOG(3,("", "...benchmarking socket "
-                  "(2 sockets, packet=512, single threaded):"));
-    
-    /* Benchmarking UDP */
-    rc = sock_producer_consumer(PJ_SOCK_DGRAM, 512, LOOP, &bandwidth);
-    if (rc != 0) return rc;
-    PJ_LOG(3,("", "....bandwidth UDP = %d KB/s", bandwidth));
-
-    /* Benchmarking TCP */
-    rc = sock_producer_consumer(PJ_SOCK_STREAM, 512, LOOP, &bandwidth);
-    if (rc != 0) return rc;
-    PJ_LOG(3,("", "....bandwidth TCP = %d KB/s", bandwidth));
-
-    return rc;
-}
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_sock_perf_test;
-#endif  /* INCLUDE_SOCK_PERF_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pjlib.h>

+#include <pj/compat/high_precision.h>

+

+

+/**

+ * \page page_pjlib_sock_perf_test Test: Socket Performance

+ *

+ * Test the performance of the socket communication. This will perform

+ * simple producer-consumer type of test, where we calculate how long

+ * does it take to send certain number of packets from producer to

+ * consumer.

+ *

+ * This file is <b>pjlib-test/sock_perf.c</b>

+ *

+ * \include pjlib-test/sock_perf.c

+ */

+

+#if INCLUDE_SOCK_PERF_TEST

+

+/*

+ * sock_producer_consumer()

+ *

+ * Simple producer-consumer benchmarking. Send loop number of

+ * buf_size size packets as fast as possible.

+ */

+static int sock_producer_consumer(int sock_type,

+                                  unsigned buf_size,

+                                  unsigned loop, 

+                                  unsigned *p_bandwidth)

+{

+    pj_sock_t consumer, producer;

+    pj_pool_t *pool;

+    char *outgoing_buffer, *incoming_buffer;

+    pj_timestamp start, stop;

+    unsigned i;

+    pj_highprec_t elapsed, bandwidth;

+    pj_size_t total_received;

+    pj_status_t rc;

+

+    /* Create pool. */

+    pool = pj_pool_create(mem, NULL, 4096, 4096, NULL);

+    if (!pool)

+        return -10;

+

+    /* Create producer-consumer pair. */

+    rc = app_socketpair(PJ_AF_INET, sock_type, 0, &consumer, &producer);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error: create socket pair", rc);

+        return -20;

+    }

+

+    /* Create buffers. */

+    outgoing_buffer = pj_pool_alloc(pool, buf_size);

+    incoming_buffer = pj_pool_alloc(pool, buf_size);

+

+    /* Start loop. */

+    pj_get_timestamp(&start);

+    total_received = 0;

+    for (i=0; i<loop; ++i) {

+        pj_ssize_t sent, part_received, received;

+	pj_time_val delay;

+

+        sent = buf_size;

+        rc = pj_sock_send(producer, outgoing_buffer, &sent, 0);

+        if (rc != PJ_SUCCESS || sent != (pj_ssize_t)buf_size) {

+            app_perror("...error: send()", rc);

+            return -61;

+        }

+

+        /* Repeat recv() until all data is part_received.

+         * This applies only for non-UDP of course, since for UDP

+         * we would expect all data to be part_received in one packet.

+         */

+        received = 0;

+        do {

+            part_received = buf_size-received;

+	    rc = pj_sock_recv(consumer, incoming_buffer+received, 

+			      &part_received, 0);

+	    if (rc != PJ_SUCCESS) {

+	        app_perror("...recv error", rc);

+	        return -70;

+	    }

+            if (part_received <= 0) {

+                PJ_LOG(3,("", "...error: socket has closed (part_received=%d)!",

+                          part_received));

+                return -73;

+            }

+	    if ((pj_size_t)part_received != buf_size-received) {

+                if (sock_type != PJ_SOCK_STREAM) {

+	            PJ_LOG(3,("", "...error: expecting %u bytes, got %u bytes",

+                              buf_size-received, part_received));

+	            return -76;

+                }

+	    }

+            received += part_received;

+        } while ((pj_size_t)received < buf_size);

+

+	total_received += received;

+

+	/* Stop test if it's been runnign for more than 10 secs. */

+	pj_get_timestamp(&stop);

+	delay = pj_elapsed_time(&start, &stop);

+	if (delay.sec > 10)

+	    break;

+    }

+

+    /* Stop timer. */

+    pj_get_timestamp(&stop);

+

+    elapsed = pj_elapsed_usec(&start, &stop);

+

+    /* bandwidth = total_received * 1000 / elapsed */

+    bandwidth = total_received;

+    pj_highprec_mul(bandwidth, 1000);

+    pj_highprec_div(bandwidth, elapsed);

+    

+    *p_bandwidth = (pj_uint32_t)bandwidth;

+

+    /* Close sockets. */

+    pj_sock_close(consumer);

+    pj_sock_close(producer);

+

+    /* Done */

+    pj_pool_release(pool);

+

+    return 0;

+}

+

+/*

+ * sock_perf_test()

+ *

+ * Main test entry.

+ */

+int sock_perf_test(void)

+{

+    enum { LOOP = 64 * 1024 };

+    int rc;

+    unsigned bandwidth;

+

+    PJ_LOG(3,("", "...benchmarking socket "

+                  "(2 sockets, packet=512, single threaded):"));

+    

+    /* Benchmarking UDP */

+    rc = sock_producer_consumer(PJ_SOCK_DGRAM, 512, LOOP, &bandwidth);

+    if (rc != 0) return rc;

+    PJ_LOG(3,("", "....bandwidth UDP = %d KB/s", bandwidth));

+

+    /* Benchmarking TCP */

+    rc = sock_producer_consumer(PJ_SOCK_STREAM, 512, LOOP, &bandwidth);

+    if (rc != 0) return rc;

+    PJ_LOG(3,("", "....bandwidth TCP = %d KB/s", bandwidth));

+

+    return rc;

+}

+

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_sock_perf_test;

+#endif  /* INCLUDE_SOCK_PERF_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/string.c b/pjlib/src/pjlib-test/string.c
index 5f1f13f..99358d3 100644
--- a/pjlib/src/pjlib-test/string.c
+++ b/pjlib/src/pjlib-test/string.c
@@ -1,158 +1,179 @@
-/* $Id$
- */
-#include <pj/string.h>
-#include <pj/pool.h>
-#include <pj/log.h>
-#include "test.h"
-
-/**
- * \page page_pjlib_string_test Test: String
- *
- * This file provides implementation of \b string_test(). It tests the
- * functionality of the string API.
- *
- * \section sleep_test_sec Scope of the Test
- *
- * API tested:
- *  - pj_str()
- *  - pj_strcmp()
- *  - pj_strcmp2()
- *  - pj_stricmp()
- *  - pj_strlen()
- *  - pj_strncmp()
- *  - pj_strnicmp()
- *  - pj_strchr()
- *  - pj_strdup()
- *  - pj_strdup2()
- *  - pj_strcpy()
- *  - pj_strcat()
- *  - pj_strtrim()
- *  - pj_utoa()
- *  - pj_strtoul()
- *  - pj_create_random_string()
- *
- *
- * This file is <b>pjlib-test/string.c</b>
- *
- * \include pjlib-test/string.c
- */
-
-#if INCLUDE_STRING_TEST
-
-#ifdef _MSC_VER
-#   pragma warning(disable: 4204)
-#endif
-
-#define HELLO_WORLD	"Hello World"
-#define JUST_HELLO	"Hello"
-#define UL_VALUE	3456789012UL
-
-int string_test(void)
-{
-    const pj_str_t hello_world = { HELLO_WORLD, strlen(HELLO_WORLD) };
-    const pj_str_t just_hello = { JUST_HELLO, strlen(JUST_HELLO) };
-    pj_str_t s1, s2, s3, s4, s5;
-    enum { RCOUNT = 10, RLEN = 16 };
-    pj_str_t random[RCOUNT];
-    pj_pool_t *pool;
-    int i;
-
-    pool = pj_pool_create(mem, NULL, 4096, 0, NULL);
-    if (!pool) return -5;
-    
-    /* 
-     * pj_str(), pj_strcmp(), pj_stricmp(), pj_strlen(), 
-     * pj_strncmp(), pj_strchr() 
-     */
-    s1 = pj_str(HELLO_WORLD);
-    if (pj_strcmp(&s1, &hello_world) != 0)
-	return -10;
-    if (pj_stricmp(&s1, &hello_world) != 0)
-	return -20;
-    if (pj_strcmp(&s1, &just_hello) <= 0)
-	return -30;
-    if (pj_stricmp(&s1, &just_hello) <= 0)
-	return -40;
-    if (pj_strlen(&s1) != strlen(HELLO_WORLD))
-	return -50;
-    if (pj_strncmp(&s1, &hello_world, 5) != 0)
-	return -60;
-    if (pj_strnicmp(&s1, &hello_world, 5) != 0)
-	return -70;
-    if (pj_strchr(&s1, HELLO_WORLD[1]) != s1.ptr+1)
-	return -80;
-
-    /* 
-     * pj_strdup() 
-     */
-    if (!pj_strdup(pool, &s2, &s1))
-	return -100;
-    if (pj_strcmp(&s1, &s2) != 0)
-	return -110;
-    
-    /* 
-     * pj_strcpy(), pj_strcat() 
-     */
-    s3.ptr = pj_pool_alloc(pool, 256);
-    if (!s3.ptr) 
-	return -200;
-    pj_strcpy(&s3, &s2);
-    pj_strcat(&s3, &just_hello);
-
-    if (pj_strcmp2(&s3, HELLO_WORLD JUST_HELLO) != 0)
-	return -210;
-
-    /* 
-     * pj_strdup2(), pj_strtrim(). 
-     */
-    pj_strdup2(pool, &s4, " " HELLO_WORLD "\t ");
-    pj_strtrim(&s4);
-    if (pj_strcmp2(&s4, HELLO_WORLD) != 0)
-	return -250;
-
-    /* 
-     * pj_utoa() 
-     */
-    s5.ptr = pj_pool_alloc(pool, 16);
-    if (!s5.ptr)
-	return -270;
-    s5.slen = pj_utoa(UL_VALUE, s5.ptr);
-
-    /* 
-     * pj_strtoul() 
-     */
-    if (pj_strtoul(&s5) != UL_VALUE)
-	return -280;
-
-    /* 
-     * pj_create_random_string() 
-     * Check that no duplicate strings are returned.
-     */
-    for (i=0; i<RCOUNT; ++i) {
-	int j;
-	
-	random[i].ptr = pj_pool_alloc(pool, RLEN);
-	if (!random[i].ptr)
-	    return -320;
-
-        random[i].slen = RLEN;
-	pj_create_random_string(random[i].ptr, RLEN);
-
-	for (j=0; j<i; ++j) {
-	    if (pj_strcmp(&random[i], &random[j])==0)
-		return -330;
-	}
-    }
-
-    /* Done. */
-    pj_pool_release(pool);
-    return 0;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_string_test;
-#endif	/* INCLUDE_STRING_TEST */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/string.h>

+#include <pj/pool.h>

+#include <pj/log.h>

+#include "test.h"

+

+/**

+ * \page page_pjlib_string_test Test: String

+ *

+ * This file provides implementation of \b string_test(). It tests the

+ * functionality of the string API.

+ *

+ * \section sleep_test_sec Scope of the Test

+ *

+ * API tested:

+ *  - pj_str()

+ *  - pj_strcmp()

+ *  - pj_strcmp2()

+ *  - pj_stricmp()

+ *  - pj_strlen()

+ *  - pj_strncmp()

+ *  - pj_strnicmp()

+ *  - pj_strchr()

+ *  - pj_strdup()

+ *  - pj_strdup2()

+ *  - pj_strcpy()

+ *  - pj_strcat()

+ *  - pj_strtrim()

+ *  - pj_utoa()

+ *  - pj_strtoul()

+ *  - pj_create_random_string()

+ *

+ *

+ * This file is <b>pjlib-test/string.c</b>

+ *

+ * \include pjlib-test/string.c

+ */

+

+#if INCLUDE_STRING_TEST

+

+#ifdef _MSC_VER

+#   pragma warning(disable: 4204)

+#endif

+

+#define HELLO_WORLD	"Hello World"

+#define JUST_HELLO	"Hello"

+#define UL_VALUE	3456789012UL

+

+int string_test(void)

+{

+    const pj_str_t hello_world = { HELLO_WORLD, strlen(HELLO_WORLD) };

+    const pj_str_t just_hello = { JUST_HELLO, strlen(JUST_HELLO) };

+    pj_str_t s1, s2, s3, s4, s5;

+    enum { RCOUNT = 10, RLEN = 16 };

+    pj_str_t random[RCOUNT];

+    pj_pool_t *pool;

+    int i;

+

+    pool = pj_pool_create(mem, NULL, 4096, 0, NULL);

+    if (!pool) return -5;

+    

+    /* 

+     * pj_str(), pj_strcmp(), pj_stricmp(), pj_strlen(), 

+     * pj_strncmp(), pj_strchr() 

+     */

+    s1 = pj_str(HELLO_WORLD);

+    if (pj_strcmp(&s1, &hello_world) != 0)

+	return -10;

+    if (pj_stricmp(&s1, &hello_world) != 0)

+	return -20;

+    if (pj_strcmp(&s1, &just_hello) <= 0)

+	return -30;

+    if (pj_stricmp(&s1, &just_hello) <= 0)

+	return -40;

+    if (pj_strlen(&s1) != strlen(HELLO_WORLD))

+	return -50;

+    if (pj_strncmp(&s1, &hello_world, 5) != 0)

+	return -60;

+    if (pj_strnicmp(&s1, &hello_world, 5) != 0)

+	return -70;

+    if (pj_strchr(&s1, HELLO_WORLD[1]) != s1.ptr+1)

+	return -80;

+

+    /* 

+     * pj_strdup() 

+     */

+    if (!pj_strdup(pool, &s2, &s1))

+	return -100;

+    if (pj_strcmp(&s1, &s2) != 0)

+	return -110;

+    

+    /* 

+     * pj_strcpy(), pj_strcat() 

+     */

+    s3.ptr = pj_pool_alloc(pool, 256);

+    if (!s3.ptr) 

+	return -200;

+    pj_strcpy(&s3, &s2);

+    pj_strcat(&s3, &just_hello);

+

+    if (pj_strcmp2(&s3, HELLO_WORLD JUST_HELLO) != 0)

+	return -210;

+

+    /* 

+     * pj_strdup2(), pj_strtrim(). 

+     */

+    pj_strdup2(pool, &s4, " " HELLO_WORLD "\t ");

+    pj_strtrim(&s4);

+    if (pj_strcmp2(&s4, HELLO_WORLD) != 0)

+	return -250;

+

+    /* 

+     * pj_utoa() 

+     */

+    s5.ptr = pj_pool_alloc(pool, 16);

+    if (!s5.ptr)

+	return -270;

+    s5.slen = pj_utoa(UL_VALUE, s5.ptr);

+

+    /* 

+     * pj_strtoul() 

+     */

+    if (pj_strtoul(&s5) != UL_VALUE)

+	return -280;

+

+    /* 

+     * pj_create_random_string() 

+     * Check that no duplicate strings are returned.

+     */

+    for (i=0; i<RCOUNT; ++i) {

+	int j;

+	

+	random[i].ptr = pj_pool_alloc(pool, RLEN);

+	if (!random[i].ptr)

+	    return -320;

+

+        random[i].slen = RLEN;

+	pj_create_random_string(random[i].ptr, RLEN);

+

+	for (j=0; j<i; ++j) {

+	    if (pj_strcmp(&random[i], &random[j])==0)

+		return -330;

+	}

+    }

+

+    /* Done. */

+    pj_pool_release(pool);

+    return 0;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_string_test;

+#endif	/* INCLUDE_STRING_TEST */

+

diff --git a/pjlib/src/pjlib-test/test.c b/pjlib/src/pjlib-test/test.c
index c9349a2..9c69a77 100644
--- a/pjlib/src/pjlib-test/test.c
+++ b/pjlib/src/pjlib-test/test.c
@@ -1,183 +1,204 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-#ifdef _MSC_VER
-#  pragma warning(disable:4127)
-#endif
-
-#define DO_TEST(test)	do { \
-			    PJ_LOG(3, ("test", "Running %s...", #test));  \
-			    rc = test; \
-			    PJ_LOG(3, ("test",  \
-				       "%s(%d)",  \
-				       (rc ? "..ERROR" : "..success"), rc)); \
-			    if (rc!=0) goto on_return; \
-			} while (0)
-
-
-pj_pool_factory *mem;
-
-int param_echo_sock_type;
-const char *param_echo_server = ECHO_SERVER_ADDRESS;
-int param_echo_port = ECHO_SERVER_START_PORT;
-
-int test_inner(void)
-{
-    pj_caching_pool caching_pool;
-    const char *filename;
-    int line;
-    int rc = 0;
-
-    mem = &caching_pool.factory;
-
-    pj_log_set_level(3);
-    pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | 
-                     PJ_LOG_HAS_MICRO_SEC);
-
-    rc = pj_init();
-    if (rc != 0) {
-	app_perror("pj_init() error!!", rc);
-	return rc;
-    }
-    
-    pj_dump_config();
-    pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );
-
-#if INCLUDE_ERRNO_TEST
-    DO_TEST( errno_test() );
-#endif
-
-#if INCLUDE_TIMESTAMP_TEST
-    DO_TEST( timestamp_test() );
-#endif
-
-#if INCLUDE_EXCEPTION_TEST
-    DO_TEST( exception_test() );
-#endif
-
-#if INCLUDE_RAND_TEST
-    DO_TEST( rand_test() );
-#endif
-
-#if INCLUDE_LIST_TEST
-    DO_TEST( list_test() );
-#endif
-
-#if INCLUDE_POOL_TEST
-    DO_TEST( pool_test() );
-#endif
-
-#if INCLUDE_POOL_PERF_TEST
-    DO_TEST( pool_perf_test() );
-#endif
-
-#if INCLUDE_STRING_TEST
-    DO_TEST( string_test() );
-#endif
-    
-#if INCLUDE_FIFOBUF_TEST
-    DO_TEST( fifobuf_test() );
-#endif
-
-#if INCLUDE_RBTREE_TEST
-    DO_TEST( rbtree_test() );
-#endif
-
-#if INCLUDE_ATOMIC_TEST
-    DO_TEST( atomic_test() );
-#endif
-
-#if INCLUDE_MUTEX_TEST
-    DO_TEST( mutex_test() );
-#endif
-
-#if INCLUDE_TIMER_TEST
-    DO_TEST( timer_test() );
-#endif
-
-#if INCLUDE_SLEEP_TEST
-    DO_TEST( sleep_test() );
-#endif
-
-#if INCLUDE_THREAD_TEST
-    DO_TEST( thread_test() );
-#endif
-
-#if INCLUDE_SOCK_TEST
-    DO_TEST( sock_test() );
-#endif
-
-#if INCLUDE_SOCK_PERF_TEST
-    DO_TEST( sock_perf_test() );
-#endif
-
-#if INCLUDE_SELECT_TEST
-    DO_TEST( select_test() );
-#endif
-
-#if INCLUDE_UDP_IOQUEUE_TEST
-    DO_TEST( udp_ioqueue_test() );
-#endif
-
-#if PJ_HAS_TCP && INCLUDE_TCP_IOQUEUE_TEST
-    DO_TEST( tcp_ioqueue_test() );
-#endif
-
-#if INCLUDE_IOQUEUE_PERF_TEST
-    DO_TEST( ioqueue_perf_test() );
-#endif
-
-#if INCLUDE_FILE_TEST
-    DO_TEST( file_test() );
-#endif
-
-#if INCLUDE_ECHO_SERVER
-    //echo_server();
-    //echo_srv_sync();
-    udp_echo_srv_ioqueue();
-
-#elif INCLUDE_ECHO_CLIENT
-    if (param_echo_sock_type == 0)
-        param_echo_sock_type = PJ_SOCK_DGRAM;
-
-    echo_client( param_echo_sock_type, 
-                 param_echo_server, 
-                 param_echo_port);
-#endif
-
-    goto on_return;
-
-on_return:
-
-    pj_caching_pool_destroy( &caching_pool );
-
-    PJ_LOG(3,("test", ""));
- 
-    pj_thread_get_stack_info(pj_thread_this(), &filename, &line);
-    PJ_LOG(3,("test", "Stack max usage: %u, deepest: %s:%u", 
-	              pj_thread_get_stack_max_usage(pj_thread_this()),
-		      filename, line));
-    if (rc == 0)
-	PJ_LOG(3,("test", "Looks like everything is okay!.."));
-    else
-	PJ_LOG(3,("test", "Test completed with error(s)"));
-    return 0;
-}
-
-int test_main(void)
-{
-    PJ_USE_EXCEPTION;
-
-    PJ_TRY {
-        return test_inner();
-    }
-    PJ_DEFAULT {
-        int id = PJ_GET_EXCEPTION();
-        PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)", 
-                  id, pj_exception_id_name(id)));
-    }
-    PJ_END;
-
-    return -1;
-}
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pjlib.h>

+#ifdef _MSC_VER

+#  pragma warning(disable:4127)

+#endif

+

+#define DO_TEST(test)	do { \

+			    PJ_LOG(3, ("test", "Running %s...", #test));  \

+			    rc = test; \

+			    PJ_LOG(3, ("test",  \

+				       "%s(%d)",  \

+				       (rc ? "..ERROR" : "..success"), rc)); \

+			    if (rc!=0) goto on_return; \

+			} while (0)

+

+

+pj_pool_factory *mem;

+

+int param_echo_sock_type;

+const char *param_echo_server = ECHO_SERVER_ADDRESS;

+int param_echo_port = ECHO_SERVER_START_PORT;

+

+int test_inner(void)

+{

+    pj_caching_pool caching_pool;

+    const char *filename;

+    int line;

+    int rc = 0;

+

+    mem = &caching_pool.factory;

+

+    pj_log_set_level(3);

+    pj_log_set_decor(PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | 

+                     PJ_LOG_HAS_MICRO_SEC);

+

+    rc = pj_init();

+    if (rc != 0) {

+	app_perror("pj_init() error!!", rc);

+	return rc;

+    }

+    

+    pj_dump_config();

+    pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );

+

+#if INCLUDE_ERRNO_TEST

+    DO_TEST( errno_test() );

+#endif

+

+#if INCLUDE_TIMESTAMP_TEST

+    DO_TEST( timestamp_test() );

+#endif

+

+#if INCLUDE_EXCEPTION_TEST

+    DO_TEST( exception_test() );

+#endif

+

+#if INCLUDE_RAND_TEST

+    DO_TEST( rand_test() );

+#endif

+

+#if INCLUDE_LIST_TEST

+    DO_TEST( list_test() );

+#endif

+

+#if INCLUDE_POOL_TEST

+    DO_TEST( pool_test() );

+#endif

+

+#if INCLUDE_POOL_PERF_TEST

+    DO_TEST( pool_perf_test() );

+#endif

+

+#if INCLUDE_STRING_TEST

+    DO_TEST( string_test() );

+#endif

+    

+#if INCLUDE_FIFOBUF_TEST

+    DO_TEST( fifobuf_test() );

+#endif

+

+#if INCLUDE_RBTREE_TEST

+    DO_TEST( rbtree_test() );

+#endif

+

+#if INCLUDE_ATOMIC_TEST

+    DO_TEST( atomic_test() );

+#endif

+

+#if INCLUDE_MUTEX_TEST

+    DO_TEST( mutex_test() );

+#endif

+

+#if INCLUDE_TIMER_TEST

+    DO_TEST( timer_test() );

+#endif

+

+#if INCLUDE_SLEEP_TEST

+    DO_TEST( sleep_test() );

+#endif

+

+#if INCLUDE_THREAD_TEST

+    DO_TEST( thread_test() );

+#endif

+

+#if INCLUDE_SOCK_TEST

+    DO_TEST( sock_test() );

+#endif

+

+#if INCLUDE_SOCK_PERF_TEST

+    DO_TEST( sock_perf_test() );

+#endif

+

+#if INCLUDE_SELECT_TEST

+    DO_TEST( select_test() );

+#endif

+

+#if INCLUDE_UDP_IOQUEUE_TEST

+    DO_TEST( udp_ioqueue_test() );

+#endif

+

+#if PJ_HAS_TCP && INCLUDE_TCP_IOQUEUE_TEST

+    DO_TEST( tcp_ioqueue_test() );

+#endif

+

+#if INCLUDE_IOQUEUE_PERF_TEST

+    DO_TEST( ioqueue_perf_test() );

+#endif

+

+#if INCLUDE_FILE_TEST

+    DO_TEST( file_test() );

+#endif

+

+#if INCLUDE_ECHO_SERVER

+    //echo_server();

+    //echo_srv_sync();

+    udp_echo_srv_ioqueue();

+

+#elif INCLUDE_ECHO_CLIENT

+    if (param_echo_sock_type == 0)

+        param_echo_sock_type = PJ_SOCK_DGRAM;

+

+    echo_client( param_echo_sock_type, 

+                 param_echo_server, 

+                 param_echo_port);

+#endif

+

+    goto on_return;

+

+on_return:

+

+    pj_caching_pool_destroy( &caching_pool );

+

+    PJ_LOG(3,("test", ""));

+ 

+    pj_thread_get_stack_info(pj_thread_this(), &filename, &line);

+    PJ_LOG(3,("test", "Stack max usage: %u, deepest: %s:%u", 

+	              pj_thread_get_stack_max_usage(pj_thread_this()),

+		      filename, line));

+    if (rc == 0)

+	PJ_LOG(3,("test", "Looks like everything is okay!.."));

+    else

+	PJ_LOG(3,("test", "Test completed with error(s)"));

+    return 0;

+}

+

+int test_main(void)

+{

+    PJ_USE_EXCEPTION;

+

+    PJ_TRY {

+        return test_inner();

+    }

+    PJ_DEFAULT {

+        int id = PJ_GET_EXCEPTION();

+        PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)", 

+                  id, pj_exception_id_name(id)));

+    }

+    PJ_END;

+

+    return -1;

+}

diff --git a/pjlib/src/pjlib-test/test.h b/pjlib/src/pjlib-test/test.h
index 1759290..0ae010c 100644
--- a/pjlib/src/pjlib-test/test.h
+++ b/pjlib/src/pjlib-test/test.h
@@ -1,95 +1,116 @@
-/* $Id$
- */
-#ifndef __PJLIB_TEST_H__
-#define __PJLIB_TEST_H__
-
-#include <pj/types.h>
-
-#define GROUP_LIBC                  1
-#define GROUP_OS                    1
-#define GROUP_DATA_STRUCTURE        1
-#define GROUP_NETWORK               1
-#define GROUP_FILE                  1
-
-#define INCLUDE_ERRNO_TEST          GROUP_LIBC
-#define INCLUDE_TIMESTAMP_TEST      GROUP_OS
-#define INCLUDE_EXCEPTION_TEST	    GROUP_LIBC
-#define INCLUDE_RAND_TEST	    GROUP_LIBC
-#define INCLUDE_LIST_TEST	    GROUP_DATA_STRUCTURE
-#define INCLUDE_POOL_TEST	    GROUP_LIBC
-#define INCLUDE_POOL_PERF_TEST	    (PJ_HAS_MALLOC && GROUP_LIBC)
-#define INCLUDE_STRING_TEST	    GROUP_DATA_STRUCTURE
-#define INCLUDE_FIFOBUF_TEST	    0	// GROUP_DATA_STRUCTURE
-#define INCLUDE_RBTREE_TEST	    GROUP_DATA_STRUCTURE
-#define INCLUDE_TIMER_TEST	    GROUP_DATA_STRUCTURE
-#define INCLUDE_ATOMIC_TEST         GROUP_OS
-#define INCLUDE_MUTEX_TEST	    GROUP_OS
-#define INCLUDE_SLEEP_TEST          GROUP_OS
-#define INCLUDE_THREAD_TEST         GROUP_OS 
-#define INCLUDE_SOCK_TEST	    GROUP_NETWORK
-#define INCLUDE_SOCK_PERF_TEST      GROUP_NETWORK
-#define INCLUDE_SELECT_TEST	    GROUP_NETWORK
-#define INCLUDE_UDP_IOQUEUE_TEST    GROUP_NETWORK
-#define INCLUDE_TCP_IOQUEUE_TEST    GROUP_NETWORK
-#define INCLUDE_IOQUEUE_PERF_TEST   GROUP_NETWORK
-#define INCLUDE_FILE_TEST           GROUP_FILE
-
-#define INCLUDE_ECHO_SERVER         0
-#define INCLUDE_ECHO_CLIENT         0
-
-
-#define ECHO_SERVER_MAX_THREADS     2
-#define ECHO_SERVER_START_PORT      65000
-#define ECHO_SERVER_ADDRESS         "compaq.home"
-#define ECHO_SERVER_DURATION_MSEC   (60*60*1000)
-
-#define ECHO_CLIENT_MAX_THREADS     6
-
-PJ_BEGIN_DECL
-
-extern int errno_test(void);
-extern int timestamp_test(void);
-extern int exception_test(void);
-extern int rand_test(void);
-extern int list_test(void);
-extern int pool_test(void);
-extern int pool_perf_test(void);
-extern int string_test(void);
-extern int fifobuf_test(void);
-extern int timer_test(void);
-extern int rbtree_test(void);
-extern int atomic_test(void);
-extern int mutex_test(void);
-extern int sleep_test(void);
-extern int thread_test(void);
-extern int sock_test(void);
-extern int sock_perf_test(void);
-extern int select_test(void);
-extern int udp_ioqueue_test(void);
-extern int tcp_ioqueue_test(void);
-extern int ioqueue_perf_test(void);
-extern int file_test(void);
-
-extern int echo_server(void);
-extern int echo_client(int sock_type, const char *server, int port);
-
-extern int echo_srv_sync(void);
-extern int udp_echo_srv_ioqueue(void);
-extern int echo_srv_common_loop(pj_atomic_t *bytes_counter);
-
-extern pj_pool_factory *mem;
-
-extern int          test_main(void);
-extern void         app_perror(const char *msg, pj_status_t err);
-extern pj_status_t  app_socket(int family, int type, int proto, int port,
-                               pj_sock_t *ptr_sock);
-extern pj_status_t  app_socketpair(int family, int type, int protocol,
-                                   pj_sock_t *server, pj_sock_t *client);
-
-//#define TRACE_(expr) PJ_LOG(3,expr)
-#define TRACE_(expr)
-
-PJ_END_DECL
-
-#endif	/* __PJLIB_TEST_H__ */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJLIB_TEST_H__

+#define __PJLIB_TEST_H__

+

+#include <pj/types.h>

+

+#define GROUP_LIBC                  1

+#define GROUP_OS                    1

+#define GROUP_DATA_STRUCTURE        1

+#define GROUP_NETWORK               1

+#define GROUP_FILE                  1

+

+#define INCLUDE_ERRNO_TEST          GROUP_LIBC

+#define INCLUDE_TIMESTAMP_TEST      GROUP_OS

+#define INCLUDE_EXCEPTION_TEST	    GROUP_LIBC

+#define INCLUDE_RAND_TEST	    GROUP_LIBC

+#define INCLUDE_LIST_TEST	    GROUP_DATA_STRUCTURE

+#define INCLUDE_POOL_TEST	    GROUP_LIBC

+#define INCLUDE_POOL_PERF_TEST	    (PJ_HAS_MALLOC && GROUP_LIBC)

+#define INCLUDE_STRING_TEST	    GROUP_DATA_STRUCTURE

+#define INCLUDE_FIFOBUF_TEST	    0	// GROUP_DATA_STRUCTURE

+#define INCLUDE_RBTREE_TEST	    GROUP_DATA_STRUCTURE

+#define INCLUDE_TIMER_TEST	    GROUP_DATA_STRUCTURE

+#define INCLUDE_ATOMIC_TEST         GROUP_OS

+#define INCLUDE_MUTEX_TEST	    GROUP_OS

+#define INCLUDE_SLEEP_TEST          GROUP_OS

+#define INCLUDE_THREAD_TEST         GROUP_OS 

+#define INCLUDE_SOCK_TEST	    GROUP_NETWORK

+#define INCLUDE_SOCK_PERF_TEST      GROUP_NETWORK

+#define INCLUDE_SELECT_TEST	    GROUP_NETWORK

+#define INCLUDE_UDP_IOQUEUE_TEST    GROUP_NETWORK

+#define INCLUDE_TCP_IOQUEUE_TEST    GROUP_NETWORK

+#define INCLUDE_IOQUEUE_PERF_TEST   GROUP_NETWORK

+#define INCLUDE_FILE_TEST           GROUP_FILE

+

+#define INCLUDE_ECHO_SERVER         0

+#define INCLUDE_ECHO_CLIENT         0

+

+

+#define ECHO_SERVER_MAX_THREADS     2

+#define ECHO_SERVER_START_PORT      65000

+#define ECHO_SERVER_ADDRESS         "compaq.home"

+#define ECHO_SERVER_DURATION_MSEC   (60*60*1000)

+

+#define ECHO_CLIENT_MAX_THREADS     6

+

+PJ_BEGIN_DECL

+

+extern int errno_test(void);

+extern int timestamp_test(void);

+extern int exception_test(void);

+extern int rand_test(void);

+extern int list_test(void);

+extern int pool_test(void);

+extern int pool_perf_test(void);

+extern int string_test(void);

+extern int fifobuf_test(void);

+extern int timer_test(void);

+extern int rbtree_test(void);

+extern int atomic_test(void);

+extern int mutex_test(void);

+extern int sleep_test(void);

+extern int thread_test(void);

+extern int sock_test(void);

+extern int sock_perf_test(void);

+extern int select_test(void);

+extern int udp_ioqueue_test(void);

+extern int tcp_ioqueue_test(void);

+extern int ioqueue_perf_test(void);

+extern int file_test(void);

+

+extern int echo_server(void);

+extern int echo_client(int sock_type, const char *server, int port);

+

+extern int echo_srv_sync(void);

+extern int udp_echo_srv_ioqueue(void);

+extern int echo_srv_common_loop(pj_atomic_t *bytes_counter);

+

+extern pj_pool_factory *mem;

+

+extern int          test_main(void);

+extern void         app_perror(const char *msg, pj_status_t err);

+extern pj_status_t  app_socket(int family, int type, int proto, int port,

+                               pj_sock_t *ptr_sock);

+extern pj_status_t  app_socketpair(int family, int type, int protocol,

+                                   pj_sock_t *server, pj_sock_t *client);

+

+//#define TRACE_(expr) PJ_LOG(3,expr)

+#define TRACE_(expr)

+

+PJ_END_DECL

+

+#endif	/* __PJLIB_TEST_H__ */

+

diff --git a/pjlib/src/pjlib-test/thread.c b/pjlib/src/pjlib-test/thread.c
index b35d9a5..a1c1bef 100644
--- a/pjlib/src/pjlib-test/thread.c
+++ b/pjlib/src/pjlib-test/thread.c
@@ -1,273 +1,294 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_thread_test Test: Thread Test
- *
- * This file contains \a thread_test() definition.
- *
- * \section thread_test_scope_sec Scope of Test
- * This tests:
- *  - whether PJ_THREAD_SUSPENDED flag works.
- *  - whether multithreading works.
- *  - whether thread timeslicing works, and threads have equal
- *    time-slice proportion.
- * 
- * APIs tested:
- *  - pj_thread_create()
- *  - pj_thread_register()
- *  - pj_thread_this()
- *  - pj_thread_get_name()
- *  - pj_thread_destroy()
- *  - pj_thread_resume()
- *  - pj_thread_sleep()
- *  - pj_thread_join()
- *  - pj_thread_destroy()
- *
- *
- * This file is <b>pjlib-test/thread.c</b>
- *
- * \include pjlib-test/thread.c
- */
-#if INCLUDE_THREAD_TEST
-
-#include <pjlib.h>
-
-#define THIS_FILE   "thread_test"
-
-static int quit_flag=0;
-
-/*
- * The thread's entry point.
- *
- * Each of the thread mainly will just execute the loop which
- * increments a variable.
- */
-static void* thread_proc(pj_uint32_t *pcounter)
-{
-    /* Test that pj_thread_register() works. */
-    pj_thread_desc desc;
-    pj_thread_t *this_thread;
-    pj_status_t rc;
-
-    rc = pj_thread_register("thread", desc, &this_thread);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error in pj_thread_register", rc);
-        return NULL;
-    }
-
-    /* Test that pj_thread_this() works */
-    this_thread = pj_thread_this();
-    if (this_thread == NULL) {
-        PJ_LOG(3,(THIS_FILE, "...error: pj_thread_this() returns NULL!"));
-        return NULL;
-    }
-
-    /* Test that pj_thread_get_name() works */
-    if (pj_thread_get_name(this_thread) == NULL) {
-        PJ_LOG(3,(THIS_FILE, "...error: pj_thread_get_name() returns NULL!"));
-        return NULL;
-    }
-
-    /* Main loop */
-    for (;!quit_flag;) {
-	(*pcounter)++;
-        //Must sleep if platform doesn't do time-slicing.
-	pj_thread_sleep(0);
-    }
-
-    return NULL;
-}
-
-/*
- * simple_thread()
- */
-static int simple_thread(const char *title, unsigned flags)
-{
-    pj_pool_t *pool;
-    pj_thread_t *thread;
-    pj_status_t rc;
-    pj_uint32_t counter = 0;
- 
-    PJ_LOG(3,(THIS_FILE, "..%s", title));
-    
-    pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
-    if (!pool)
-	return -1000;
-
-    quit_flag = 0;
-
-    rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc,
-			  &counter,
-			  PJ_THREAD_DEFAULT_STACK_SIZE,
-			  flags,
-			  &thread);
-
-    if (rc != PJ_SUCCESS) {
-	app_perror("...error: unable to create thread", rc);
-	return -1010;
-    }
-
-    if (flags & PJ_THREAD_SUSPENDED) {
-	rc = pj_thread_resume(thread);
-	if (rc != PJ_SUCCESS) {
-	    app_perror("...error: resume thread error", rc);
-	    return -1020;
-	}
-    }
-    
-    PJ_LOG(3,(THIS_FILE, "..waiting for thread to quit.."));
-
-    quit_flag = 1;
-    pj_thread_join(thread);
-
-    pj_pool_release(pool);
-
-    PJ_LOG(3,(THIS_FILE, "...%s success", title));
-    return PJ_SUCCESS;
-}
-
-
-/*
- * timeslice_test()
- */
-static int timeslice_test(void)
-{
-    enum { NUM_THREADS = 4 };
-    pj_pool_t *pool;
-    pj_uint32_t counter[NUM_THREADS], lowest, highest, diff;
-    pj_thread_t *thread[NUM_THREADS];
-    int i;
-    pj_status_t rc;
-
-    quit_flag = 0;
-
-    pool = pj_pool_create(mem, NULL, 4096, 0, NULL);
-    if (!pool)
-        return -10;
-
-    PJ_LOG(3,(THIS_FILE, "..timeslice testing with %d threads", NUM_THREADS));
-
-    /* Create all threads in suspended mode. */
-    for (i=0; i<NUM_THREADS; ++i) {
-        counter[i] = 0;
-        rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc, 
-			      &counter[i], 
-                              PJ_THREAD_DEFAULT_STACK_SIZE, 
-                              PJ_THREAD_SUSPENDED, 
-                              &thread[i]);
-        if (rc!=PJ_SUCCESS) {
-            app_perror("...ERROR in pj_thread_create()", rc);
-            return -20;
-        }
-    }
-
-    /* Sleep for 1 second.
-     * The purpose of this is to test whether all threads are suspended.
-     */
-    pj_thread_sleep(1000);
-
-    /* Check that all counters are still zero. */
-    for (i=0; i<NUM_THREADS; ++i) {
-        if (counter[i] != 0) {
-            PJ_LOG(3,(THIS_FILE, "....ERROR! Thread %d-th is not suspended!", 
-		      i));
-            return -30;
-        }
-    }
-
-    /* Now resume all threads. */
-    for (i=0; i<NUM_THREADS; ++i) {
-        rc = pj_thread_resume(thread[i]);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...ERROR in pj_thread_resume()", rc);
-            return -40;
-        }
-    }
-
-    /* Main thread sleeps for some time to allow threads to run. 
-     * The longer we sleep, the more accurate the calculation will be,
-     * but it'll make user waits for longer for the test to finish.
-     */
-    pj_thread_sleep(5000);
-
-    /* Signal all threads to quit. */
-    quit_flag = 1;
-
-    /* Wait until all threads quit, then destroy. */
-    for (i=0; i<NUM_THREADS; ++i) {
-        rc = pj_thread_join(thread[i]);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...ERROR in pj_thread_join()", rc);
-            return -50;
-        }
-        rc = pj_thread_destroy(thread[i]);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...ERROR in pj_thread_destroy()", rc);
-            return -60;
-        }
-    }
-
-    /* Now examine the value of the counters.
-     * Check that all threads had equal proportion of processing.
-     */
-    lowest = 0xFFFFFFFF;
-    highest = 0;
-    for (i=0; i<NUM_THREADS; ++i) {
-        if (counter[i] < lowest)
-            lowest = counter[i];
-        if (counter[i] > highest)
-            highest = counter[i];
-    }
-
-    /* Check that all threads are running. */
-    if (lowest < 2) {
-        PJ_LOG(3,(THIS_FILE, "...ERROR: not all threads were running!"));
-        return -70;
-    }
-
-    /* The difference between lowest and higest should be lower than 50%.
-     */
-    diff = (highest-lowest)*100 / ((highest+lowest)/2);
-    if ( diff >= 50) {
-        PJ_LOG(3,(THIS_FILE, "...ERROR: thread didn't have equal timeslice!"));
-        PJ_LOG(3,(THIS_FILE, ".....lowest counter=%u, highest counter=%u, diff=%u%%",
-                             lowest, highest, diff));
-        return -80;
-    } else {
-        PJ_LOG(3,(THIS_FILE, 
-                  "...info: timeslice diff between lowest & highest=%u%%",
-                  diff));
-    }
-
-    return 0;
-}
-
-int thread_test(void)
-{
-    int rc;
-
-    rc = simple_thread("simple thread test", 0);
-    if (rc != PJ_SUCCESS)
-	return rc;
-    
-    rc = simple_thread("suspended thread test", PJ_THREAD_SUSPENDED);
-    if (rc != PJ_SUCCESS)
-	return rc;
-    
-    rc = timeslice_test();
-    if (rc != PJ_SUCCESS)
-	return rc;
-
-    return rc;
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_thread_test;
-#endif	/* INCLUDE_THREAD_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+/**

+ * \page page_pjlib_thread_test Test: Thread Test

+ *

+ * This file contains \a thread_test() definition.

+ *

+ * \section thread_test_scope_sec Scope of Test

+ * This tests:

+ *  - whether PJ_THREAD_SUSPENDED flag works.

+ *  - whether multithreading works.

+ *  - whether thread timeslicing works, and threads have equal

+ *    time-slice proportion.

+ * 

+ * APIs tested:

+ *  - pj_thread_create()

+ *  - pj_thread_register()

+ *  - pj_thread_this()

+ *  - pj_thread_get_name()

+ *  - pj_thread_destroy()

+ *  - pj_thread_resume()

+ *  - pj_thread_sleep()

+ *  - pj_thread_join()

+ *  - pj_thread_destroy()

+ *

+ *

+ * This file is <b>pjlib-test/thread.c</b>

+ *

+ * \include pjlib-test/thread.c

+ */

+#if INCLUDE_THREAD_TEST

+

+#include <pjlib.h>

+

+#define THIS_FILE   "thread_test"

+

+static int quit_flag=0;

+

+/*

+ * The thread's entry point.

+ *

+ * Each of the thread mainly will just execute the loop which

+ * increments a variable.

+ */

+static void* thread_proc(pj_uint32_t *pcounter)

+{

+    /* Test that pj_thread_register() works. */

+    pj_thread_desc desc;

+    pj_thread_t *this_thread;

+    pj_status_t rc;

+

+    rc = pj_thread_register("thread", desc, &this_thread);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error in pj_thread_register", rc);

+        return NULL;

+    }

+

+    /* Test that pj_thread_this() works */

+    this_thread = pj_thread_this();

+    if (this_thread == NULL) {

+        PJ_LOG(3,(THIS_FILE, "...error: pj_thread_this() returns NULL!"));

+        return NULL;

+    }

+

+    /* Test that pj_thread_get_name() works */

+    if (pj_thread_get_name(this_thread) == NULL) {

+        PJ_LOG(3,(THIS_FILE, "...error: pj_thread_get_name() returns NULL!"));

+        return NULL;

+    }

+

+    /* Main loop */

+    for (;!quit_flag;) {

+	(*pcounter)++;

+        //Must sleep if platform doesn't do time-slicing.

+	pj_thread_sleep(0);

+    }

+

+    return NULL;

+}

+

+/*

+ * simple_thread()

+ */

+static int simple_thread(const char *title, unsigned flags)

+{

+    pj_pool_t *pool;

+    pj_thread_t *thread;

+    pj_status_t rc;

+    pj_uint32_t counter = 0;

+ 

+    PJ_LOG(3,(THIS_FILE, "..%s", title));

+    

+    pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);

+    if (!pool)

+	return -1000;

+

+    quit_flag = 0;

+

+    rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc,

+			  &counter,

+			  PJ_THREAD_DEFAULT_STACK_SIZE,

+			  flags,

+			  &thread);

+

+    if (rc != PJ_SUCCESS) {

+	app_perror("...error: unable to create thread", rc);

+	return -1010;

+    }

+

+    if (flags & PJ_THREAD_SUSPENDED) {

+	rc = pj_thread_resume(thread);

+	if (rc != PJ_SUCCESS) {

+	    app_perror("...error: resume thread error", rc);

+	    return -1020;

+	}

+    }

+    

+    PJ_LOG(3,(THIS_FILE, "..waiting for thread to quit.."));

+

+    quit_flag = 1;

+    pj_thread_join(thread);

+

+    pj_pool_release(pool);

+

+    PJ_LOG(3,(THIS_FILE, "...%s success", title));

+    return PJ_SUCCESS;

+}

+

+

+/*

+ * timeslice_test()

+ */

+static int timeslice_test(void)

+{

+    enum { NUM_THREADS = 4 };

+    pj_pool_t *pool;

+    pj_uint32_t counter[NUM_THREADS], lowest, highest, diff;

+    pj_thread_t *thread[NUM_THREADS];

+    int i;

+    pj_status_t rc;

+

+    quit_flag = 0;

+

+    pool = pj_pool_create(mem, NULL, 4096, 0, NULL);

+    if (!pool)

+        return -10;

+

+    PJ_LOG(3,(THIS_FILE, "..timeslice testing with %d threads", NUM_THREADS));

+

+    /* Create all threads in suspended mode. */

+    for (i=0; i<NUM_THREADS; ++i) {

+        counter[i] = 0;

+        rc = pj_thread_create(pool, "thread", (pj_thread_proc*)&thread_proc, 

+			      &counter[i], 

+                              PJ_THREAD_DEFAULT_STACK_SIZE, 

+                              PJ_THREAD_SUSPENDED, 

+                              &thread[i]);

+        if (rc!=PJ_SUCCESS) {

+            app_perror("...ERROR in pj_thread_create()", rc);

+            return -20;

+        }

+    }

+

+    /* Sleep for 1 second.

+     * The purpose of this is to test whether all threads are suspended.

+     */

+    pj_thread_sleep(1000);

+

+    /* Check that all counters are still zero. */

+    for (i=0; i<NUM_THREADS; ++i) {

+        if (counter[i] != 0) {

+            PJ_LOG(3,(THIS_FILE, "....ERROR! Thread %d-th is not suspended!", 

+		      i));

+            return -30;

+        }

+    }

+

+    /* Now resume all threads. */

+    for (i=0; i<NUM_THREADS; ++i) {

+        rc = pj_thread_resume(thread[i]);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...ERROR in pj_thread_resume()", rc);

+            return -40;

+        }

+    }

+

+    /* Main thread sleeps for some time to allow threads to run. 

+     * The longer we sleep, the more accurate the calculation will be,

+     * but it'll make user waits for longer for the test to finish.

+     */

+    pj_thread_sleep(5000);

+

+    /* Signal all threads to quit. */

+    quit_flag = 1;

+

+    /* Wait until all threads quit, then destroy. */

+    for (i=0; i<NUM_THREADS; ++i) {

+        rc = pj_thread_join(thread[i]);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...ERROR in pj_thread_join()", rc);

+            return -50;

+        }

+        rc = pj_thread_destroy(thread[i]);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...ERROR in pj_thread_destroy()", rc);

+            return -60;

+        }

+    }

+

+    /* Now examine the value of the counters.

+     * Check that all threads had equal proportion of processing.

+     */

+    lowest = 0xFFFFFFFF;

+    highest = 0;

+    for (i=0; i<NUM_THREADS; ++i) {

+        if (counter[i] < lowest)

+            lowest = counter[i];

+        if (counter[i] > highest)

+            highest = counter[i];

+    }

+

+    /* Check that all threads are running. */

+    if (lowest < 2) {

+        PJ_LOG(3,(THIS_FILE, "...ERROR: not all threads were running!"));

+        return -70;

+    }

+

+    /* The difference between lowest and higest should be lower than 50%.

+     */

+    diff = (highest-lowest)*100 / ((highest+lowest)/2);

+    if ( diff >= 50) {

+        PJ_LOG(3,(THIS_FILE, "...ERROR: thread didn't have equal timeslice!"));

+        PJ_LOG(3,(THIS_FILE, ".....lowest counter=%u, highest counter=%u, diff=%u%%",

+                             lowest, highest, diff));

+        return -80;

+    } else {

+        PJ_LOG(3,(THIS_FILE, 

+                  "...info: timeslice diff between lowest & highest=%u%%",

+                  diff));

+    }

+

+    return 0;

+}

+

+int thread_test(void)

+{

+    int rc;

+

+    rc = simple_thread("simple thread test", 0);

+    if (rc != PJ_SUCCESS)

+	return rc;

+    

+    rc = simple_thread("suspended thread test", PJ_THREAD_SUSPENDED);

+    if (rc != PJ_SUCCESS)

+	return rc;

+    

+    rc = timeslice_test();

+    if (rc != PJ_SUCCESS)

+	return rc;

+

+    return rc;

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_thread_test;

+#endif	/* INCLUDE_THREAD_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/timer.c b/pjlib/src/pjlib-test/timer.c
index c6922cf..4f3d4b8 100644
--- a/pjlib/src/pjlib-test/timer.c
+++ b/pjlib/src/pjlib-test/timer.c
@@ -1,170 +1,191 @@
-/* $Id$
- */
-#include "test.h"
-
-/**
- * \page page_pjlib_timer_test Test: Timer
- *
- * This file provides implementation of \b timer_test(). It tests the
- * functionality of the timer heap.
- *
- *
- * This file is <b>pjlib-test/timer.c</b>
- *
- * \include pjlib-test/timer.c
- */
-
-
-#if INCLUDE_TIMER_TEST
-
-#include <pjlib.h>
-
-#define LOOP		16
-#define MIN_COUNT	250
-#define MAX_COUNT	(LOOP * MIN_COUNT)
-#define MIN_DELAY	2
-#define	D		(MAX_COUNT / 32000)
-#define DELAY		(D < MIN_DELAY ? MIN_DELAY : D)
-#define THIS_FILE	"timer_test"
-
-
-static void timer_callback(pj_timer_heap_t *ht, pj_timer_entry *e)
-{
-    PJ_UNUSED_ARG(ht);
-    PJ_UNUSED_ARG(e);
-}
-
-static int test_timer_heap(void)
-{
-    int i, j;
-    pj_timer_entry *entry;
-    pj_pool_t *pool;
-    pj_timer_heap_t *timer;
-    pj_time_val delay;
-    pj_status_t rc;    int err=0;
-    unsigned size, count;
-
-    size = pj_timer_heap_mem_size(MAX_COUNT)+MAX_COUNT*sizeof(pj_timer_entry);
-    pool = pj_pool_create( mem, NULL, size, 4000, NULL);
-    if (!pool) {
-	PJ_LOG(3,("test", "...error: unable to create pool of %u bytes",
-		  size));
-	return -10;
-    }
-
-    entry = (pj_timer_entry*)pj_pool_calloc(pool, MAX_COUNT, sizeof(*entry));
-    if (!entry)
-	return -20;
-
-    for (i=0; i<MAX_COUNT; ++i) {
-	entry[i].cb = &timer_callback;
-    }
-    rc = pj_timer_heap_create(pool, MAX_COUNT, 0, &timer);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...error: unable to create timer heap", rc);
-	return -30;
-    }
-
-    count = MIN_COUNT;
-    for (i=0; i<LOOP; ++i) {
-	int early = 0;
-	int done=0;
-	int cancelled=0;
-	int rc;
-	pj_timestamp t1, t2, t_sched, t_cancel, t_poll;
-	pj_time_val now, expire;
-
-	pj_gettimeofday(&now);
-	pj_srand(now.sec);
-	t_sched.u32.lo = t_cancel.u32.lo = t_poll.u32.lo = 0;
-
-	// Register timers
-	for (j=0; j<(int)count; ++j) {
-	    delay.sec = pj_rand() % DELAY;
-	    delay.msec = pj_rand() % 1000;
-
-	    // Schedule timer
-	    pj_get_timestamp(&t1);
-	    rc = pj_timer_heap_schedule(timer, &entry[j], &delay);
-	    if (rc != 0)
-		return -40;
-	    pj_get_timestamp(&t2);
-
-	    t_sched.u32.lo += (t2.u32.lo - t1.u32.lo);
-
-	    // Poll timers.
-	    pj_get_timestamp(&t1);
-	    rc = pj_timer_heap_poll(timer, NULL);
-	    pj_get_timestamp(&t2);
-	    if (rc > 0) {
-		t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
-		early += rc;
-	    }
-	}
-
-	// Set the time where all timers should finish
-	pj_gettimeofday(&expire);
-	delay.sec = DELAY; 
-	delay.msec = 0;
-	PJ_TIME_VAL_ADD(expire, delay);
-
-	// Wait unfil all timers finish, cancel some of them.
-	do {
-	    int index = pj_rand() % count;
-	    pj_get_timestamp(&t1);
-	    rc = pj_timer_heap_cancel(timer, &entry[index]);
-	    pj_get_timestamp(&t2);
-	    if (rc > 0) {
-		cancelled += rc;
-		t_cancel.u32.lo += (t2.u32.lo - t1.u32.lo);
-	    }
-
-	    pj_gettimeofday(&now);
-
-	    pj_get_timestamp(&t1);
-	    rc = pj_timer_heap_poll(timer, NULL);
-	    pj_get_timestamp(&t2);
-	    if (rc > 0) {
-		done += rc;
-		t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);
-	    }
-
-	} while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0);
-
-	if (pj_timer_heap_count(timer)) {
-	    PJ_LOG(3, (THIS_FILE, "ERROR: %d timers left", 
-		       pj_timer_heap_count(timer)));
-	    ++err;
-	}
-	t_sched.u32.lo /= count; 
-	t_cancel.u32.lo /= count;
-	t_poll.u32.lo /= count;
-	PJ_LOG(4, (THIS_FILE, 
-	        "...ok (count:%d, early:%d, cancelled:%d, "
-		"sched:%d, cancel:%d poll:%d)", 
-		count, early, cancelled, t_sched.u32.lo, t_cancel.u32.lo,
-		t_poll.u32.lo));
-
-	count = count * 2;
-	if (count > MAX_COUNT)
-	    break;
-    }
-
-    pj_pool_release(pool);
-    return err;
-}
-
-
-int timer_test()
-{
-    return test_timer_heap();
-}
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_timer_test;
-#endif	/* INCLUDE_TIMER_TEST */
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+

+/**

+ * \page page_pjlib_timer_test Test: Timer

+ *

+ * This file provides implementation of \b timer_test(). It tests the

+ * functionality of the timer heap.

+ *

+ *

+ * This file is <b>pjlib-test/timer.c</b>

+ *

+ * \include pjlib-test/timer.c

+ */

+

+

+#if INCLUDE_TIMER_TEST

+

+#include <pjlib.h>

+

+#define LOOP		16

+#define MIN_COUNT	250

+#define MAX_COUNT	(LOOP * MIN_COUNT)

+#define MIN_DELAY	2

+#define	D		(MAX_COUNT / 32000)

+#define DELAY		(D < MIN_DELAY ? MIN_DELAY : D)

+#define THIS_FILE	"timer_test"

+

+

+static void timer_callback(pj_timer_heap_t *ht, pj_timer_entry *e)

+{

+    PJ_UNUSED_ARG(ht);

+    PJ_UNUSED_ARG(e);

+}

+

+static int test_timer_heap(void)

+{

+    int i, j;

+    pj_timer_entry *entry;

+    pj_pool_t *pool;

+    pj_timer_heap_t *timer;

+    pj_time_val delay;

+    pj_status_t rc;    int err=0;

+    unsigned size, count;

+

+    size = pj_timer_heap_mem_size(MAX_COUNT)+MAX_COUNT*sizeof(pj_timer_entry);

+    pool = pj_pool_create( mem, NULL, size, 4000, NULL);

+    if (!pool) {

+	PJ_LOG(3,("test", "...error: unable to create pool of %u bytes",

+		  size));

+	return -10;

+    }

+

+    entry = (pj_timer_entry*)pj_pool_calloc(pool, MAX_COUNT, sizeof(*entry));

+    if (!entry)

+	return -20;

+

+    for (i=0; i<MAX_COUNT; ++i) {

+	entry[i].cb = &timer_callback;

+    }

+    rc = pj_timer_heap_create(pool, MAX_COUNT, &timer);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...error: unable to create timer heap", rc);

+	return -30;

+    }

+

+    count = MIN_COUNT;

+    for (i=0; i<LOOP; ++i) {

+	int early = 0;

+	int done=0;

+	int cancelled=0;

+	int rc;

+	pj_timestamp t1, t2, t_sched, t_cancel, t_poll;

+	pj_time_val now, expire;

+

+	pj_gettimeofday(&now);

+	pj_srand(now.sec);

+	t_sched.u32.lo = t_cancel.u32.lo = t_poll.u32.lo = 0;

+

+	// Register timers

+	for (j=0; j<(int)count; ++j) {

+	    delay.sec = pj_rand() % DELAY;

+	    delay.msec = pj_rand() % 1000;

+

+	    // Schedule timer

+	    pj_get_timestamp(&t1);

+	    rc = pj_timer_heap_schedule(timer, &entry[j], &delay);

+	    if (rc != 0)

+		return -40;

+	    pj_get_timestamp(&t2);

+

+	    t_sched.u32.lo += (t2.u32.lo - t1.u32.lo);

+

+	    // Poll timers.

+	    pj_get_timestamp(&t1);

+	    rc = pj_timer_heap_poll(timer, NULL);

+	    pj_get_timestamp(&t2);

+	    if (rc > 0) {

+		t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);

+		early += rc;

+	    }

+	}

+

+	// Set the time where all timers should finish

+	pj_gettimeofday(&expire);

+	delay.sec = DELAY; 

+	delay.msec = 0;

+	PJ_TIME_VAL_ADD(expire, delay);

+

+	// Wait unfil all timers finish, cancel some of them.

+	do {

+	    int index = pj_rand() % count;

+	    pj_get_timestamp(&t1);

+	    rc = pj_timer_heap_cancel(timer, &entry[index]);

+	    pj_get_timestamp(&t2);

+	    if (rc > 0) {

+		cancelled += rc;

+		t_cancel.u32.lo += (t2.u32.lo - t1.u32.lo);

+	    }

+

+	    pj_gettimeofday(&now);

+

+	    pj_get_timestamp(&t1);

+	    rc = pj_timer_heap_poll(timer, NULL);

+	    pj_get_timestamp(&t2);

+	    if (rc > 0) {

+		done += rc;

+		t_poll.u32.lo += (t2.u32.lo - t1.u32.lo);

+	    }

+

+	} while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0);

+

+	if (pj_timer_heap_count(timer)) {

+	    PJ_LOG(3, (THIS_FILE, "ERROR: %d timers left", 

+		       pj_timer_heap_count(timer)));

+	    ++err;

+	}

+	t_sched.u32.lo /= count; 

+	t_cancel.u32.lo /= count;

+	t_poll.u32.lo /= count;

+	PJ_LOG(4, (THIS_FILE, 

+	        "...ok (count:%d, early:%d, cancelled:%d, "

+		"sched:%d, cancel:%d poll:%d)", 

+		count, early, cancelled, t_sched.u32.lo, t_cancel.u32.lo,

+		t_poll.u32.lo));

+

+	count = count * 2;

+	if (count > MAX_COUNT)

+	    break;

+    }

+

+    pj_pool_release(pool);

+    return err;

+}

+

+

+int timer_test()

+{

+    return test_timer_heap();

+}

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_timer_test;

+#endif	/* INCLUDE_TIMER_TEST */

+

+

diff --git a/pjlib/src/pjlib-test/timestamp.c b/pjlib/src/pjlib-test/timestamp.c
index deeab05..347d256 100644
--- a/pjlib/src/pjlib-test/timestamp.c
+++ b/pjlib/src/pjlib-test/timestamp.c
@@ -1,127 +1,148 @@
-/* $Id$
- */
-#include "test.h"
-#include <pj/os.h>
-#include <pj/log.h>
-
-
-/**
- * \page page_pjlib_timestamp_test Test: Timestamp
- *
- * This file provides implementation of timestamp_test()
- *
- * \section timestamp_test_sec Scope of the Test
- *
- * This tests whether timestamp API works.
- *
- * API tested:
- *  - pj_get_timestamp_freq()
- *  - pj_get_timestamp()
- *  - pj_elapsed_usec()
- *  - PJ_LOG()
- *
- *
- * This file is <b>pjlib-test/timestamp.c</b>
- *
- * \include pjlib-test/timestamp.c
- */
-
-#if INCLUDE_TIMESTAMP_TEST
-
-#define THIS_FILE   "timestamp"
-
-int timestamp_test(void)
-{
-    enum { CONSECUTIVE_LOOP = 1000 };
-    volatile unsigned i;
-    pj_timestamp freq, t1, t2;
-    unsigned elapsed;
-    pj_status_t rc;
-
-    PJ_LOG(3,(THIS_FILE, "...Testing timestamp (high res time)"));
-    
-    /* Get and display timestamp frequency. */
-    if ((rc=pj_get_timestamp_freq(&freq)) != PJ_SUCCESS) {
-	app_perror("...ERROR: get timestamp freq", rc);
-	return -1000;
-    }
-
-    PJ_LOG(3,(THIS_FILE, "....frequency: hiword=%lu loword=%lu", 
-			freq.u32.hi, freq.u32.lo));
-
-    PJ_LOG(3,(THIS_FILE, "...checking if time can run backwards (pls wait).."));
-
-    /*
-     * Check if consecutive readings should yield timestamp value
-     * that is bigger than previous value.
-     * First we get the first timestamp.
-     */
-    rc = pj_get_timestamp(&t1);
-    if (rc != PJ_SUCCESS) {
-	app_perror("...ERROR: get timestamp", rc);
-	return -1001;
-    }
-    for (i=0; i<CONSECUTIVE_LOOP; ++i) {
-        /*
-	volatile unsigned j;
-	for (j=0; j<1000; ++j)
-	    ;
-         */
-        pj_thread_sleep(1);
-	rc = pj_get_timestamp(&t2);
-	if (rc != PJ_SUCCESS) {
-	    app_perror("...ERROR: get timestamp", rc);
-	    return -1002;
-	}
-	/* compare t2 with t1, expecting t2 >= t1. */
-	if (t2.u32.hi < t1.u32.hi ||
-	    (t2.u32.hi == t1.u32.hi && t2.u32.lo < t1.u32.lo))
-	{
-	    PJ_LOG(3,(THIS_FILE, "...ERROR: timestamp runs backwards!"));
-	    return -1003;
-	}
-    }
-
-    /* 
-     * Simple test to time some loop. 
-     */
-    PJ_LOG(3,(THIS_FILE, "....testing simple 1000000 loop"));
-
-
-    /* Mark start time. */
-    if ((rc=pj_get_timestamp(&t1)) != PJ_SUCCESS) {
-	app_perror("....error: cat't get timestamp", rc);
-	return -1010;
-    }
-
-    /* Loop.. */
-    for (i=0; i<1000000; ++i)
-	;
-
-    /* Mark end time. */
-    pj_get_timestamp(&t2);
-
-    /* Get elapsed time in usec. */
-    elapsed = pj_elapsed_usec(&t1, &t2);
-    PJ_LOG(3,(THIS_FILE, "....elapsed: %u usec", (unsigned)elapsed));
-
-    /* See if elapsed time is reasonable. */
-    if (elapsed < 1 || elapsed > 100000) {
-	PJ_LOG(3,(THIS_FILE, "....error: elapsed time outside window (%u, "
-			     "t1.u32.hi=%u, t1.u32.lo=%u, "
-			     "t2.u32.hi=%u, t2.u32.lo=%u)",
-			     elapsed, 
-			     t1.u32.hi, t1.u32.lo, t2.u32.hi, t2.u32.lo));
-	return -1030;
-    }
-    return 0;
-}
-
-
-#else
-/* To prevent warning about "translation unit is empty"
- * when this test is disabled. 
- */
-int dummy_timestamp_test;
-#endif	/* INCLUDE_TIMESTAMP_TEST */
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pj/os.h>

+#include <pj/log.h>

+

+

+/**

+ * \page page_pjlib_timestamp_test Test: Timestamp

+ *

+ * This file provides implementation of timestamp_test()

+ *

+ * \section timestamp_test_sec Scope of the Test

+ *

+ * This tests whether timestamp API works.

+ *

+ * API tested:

+ *  - pj_get_timestamp_freq()

+ *  - pj_get_timestamp()

+ *  - pj_elapsed_usec()

+ *  - PJ_LOG()

+ *

+ *

+ * This file is <b>pjlib-test/timestamp.c</b>

+ *

+ * \include pjlib-test/timestamp.c

+ */

+

+#if INCLUDE_TIMESTAMP_TEST

+

+#define THIS_FILE   "timestamp"

+

+int timestamp_test(void)

+{

+    enum { CONSECUTIVE_LOOP = 1000 };

+    volatile unsigned i;

+    pj_timestamp freq, t1, t2;

+    unsigned elapsed;

+    pj_status_t rc;

+

+    PJ_LOG(3,(THIS_FILE, "...Testing timestamp (high res time)"));

+    

+    /* Get and display timestamp frequency. */

+    if ((rc=pj_get_timestamp_freq(&freq)) != PJ_SUCCESS) {

+	app_perror("...ERROR: get timestamp freq", rc);

+	return -1000;

+    }

+

+    PJ_LOG(3,(THIS_FILE, "....frequency: hiword=%lu loword=%lu", 

+			freq.u32.hi, freq.u32.lo));

+

+    PJ_LOG(3,(THIS_FILE, "...checking if time can run backwards (pls wait).."));

+

+    /*

+     * Check if consecutive readings should yield timestamp value

+     * that is bigger than previous value.

+     * First we get the first timestamp.

+     */

+    rc = pj_get_timestamp(&t1);

+    if (rc != PJ_SUCCESS) {

+	app_perror("...ERROR: get timestamp", rc);

+	return -1001;

+    }

+    for (i=0; i<CONSECUTIVE_LOOP; ++i) {

+        /*

+	volatile unsigned j;

+	for (j=0; j<1000; ++j)

+	    ;

+         */

+        pj_thread_sleep(1);

+	rc = pj_get_timestamp(&t2);

+	if (rc != PJ_SUCCESS) {

+	    app_perror("...ERROR: get timestamp", rc);

+	    return -1002;

+	}

+	/* compare t2 with t1, expecting t2 >= t1. */

+	if (t2.u32.hi < t1.u32.hi ||

+	    (t2.u32.hi == t1.u32.hi && t2.u32.lo < t1.u32.lo))

+	{

+	    PJ_LOG(3,(THIS_FILE, "...ERROR: timestamp runs backwards!"));

+	    return -1003;

+	}

+    }

+

+    /* 

+     * Simple test to time some loop. 

+     */

+    PJ_LOG(3,(THIS_FILE, "....testing simple 1000000 loop"));

+

+

+    /* Mark start time. */

+    if ((rc=pj_get_timestamp(&t1)) != PJ_SUCCESS) {

+	app_perror("....error: cat't get timestamp", rc);

+	return -1010;

+    }

+

+    /* Loop.. */

+    for (i=0; i<1000000; ++i)

+	;

+

+    /* Mark end time. */

+    pj_get_timestamp(&t2);

+

+    /* Get elapsed time in usec. */

+    elapsed = pj_elapsed_usec(&t1, &t2);

+    PJ_LOG(3,(THIS_FILE, "....elapsed: %u usec", (unsigned)elapsed));

+

+    /* See if elapsed time is reasonable. */

+    if (elapsed < 1 || elapsed > 100000) {

+	PJ_LOG(3,(THIS_FILE, "....error: elapsed time outside window (%u, "

+			     "t1.u32.hi=%u, t1.u32.lo=%u, "

+			     "t2.u32.hi=%u, t2.u32.lo=%u)",

+			     elapsed, 

+			     t1.u32.hi, t1.u32.lo, t2.u32.hi, t2.u32.lo));

+	return -1030;

+    }

+    return 0;

+}

+

+

+#else

+/* To prevent warning about "translation unit is empty"

+ * when this test is disabled. 

+ */

+int dummy_timestamp_test;

+#endif	/* INCLUDE_TIMESTAMP_TEST */

+

diff --git a/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c b/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
index 981ff30..d9b746d 100644
--- a/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
+++ b/pjlib/src/pjlib-test/udp_echo_srv_ioqueue.c
@@ -1,5 +1,26 @@
 /* $Id$

  */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

 #include <pjlib.h>

 #include "test.h"

 

diff --git a/pjlib/src/pjlib-test/udp_echo_srv_sync.c b/pjlib/src/pjlib-test/udp_echo_srv_sync.c
index b1a59e4..c229e61 100644
--- a/pjlib/src/pjlib-test/udp_echo_srv_sync.c
+++ b/pjlib/src/pjlib-test/udp_echo_srv_sync.c
@@ -1,147 +1,168 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-static pj_atomic_t *total_bytes;
-
-static int worker_thread(void *arg)
-{
-    pj_sock_t    sock = (pj_sock_t)arg;
-    char         buf[512];
-    pj_status_t  last_recv_err = PJ_SUCCESS, last_write_err = PJ_SUCCESS;
-
-    for (;;) {
-        pj_ssize_t len;
-        pj_status_t rc;
-        pj_sockaddr_in addr;
-        int addrlen;
-
-        len = sizeof(buf);
-        addrlen = sizeof(addr);
-        rc = pj_sock_recvfrom(sock, buf, &len, 0, &addr, &addrlen);
-        if (rc != 0) {
-            if (rc != last_recv_err) {
-                app_perror("...recv error", rc);
-                last_recv_err = rc;
-            }
-            continue;
-        }
-
-        pj_atomic_add(total_bytes, len);
-
-        rc = pj_sock_sendto(sock, buf, &len, 0, &addr, addrlen);
-        if (rc != PJ_SUCCESS) {
-            if (rc != last_write_err) {
-                app_perror("...send error", rc);
-                last_write_err = rc;
-            }
-            continue;
-        }
-    }
-}
-
-
-int echo_srv_sync(void)
-{
-    pj_pool_t *pool;
-    pj_sock_t sock;
-    pj_thread_t *thread[ECHO_SERVER_MAX_THREADS];
-    pj_status_t rc;
-    int i;
-
-    pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
-    if (!pool)
-        return -5;
-
-    rc = pj_atomic_create(pool, 0, &total_bytes);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...unable to create atomic_var", rc);
-        return -6;
-    }
-
-    rc = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM,0, ECHO_SERVER_START_PORT, &sock);
-    if (rc != PJ_SUCCESS) {
-        app_perror("...socket error", rc);
-        return -10;
-    }
-
-    for (i=0; i<ECHO_SERVER_MAX_THREADS; ++i) {
-        rc = pj_thread_create(pool, NULL, &worker_thread, (void*)sock,
-                              PJ_THREAD_DEFAULT_STACK_SIZE, 0,
-                              &thread[i]);
-        if (rc != PJ_SUCCESS) {
-            app_perror("...unable to create thread", rc);
-            return -20;
-        }
-    }
-
-    PJ_LOG(3,("", "...UDP echo server running with %d threads at port %d",
-                  ECHO_SERVER_MAX_THREADS, ECHO_SERVER_START_PORT));
-    PJ_LOG(3,("", "...Press Ctrl-C to abort"));
-
-    echo_srv_common_loop(total_bytes);
-    return 0;
-}
-
-
-int echo_srv_common_loop(pj_atomic_t *bytes_counter)
-{
-    pj_highprec_t last_received, avg_bw, highest_bw;
-    pj_time_val last_print;
-    unsigned count;
-    const char *ioqueue_name;
-
-    last_received = 0;
-    pj_gettimeofday(&last_print);
-    avg_bw = highest_bw = 0;
-    count = 0;
-
-    ioqueue_name = pj_ioqueue_name();
-
-    for (;;) {
-        pj_highprec_t received, cur_received, bw;
-        unsigned msec;
-        pj_time_val now, duration;
-
-        pj_thread_sleep(1000);
-
-        received = cur_received = pj_atomic_get(bytes_counter);
-        cur_received = cur_received - last_received;
-
-        pj_gettimeofday(&now);
-        duration = now;
-        PJ_TIME_VAL_SUB(duration, last_print);
-        msec = PJ_TIME_VAL_MSEC(duration);
-        
-        bw = cur_received;
-        pj_highprec_mul(bw, 1000);
-        pj_highprec_div(bw, msec);
-
-        last_print = now;
-        last_received = received;
-
-        avg_bw = avg_bw + bw;
-        count++;
-
-        PJ_LOG(3,("", "%s UDP (%d threads): %u KB/s (avg=%u KB/s) %s", 
-		  ioqueue_name,
-                  ECHO_SERVER_MAX_THREADS, 
-                  (unsigned)(bw / 1000),
-                  (unsigned)(avg_bw / count / 1000),
-                  (count==20 ? "<ses avg>" : "")));
-
-        if (count==20) {
-            if (avg_bw/count > highest_bw)
-                highest_bw = avg_bw/count;
-
-            count = 0;
-            avg_bw = 0;
-
-            PJ_LOG(3,("", "Highest average bandwidth=%u KB/s",
-                          (unsigned)(highest_bw/1000)));
-        }
-    }
-}
-
-
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pjlib.h>

+

+static pj_atomic_t *total_bytes;

+

+static int worker_thread(void *arg)

+{

+    pj_sock_t    sock = (pj_sock_t)arg;

+    char         buf[512];

+    pj_status_t  last_recv_err = PJ_SUCCESS, last_write_err = PJ_SUCCESS;

+

+    for (;;) {

+        pj_ssize_t len;

+        pj_status_t rc;

+        pj_sockaddr_in addr;

+        int addrlen;

+

+        len = sizeof(buf);

+        addrlen = sizeof(addr);

+        rc = pj_sock_recvfrom(sock, buf, &len, 0, &addr, &addrlen);

+        if (rc != 0) {

+            if (rc != last_recv_err) {

+                app_perror("...recv error", rc);

+                last_recv_err = rc;

+            }

+            continue;

+        }

+

+        pj_atomic_add(total_bytes, len);

+

+        rc = pj_sock_sendto(sock, buf, &len, 0, &addr, addrlen);

+        if (rc != PJ_SUCCESS) {

+            if (rc != last_write_err) {

+                app_perror("...send error", rc);

+                last_write_err = rc;

+            }

+            continue;

+        }

+    }

+}

+

+

+int echo_srv_sync(void)

+{

+    pj_pool_t *pool;

+    pj_sock_t sock;

+    pj_thread_t *thread[ECHO_SERVER_MAX_THREADS];

+    pj_status_t rc;

+    int i;

+

+    pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);

+    if (!pool)

+        return -5;

+

+    rc = pj_atomic_create(pool, 0, &total_bytes);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...unable to create atomic_var", rc);

+        return -6;

+    }

+

+    rc = app_socket(PJ_AF_INET, PJ_SOCK_DGRAM,0, ECHO_SERVER_START_PORT, &sock);

+    if (rc != PJ_SUCCESS) {

+        app_perror("...socket error", rc);

+        return -10;

+    }

+

+    for (i=0; i<ECHO_SERVER_MAX_THREADS; ++i) {

+        rc = pj_thread_create(pool, NULL, &worker_thread, (void*)sock,

+                              PJ_THREAD_DEFAULT_STACK_SIZE, 0,

+                              &thread[i]);

+        if (rc != PJ_SUCCESS) {

+            app_perror("...unable to create thread", rc);

+            return -20;

+        }

+    }

+

+    PJ_LOG(3,("", "...UDP echo server running with %d threads at port %d",

+                  ECHO_SERVER_MAX_THREADS, ECHO_SERVER_START_PORT));

+    PJ_LOG(3,("", "...Press Ctrl-C to abort"));

+

+    echo_srv_common_loop(total_bytes);

+    return 0;

+}

+

+

+int echo_srv_common_loop(pj_atomic_t *bytes_counter)

+{

+    pj_highprec_t last_received, avg_bw, highest_bw;

+    pj_time_val last_print;

+    unsigned count;

+    const char *ioqueue_name;

+

+    last_received = 0;

+    pj_gettimeofday(&last_print);

+    avg_bw = highest_bw = 0;

+    count = 0;

+

+    ioqueue_name = pj_ioqueue_name();

+

+    for (;;) {

+        pj_highprec_t received, cur_received, bw;

+        unsigned msec;

+        pj_time_val now, duration;

+

+        pj_thread_sleep(1000);

+

+        received = cur_received = pj_atomic_get(bytes_counter);

+        cur_received = cur_received - last_received;

+

+        pj_gettimeofday(&now);

+        duration = now;

+        PJ_TIME_VAL_SUB(duration, last_print);

+        msec = PJ_TIME_VAL_MSEC(duration);

+        

+        bw = cur_received;

+        pj_highprec_mul(bw, 1000);

+        pj_highprec_div(bw, msec);

+

+        last_print = now;

+        last_received = received;

+

+        avg_bw = avg_bw + bw;

+        count++;

+

+        PJ_LOG(3,("", "%s UDP (%d threads): %u KB/s (avg=%u KB/s) %s", 

+		  ioqueue_name,

+                  ECHO_SERVER_MAX_THREADS, 

+                  (unsigned)(bw / 1000),

+                  (unsigned)(avg_bw / count / 1000),

+                  (count==20 ? "<ses avg>" : "")));

+

+        if (count==20) {

+            if (avg_bw/count > highest_bw)

+                highest_bw = avg_bw/count;

+

+            count = 0;

+            avg_bw = 0;

+

+            PJ_LOG(3,("", "Highest average bandwidth=%u KB/s",

+                          (unsigned)(highest_bw/1000)));

+        }

+    }

+}

+

+

diff --git a/pjlib/src/pjlib-test/util.c b/pjlib/src/pjlib-test/util.c
index 2d98571..44281e2 100644
--- a/pjlib/src/pjlib-test/util.c
+++ b/pjlib/src/pjlib-test/util.c
@@ -1,115 +1,136 @@
-/* $Id$
- */
-#include "test.h"
-#include <pjlib.h>
-
-void app_perror(const char *msg, pj_status_t rc)
-{
-    char errbuf[256];
-
-    PJ_CHECK_STACK();
-
-    pj_strerror(rc, errbuf, sizeof(errbuf));
-    PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf));
-}
-
-#define SERVER 0
-#define CLIENT 1
-
-pj_status_t app_socket(int family, int type, int proto, int port,
-                       pj_sock_t *ptr_sock)
-{
-    pj_sockaddr_in addr;
-    pj_sock_t sock;
-    pj_status_t rc;
-
-    rc = pj_sock_socket(family, type, proto, &sock);
-    if (rc != PJ_SUCCESS)
-        return rc;
-
-    pj_memset(&addr, 0, sizeof(addr));
-    addr.sin_family = (pj_uint16_t)family;
-    addr.sin_port = (short)(port!=-1 ? pj_htons((pj_uint16_t)port) : 0);
-    rc = pj_sock_bind(sock, &addr, sizeof(addr));
-    if (rc != PJ_SUCCESS)
-        return rc;
-    
-    if (type == PJ_SOCK_STREAM) {
-        rc = pj_sock_listen(sock, 5);
-        if (rc != PJ_SUCCESS)
-            return rc;
-    }
-
-    *ptr_sock = sock;
-    return PJ_SUCCESS;
-}
-
-pj_status_t app_socketpair(int family, int type, int protocol,
-                           pj_sock_t *serverfd, pj_sock_t *clientfd)
-{
-    int i;
-    static unsigned short port = 11000;
-    pj_sockaddr_in addr;
-    pj_str_t s;
-    pj_status_t rc = 0;
-    pj_sock_t sock[2];
-
-    /* Create both sockets. */
-    for (i=0; i<2; ++i) {
-        rc = pj_sock_socket(family, type, protocol, &sock[i]);
-        if (rc != PJ_SUCCESS) {
-            if (i==1)
-                pj_sock_close(sock[0]);
-            return rc;
-        }
-    }
-
-    /* Retry bind */
-    pj_memset(&addr, 0, sizeof(addr));
-    addr.sin_family = PJ_AF_INET;
-    for (i=0; i<5; ++i) {
-        addr.sin_port = pj_htons(port++);
-        rc = pj_sock_bind(sock[SERVER], &addr, sizeof(addr));
-        if (rc == PJ_SUCCESS)
-            break;
-    }
-
-    if (rc != PJ_SUCCESS)
-        goto on_error;
-
-    /* For TCP, listen the socket. */
-    if (type == PJ_SOCK_STREAM) {
-        rc = pj_sock_listen(sock[SERVER], PJ_SOMAXCONN);
-        if (rc != PJ_SUCCESS)
-            goto on_error;
-    }
-
-    /* Connect client socket. */
-    addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));
-    rc = pj_sock_connect(sock[CLIENT], &addr, sizeof(addr));
-    if (rc != PJ_SUCCESS)
-        goto on_error;
-
-    /* For TCP, must accept(), and get the new socket. */
-    if (type == PJ_SOCK_STREAM) {
-        pj_sock_t newserver;
-
-        rc = pj_sock_accept(sock[SERVER], &newserver, NULL, NULL);
-        if (rc != PJ_SUCCESS)
-            goto on_error;
-
-        /* Replace server socket with new socket. */
-        pj_sock_close(sock[SERVER]);
-        sock[SERVER] = newserver;
-    }
-
-    *serverfd = sock[SERVER];
-    *clientfd = sock[CLIENT];
-
-    return rc;
-
-on_error:
-    for (i=0; i<2; ++i)
-        pj_sock_close(sock[i]);
-    return rc;
-}
+/* $Id$

+ */

+/* 

+ * PJLIB - PJ Foundation Library

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "test.h"

+#include <pjlib.h>

+

+void app_perror(const char *msg, pj_status_t rc)

+{

+    char errbuf[256];

+

+    PJ_CHECK_STACK();

+

+    pj_strerror(rc, errbuf, sizeof(errbuf));

+    PJ_LOG(1,("test", "%s: [pj_status_t=%d] %s", msg, rc, errbuf));

+}

+

+#define SERVER 0

+#define CLIENT 1

+

+pj_status_t app_socket(int family, int type, int proto, int port,

+                       pj_sock_t *ptr_sock)

+{

+    pj_sockaddr_in addr;

+    pj_sock_t sock;

+    pj_status_t rc;

+

+    rc = pj_sock_socket(family, type, proto, &sock);

+    if (rc != PJ_SUCCESS)

+        return rc;

+

+    pj_memset(&addr, 0, sizeof(addr));

+    addr.sin_family = (pj_uint16_t)family;

+    addr.sin_port = (short)(port!=-1 ? pj_htons((pj_uint16_t)port) : 0);

+    rc = pj_sock_bind(sock, &addr, sizeof(addr));

+    if (rc != PJ_SUCCESS)

+        return rc;

+    

+    if (type == PJ_SOCK_STREAM) {

+        rc = pj_sock_listen(sock, 5);

+        if (rc != PJ_SUCCESS)

+            return rc;

+    }

+

+    *ptr_sock = sock;

+    return PJ_SUCCESS;

+}

+

+pj_status_t app_socketpair(int family, int type, int protocol,

+                           pj_sock_t *serverfd, pj_sock_t *clientfd)

+{

+    int i;

+    static unsigned short port = 11000;

+    pj_sockaddr_in addr;

+    pj_str_t s;

+    pj_status_t rc = 0;

+    pj_sock_t sock[2];

+

+    /* Create both sockets. */

+    for (i=0; i<2; ++i) {

+        rc = pj_sock_socket(family, type, protocol, &sock[i]);

+        if (rc != PJ_SUCCESS) {

+            if (i==1)

+                pj_sock_close(sock[0]);

+            return rc;

+        }

+    }

+

+    /* Retry bind */

+    pj_memset(&addr, 0, sizeof(addr));

+    addr.sin_family = PJ_AF_INET;

+    for (i=0; i<5; ++i) {

+        addr.sin_port = pj_htons(port++);

+        rc = pj_sock_bind(sock[SERVER], &addr, sizeof(addr));

+        if (rc == PJ_SUCCESS)

+            break;

+    }

+

+    if (rc != PJ_SUCCESS)

+        goto on_error;

+

+    /* For TCP, listen the socket. */

+    if (type == PJ_SOCK_STREAM) {

+        rc = pj_sock_listen(sock[SERVER], PJ_SOMAXCONN);

+        if (rc != PJ_SUCCESS)

+            goto on_error;

+    }

+

+    /* Connect client socket. */

+    addr.sin_addr = pj_inet_addr(pj_cstr(&s, "127.0.0.1"));

+    rc = pj_sock_connect(sock[CLIENT], &addr, sizeof(addr));

+    if (rc != PJ_SUCCESS)

+        goto on_error;

+

+    /* For TCP, must accept(), and get the new socket. */

+    if (type == PJ_SOCK_STREAM) {

+        pj_sock_t newserver;

+

+        rc = pj_sock_accept(sock[SERVER], &newserver, NULL, NULL);

+        if (rc != PJ_SUCCESS)

+            goto on_error;

+

+        /* Replace server socket with new socket. */

+        pj_sock_close(sock[SERVER]);

+        sock[SERVER] = newserver;

+    }

+

+    *serverfd = sock[SERVER];

+    *clientfd = sock[CLIENT];

+

+    return rc;

+

+on_error:

+    for (i=0; i<2; ++i)

+        pj_sock_close(sock[i]);

+    return rc;

+}

diff --git a/pjmedia/src/pjmedia.h b/pjmedia/src/pjmedia.h
index 627d15c..534e0f2 100644
--- a/pjmedia/src/pjmedia.h
+++ b/pjmedia/src/pjmedia.h
@@ -1,17 +1,38 @@
-/* $Id$
- *
- */
-#ifndef __PJMEDIA_H__
-#define __PJMEDIA_H__
-
-#include <pjmedia/codec.h>
-#include <pjmedia/jbuf.h>
-#include <pjmedia/mediamgr.h>
-#include <pjmedia/rtcp.h>
-#include <pjmedia/rtp.h>
-#include <pjmedia/session.h>
-#include <pjmedia/sound.h>
-#include <pjmedia/sdp.h>
-
-#endif	/* __PJMEDIA_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __PJMEDIA_H__

+#define __PJMEDIA_H__

+

+#include <pjmedia/codec.h>

+#include <pjmedia/jbuf.h>

+#include <pjmedia/mediamgr.h>

+#include <pjmedia/rtcp.h>

+#include <pjmedia/rtp.h>

+#include <pjmedia/session.h>

+#include <pjmedia/sound.h>

+#include <pjmedia/sdp.h>

+

+#endif	/* __PJMEDIA_H__ */

+

diff --git a/pjmedia/src/pjmedia/codec.c b/pjmedia/src/pjmedia/codec.c
index d64ac05..c1e12f9 100644
--- a/pjmedia/src/pjmedia/codec.c
+++ b/pjmedia/src/pjmedia/codec.c
@@ -1,91 +1,112 @@
-/* $Id$
- *
- */
-#include <pjmedia/codec.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/log.h>
-
-#define THIS_FILE   "codec.c"
-
-static void enum_all_codecs (pj_codec_mgr *cm)
-{
-    pj_codec_factory *cf;
-
-    cf = cm->factory_list.next;
-    cm->codec_cnt = 0;
-    while (cf != &cm->factory_list) {
-	pj_codec_id temp[PJ_CODEC_MGR_MAX_CODECS];
-	int i, cnt;
-
-	cnt = cf->op->enum_codecs (cf, PJ_CODEC_MGR_MAX_CODECS, temp);
-	if (cnt > PJ_CODEC_MGR_MAX_CODECS) {
-	    pj_assert(0);
-	    PJ_LOG(4, (THIS_FILE, "Too many codecs reported by factory"));
-	    cnt = PJ_CODEC_MGR_MAX_CODECS;
-	}
-
-	for (i=0; i<cnt && cm->codec_cnt < PJ_CODEC_MGR_MAX_CODECS; ++i) {
-	    cm->codecs[cm->codec_cnt++] = temp[i];
-	}
-
-	cf = cf->next;
-    }
-}
-
-PJ_DEF(pj_status_t) pj_codec_mgr_init (pj_codec_mgr *mgr)
-{
-    pj_list_init (&mgr->factory_list);
-    mgr->codec_cnt = 0;
-    return 0;
-}
-
-PJ_DEF(pj_status_t) pj_codec_mgr_register_factory (pj_codec_mgr *mgr,
-						   pj_codec_factory *factory)
-{
-    pj_list_insert_before (&mgr->factory_list, factory);
-    enum_all_codecs (mgr);
-    return 0;
-}
-
-PJ_DEF(void) pj_codec_mgr_unregister_factory (pj_codec_mgr *mgr, pj_codec_factory *factory)
-{
-    PJ_UNUSED_ARG(mgr)
-    pj_list_erase(factory);
-    enum_all_codecs (mgr);
-}
-
-PJ_DEF(unsigned)
-pj_codec_mgr_enum_codecs (pj_codec_mgr *mgr, unsigned count, const pj_codec_id *codecs[])
-{
-    unsigned i;
-
-    if (count > mgr->codec_cnt)
-	count = mgr->codec_cnt;
-
-    for (i=0; i<count; ++i)
-	codecs[i] = &mgr->codecs[i];
-
-    return mgr->codec_cnt;
-}
-
-PJ_DEF(pj_codec*) pj_codec_mgr_alloc_codec (pj_codec_mgr *mgr, const struct pj_codec_id *id)
-{
-    pj_codec_factory *factory = mgr->factory_list.next;
-    while (factory != &mgr->factory_list) {
-	if ( (*factory->op->match_id)(factory, id) == 0 ) {
-	    pj_codec *codec = (*factory->op->alloc_codec)(factory, id);
-	    if (codec != NULL)
-		return codec;
-	}
-	factory = factory->next;
-    }
-    return NULL;
-}
-
-PJ_DEF(void) pj_codec_mgr_dealloc_codec (pj_codec_mgr *mgr, pj_codec *codec)
-{
-    PJ_UNUSED_ARG(mgr)
-    (*codec->factory->op->dealloc_codec)(codec->factory, codec);
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjmedia/codec.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/log.h>

+

+#define THIS_FILE   "codec.c"

+

+static void enum_all_codecs (pj_codec_mgr *cm)

+{

+    pj_codec_factory *cf;

+

+    cf = cm->factory_list.next;

+    cm->codec_cnt = 0;

+    while (cf != &cm->factory_list) {

+	pj_codec_id temp[PJ_CODEC_MGR_MAX_CODECS];

+	int i, cnt;

+

+	cnt = cf->op->enum_codecs (cf, PJ_CODEC_MGR_MAX_CODECS, temp);

+	if (cnt > PJ_CODEC_MGR_MAX_CODECS) {

+	    pj_assert(0);

+	    PJ_LOG(4, (THIS_FILE, "Too many codecs reported by factory"));

+	    cnt = PJ_CODEC_MGR_MAX_CODECS;

+	}

+

+	for (i=0; i<cnt && cm->codec_cnt < PJ_CODEC_MGR_MAX_CODECS; ++i) {

+	    cm->codecs[cm->codec_cnt++] = temp[i];

+	}

+

+	cf = cf->next;

+    }

+}

+

+PJ_DEF(pj_status_t) pj_codec_mgr_init (pj_codec_mgr *mgr)

+{

+    pj_list_init (&mgr->factory_list);

+    mgr->codec_cnt = 0;

+    return 0;

+}

+

+PJ_DEF(pj_status_t) pj_codec_mgr_register_factory (pj_codec_mgr *mgr,

+						   pj_codec_factory *factory)

+{

+    pj_list_insert_before (&mgr->factory_list, factory);

+    enum_all_codecs (mgr);

+    return 0;

+}

+

+PJ_DEF(void) pj_codec_mgr_unregister_factory (pj_codec_mgr *mgr, pj_codec_factory *factory)

+{

+    PJ_UNUSED_ARG(mgr)

+    pj_list_erase(factory);

+    enum_all_codecs (mgr);

+}

+

+PJ_DEF(unsigned)

+pj_codec_mgr_enum_codecs (pj_codec_mgr *mgr, unsigned count, const pj_codec_id *codecs[])

+{

+    unsigned i;

+

+    if (count > mgr->codec_cnt)

+	count = mgr->codec_cnt;

+

+    for (i=0; i<count; ++i)

+	codecs[i] = &mgr->codecs[i];

+

+    return mgr->codec_cnt;

+}

+

+PJ_DEF(pj_codec*) pj_codec_mgr_alloc_codec (pj_codec_mgr *mgr, const struct pj_codec_id *id)

+{

+    pj_codec_factory *factory = mgr->factory_list.next;

+    while (factory != &mgr->factory_list) {

+	if ( (*factory->op->match_id)(factory, id) == 0 ) {

+	    pj_codec *codec = (*factory->op->alloc_codec)(factory, id);

+	    if (codec != NULL)

+		return codec;

+	}

+	factory = factory->next;

+    }

+    return NULL;

+}

+

+PJ_DEF(void) pj_codec_mgr_dealloc_codec (pj_codec_mgr *mgr, pj_codec *codec)

+{

+    PJ_UNUSED_ARG(mgr)

+    (*codec->factory->op->dealloc_codec)(codec->factory, codec);

+}

+

diff --git a/pjmedia/src/pjmedia/codec.h b/pjmedia/src/pjmedia/codec.h
index fcf2384..bf20d19 100644
--- a/pjmedia/src/pjmedia/codec.h
+++ b/pjmedia/src/pjmedia/codec.h
@@ -1,339 +1,360 @@
-/* $Id$
- *
- */
-
-#ifndef __PJMEDIA_CODEC_H__
-#define __PJMEDIA_CODEC_H__
-
-
-/**
- * @file codec.h
- * @brief Codec framework.
- */
-
-#include <pj/list.h>
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJMED_CODEC Codec framework.
- * @ingroup PJMEDIA
- * @{
- */
-
-/** Top most media type. */
-typedef enum pj_media_type
-{
-    /** No type. */
-    PJ_MEDIA_TYPE_NONE = 0,
-
-    /** The media is audio */
-    PJ_MEDIA_TYPE_AUDIO = 1,
-
-    /** The media is video. */
-    PJ_MEDIA_TYPE_VIDEO = 2,
-
-    /** Unknown media type, in this case the name will be specified in 
-     *  encoding_name.
-     */
-    PJ_MEDIA_TYPE_UNKNOWN = 3,
-
-} pj_media_type;
-
-
-/** Media direction. */
-typedef enum pj_media_dir_t
-{
-    /** None */
-    PJ_MEDIA_DIR_NONE = 0,
-
-    /** Encoding (outgoing to network) stream */
-    PJ_MEDIA_DIR_ENCODING = 1,
-
-    /** Decoding (incoming from network) stream. */
-    PJ_MEDIA_DIR_DECODING = 2,
-
-    /** Incoming and outgoing stream. */
-    PJ_MEDIA_DIR_ENCODING_DECODING = 3,
-
-} pj_media_dir_t;
-
-
-/** Standard RTP paylist types. */
-typedef enum pj_rtp_pt
-{
-    PJ_RTP_PT_PCMU = 0,		/* audio PCMU */
-    PJ_RTP_PT_GSM  = 3,		/* audio GSM */
-    PJ_RTP_PT_G723 = 4,		/* audio G723 */
-    PJ_RTP_PT_DVI4_8K = 5,	/* audio DVI4 8KHz */
-    PJ_RTP_PT_DVI4_16K = 6,	/* audio DVI4 16Khz */
-    PJ_RTP_PT_LPC = 7,		/* audio LPC */
-    PJ_RTP_PT_PCMA = 8,		/* audio PCMA */
-    PJ_RTP_PT_G722 = 9,		/* audio G722 */
-    PJ_RTP_PT_L16_2 = 10,	/* audio 16bit linear 44.1KHz stereo */
-    PJ_RTP_PT_L16_1 = 11,	/* audio 16bit linear 44.1KHz mono */
-    PJ_RTP_PT_QCELP = 12,	/* audio QCELP */
-    PJ_RTP_PT_CN = 13,		/* audio Comfort Noise */
-    PJ_RTP_PT_MPA = 14,		/* audio MPEG1 or MPEG2 as elementary streams */
-    PJ_RTP_PT_G728 = 15,	/* audio G728 */
-    PJ_RTP_PT_DVI4_11K = 16,	/* audio DVI4 11.025KHz mono */
-    PJ_RTP_PT_DVI4_22K = 17,	/* audio DVI4 22.050KHz mono */
-    PJ_RTP_PT_G729 = 18,	/* audio G729 */
-    PJ_RTP_PT_CELB = 25,	/* video/comb Cell-B by Sun Microsystems (RFC 2029) */
-    PJ_RTP_PT_JPEG = 26,	/* video JPEG */
-    PJ_RTP_PT_NV = 28,		/* video NV implemented by nv program by Xerox */
-    PJ_RTP_PT_H261 = 31,	/* video H261 */
-    PJ_RTP_PT_MPV = 32,		/* video MPEG1 or MPEG2 elementary streams */
-    PJ_RTP_PT_MP2T = 33,	/* video MPEG2 transport */
-    PJ_RTP_PT_H263 = 34,	/* video H263 */
-
-    PJ_RTP_PT_DYNAMIC = 96,	/* start of dynamic RTP payload */
-} pj_rtp_pt;
-
-
-/** Identification used to search for codec factory that supports specific 
- *  codec specification. 
- */
-typedef struct pj_codec_id
-{
-    /** Media type. */
-    pj_media_type   type;
-
-    /** Payload type (can be dynamic). */
-    unsigned	    pt;
-
-    /** Encoding name, must be present if the payload type is dynamic. */
-    pj_str_t	    encoding_name;
-
-    /** Sampling rate. */
-    unsigned	    sample_rate;
-} pj_codec_id;
-
-
-/** Detailed codec attributes used both to configure a codec and to query
- *  the capability of codec factories.
- */
-typedef struct pj_codec_attr
-{
-    pj_uint32_t	sample_rate;	    /* Sampling rate in Hz */
-    pj_uint32_t	avg_bps;	    /* Average bandwidth in bits per second */
-
-    pj_uint8_t	pcm_bits_per_sample;/* Bits per sample in the PCM side */
-    pj_uint16_t	ptime;		    /* Packet time in miliseconds */
-
-    unsigned	pt:8;		    /* Payload type. */
-    unsigned    vad_enabled:1;	    /* Voice Activity Detector. */
-    unsigned    cng_enabled:1;	    /* Comfort Noise Generator. */
-    unsigned    lpf_enabled:1;	    /* Low pass filter */
-    unsigned    hpf_enabled:1;	    /* High pass filter */
-    unsigned    penh_enabled:1;	    /* Perceptual Enhancement */
-    unsigned    concl_enabled:1;    /* Packet loss concealment */
-    unsigned    reserved_bit:1;
-
-} pj_codec_attr;
-
-/** Types of audio frame. */
-typedef enum pj_audio_frame_type
-{
-    /** The frame is a silence audio frame. */
-    PJ_AUDIO_FRAME_SILENCE,
-
-    /** The frame is a non-silence audio frame. */
-    PJ_AUDIO_FRAME_AUDIO,
-
-} pj_audio_frame_type;
-
-typedef struct pj_codec pj_codec;
-typedef struct pj_codec_factory pj_codec_factory;
-
-
-/** This structure describes an audio frame. */
-struct pj_audio_frame
-{
-    /** Type: silence or non-silence. */
-    pj_audio_frame_type type;
-
-    /** Pointer to buffer. */
-    void	*buf;
-
-    /** Frame size in bytes. */
-    unsigned	 size;
-};
-
-/**
- * Operations that must be supported by the codec.
- */
-typedef struct pj_codec_op
-{
-    /** Get default attributes. */
-    pj_status_t (*default_attr) (pj_codec *codec, pj_codec_attr *attr);
-
-    /** Open and initialize codec using the specified attribute.
-     *  @return zero on success.
-     */
-    pj_status_t	(*init)( pj_codec *codec, pj_pool_t *pool );
-
-    /** Close and shutdown codec.
-     */
-    pj_status_t	(*open)( pj_codec *codec, pj_codec_attr *attr );
-
-    /** Close and shutdown codec.
-     */
-    pj_status_t (*close)( pj_codec *codec );
-
-    /** Encode frame.
-     */
-    pj_status_t (*encode)( pj_codec *codec, const struct pj_audio_frame *input,
-			   unsigned output_buf_len, struct pj_audio_frame *output);
-
-    /** Decode frame.
-     */
-    pj_status_t (*decode)( pj_codec *codec, const struct pj_audio_frame *input,
-			   unsigned output_buf_len, struct pj_audio_frame *output);
-
-} pj_codec_op;
-
-/**
- * A codec describes an instance to encode or decode media frames. 
- */
-struct pj_codec
-{
-    /** Entries to put this codec instance in codec factory's list. */
-    PJ_DECL_LIST_MEMBER(struct pj_codec)
-
-    /** Codec's private data. */
-    void	*codec_data;
-
-    /** Codec factory where this codec was allocated. */
-    pj_codec_factory *factory;
-
-    /** Operations to codec. */
-    pj_codec_op	*op;
-};
-
-/**
- * This structure describes operations that must be supported by codec factories.
- */
-typedef struct pj_codec_factory_op
-{
-    /** Check whether the factory can create codec with the specified ID.
-     *  @param factory The codec factory.
-     *  @param id  The codec ID.
-     *  @return zero it matches.
-     */
-    pj_status_t	(*match_id)( pj_codec_factory *factory, const pj_codec_id *id );
-
-    /** Create default attributes for the specified codec ID. This function can
-     *  be called by application to get the capability of the codec.
-     *  @param factory The codec factory.
-     *  @param id  The codec ID.
-     *  @param attr The attribute to be initialized.
-     *  @return zero if success.
-     */
-    pj_status_t (*default_attr)( pj_codec_factory *factory, const pj_codec_id *id,
-				 pj_codec_attr *attr );
-
-    /** Enumerate supported codecs.
-     *  @param factory The codec factory.
-     *  @param count Number of entries in the array.
-     *  @param codecs The codec array.
-     *  @return the total number of supported codecs, which can be less or 
-     *          greater than requested.
-     */
-    unsigned (*enum_codecs) (pj_codec_factory *factory, unsigned count, pj_codec_id codecs[]);
-
-    /** This function is called by codec manager to instantiate one codec
-     *  instance.
-     *  @param factory The codec factory.
-     *  @param id  The codec ID.
-     *  @return the instance of the codec, or NULL if codec can not be created.
-     */
-    pj_codec* (*alloc_codec)( pj_codec_factory *factory, const pj_codec_id *id);
-
-    /** This function is called by codec manager to return a particular instance
-     *  of codec back to the codec factory.
-     *  @param factory The codec factory.
-     *  @param codec The codec instance to be returned.
-     */
-    void (*dealloc_codec)( pj_codec_factory *factory, pj_codec *codec );
-
-} pj_codec_factory_op;
-
-/**
- * Codec factory describes a module that is able to create codec with specific
- * capabilities. These capabilities can be queried by codec manager to create
- * instances of codec.
- */
-struct pj_codec_factory
-{
-    /** Entries to put this structure in the codec manager list. */
-    PJ_DECL_LIST_MEMBER(struct pj_codec_factory)
-
-    /** The factory's private data. */
-    void		*factory_data;
-
-    /** Operations to the factory. */
-    pj_codec_factory_op *op;
-
-};
-
-/**
- * Declare maximum codecs
- */
-#define PJ_CODEC_MGR_MAX_CODECS	    32
-
-/**
- * Codec manager maintains codec factory etc.
- */
-typedef struct pj_codec_mgr
-{
-    pj_codec_factory factory_list;
-    unsigned	     codec_cnt;
-    pj_codec_id	     codecs[PJ_CODEC_MGR_MAX_CODECS];
-} pj_codec_mgr;
-
-/**
- * Init codec manager.
- */
-PJ_DECL(pj_status_t) 
-pj_codec_mgr_init (pj_codec_mgr *mgr);
-
-/** 
- * Register codec to codec manager. 
- */
-PJ_DECL(pj_status_t) 
-pj_codec_mgr_register_factory (pj_codec_mgr *mgr, pj_codec_factory *factory);
-
-/**
- * Unregister codec.
- */
-PJ_DECL(void) 
-pj_codec_mgr_unregister_factory (pj_codec_mgr *mgr, pj_codec_factory *factory);
-
-/**
- * Enumerate codecs.
- */
-PJ_DECL(unsigned)
-pj_codec_mgr_enum_codecs (pj_codec_mgr *mgr, unsigned count, const pj_codec_id *codecs[]);
-
-/**
- * Open codec.
- */
-PJ_DECL(pj_codec*) 
-pj_codec_mgr_alloc_codec (pj_codec_mgr *mgr, const struct pj_codec_id *id);
-
-/**
- * Close codec.
- */
-PJ_DECL(void) 
-pj_codec_mgr_dealloc_codec (pj_codec_mgr *mgr, pj_codec *codec);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-
-#endif	/* __PJMEDIA_CODEC_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJMEDIA_CODEC_H__

+#define __PJMEDIA_CODEC_H__

+

+

+/**

+ * @file codec.h

+ * @brief Codec framework.

+ */

+

+#include <pj/list.h>

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJMED_CODEC Codec framework.

+ * @ingroup PJMEDIA

+ * @{

+ */

+

+/** Top most media type. */

+typedef enum pj_media_type

+{

+    /** No type. */

+    PJ_MEDIA_TYPE_NONE = 0,

+

+    /** The media is audio */

+    PJ_MEDIA_TYPE_AUDIO = 1,

+

+    /** The media is video. */

+    PJ_MEDIA_TYPE_VIDEO = 2,

+

+    /** Unknown media type, in this case the name will be specified in 

+     *  encoding_name.

+     */

+    PJ_MEDIA_TYPE_UNKNOWN = 3,

+

+} pj_media_type;

+

+

+/** Media direction. */

+typedef enum pj_media_dir_t

+{

+    /** None */

+    PJ_MEDIA_DIR_NONE = 0,

+

+    /** Encoding (outgoing to network) stream */

+    PJ_MEDIA_DIR_ENCODING = 1,

+

+    /** Decoding (incoming from network) stream. */

+    PJ_MEDIA_DIR_DECODING = 2,

+

+    /** Incoming and outgoing stream. */

+    PJ_MEDIA_DIR_ENCODING_DECODING = 3,

+

+} pj_media_dir_t;

+

+

+/** Standard RTP paylist types. */

+typedef enum pj_rtp_pt

+{

+    PJ_RTP_PT_PCMU = 0,		/* audio PCMU */

+    PJ_RTP_PT_GSM  = 3,		/* audio GSM */

+    PJ_RTP_PT_G723 = 4,		/* audio G723 */

+    PJ_RTP_PT_DVI4_8K = 5,	/* audio DVI4 8KHz */

+    PJ_RTP_PT_DVI4_16K = 6,	/* audio DVI4 16Khz */

+    PJ_RTP_PT_LPC = 7,		/* audio LPC */

+    PJ_RTP_PT_PCMA = 8,		/* audio PCMA */

+    PJ_RTP_PT_G722 = 9,		/* audio G722 */

+    PJ_RTP_PT_L16_2 = 10,	/* audio 16bit linear 44.1KHz stereo */

+    PJ_RTP_PT_L16_1 = 11,	/* audio 16bit linear 44.1KHz mono */

+    PJ_RTP_PT_QCELP = 12,	/* audio QCELP */

+    PJ_RTP_PT_CN = 13,		/* audio Comfort Noise */

+    PJ_RTP_PT_MPA = 14,		/* audio MPEG1 or MPEG2 as elementary streams */

+    PJ_RTP_PT_G728 = 15,	/* audio G728 */

+    PJ_RTP_PT_DVI4_11K = 16,	/* audio DVI4 11.025KHz mono */

+    PJ_RTP_PT_DVI4_22K = 17,	/* audio DVI4 22.050KHz mono */

+    PJ_RTP_PT_G729 = 18,	/* audio G729 */

+    PJ_RTP_PT_CELB = 25,	/* video/comb Cell-B by Sun Microsystems (RFC 2029) */

+    PJ_RTP_PT_JPEG = 26,	/* video JPEG */

+    PJ_RTP_PT_NV = 28,		/* video NV implemented by nv program by Xerox */

+    PJ_RTP_PT_H261 = 31,	/* video H261 */

+    PJ_RTP_PT_MPV = 32,		/* video MPEG1 or MPEG2 elementary streams */

+    PJ_RTP_PT_MP2T = 33,	/* video MPEG2 transport */

+    PJ_RTP_PT_H263 = 34,	/* video H263 */

+

+    PJ_RTP_PT_DYNAMIC = 96,	/* start of dynamic RTP payload */

+} pj_rtp_pt;

+

+

+/** Identification used to search for codec factory that supports specific 

+ *  codec specification. 

+ */

+typedef struct pj_codec_id

+{

+    /** Media type. */

+    pj_media_type   type;

+

+    /** Payload type (can be dynamic). */

+    unsigned	    pt;

+

+    /** Encoding name, must be present if the payload type is dynamic. */

+    pj_str_t	    encoding_name;

+

+    /** Sampling rate. */

+    unsigned	    sample_rate;

+} pj_codec_id;

+

+

+/** Detailed codec attributes used both to configure a codec and to query

+ *  the capability of codec factories.

+ */

+typedef struct pj_codec_attr

+{

+    pj_uint32_t	sample_rate;	    /* Sampling rate in Hz */

+    pj_uint32_t	avg_bps;	    /* Average bandwidth in bits per second */

+

+    pj_uint8_t	pcm_bits_per_sample;/* Bits per sample in the PCM side */

+    pj_uint16_t	ptime;		    /* Packet time in miliseconds */

+

+    unsigned	pt:8;		    /* Payload type. */

+    unsigned    vad_enabled:1;	    /* Voice Activity Detector. */

+    unsigned    cng_enabled:1;	    /* Comfort Noise Generator. */

+    unsigned    lpf_enabled:1;	    /* Low pass filter */

+    unsigned    hpf_enabled:1;	    /* High pass filter */

+    unsigned    penh_enabled:1;	    /* Perceptual Enhancement */

+    unsigned    concl_enabled:1;    /* Packet loss concealment */

+    unsigned    reserved_bit:1;

+

+} pj_codec_attr;

+

+/** Types of audio frame. */

+typedef enum pj_audio_frame_type

+{

+    /** The frame is a silence audio frame. */

+    PJ_AUDIO_FRAME_SILENCE,

+

+    /** The frame is a non-silence audio frame. */

+    PJ_AUDIO_FRAME_AUDIO,

+

+} pj_audio_frame_type;

+

+typedef struct pj_codec pj_codec;

+typedef struct pj_codec_factory pj_codec_factory;

+

+

+/** This structure describes an audio frame. */

+struct pj_audio_frame

+{

+    /** Type: silence or non-silence. */

+    pj_audio_frame_type type;

+

+    /** Pointer to buffer. */

+    void	*buf;

+

+    /** Frame size in bytes. */

+    unsigned	 size;

+};

+

+/**

+ * Operations that must be supported by the codec.

+ */

+typedef struct pj_codec_op

+{

+    /** Get default attributes. */

+    pj_status_t (*default_attr) (pj_codec *codec, pj_codec_attr *attr);

+

+    /** Open and initialize codec using the specified attribute.

+     *  @return zero on success.

+     */

+    pj_status_t	(*init)( pj_codec *codec, pj_pool_t *pool );

+

+    /** Close and shutdown codec.

+     */

+    pj_status_t	(*open)( pj_codec *codec, pj_codec_attr *attr );

+

+    /** Close and shutdown codec.

+     */

+    pj_status_t (*close)( pj_codec *codec );

+

+    /** Encode frame.

+     */

+    pj_status_t (*encode)( pj_codec *codec, const struct pj_audio_frame *input,

+			   unsigned output_buf_len, struct pj_audio_frame *output);

+

+    /** Decode frame.

+     */

+    pj_status_t (*decode)( pj_codec *codec, const struct pj_audio_frame *input,

+			   unsigned output_buf_len, struct pj_audio_frame *output);

+

+} pj_codec_op;

+

+/**

+ * A codec describes an instance to encode or decode media frames. 

+ */

+struct pj_codec

+{

+    /** Entries to put this codec instance in codec factory's list. */

+    PJ_DECL_LIST_MEMBER(struct pj_codec)

+

+    /** Codec's private data. */

+    void	*codec_data;

+

+    /** Codec factory where this codec was allocated. */

+    pj_codec_factory *factory;

+

+    /** Operations to codec. */

+    pj_codec_op	*op;

+};

+

+/**

+ * This structure describes operations that must be supported by codec factories.

+ */

+typedef struct pj_codec_factory_op

+{

+    /** Check whether the factory can create codec with the specified ID.

+     *  @param factory The codec factory.

+     *  @param id  The codec ID.

+     *  @return zero it matches.

+     */

+    pj_status_t	(*match_id)( pj_codec_factory *factory, const pj_codec_id *id );

+

+    /** Create default attributes for the specified codec ID. This function can

+     *  be called by application to get the capability of the codec.

+     *  @param factory The codec factory.

+     *  @param id  The codec ID.

+     *  @param attr The attribute to be initialized.

+     *  @return zero if success.

+     */

+    pj_status_t (*default_attr)( pj_codec_factory *factory, const pj_codec_id *id,

+				 pj_codec_attr *attr );

+

+    /** Enumerate supported codecs.

+     *  @param factory The codec factory.

+     *  @param count Number of entries in the array.

+     *  @param codecs The codec array.

+     *  @return the total number of supported codecs, which can be less or 

+     *          greater than requested.

+     */

+    unsigned (*enum_codecs) (pj_codec_factory *factory, unsigned count, pj_codec_id codecs[]);

+

+    /** This function is called by codec manager to instantiate one codec

+     *  instance.

+     *  @param factory The codec factory.

+     *  @param id  The codec ID.

+     *  @return the instance of the codec, or NULL if codec can not be created.

+     */

+    pj_codec* (*alloc_codec)( pj_codec_factory *factory, const pj_codec_id *id);

+

+    /** This function is called by codec manager to return a particular instance

+     *  of codec back to the codec factory.

+     *  @param factory The codec factory.

+     *  @param codec The codec instance to be returned.

+     */

+    void (*dealloc_codec)( pj_codec_factory *factory, pj_codec *codec );

+

+} pj_codec_factory_op;

+

+/**

+ * Codec factory describes a module that is able to create codec with specific

+ * capabilities. These capabilities can be queried by codec manager to create

+ * instances of codec.

+ */

+struct pj_codec_factory

+{

+    /** Entries to put this structure in the codec manager list. */

+    PJ_DECL_LIST_MEMBER(struct pj_codec_factory)

+

+    /** The factory's private data. */

+    void		*factory_data;

+

+    /** Operations to the factory. */

+    pj_codec_factory_op *op;

+

+};

+

+/**

+ * Declare maximum codecs

+ */

+#define PJ_CODEC_MGR_MAX_CODECS	    32

+

+/**

+ * Codec manager maintains codec factory etc.

+ */

+typedef struct pj_codec_mgr

+{

+    pj_codec_factory factory_list;

+    unsigned	     codec_cnt;

+    pj_codec_id	     codecs[PJ_CODEC_MGR_MAX_CODECS];

+} pj_codec_mgr;

+

+/**

+ * Init codec manager.

+ */

+PJ_DECL(pj_status_t) 

+pj_codec_mgr_init (pj_codec_mgr *mgr);

+

+/** 

+ * Register codec to codec manager. 

+ */

+PJ_DECL(pj_status_t) 

+pj_codec_mgr_register_factory (pj_codec_mgr *mgr, pj_codec_factory *factory);

+

+/**

+ * Unregister codec.

+ */

+PJ_DECL(void) 

+pj_codec_mgr_unregister_factory (pj_codec_mgr *mgr, pj_codec_factory *factory);

+

+/**

+ * Enumerate codecs.

+ */

+PJ_DECL(unsigned)

+pj_codec_mgr_enum_codecs (pj_codec_mgr *mgr, unsigned count, const pj_codec_id *codecs[]);

+

+/**

+ * Open codec.

+ */

+PJ_DECL(pj_codec*) 

+pj_codec_mgr_alloc_codec (pj_codec_mgr *mgr, const struct pj_codec_id *id);

+

+/**

+ * Close codec.

+ */

+PJ_DECL(void) 

+pj_codec_mgr_dealloc_codec (pj_codec_mgr *mgr, pj_codec *codec);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+

+#endif	/* __PJMEDIA_CODEC_H__ */

diff --git a/pjmedia/src/pjmedia/config.h b/pjmedia/src/pjmedia/config.h
index cc38892..757a8dc 100644
--- a/pjmedia/src/pjmedia/config.h
+++ b/pjmedia/src/pjmedia/config.h
@@ -1,13 +1,34 @@
-/* $Id$
- *
- */
-
-#ifndef __PJMED_CONFIG_H__
-#define __PJMED_CONFIG_H__
-
-/**
- * @defgroup PJMEDIA Media Stack
- */
-
-
-#endif	/* __PJMED_CONFIG_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJMED_CONFIG_H__

+#define __PJMED_CONFIG_H__

+

+/**

+ * @defgroup PJMEDIA Media Stack

+ */

+

+

+#endif	/* __PJMED_CONFIG_H__ */

diff --git a/pjmedia/src/pjmedia/dsound.c b/pjmedia/src/pjmedia/dsound.c
index 6f3b67d..22b0a5d 100644
--- a/pjmedia/src/pjmedia/dsound.c
+++ b/pjmedia/src/pjmedia/dsound.c
@@ -1,863 +1,884 @@
-/* $Id$
- *
- */
-
-#ifdef _MSC_VER
-//# pragma warning(disable: 4201)   // non-standard extension: nameless struct/union
-# pragma warning(push, 3)
-#endif
-#include <pj/config.h>
-#include <pj/os.h>
-#include <pj/log.h>
-
-#include <dsound.h>
-#include <stdio.h>
-#include <assert.h>
-#include <pjmedia/sound.h>
-
-#define THIS_FILE   "dsound.c"
-
-/*
- * Constants
- */
-#define PACKET_BUFFER_COUNT 4
-
-typedef struct PJ_Direct_Sound_Device PJ_Direct_Sound_Device;
-
-
-/*
- * DirectSound Factory Operations
- */
-static pj_status_t dsound_init(void);
-static const char *dsound_get_name(void);
-static pj_status_t dsound_destroy(void);
-static pj_status_t dsound_enum_devices(int *count, char *dev_names[]);
-static pj_status_t dsound_create_dev(const char *dev_name, pj_snd_dev *dev);
-static pj_status_t dsound_destroy_dev(pj_snd_dev *dev);
-
-
-/*
- * DirectSound Device Operations
- */
-static pj_status_t dsound_dev_open( pj_snd_dev *dev, pj_snd_role_t role );
-static pj_status_t dsound_dev_close( pj_snd_dev *dev );
-static pj_status_t dsound_dev_play( pj_snd_dev *dev );
-static pj_status_t dsound_dev_record( pj_snd_dev *dev );
-
-/*
- * Utils.
- */
-static pj_status_t dsound_destroy_dsound_dev( PJ_Direct_Sound_Device *dsDev );
-
-
-static pj_snd_dev_factory dsound_factory = 
-{
-    &dsound_init,
-    &dsound_get_name,
-    &dsound_destroy,
-    &dsound_enum_devices,
-    &dsound_create_dev,
-    &dsound_destroy_dev
-};
-
-static struct pj_snd_dev_op dsound_dev_op = 
-{
-    &dsound_dev_open,
-    &dsound_dev_close,
-    &dsound_dev_play,
-    &dsound_dev_record
-};
-
-#define DSOUND_TYPE_PLAYER	1
-#define DSOUND_TYPE_RECORDER	2
-
-typedef struct Direct_Sound_Descriptor
-{
-    int			type;
-
-    LPDIRECTSOUND	lpDsPlay;
-    LPDIRECTSOUNDBUFFER	lpDsPlayBuffer;
-
-    LPDIRECTSOUNDCAPTURE	lpDsCapture;
-    LPDIRECTSOUNDCAPTUREBUFFER	lpDsCaptureBuffer;
-
-    LPDIRECTSOUNDNOTIFY	lpDsNotify;
-    HANDLE		hEvent;
-    HANDLE		hThread;
-    HANDLE		hStartEvent;
-    DWORD		dwThreadQuitFlag;
-    pj_thread_desc	thread_desc;
-    pj_thread_t	       *thread;
-} Direct_Sound_Descriptor;
-
-struct PJ_Direct_Sound_Device
-{
-    Direct_Sound_Descriptor playDesc;
-    Direct_Sound_Descriptor recDesc;
-};
-
-struct Thread_Param
-{
-    pj_snd_dev	    *dev;
-    Direct_Sound_Descriptor *desc;
-};
-
-PJ_DEF(pj_snd_dev_factory*) pj_dsound_get_factory()
-{
-    return &dsound_factory;
-}
-
-/*
- * Init DirectSound.
- */
-static pj_status_t dsound_init(void)
-{
-    /* Nothing to do. */
-    return 0;
-}
-
-/*
- * Get the name of the factory.
- */
-static const char *dsound_get_name(void)
-{
-    return "DirectSound";
-}
-
-/*
- * Destroy DirectSound.
- */
-static pj_status_t dsound_destroy(void)
-{
-    /* TODO: clean up devices in case application haven't done it. */
-    return 0;
-}
-
-/*
- * Enum devices in the system.
- */
-static pj_status_t dsound_enum_devices(int *count, char *dev_names[])
-{
-    dev_names[0] = "DirectSound Default Device";
-    *count = 1;
-    return 0;
-}
-
-/*
- * Create DirectSound device.
- */
-static pj_status_t dsound_create_dev(const char *dev_name, pj_snd_dev *dev)
-{
-    PJ_Direct_Sound_Device *dsDev;
-
-    /* TODO: create based on the name. */
-    PJ_TODO(DSOUND_CREATE_DEVICE_BY_NAME);
-    
-    /* Create DirectSound structure. */
-    dsDev = malloc(sizeof(*dsDev));
-    if (!dsDev) {
-	PJ_LOG(1,(THIS_FILE, "No memory to allocate device!"));
-	return -1;
-    }
-    memset(dsDev, 0, sizeof(*dsDev));
-
-    /* Associate DirectSound device with device. */
-    dev->device = dsDev;
-    dev->op = &dsound_dev_op;
-
-    return 0;
-}
-
-/*
- * Destroy DirectSound device.
- */
-static pj_status_t dsound_destroy_dev( pj_snd_dev *dev )
-{
-    if (dev->device) {
-	free(dev->device);
-	dev->device = NULL;
-    }
-    return 0;
-}
-
-static void dsound_release_descriptor(Direct_Sound_Descriptor *desc)
-{
-    if (desc->lpDsNotify)
-	IDirectSoundNotify_Release( desc->lpDsNotify );
-    
-    if (desc->hEvent)
-	CloseHandle(desc->hEvent);
-
-    if (desc->lpDsPlayBuffer)
-	IDirectSoundBuffer_Release( desc->lpDsPlayBuffer );
-
-    if (desc->lpDsPlay)
-	IDirectSound_Release( desc->lpDsPlay );
-
-    if (desc->lpDsCaptureBuffer)
-	IDirectSoundCaptureBuffer_Release(desc->lpDsCaptureBuffer);
-
-    if (desc->lpDsCapture)
-	IDirectSoundCapture_Release(desc->lpDsCapture);
-}
-
-/*
- * Destroy DirectSound resources.
- */
-static pj_status_t dsound_destroy_dsound_dev( PJ_Direct_Sound_Device *dsDev )
-{
-    dsound_release_descriptor( &dsDev->playDesc );
-    dsound_release_descriptor( &dsDev->recDesc );
-    memset(dsDev, 0, sizeof(*dsDev));
-    return 0;
-}
-
-static void init_waveformatex (PCMWAVEFORMAT *pcmwf, pj_snd_dev *dev)
-{
-    memset(pcmwf, 0, sizeof(PCMWAVEFORMAT)); 
-    pcmwf->wf.wFormatTag = WAVE_FORMAT_PCM; 
-    pcmwf->wf.nChannels = 1;
-    pcmwf->wf.nSamplesPerSec = dev->param.samples_per_sec;
-    pcmwf->wf.nBlockAlign = dev->param.bytes_per_frame;
-    pcmwf->wf.nAvgBytesPerSec = 
-	dev->param.samples_per_sec * dev->param.bytes_per_frame;
-    pcmwf->wBitsPerSample = dev->param.bits_per_sample;
-}
-
-/*
- * Initialize DirectSound player device.
- */
-static pj_status_t dsound_init_player (pj_snd_dev *dev)
-{
-    HRESULT hr;
-    HWND hwnd;
-    PCMWAVEFORMAT pcmwf; 
-    DSBUFFERDESC dsbdesc;
-    DSBPOSITIONNOTIFY dsPosNotify[PACKET_BUFFER_COUNT];
-    unsigned i;
-    PJ_Direct_Sound_Device *dsDev = dev->device;
-
-    /*
-     * Check parameters.
-     */
-    if (dev->play_cb == NULL) {
-	assert(0);
-	return -1;
-    }
-    if (dev->device == NULL) {
-	assert(0);
-	return -1;
-    }
-
-    PJ_LOG(4,(THIS_FILE, "Creating DirectSound player device"));
-
-    /*
-     * Create DirectSound device.
-     */
-    hr = DirectSoundCreate(NULL, &dsDev->playDesc.lpDsPlay, NULL);
-    if (FAILED(hr))
-	goto on_error;
-
-    hwnd = GetForegroundWindow();
-    if (hwnd == NULL) {
-	hwnd = GetDesktopWindow();
-    }    
-    hr = IDirectSound_SetCooperativeLevel( dsDev->playDesc.lpDsPlay, hwnd, 
-					   DSSCL_PRIORITY);
-    if FAILED(hr)
-	goto on_error;
-    
-    /*
-     * Create DirectSound play buffer.
-     */    
-    // Set up wave format structure. 
-    init_waveformatex (&pcmwf, dev);
-
-    // Set up DSBUFFERDESC structure. 
-    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); 
-    dsbdesc.dwSize = sizeof(DSBUFFERDESC); 
-    dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY |
-		      DSBCAPS_GETCURRENTPOSITION2;
-
-    dsbdesc.dwBufferBytes = 
-	(PACKET_BUFFER_COUNT * dev->param.bytes_per_frame * 
-	 dev->param.frames_per_packet); 
-    dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; 
-
-    // Create buffer. 
-    hr = IDirectSound_CreateSoundBuffer(dsDev->playDesc.lpDsPlay, &dsbdesc, 
-					&dsDev->playDesc.lpDsPlayBuffer, NULL); 
-    if (FAILED(hr) )
-	goto on_error;
-
-    /*
-     * Create event for play notification.
-     */
-    dsDev->playDesc.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
-    if (dsDev->playDesc.hEvent == NULL)
-	goto on_error;
-
-    /*
-     * Setup notification for play.
-     */
-    hr = IDirectSoundBuffer_QueryInterface( dsDev->playDesc.lpDsPlayBuffer, 
-					    &IID_IDirectSoundNotify, 
-					    (LPVOID *)&dsDev->playDesc.lpDsNotify); 
-    if (FAILED(hr))
-	goto on_error;
-
-    
-    for (i=0; i<PACKET_BUFFER_COUNT; ++i) {
-	dsPosNotify[i].dwOffset = i * dev->param.bytes_per_frame * 
-				  dev->param.frames_per_packet;
-	dsPosNotify[i].hEventNotify = dsDev->playDesc.hEvent;
-    }
-    
-    hr = IDirectSoundNotify_SetNotificationPositions( dsDev->playDesc.lpDsNotify, 
-						      PACKET_BUFFER_COUNT, 
-						      dsPosNotify);
-    if (FAILED(hr))
-	goto on_error;
-
-    /* Done setting up play device. */
-    PJ_LOG(4,(THIS_FILE, "DirectSound player device created"));
-
-    return 0;
-
-on_error:
-    PJ_LOG(2,(THIS_FILE, "Error creating player device, hresult=0x%x", hr));
-    dsound_destroy_dsound_dev(dsDev);
-    return -1;
-}
-
-/*
- * Initialize DirectSound recorder device
- */
-static pj_status_t dsound_init_recorder (pj_snd_dev *dev)
-{
-    HRESULT hr;
-    PCMWAVEFORMAT pcmwf; 
-    DSCBUFFERDESC dscbdesc;
-    DSBPOSITIONNOTIFY dsPosNotify[PACKET_BUFFER_COUNT];
-    unsigned i;
-    PJ_Direct_Sound_Device *dsDev = dev->device;
-
-    /*
-     * Check parameters.
-     */
-    if (dev->rec_cb == NULL) {
-	assert(0);
-	return -1;
-    }
-    if (dev->device == NULL) {
-	assert(0);
-	return -1;
-    }
-
-    PJ_LOG(4,(THIS_FILE, "Creating DirectSound recorder device"));
-
-    /*
-     * Creating recorder device.
-     */
-    hr = DirectSoundCaptureCreate(NULL, &dsDev->recDesc.lpDsCapture, NULL);
-    if (FAILED(hr))
-	goto on_error;
-
-    /* Init wave format */
-    init_waveformatex (&pcmwf, dev);
-
-    /* 
-     * Setup capture buffer using sound buffer structure that was passed
-     * to play buffer creation earlier.
-     */
-    memset(&dscbdesc, 0, sizeof(DSCBUFFERDESC));
-    dscbdesc.dwSize = sizeof(DSCBUFFERDESC); 
-    dscbdesc.dwFlags = DSCBCAPS_WAVEMAPPED ;
-    dscbdesc.dwBufferBytes = 
-	(PACKET_BUFFER_COUNT * dev->param.bytes_per_frame * 
-	 dev->param.frames_per_packet); 
-    dscbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; 
-
-    hr = IDirectSoundCapture_CreateCaptureBuffer( dsDev->recDesc.lpDsCapture,
-						  &dscbdesc, 
-						  &dsDev->recDesc.lpDsCaptureBuffer, 
-						  NULL);
-    if (FAILED(hr))
-	goto on_error;
-
-    /*
-     * Create event for play notification.
-     */
-    dsDev->recDesc.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);
-    if (dsDev->recDesc.hEvent == NULL)
-	goto on_error;
-
-    /*
-     * Setup notifications for recording.
-     */
-    hr = IDirectSoundCaptureBuffer_QueryInterface( dsDev->recDesc.lpDsCaptureBuffer, 
-						   &IID_IDirectSoundNotify, 
-						   (LPVOID *)&dsDev->recDesc.lpDsNotify); 
-    if (FAILED(hr))
-	goto on_error;
-
-    
-    for (i=0; i<PACKET_BUFFER_COUNT; ++i) {
-	dsPosNotify[i].dwOffset = i * dev->param.bytes_per_frame * 
-				  dev->param.frames_per_packet;
-	dsPosNotify[i].hEventNotify = dsDev->recDesc.hEvent;
-    }
-    
-    hr = IDirectSoundNotify_SetNotificationPositions( dsDev->recDesc.lpDsNotify, 
-						      PACKET_BUFFER_COUNT, 
-						      dsPosNotify);
-    if (FAILED(hr))
-	goto on_error;
-
-    /* Done setting up recorder device. */
-    PJ_LOG(4,(THIS_FILE, "DirectSound recorder device created"));
-
-    return 0;
-
-on_error:
-    PJ_LOG(4,(THIS_FILE, "Error creating device, hresult=%d", hr));
-    dsound_destroy_dsound_dev(dsDev);
-    return -1;
-}
-
-/*
- * Initialize DirectSound device.
- */
-static pj_status_t dsound_dev_open( pj_snd_dev *dev, pj_snd_role_t role )
-{
-    PJ_Direct_Sound_Device *dsDev = dev->device;
-    pj_status_t status;
-
-    dsDev->playDesc.type = DSOUND_TYPE_PLAYER;
-    dsDev->recDesc.type = DSOUND_TYPE_RECORDER;
-
-    if (role & PJ_SOUND_PLAYER) {
-	status = dsound_init_player (dev);
-	if (status != 0)
-	    return status;
-    }
-
-    if (role & PJ_SOUND_RECORDER) {
-	status = dsound_init_recorder (dev);
-	if (status != 0)
-	    return status;
-    }
-
-    return 0;
-}
-
-/*
- * Close DirectSound device.
- */
-static pj_status_t dsound_dev_close( pj_snd_dev *dev )
-{
-    PJ_LOG(4,(THIS_FILE, "Closing DirectSound device"));
-
-    if (dev->device) {
-	PJ_Direct_Sound_Device *dsDev = dev->device;
-
-	if (dsDev->playDesc.hThread) {
-	    PJ_LOG(4,(THIS_FILE, "Stopping DirectSound player"));
-	    dsDev->playDesc.dwThreadQuitFlag = 1;
-	    SetEvent(dsDev->playDesc.hEvent);
-	    if (WaitForSingleObject(dsDev->playDesc.hThread, 1000) != WAIT_OBJECT_0) {
-		PJ_LOG(4,(THIS_FILE, "Timed out waiting player thread to quit"));
-		TerminateThread(dsDev->playDesc.hThread, -1);
-		IDirectSoundBuffer_Stop( dsDev->playDesc.lpDsPlayBuffer );
-	    }
-	    
-	    pj_thread_destroy (dsDev->playDesc.thread);
-	}
-
-	if (dsDev->recDesc.hThread) {
-	    PJ_LOG(4,(THIS_FILE, "Stopping DirectSound recorder"));
-	    dsDev->recDesc.dwThreadQuitFlag = 1;
-	    SetEvent(dsDev->recDesc.hEvent);
-	    if (WaitForSingleObject(dsDev->recDesc.hThread, 1000) != WAIT_OBJECT_0) {
-		PJ_LOG(4,(THIS_FILE, "Timed out waiting recorder thread to quit"));
-		TerminateThread(dsDev->recDesc.hThread, -1);
-		IDirectSoundCaptureBuffer_Stop( dsDev->recDesc.lpDsCaptureBuffer );
-	    }
-	    
-	    pj_thread_destroy (dsDev->recDesc.thread);
-	}
-
-	dsound_destroy_dsound_dev( dev->device );
-	dev->op = NULL;
-    }
-
-    PJ_LOG(4,(THIS_FILE, "DirectSound device closed"));
-    return 0;
-}
-
-static BOOL AppReadDataFromBuffer(LPDIRECTSOUNDCAPTUREBUFFER lpDsb, // The buffer.
-				  DWORD dwOffset,		    // Our own write cursor.
-				  LPBYTE lpbSoundData,		    // Start of our data.
-				  DWORD dwSoundBytes)		    // Size of block to copy.
-{ 
-    LPVOID  lpvPtr1; 
-    DWORD dwBytes1; 
-    LPVOID  lpvPtr2; 
-    DWORD dwBytes2; 
-    HRESULT hr; 
-    
-    // Obtain memory address of write block. This will be in two parts
-    // if the block wraps around.
-    
-    hr = IDirectSoundCaptureBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 
-					 &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
-    
-    if SUCCEEDED(hr) { 
-	// Read from pointers. 
-	CopyMemory(lpbSoundData, lpvPtr1, dwBytes1); 
-	if (lpvPtr2 != NULL)
-	    CopyMemory(lpbSoundData+dwBytes1, lpvPtr2, dwBytes2); 
-	
-	// Release the data back to DirectSound. 
-	hr = IDirectSoundCaptureBuffer_Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); 
-	if SUCCEEDED(hr)
-	    return TRUE; 
-    } 
-    
-    // Lock, Unlock, or Restore failed. 
-    return FALSE; 
-}
-
-
-static BOOL AppWriteDataToBuffer(LPDIRECTSOUNDBUFFER lpDsb,  // The buffer.
-				 DWORD dwOffset,	      // Our own write cursor.
-				 LPBYTE lpbSoundData,	      // Start of our data.
-				 DWORD dwSoundBytes)	      // Size of block to copy.
-{ 
-    LPVOID  lpvPtr1; 
-    DWORD dwBytes1; 
-    LPVOID  lpvPtr2; 
-    DWORD dwBytes2; 
-    HRESULT hr; 
-    
-    // Obtain memory address of write block. This will be in two parts
-    // if the block wraps around.
-    
-    hr = IDirectSoundBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 
-				  &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
-    
-    // If the buffer was lost, restore and retry lock. 
-    if (DSERR_BUFFERLOST == hr) { 
-	IDirectSoundBuffer_Restore(lpDsb); 
-	hr = IDirectSoundBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, 
-				      &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
-    } 
-    if SUCCEEDED(hr) { 
-	CopyMemory(lpvPtr1, lpbSoundData, dwBytes1); 
-	if (NULL != lpvPtr2) 
-	    CopyMemory(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2); 
-	
-	hr = IDirectSoundBuffer_Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); 
-	if SUCCEEDED(hr)
-	    return TRUE; 
-    } 
-    
-    return FALSE; 
-}
-
-
-/*
- * Player thread.
- */
-static DWORD WINAPI dsound_dev_thread(void *arg)
-{
-    struct Thread_Param *param = arg;
-    pj_snd_dev *dev = param->dev;
-    Direct_Sound_Descriptor *desc = param->desc;
-    unsigned bytes_per_pkt = dev->param.bytes_per_frame *
-			     dev->param.frames_per_packet;
-    unsigned samples_per_pkt = dev->param.samples_per_frame *
-			       dev->param.frames_per_packet;
-    void *buffer = NULL;
-    DWORD size;
-    pj_status_t status;
-    DWORD sample_pos;
-    DWORD byte_pos;
-    DWORD buffer_size = 
-	(PACKET_BUFFER_COUNT * dev->param.bytes_per_frame * 
-	 dev->param.frames_per_packet);
-    HRESULT hr;
-
-    PJ_LOG(4,(THIS_FILE, "DirectSound thread starting"));
-
-    /* Allocate buffer for sound data */
-    buffer = malloc(bytes_per_pkt);
-    if (!buffer) {
-	PJ_LOG(1,(THIS_FILE, "Unable to allocate packet buffer!"));
-	return (DWORD)-1;
-    }
-
-    desc->thread = pj_thread_register ("dsound", desc->thread_desc);
-    if (desc->thread == NULL)
-	return (DWORD)-1;
-
-    /*
-     * Start playing or recording!
-     */
-    if (desc->type == DSOUND_TYPE_PLAYER) {
-	hr = IDirectSoundBuffer_SetCurrentPosition( desc->lpDsPlayBuffer, 0);
-	if (FAILED(hr)) {
-	    PJ_LOG(1,(THIS_FILE, "DirectSound play: SetCurrentPosition() error %d", hr));
-	    goto on_error;
-	}
-
-	hr = IDirectSoundBuffer_Play(desc->lpDsPlayBuffer, 0, 0, DSBPLAY_LOOPING);
-	if (FAILED(hr)) {
-	    PJ_LOG(1,(THIS_FILE, "DirectSound: Play() error %d", hr));
-	    goto on_error;
-	}
-    } else {
-	hr = IDirectSoundCaptureBuffer_Start(desc->lpDsCaptureBuffer, DSCBSTART_LOOPING );
-	if (FAILED(hr)) {
-	    PJ_LOG(1,(THIS_FILE, "DirectSound: Record() error %d", hr));
-	    goto on_error;
-	}
-    }
-
-    /*
-     * Reset initial positions.
-     */
-    byte_pos = 0xFFFFFFFF;
-    sample_pos = 0;
-
-    /*
-     * Wait to get the first notification.
-     */
-    if (WaitForSingleObject(desc->hEvent, 100) != WAIT_OBJECT_0) {
-	PJ_LOG(1,(THIS_FILE, "DirectSound: error getting notification"));
-	goto on_error;
-    }
-
-	
-    /* Get initial byte position. */
-    if (desc->type == DSOUND_TYPE_PLAYER) {
-	hr = IDirectSoundBuffer_GetCurrentPosition( desc->lpDsPlayBuffer, 
-						    NULL, &byte_pos );
-	if (FAILED(hr)) {
-	    PJ_LOG(1,(THIS_FILE, "DirectSound: unable to get "
-				 "position, err %d", hr));
-	    goto on_error;
-	}
-    } else {
-	hr = IDirectSoundCaptureBuffer_GetCurrentPosition( desc->lpDsCaptureBuffer, 
-							   NULL, &byte_pos );
-	if (FAILED(hr)) {
-	    PJ_LOG(1,(THIS_FILE, "DirectSound: unable to get "
-				 "position, err %d", hr));
-	    goto on_error;
-	}
-    }
-
-    /* Signal main thread that we're running. */
-    assert( desc->hStartEvent );
-    SetEvent( desc->hStartEvent );
-
-    /*
-     * Loop while not signalled to quit, wait for event object to be signalled
-     * by DirectSound play buffer, then request for sound data from the 
-     * application and write it to DirectSound buffer.
-     */
-    do {
-	
-	/* Call callback to get sound data */
-	if (desc->type == DSOUND_TYPE_PLAYER) {
-	    size = bytes_per_pkt;
-	    status = (*dev->play_cb)(dev, sample_pos, buffer, &size);
-
-	    /* Quit thread on error. */
-	    if (status != 0)
-		break;
-
-	    /* Write zeroes when we've got nothing from application. */
-	    if (size == 0) {
-		memset(buffer, 0, bytes_per_pkt);
-		size = bytes_per_pkt;
-	    }
-
-	    /* Write to DirectSound buffer. */
-	    AppWriteDataToBuffer( desc->lpDsPlayBuffer, byte_pos,
-				  (LPBYTE)buffer, size);
-
-	} else {
-	    /* Capture from DirectSound buffer. */
-	    size = bytes_per_pkt;
-	    if (AppReadDataFromBuffer( desc->lpDsCaptureBuffer, byte_pos,
-				       (LPBYTE)buffer, size)) {
-
-	    } else {
-		memset(buffer, 0, size);
-	    }
-
-	    /* Call callback */
-	    status = (*dev->rec_cb)(dev, sample_pos, buffer, size);
-
-	    /* Quit thread on error. */
-	    if (status != 0)
-		break;
-	}
-
-	/* Increment position. */
-	byte_pos += size;
-	if (byte_pos >= buffer_size)
-	    byte_pos -= buffer_size;
-	sample_pos += samples_per_pkt;
-
-	while (WaitForSingleObject(desc->hEvent, 500) != WAIT_OBJECT_0 &&
-	       (!desc->dwThreadQuitFlag)) 
-	{
-	    Sleep(1);
-	}
-    } while (!desc->dwThreadQuitFlag);
-
-
-    PJ_LOG(4,(THIS_FILE, "DirectSound: stopping.."));
-
-    free(buffer);
-    if (desc->type == DSOUND_TYPE_PLAYER) {
-	IDirectSoundBuffer_Stop( desc->lpDsPlayBuffer );
-    } else {
-	IDirectSoundCaptureBuffer_Stop( desc->lpDsCaptureBuffer );
-    }
-    return 0;
-
-on_error:
-    PJ_LOG(4,(THIS_FILE, "DirectSound play stopping"));
-
-    if (buffer) 
-	free(buffer);
-    if (desc->type == DSOUND_TYPE_PLAYER) {
-	IDirectSoundBuffer_Stop( desc->lpDsPlayBuffer );
-    } else {
-	IDirectSoundCaptureBuffer_Stop( desc->lpDsCaptureBuffer );
-    }
-    desc->dwThreadQuitFlag = 1;
-
-    /* Signal main thread that we failed to initialize */
-    assert( desc->hStartEvent );
-    SetEvent( desc->hStartEvent );
-    return -1;
-}
-
-
-/*
- * Generic starter for play/record.
- */
-static pj_status_t dsound_dev_play_record( pj_snd_dev *dev,
-					   Direct_Sound_Descriptor *desc )
-{
-    DWORD threadId;
-    int op_type = desc->type;
-    const char *op_name = (op_type == DSOUND_TYPE_PLAYER) ? "play" : "record";
-    struct Thread_Param param;
-
-    PJ_LOG(4,(THIS_FILE, "DirectSound %s()", op_name));
-
-    /*
-     * Create event for the thread to signal us that it is starting or
-     * quitting during startup.
-     */
-    desc->hStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (desc->hStartEvent == NULL) {
-	PJ_LOG(1,(THIS_FILE, "DirectSound %s: unable to create event", op_name));
-	return -1;
-    }
-
-    param.dev = dev;
-    param.desc = desc;
-
-    /*
-     * Create thread to handle feeding up data to player/recorder.
-     */
-    desc->hThread = NULL;
-    desc->dwThreadQuitFlag = 0;
-    desc->hThread = CreateThread( NULL, 0, &dsound_dev_thread, &param, 
-					    CREATE_SUSPENDED, &threadId);
-    if (!desc->hThread) {
-	PJ_LOG(1,(THIS_FILE, "DirectSound %s(): unable to create thread", op_name));
-	return -1;
-    }
-
-    SetThreadPriority( desc->hThread, THREAD_PRIORITY_HIGHEST);
-
-    /*
-     * Resume thread.
-     */
-    if (ResumeThread(desc->hThread) == (DWORD)-1) {
-	PJ_LOG(1,(THIS_FILE, "DirectSound %s(): unable to resume thread", op_name));
-	goto on_error;
-    }
-
-    /*
-     * Wait until we've got signal from the thread that it has successfully
-     * started, or when it is quitting.
-     */
-    WaitForSingleObject( desc->hStartEvent, INFINITE);
-
-    /* We can destroy the event now. */
-    CloseHandle( desc->hStartEvent );
-    desc->hStartEvent = NULL;
-
-    /* Examine thread status. */
-    if (desc->dwThreadQuitFlag != 0) {
-	/* Thread failed to initialize */
-	WaitForSingleObject(desc->hThread, INFINITE);
-	CloseHandle(desc->hThread);
-	desc->hThread = NULL;
-	return -1;
-    }
-
-    return 0;
-
-on_error:
-    TerminateThread(desc->hThread, -1);
-    CloseHandle(desc->hThread);
-    desc->hThread = NULL;
-    return -1;
-}
-
-/*
- * Start playing.
- */
-static pj_status_t dsound_dev_play( pj_snd_dev *dev )
-{
-    PJ_Direct_Sound_Device *dsDev = dev->device;
-
-    assert(dsDev);
-    if (!dsDev) {
-	assert(0);
-	return -1;
-    }
-
-    return dsound_dev_play_record( dev, &dsDev->playDesc );
-}
-
-/*
- * Start recording.
- */
-static pj_status_t dsound_dev_record( pj_snd_dev *dev )
-{
-    PJ_Direct_Sound_Device *dsDev = dev->device;
-
-    assert(dsDev);
-    if (!dsDev) {
-	assert(0);
-	return -1;
-    }
-
-    return dsound_dev_play_record( dev, &dsDev->recDesc );
-}
-
-#ifdef _MSC_VER
-# pragma warning(pop)
-# pragma warning(disable: 4514)	// unreferenced inline function has been removed
-#endif
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifdef _MSC_VER

+//# pragma warning(disable: 4201)   // non-standard extension: nameless struct/union

+# pragma warning(push, 3)

+#endif

+#include <pj/config.h>

+#include <pj/os.h>

+#include <pj/log.h>

+

+#include <dsound.h>

+#include <stdio.h>

+#include <assert.h>

+#include <pjmedia/sound.h>

+

+#define THIS_FILE   "dsound.c"

+

+/*

+ * Constants

+ */

+#define PACKET_BUFFER_COUNT 4

+

+typedef struct PJ_Direct_Sound_Device PJ_Direct_Sound_Device;

+

+

+/*

+ * DirectSound Factory Operations

+ */

+static pj_status_t dsound_init(void);

+static const char *dsound_get_name(void);

+static pj_status_t dsound_destroy(void);

+static pj_status_t dsound_enum_devices(int *count, char *dev_names[]);

+static pj_status_t dsound_create_dev(const char *dev_name, pj_snd_dev *dev);

+static pj_status_t dsound_destroy_dev(pj_snd_dev *dev);

+

+

+/*

+ * DirectSound Device Operations

+ */

+static pj_status_t dsound_dev_open( pj_snd_dev *dev, pj_snd_role_t role );

+static pj_status_t dsound_dev_close( pj_snd_dev *dev );

+static pj_status_t dsound_dev_play( pj_snd_dev *dev );

+static pj_status_t dsound_dev_record( pj_snd_dev *dev );

+

+/*

+ * Utils.

+ */

+static pj_status_t dsound_destroy_dsound_dev( PJ_Direct_Sound_Device *dsDev );

+

+

+static pj_snd_dev_factory dsound_factory = 

+{

+    &dsound_init,

+    &dsound_get_name,

+    &dsound_destroy,

+    &dsound_enum_devices,

+    &dsound_create_dev,

+    &dsound_destroy_dev

+};

+

+static struct pj_snd_dev_op dsound_dev_op = 

+{

+    &dsound_dev_open,

+    &dsound_dev_close,

+    &dsound_dev_play,

+    &dsound_dev_record

+};

+

+#define DSOUND_TYPE_PLAYER	1

+#define DSOUND_TYPE_RECORDER	2

+

+typedef struct Direct_Sound_Descriptor

+{

+    int			type;

+

+    LPDIRECTSOUND	lpDsPlay;

+    LPDIRECTSOUNDBUFFER	lpDsPlayBuffer;

+

+    LPDIRECTSOUNDCAPTURE	lpDsCapture;

+    LPDIRECTSOUNDCAPTUREBUFFER	lpDsCaptureBuffer;

+

+    LPDIRECTSOUNDNOTIFY	lpDsNotify;

+    HANDLE		hEvent;

+    HANDLE		hThread;

+    HANDLE		hStartEvent;

+    DWORD		dwThreadQuitFlag;

+    pj_thread_desc	thread_desc;

+    pj_thread_t	       *thread;

+} Direct_Sound_Descriptor;

+

+struct PJ_Direct_Sound_Device

+{

+    Direct_Sound_Descriptor playDesc;

+    Direct_Sound_Descriptor recDesc;

+};

+

+struct Thread_Param

+{

+    pj_snd_dev	    *dev;

+    Direct_Sound_Descriptor *desc;

+};

+

+PJ_DEF(pj_snd_dev_factory*) pj_dsound_get_factory()

+{

+    return &dsound_factory;

+}

+

+/*

+ * Init DirectSound.

+ */

+static pj_status_t dsound_init(void)

+{

+    /* Nothing to do. */

+    return 0;

+}

+

+/*

+ * Get the name of the factory.

+ */

+static const char *dsound_get_name(void)

+{

+    return "DirectSound";

+}

+

+/*

+ * Destroy DirectSound.

+ */

+static pj_status_t dsound_destroy(void)

+{

+    /* TODO: clean up devices in case application haven't done it. */

+    return 0;

+}

+

+/*

+ * Enum devices in the system.

+ */

+static pj_status_t dsound_enum_devices(int *count, char *dev_names[])

+{

+    dev_names[0] = "DirectSound Default Device";

+    *count = 1;

+    return 0;

+}

+

+/*

+ * Create DirectSound device.

+ */

+static pj_status_t dsound_create_dev(const char *dev_name, pj_snd_dev *dev)

+{

+    PJ_Direct_Sound_Device *dsDev;

+

+    /* TODO: create based on the name. */

+    PJ_TODO(DSOUND_CREATE_DEVICE_BY_NAME);

+    

+    /* Create DirectSound structure. */

+    dsDev = malloc(sizeof(*dsDev));

+    if (!dsDev) {

+	PJ_LOG(1,(THIS_FILE, "No memory to allocate device!"));

+	return -1;

+    }

+    memset(dsDev, 0, sizeof(*dsDev));

+

+    /* Associate DirectSound device with device. */

+    dev->device = dsDev;

+    dev->op = &dsound_dev_op;

+

+    return 0;

+}

+

+/*

+ * Destroy DirectSound device.

+ */

+static pj_status_t dsound_destroy_dev( pj_snd_dev *dev )

+{

+    if (dev->device) {

+	free(dev->device);

+	dev->device = NULL;

+    }

+    return 0;

+}

+

+static void dsound_release_descriptor(Direct_Sound_Descriptor *desc)

+{

+    if (desc->lpDsNotify)

+	IDirectSoundNotify_Release( desc->lpDsNotify );

+    

+    if (desc->hEvent)

+	CloseHandle(desc->hEvent);

+

+    if (desc->lpDsPlayBuffer)

+	IDirectSoundBuffer_Release( desc->lpDsPlayBuffer );

+

+    if (desc->lpDsPlay)

+	IDirectSound_Release( desc->lpDsPlay );

+

+    if (desc->lpDsCaptureBuffer)

+	IDirectSoundCaptureBuffer_Release(desc->lpDsCaptureBuffer);

+

+    if (desc->lpDsCapture)

+	IDirectSoundCapture_Release(desc->lpDsCapture);

+}

+

+/*

+ * Destroy DirectSound resources.

+ */

+static pj_status_t dsound_destroy_dsound_dev( PJ_Direct_Sound_Device *dsDev )

+{

+    dsound_release_descriptor( &dsDev->playDesc );

+    dsound_release_descriptor( &dsDev->recDesc );

+    memset(dsDev, 0, sizeof(*dsDev));

+    return 0;

+}

+

+static void init_waveformatex (PCMWAVEFORMAT *pcmwf, pj_snd_dev *dev)

+{

+    memset(pcmwf, 0, sizeof(PCMWAVEFORMAT)); 

+    pcmwf->wf.wFormatTag = WAVE_FORMAT_PCM; 

+    pcmwf->wf.nChannels = 1;

+    pcmwf->wf.nSamplesPerSec = dev->param.samples_per_sec;

+    pcmwf->wf.nBlockAlign = dev->param.bytes_per_frame;

+    pcmwf->wf.nAvgBytesPerSec = 

+	dev->param.samples_per_sec * dev->param.bytes_per_frame;

+    pcmwf->wBitsPerSample = dev->param.bits_per_sample;

+}

+

+/*

+ * Initialize DirectSound player device.

+ */

+static pj_status_t dsound_init_player (pj_snd_dev *dev)

+{

+    HRESULT hr;

+    HWND hwnd;

+    PCMWAVEFORMAT pcmwf; 

+    DSBUFFERDESC dsbdesc;

+    DSBPOSITIONNOTIFY dsPosNotify[PACKET_BUFFER_COUNT];

+    unsigned i;

+    PJ_Direct_Sound_Device *dsDev = dev->device;

+

+    /*

+     * Check parameters.

+     */

+    if (dev->play_cb == NULL) {

+	assert(0);

+	return -1;

+    }

+    if (dev->device == NULL) {

+	assert(0);

+	return -1;

+    }

+

+    PJ_LOG(4,(THIS_FILE, "Creating DirectSound player device"));

+

+    /*

+     * Create DirectSound device.

+     */

+    hr = DirectSoundCreate(NULL, &dsDev->playDesc.lpDsPlay, NULL);

+    if (FAILED(hr))

+	goto on_error;

+

+    hwnd = GetForegroundWindow();

+    if (hwnd == NULL) {

+	hwnd = GetDesktopWindow();

+    }    

+    hr = IDirectSound_SetCooperativeLevel( dsDev->playDesc.lpDsPlay, hwnd, 

+					   DSSCL_PRIORITY);

+    if FAILED(hr)

+	goto on_error;

+    

+    /*

+     * Create DirectSound play buffer.

+     */    

+    // Set up wave format structure. 

+    init_waveformatex (&pcmwf, dev);

+

+    // Set up DSBUFFERDESC structure. 

+    memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); 

+    dsbdesc.dwSize = sizeof(DSBUFFERDESC); 

+    dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY |

+		      DSBCAPS_GETCURRENTPOSITION2;

+

+    dsbdesc.dwBufferBytes = 

+	(PACKET_BUFFER_COUNT * dev->param.bytes_per_frame * 

+	 dev->param.frames_per_packet); 

+    dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; 

+

+    // Create buffer. 

+    hr = IDirectSound_CreateSoundBuffer(dsDev->playDesc.lpDsPlay, &dsbdesc, 

+					&dsDev->playDesc.lpDsPlayBuffer, NULL); 

+    if (FAILED(hr) )

+	goto on_error;

+

+    /*

+     * Create event for play notification.

+     */

+    dsDev->playDesc.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);

+    if (dsDev->playDesc.hEvent == NULL)

+	goto on_error;

+

+    /*

+     * Setup notification for play.

+     */

+    hr = IDirectSoundBuffer_QueryInterface( dsDev->playDesc.lpDsPlayBuffer, 

+					    &IID_IDirectSoundNotify, 

+					    (LPVOID *)&dsDev->playDesc.lpDsNotify); 

+    if (FAILED(hr))

+	goto on_error;

+

+    

+    for (i=0; i<PACKET_BUFFER_COUNT; ++i) {

+	dsPosNotify[i].dwOffset = i * dev->param.bytes_per_frame * 

+				  dev->param.frames_per_packet;

+	dsPosNotify[i].hEventNotify = dsDev->playDesc.hEvent;

+    }

+    

+    hr = IDirectSoundNotify_SetNotificationPositions( dsDev->playDesc.lpDsNotify, 

+						      PACKET_BUFFER_COUNT, 

+						      dsPosNotify);

+    if (FAILED(hr))

+	goto on_error;

+

+    /* Done setting up play device. */

+    PJ_LOG(4,(THIS_FILE, "DirectSound player device created"));

+

+    return 0;

+

+on_error:

+    PJ_LOG(2,(THIS_FILE, "Error creating player device, hresult=0x%x", hr));

+    dsound_destroy_dsound_dev(dsDev);

+    return -1;

+}

+

+/*

+ * Initialize DirectSound recorder device

+ */

+static pj_status_t dsound_init_recorder (pj_snd_dev *dev)

+{

+    HRESULT hr;

+    PCMWAVEFORMAT pcmwf; 

+    DSCBUFFERDESC dscbdesc;

+    DSBPOSITIONNOTIFY dsPosNotify[PACKET_BUFFER_COUNT];

+    unsigned i;

+    PJ_Direct_Sound_Device *dsDev = dev->device;

+

+    /*

+     * Check parameters.

+     */

+    if (dev->rec_cb == NULL) {

+	assert(0);

+	return -1;

+    }

+    if (dev->device == NULL) {

+	assert(0);

+	return -1;

+    }

+

+    PJ_LOG(4,(THIS_FILE, "Creating DirectSound recorder device"));

+

+    /*

+     * Creating recorder device.

+     */

+    hr = DirectSoundCaptureCreate(NULL, &dsDev->recDesc.lpDsCapture, NULL);

+    if (FAILED(hr))

+	goto on_error;

+

+    /* Init wave format */

+    init_waveformatex (&pcmwf, dev);

+

+    /* 

+     * Setup capture buffer using sound buffer structure that was passed

+     * to play buffer creation earlier.

+     */

+    memset(&dscbdesc, 0, sizeof(DSCBUFFERDESC));

+    dscbdesc.dwSize = sizeof(DSCBUFFERDESC); 

+    dscbdesc.dwFlags = DSCBCAPS_WAVEMAPPED ;

+    dscbdesc.dwBufferBytes = 

+	(PACKET_BUFFER_COUNT * dev->param.bytes_per_frame * 

+	 dev->param.frames_per_packet); 

+    dscbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf; 

+

+    hr = IDirectSoundCapture_CreateCaptureBuffer( dsDev->recDesc.lpDsCapture,

+						  &dscbdesc, 

+						  &dsDev->recDesc.lpDsCaptureBuffer, 

+						  NULL);

+    if (FAILED(hr))

+	goto on_error;

+

+    /*

+     * Create event for play notification.

+     */

+    dsDev->recDesc.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL);

+    if (dsDev->recDesc.hEvent == NULL)

+	goto on_error;

+

+    /*

+     * Setup notifications for recording.

+     */

+    hr = IDirectSoundCaptureBuffer_QueryInterface( dsDev->recDesc.lpDsCaptureBuffer, 

+						   &IID_IDirectSoundNotify, 

+						   (LPVOID *)&dsDev->recDesc.lpDsNotify); 

+    if (FAILED(hr))

+	goto on_error;

+

+    

+    for (i=0; i<PACKET_BUFFER_COUNT; ++i) {

+	dsPosNotify[i].dwOffset = i * dev->param.bytes_per_frame * 

+				  dev->param.frames_per_packet;

+	dsPosNotify[i].hEventNotify = dsDev->recDesc.hEvent;

+    }

+    

+    hr = IDirectSoundNotify_SetNotificationPositions( dsDev->recDesc.lpDsNotify, 

+						      PACKET_BUFFER_COUNT, 

+						      dsPosNotify);

+    if (FAILED(hr))

+	goto on_error;

+

+    /* Done setting up recorder device. */

+    PJ_LOG(4,(THIS_FILE, "DirectSound recorder device created"));

+

+    return 0;

+

+on_error:

+    PJ_LOG(4,(THIS_FILE, "Error creating device, hresult=%d", hr));

+    dsound_destroy_dsound_dev(dsDev);

+    return -1;

+}

+

+/*

+ * Initialize DirectSound device.

+ */

+static pj_status_t dsound_dev_open( pj_snd_dev *dev, pj_snd_role_t role )

+{

+    PJ_Direct_Sound_Device *dsDev = dev->device;

+    pj_status_t status;

+

+    dsDev->playDesc.type = DSOUND_TYPE_PLAYER;

+    dsDev->recDesc.type = DSOUND_TYPE_RECORDER;

+

+    if (role & PJ_SOUND_PLAYER) {

+	status = dsound_init_player (dev);

+	if (status != 0)

+	    return status;

+    }

+

+    if (role & PJ_SOUND_RECORDER) {

+	status = dsound_init_recorder (dev);

+	if (status != 0)

+	    return status;

+    }

+

+    return 0;

+}

+

+/*

+ * Close DirectSound device.

+ */

+static pj_status_t dsound_dev_close( pj_snd_dev *dev )

+{

+    PJ_LOG(4,(THIS_FILE, "Closing DirectSound device"));

+

+    if (dev->device) {

+	PJ_Direct_Sound_Device *dsDev = dev->device;

+

+	if (dsDev->playDesc.hThread) {

+	    PJ_LOG(4,(THIS_FILE, "Stopping DirectSound player"));

+	    dsDev->playDesc.dwThreadQuitFlag = 1;

+	    SetEvent(dsDev->playDesc.hEvent);

+	    if (WaitForSingleObject(dsDev->playDesc.hThread, 1000) != WAIT_OBJECT_0) {

+		PJ_LOG(4,(THIS_FILE, "Timed out waiting player thread to quit"));

+		TerminateThread(dsDev->playDesc.hThread, -1);

+		IDirectSoundBuffer_Stop( dsDev->playDesc.lpDsPlayBuffer );

+	    }

+	    

+	    pj_thread_destroy (dsDev->playDesc.thread);

+	}

+

+	if (dsDev->recDesc.hThread) {

+	    PJ_LOG(4,(THIS_FILE, "Stopping DirectSound recorder"));

+	    dsDev->recDesc.dwThreadQuitFlag = 1;

+	    SetEvent(dsDev->recDesc.hEvent);

+	    if (WaitForSingleObject(dsDev->recDesc.hThread, 1000) != WAIT_OBJECT_0) {

+		PJ_LOG(4,(THIS_FILE, "Timed out waiting recorder thread to quit"));

+		TerminateThread(dsDev->recDesc.hThread, -1);

+		IDirectSoundCaptureBuffer_Stop( dsDev->recDesc.lpDsCaptureBuffer );

+	    }

+	    

+	    pj_thread_destroy (dsDev->recDesc.thread);

+	}

+

+	dsound_destroy_dsound_dev( dev->device );

+	dev->op = NULL;

+    }

+

+    PJ_LOG(4,(THIS_FILE, "DirectSound device closed"));

+    return 0;

+}

+

+static BOOL AppReadDataFromBuffer(LPDIRECTSOUNDCAPTUREBUFFER lpDsb, // The buffer.

+				  DWORD dwOffset,		    // Our own write cursor.

+				  LPBYTE lpbSoundData,		    // Start of our data.

+				  DWORD dwSoundBytes)		    // Size of block to copy.

+{ 

+    LPVOID  lpvPtr1; 

+    DWORD dwBytes1; 

+    LPVOID  lpvPtr2; 

+    DWORD dwBytes2; 

+    HRESULT hr; 

+    

+    // Obtain memory address of write block. This will be in two parts

+    // if the block wraps around.

+    

+    hr = IDirectSoundCaptureBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 

+					 &dwBytes1, &lpvPtr2, &dwBytes2, 0); 

+    

+    if SUCCEEDED(hr) { 

+	// Read from pointers. 

+	CopyMemory(lpbSoundData, lpvPtr1, dwBytes1); 

+	if (lpvPtr2 != NULL)

+	    CopyMemory(lpbSoundData+dwBytes1, lpvPtr2, dwBytes2); 

+	

+	// Release the data back to DirectSound. 

+	hr = IDirectSoundCaptureBuffer_Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); 

+	if SUCCEEDED(hr)

+	    return TRUE; 

+    } 

+    

+    // Lock, Unlock, or Restore failed. 

+    return FALSE; 

+}

+

+

+static BOOL AppWriteDataToBuffer(LPDIRECTSOUNDBUFFER lpDsb,  // The buffer.

+				 DWORD dwOffset,	      // Our own write cursor.

+				 LPBYTE lpbSoundData,	      // Start of our data.

+				 DWORD dwSoundBytes)	      // Size of block to copy.

+{ 

+    LPVOID  lpvPtr1; 

+    DWORD dwBytes1; 

+    LPVOID  lpvPtr2; 

+    DWORD dwBytes2; 

+    HRESULT hr; 

+    

+    // Obtain memory address of write block. This will be in two parts

+    // if the block wraps around.

+    

+    hr = IDirectSoundBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 

+				  &dwBytes1, &lpvPtr2, &dwBytes2, 0); 

+    

+    // If the buffer was lost, restore and retry lock. 

+    if (DSERR_BUFFERLOST == hr) { 

+	IDirectSoundBuffer_Restore(lpDsb); 

+	hr = IDirectSoundBuffer_Lock( lpDsb, dwOffset, dwSoundBytes, 

+				      &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); 

+    } 

+    if SUCCEEDED(hr) { 

+	CopyMemory(lpvPtr1, lpbSoundData, dwBytes1); 

+	if (NULL != lpvPtr2) 

+	    CopyMemory(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2); 

+	

+	hr = IDirectSoundBuffer_Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, dwBytes2); 

+	if SUCCEEDED(hr)

+	    return TRUE; 

+    } 

+    

+    return FALSE; 

+}

+

+

+/*

+ * Player thread.

+ */

+static DWORD WINAPI dsound_dev_thread(void *arg)

+{

+    struct Thread_Param *param = arg;

+    pj_snd_dev *dev = param->dev;

+    Direct_Sound_Descriptor *desc = param->desc;

+    unsigned bytes_per_pkt = dev->param.bytes_per_frame *

+			     dev->param.frames_per_packet;

+    unsigned samples_per_pkt = dev->param.samples_per_frame *

+			       dev->param.frames_per_packet;

+    void *buffer = NULL;

+    DWORD size;

+    pj_status_t status;

+    DWORD sample_pos;

+    DWORD byte_pos;

+    DWORD buffer_size = 

+	(PACKET_BUFFER_COUNT * dev->param.bytes_per_frame * 

+	 dev->param.frames_per_packet);

+    HRESULT hr;

+

+    PJ_LOG(4,(THIS_FILE, "DirectSound thread starting"));

+

+    /* Allocate buffer for sound data */

+    buffer = malloc(bytes_per_pkt);

+    if (!buffer) {

+	PJ_LOG(1,(THIS_FILE, "Unable to allocate packet buffer!"));

+	return (DWORD)-1;

+    }

+

+    desc->thread = pj_thread_register ("dsound", desc->thread_desc);

+    if (desc->thread == NULL)

+	return (DWORD)-1;

+

+    /*

+     * Start playing or recording!

+     */

+    if (desc->type == DSOUND_TYPE_PLAYER) {

+	hr = IDirectSoundBuffer_SetCurrentPosition( desc->lpDsPlayBuffer, 0);

+	if (FAILED(hr)) {

+	    PJ_LOG(1,(THIS_FILE, "DirectSound play: SetCurrentPosition() error %d", hr));

+	    goto on_error;

+	}

+

+	hr = IDirectSoundBuffer_Play(desc->lpDsPlayBuffer, 0, 0, DSBPLAY_LOOPING);

+	if (FAILED(hr)) {

+	    PJ_LOG(1,(THIS_FILE, "DirectSound: Play() error %d", hr));

+	    goto on_error;

+	}

+    } else {

+	hr = IDirectSoundCaptureBuffer_Start(desc->lpDsCaptureBuffer, DSCBSTART_LOOPING );

+	if (FAILED(hr)) {

+	    PJ_LOG(1,(THIS_FILE, "DirectSound: Record() error %d", hr));

+	    goto on_error;

+	}

+    }

+

+    /*

+     * Reset initial positions.

+     */

+    byte_pos = 0xFFFFFFFF;

+    sample_pos = 0;

+

+    /*

+     * Wait to get the first notification.

+     */

+    if (WaitForSingleObject(desc->hEvent, 100) != WAIT_OBJECT_0) {

+	PJ_LOG(1,(THIS_FILE, "DirectSound: error getting notification"));

+	goto on_error;

+    }

+

+	

+    /* Get initial byte position. */

+    if (desc->type == DSOUND_TYPE_PLAYER) {

+	hr = IDirectSoundBuffer_GetCurrentPosition( desc->lpDsPlayBuffer, 

+						    NULL, &byte_pos );

+	if (FAILED(hr)) {

+	    PJ_LOG(1,(THIS_FILE, "DirectSound: unable to get "

+				 "position, err %d", hr));

+	    goto on_error;

+	}

+    } else {

+	hr = IDirectSoundCaptureBuffer_GetCurrentPosition( desc->lpDsCaptureBuffer, 

+							   NULL, &byte_pos );

+	if (FAILED(hr)) {

+	    PJ_LOG(1,(THIS_FILE, "DirectSound: unable to get "

+				 "position, err %d", hr));

+	    goto on_error;

+	}

+    }

+

+    /* Signal main thread that we're running. */

+    assert( desc->hStartEvent );

+    SetEvent( desc->hStartEvent );

+

+    /*

+     * Loop while not signalled to quit, wait for event object to be signalled

+     * by DirectSound play buffer, then request for sound data from the 

+     * application and write it to DirectSound buffer.

+     */

+    do {

+	

+	/* Call callback to get sound data */

+	if (desc->type == DSOUND_TYPE_PLAYER) {

+	    size = bytes_per_pkt;

+	    status = (*dev->play_cb)(dev, sample_pos, buffer, &size);

+

+	    /* Quit thread on error. */

+	    if (status != 0)

+		break;

+

+	    /* Write zeroes when we've got nothing from application. */

+	    if (size == 0) {

+		memset(buffer, 0, bytes_per_pkt);

+		size = bytes_per_pkt;

+	    }

+

+	    /* Write to DirectSound buffer. */

+	    AppWriteDataToBuffer( desc->lpDsPlayBuffer, byte_pos,

+				  (LPBYTE)buffer, size);

+

+	} else {

+	    /* Capture from DirectSound buffer. */

+	    size = bytes_per_pkt;

+	    if (AppReadDataFromBuffer( desc->lpDsCaptureBuffer, byte_pos,

+				       (LPBYTE)buffer, size)) {

+

+	    } else {

+		memset(buffer, 0, size);

+	    }

+

+	    /* Call callback */

+	    status = (*dev->rec_cb)(dev, sample_pos, buffer, size);

+

+	    /* Quit thread on error. */

+	    if (status != 0)

+		break;

+	}

+

+	/* Increment position. */

+	byte_pos += size;

+	if (byte_pos >= buffer_size)

+	    byte_pos -= buffer_size;

+	sample_pos += samples_per_pkt;

+

+	while (WaitForSingleObject(desc->hEvent, 500) != WAIT_OBJECT_0 &&

+	       (!desc->dwThreadQuitFlag)) 

+	{

+	    Sleep(1);

+	}

+    } while (!desc->dwThreadQuitFlag);

+

+

+    PJ_LOG(4,(THIS_FILE, "DirectSound: stopping.."));

+

+    free(buffer);

+    if (desc->type == DSOUND_TYPE_PLAYER) {

+	IDirectSoundBuffer_Stop( desc->lpDsPlayBuffer );

+    } else {

+	IDirectSoundCaptureBuffer_Stop( desc->lpDsCaptureBuffer );

+    }

+    return 0;

+

+on_error:

+    PJ_LOG(4,(THIS_FILE, "DirectSound play stopping"));

+

+    if (buffer) 

+	free(buffer);

+    if (desc->type == DSOUND_TYPE_PLAYER) {

+	IDirectSoundBuffer_Stop( desc->lpDsPlayBuffer );

+    } else {

+	IDirectSoundCaptureBuffer_Stop( desc->lpDsCaptureBuffer );

+    }

+    desc->dwThreadQuitFlag = 1;

+

+    /* Signal main thread that we failed to initialize */

+    assert( desc->hStartEvent );

+    SetEvent( desc->hStartEvent );

+    return -1;

+}

+

+

+/*

+ * Generic starter for play/record.

+ */

+static pj_status_t dsound_dev_play_record( pj_snd_dev *dev,

+					   Direct_Sound_Descriptor *desc )

+{

+    DWORD threadId;

+    int op_type = desc->type;

+    const char *op_name = (op_type == DSOUND_TYPE_PLAYER) ? "play" : "record";

+    struct Thread_Param param;

+

+    PJ_LOG(4,(THIS_FILE, "DirectSound %s()", op_name));

+

+    /*

+     * Create event for the thread to signal us that it is starting or

+     * quitting during startup.

+     */

+    desc->hStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

+    if (desc->hStartEvent == NULL) {

+	PJ_LOG(1,(THIS_FILE, "DirectSound %s: unable to create event", op_name));

+	return -1;

+    }

+

+    param.dev = dev;

+    param.desc = desc;

+

+    /*

+     * Create thread to handle feeding up data to player/recorder.

+     */

+    desc->hThread = NULL;

+    desc->dwThreadQuitFlag = 0;

+    desc->hThread = CreateThread( NULL, 0, &dsound_dev_thread, &param, 

+					    CREATE_SUSPENDED, &threadId);

+    if (!desc->hThread) {

+	PJ_LOG(1,(THIS_FILE, "DirectSound %s(): unable to create thread", op_name));

+	return -1;

+    }

+

+    SetThreadPriority( desc->hThread, THREAD_PRIORITY_HIGHEST);

+

+    /*

+     * Resume thread.

+     */

+    if (ResumeThread(desc->hThread) == (DWORD)-1) {

+	PJ_LOG(1,(THIS_FILE, "DirectSound %s(): unable to resume thread", op_name));

+	goto on_error;

+    }

+

+    /*

+     * Wait until we've got signal from the thread that it has successfully

+     * started, or when it is quitting.

+     */

+    WaitForSingleObject( desc->hStartEvent, INFINITE);

+

+    /* We can destroy the event now. */

+    CloseHandle( desc->hStartEvent );

+    desc->hStartEvent = NULL;

+

+    /* Examine thread status. */

+    if (desc->dwThreadQuitFlag != 0) {

+	/* Thread failed to initialize */

+	WaitForSingleObject(desc->hThread, INFINITE);

+	CloseHandle(desc->hThread);

+	desc->hThread = NULL;

+	return -1;

+    }

+

+    return 0;

+

+on_error:

+    TerminateThread(desc->hThread, -1);

+    CloseHandle(desc->hThread);

+    desc->hThread = NULL;

+    return -1;

+}

+

+/*

+ * Start playing.

+ */

+static pj_status_t dsound_dev_play( pj_snd_dev *dev )

+{

+    PJ_Direct_Sound_Device *dsDev = dev->device;

+

+    assert(dsDev);

+    if (!dsDev) {

+	assert(0);

+	return -1;

+    }

+

+    return dsound_dev_play_record( dev, &dsDev->playDesc );

+}

+

+/*

+ * Start recording.

+ */

+static pj_status_t dsound_dev_record( pj_snd_dev *dev )

+{

+    PJ_Direct_Sound_Device *dsDev = dev->device;

+

+    assert(dsDev);

+    if (!dsDev) {

+	assert(0);

+	return -1;

+    }

+

+    return dsound_dev_play_record( dev, &dsDev->recDesc );

+}

+

+#ifdef _MSC_VER

+# pragma warning(pop)

+# pragma warning(disable: 4514)	// unreferenced inline function has been removed

+#endif

diff --git a/pjmedia/src/pjmedia/g711.c b/pjmedia/src/pjmedia/g711.c
index e8ff968..e953170 100644
--- a/pjmedia/src/pjmedia/g711.c
+++ b/pjmedia/src/pjmedia/g711.c
@@ -1,602 +1,623 @@
-/* $Id$
- *
- */
-/* This file contains file from Sun Microsystems, Inc, with the complete 
- * copyright notice in the second half of this file.
- */
-#include <pjmedia/codec.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <string.h>	/* memset */
-
-#define G711_BPS	64000
-#define G711_CODEC_CNT	0	/* number of codec to preallocate in memory */
-
-/* These are the only public functions exported to applications */
-PJ_DECL(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *pool);
-PJ_DECL(pj_status_t) g711_deinit_factory (pj_codec_factory *factory);
-
-/* Algorithm prototypes. */
-static unsigned char linear2alaw(int		pcm_val);   /* 2's complement (16-bit range) */
-static int	     alaw2linear(unsigned char	a_val);
-static unsigned char linear2ulaw(int		pcm_val);
-static int	     ulaw2linear(unsigned char	u_val);
-
-/* Prototypes for G711 factory */
-static pj_status_t  g711_match_id( pj_codec_factory *factory, const pj_codec_id *id );
-static pj_status_t  g711_default_attr( pj_codec_factory *factory, const pj_codec_id *id, pj_codec_attr *attr );
-static unsigned	    g711_enum_codecs (pj_codec_factory *factory, unsigned count, pj_codec_id codecs[]);
-static pj_codec*    g711_alloc_codec( pj_codec_factory *factory, const pj_codec_id *id);
-static void	    g711_dealloc_codec( pj_codec_factory *factory, pj_codec *codec );
-
-/* Prototypes for G711 implementation. */
-static pj_status_t  g711_codec_default_attr (pj_codec *codec, pj_codec_attr *attr);
-static pj_status_t  g711_init( pj_codec *codec, pj_pool_t *pool );
-static pj_status_t  g711_open( pj_codec *codec, pj_codec_attr *attr );
-static pj_status_t  g711_close( pj_codec *codec );
-static pj_status_t  g711_encode( pj_codec *codec, const struct pj_audio_frame *input,
-				 unsigned output_buf_len, struct pj_audio_frame *output);
-static pj_status_t  g711_decode( pj_codec *codec, const struct pj_audio_frame *input,
-				 unsigned output_buf_len, struct pj_audio_frame *output);
-
-/* Definition for G711 codec operations. */
-static pj_codec_op g711_op = 
-{
-    &g711_codec_default_attr ,
-    &g711_init,
-    &g711_open,
-    &g711_close,
-    &g711_encode,
-    &g711_decode
-};
-
-/* Definition for G711 codec factory operations. */
-static pj_codec_factory_op g711_factory_op =
-{
-    &g711_match_id,
-    &g711_default_attr,
-    &g711_enum_codecs,
-    &g711_alloc_codec,
-    &g711_dealloc_codec
-};
-
-/* G711 factory private data */
-struct g711_factory_private
-{
-    pj_pool_t  *pool;
-    pj_codec	codec_list;
-};
-
-/* G711 codec private data. */
-struct g711_private
-{
-    unsigned pt;
-};
-
-
-PJ_DEF(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *pool)
-{
-    struct g711_factory_private *priv;
-    //enum { CODEC_MEM_SIZE = sizeof(pj_codec) + sizeof(struct g711_private) + 4 };
-
-    /* Create pool. */
-    /*
-    pool = pj_pool_pool_create_pool(pp, "g711ftry", 
-					G711_CODEC_CNT*CODEC_MEM_SIZE + 
-					sizeof(struct g711_factory_private),
-				        CODEC_MEM_SIZE, NULL);
-    if (!pool)
-	return -1;
-    */
-
-    priv = pj_pool_alloc(pool, sizeof(struct g711_factory_private));
-    if (!priv)
-	return -1;
-
-    factory->factory_data = priv;
-    factory->op = &g711_factory_op;
-
-    priv->pool = pool;
-    pj_list_init(&priv->codec_list);
-    return 0;
-}
-
-PJ_DEF(pj_status_t) g711_deinit_factory (pj_codec_factory *factory)
-{
-    struct g711_factory_private *priv = factory->factory_data;
-
-    /* Invalidate member to help detect errors */
-    priv->pool = NULL;
-    priv->codec_list.next = priv->codec_list.prev = NULL;
-    return 0;
-}
-
-static pj_status_t g711_match_id( pj_codec_factory *factory, const pj_codec_id *id )
-{
-    PJ_UNUSED_ARG(factory)
-
-    /* It's sufficient to check payload type only. */
-    return (id->pt==PJ_RTP_PT_PCMU || id->pt==PJ_RTP_PT_PCMA) ? 0 : -1;
-}
-
-static pj_status_t g711_default_attr (pj_codec_factory *factory, 
-				      const pj_codec_id *id, 
-				      pj_codec_attr *attr )
-{
-    PJ_UNUSED_ARG(factory)
-
-    memset(attr, 0, sizeof(pj_codec_attr));
-    attr->sample_rate = 8000;
-    attr->avg_bps = G711_BPS;
-    attr->pcm_bits_per_sample = 16;
-    attr->ptime = 20;
-    attr->pt = id->pt;
-
-    /* Default all flag bits disabled. */
-
-    return PJ_SUCCESS;
-}
-
-static unsigned	g711_enum_codecs (pj_codec_factory *factory, 
-				  unsigned count, pj_codec_id codecs[])
-{
-    PJ_UNUSED_ARG(factory)
-
-    if (count > 0) {
-	codecs[0].type = PJ_MEDIA_TYPE_AUDIO;
-	codecs[0].pt = PJ_RTP_PT_PCMU;
-	codecs[0].encoding_name = pj_str("PCMU");
-	codecs[0].sample_rate = 8000;
-    }
-    if (count > 1) {
-	codecs[1].type = PJ_MEDIA_TYPE_AUDIO;
-	codecs[1].pt = PJ_RTP_PT_PCMA;
-	codecs[1].encoding_name = pj_str("PCMA");
-	codecs[1].sample_rate = 8000;
-    }
-
-    return 2;
-}
-
-static pj_codec *g711_alloc_codec( pj_codec_factory *factory, const pj_codec_id *id)
-{
-    struct g711_factory_private *priv = factory->factory_data;
-    pj_codec *codec = NULL;
-
-    /* Allocate new codec if no more is available */
-    if (pj_list_empty(&priv->codec_list)) {
-	struct g711_private *codec_priv;
-
-	codec = pj_pool_alloc(priv->pool, sizeof(pj_codec));
-	codec_priv = pj_pool_alloc(priv->pool, sizeof(struct g711_private));
-	if (!codec || !codec_priv)
-	    return NULL;
-
-	codec_priv->pt = id->pt;
-
-	codec->factory = factory;
-	codec->op = &g711_op;
-	codec->codec_data = codec_priv;
-    } else {
-	codec = priv->codec_list.next;
-	pj_list_erase(codec);
-    }
-
-    /* Zero the list, for error detection in g711_dealloc_codec */
-    codec->next = codec->prev = NULL;
-
-    return codec;
-}
-
-static void g711_dealloc_codec( pj_codec_factory *factory, pj_codec *codec )
-{
-    struct g711_factory_private *priv = factory->factory_data;
-
-    /* Check that this node has not been deallocated before */
-    pj_assert (codec->next==NULL && codec->prev==NULL);
-    if (codec->next!=NULL || codec->prev!=NULL) {
-	return;
-    }
-
-    /* Insert at the back of the list */
-    pj_list_insert_before(&priv->codec_list, codec);
-}
-
-static pj_status_t g711_codec_default_attr  (pj_codec *codec, pj_codec_attr *attr)
-{
-    struct g711_private *priv = codec->codec_data;
-    pj_codec_id id;
-
-    id.pt = priv->pt;
-    return g711_default_attr (NULL, &id, attr);
-}
-
-static pj_status_t g711_init( pj_codec *codec, pj_pool_t *pool )
-{
-    /* There's nothing to do here really */
-    PJ_UNUSED_ARG(codec)
-    PJ_UNUSED_ARG(pool)
-
-    return PJ_SUCCESS;
-}
-
-static pj_status_t g711_open( pj_codec *codec, pj_codec_attr *attr )
-{
-    struct g711_private *priv = codec->codec_data;
-    priv->pt = attr->pt;
-    return PJ_SUCCESS;
-}
-
-static pj_status_t g711_close( pj_codec *codec )
-{
-    PJ_UNUSED_ARG(codec);
-    /* Nothing to do */
-    return PJ_SUCCESS;
-}
-
-static pj_status_t  g711_encode( pj_codec *codec, const struct pj_audio_frame *input,
-				 unsigned output_buf_len, struct pj_audio_frame *output)
-{
-    pj_int16_t *samples = (pj_int16_t*) input->buf;
-    struct g711_private *priv = codec->codec_data;
-
-    /* Check output buffer length */
-    if (output_buf_len < input->size / 2)
-	return -1;
-
-    /* Encode */
-    if (priv->pt == PJ_RTP_PT_PCMA) {
-	unsigned i;
-	pj_uint8_t *dst = output->buf;
-
-	for (i=0; i!=input->size/2; ++i, ++dst) {
-	    *dst = linear2alaw(samples[i]);
-	}
-    } else if (priv->pt == PJ_RTP_PT_PCMU) {
-	unsigned i;
-	pj_uint8_t *dst = output->buf;
-
-	for (i=0; i!=input->size/2; ++i, ++dst) {
-	    *dst = linear2ulaw(samples[i]);
-	}
-
-    } else {
-	return -1;
-    }
-
-    output->type = PJ_AUDIO_FRAME_AUDIO;
-    output->size = input->size / 2;
-
-    return 0;
-}
-
-static pj_status_t  g711_decode( pj_codec *codec, const struct pj_audio_frame *input,
-				 unsigned output_buf_len, struct pj_audio_frame *output)
-{
-    struct g711_private *priv = codec->codec_data;
-
-    /* Check output buffer length */
-    if (output_buf_len < input->size * 2)
-	return -1;
-
-    /* Decode */
-    if (priv->pt == PJ_RTP_PT_PCMA) {
-	unsigned i;
-	pj_uint8_t *src = input->buf;
-	pj_uint16_t *dst = output->buf;
-
-	for (i=0; i!=input->size; ++i) {
-	    *dst++ = (pj_uint16_t) alaw2linear(*src++);
-	}
-    } else if (priv->pt == PJ_RTP_PT_PCMU) {
-	unsigned i;
-	pj_uint8_t *src = input->buf;
-	pj_uint16_t *dst = output->buf;
-
-	for (i=0; i!=input->size; ++i) {
-	    *dst++ = (pj_uint16_t) ulaw2linear(*src++);
-	}
-
-    } else {
-	return -1;
-    }
-
-    output->type = PJ_AUDIO_FRAME_AUDIO;
-    output->size = input->size * 2;
-
-    return 0;
-}
-
-
-/*
- * This source code is a product of Sun Microsystems, Inc. and is provided
- * for unrestricted use.  Users may copy or modify this source code without
- * charge.
- *
- * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
- * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
- *
- * Sun source code is provided with no support and without any obligation on
- * the part of Sun Microsystems, Inc. to assist in its use, correction,
- * modification or enhancement.
- *
- * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
- * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
- * OR ANY PART THEREOF.
- *
- * In no event will Sun Microsystems, Inc. be liable for any lost revenue
- * or profits or other special, indirect and consequential damages, even if
- * Sun has been advised of the possibility of such damages.
- *
- * Sun Microsystems, Inc.
- * 2550 Garcia Avenue
- * Mountain View, California  94043
- */
-
-
-
-#ifdef _MSC_VER
-#  pragma warning ( disable: 4244 ) /* Conversion from int to char etc */
-#endif
-
-/*
- * g711.c
- *
- * u-law, A-law and linear PCM conversions.
- */
-#define	SIGN_BIT	(0x80)		/* Sign bit for a A-law byte. */
-#define	QUANT_MASK	(0xf)		/* Quantization field mask. */
-#define	NSEGS		(8)		/* Number of A-law segments. */
-#define	SEG_SHIFT	(4)		/* Left shift for segment number. */
-#define	SEG_MASK	(0x70)		/* Segment field mask. */
-
-static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
-			    0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};
-
-/* copy from CCITT G.711 specifications */
-static unsigned char _u2a[128] = {		/* u- to A-law conversions */
-	1,	1,	2,	2,	3,	3,	4,	4,
-	5,	5,	6,	6,	7,	7,	8,	8,
-	9,	10,	11,	12,	13,	14,	15,	16,
-	17,	18,	19,	20,	21,	22,	23,	24,
-	25,	27,	29,	31,	33,	34,	35,	36,
-	37,	38,	39,	40,	41,	42,	43,	44,
-	46,	48,	49,	50,	51,	52,	53,	54,
-	55,	56,	57,	58,	59,	60,	61,	62,
-	64,	65,	66,	67,	68,	69,	70,	71,
-	72,	73,	74,	75,	76,	77,	78,	79,
-	81,	82,	83,	84,	85,	86,	87,	88,
-	89,	90,	91,	92,	93,	94,	95,	96,
-	97,	98,	99,	100,	101,	102,	103,	104,
-	105,	106,	107,	108,	109,	110,	111,	112,
-	113,	114,	115,	116,	117,	118,	119,	120,
-	121,	122,	123,	124,	125,	126,	127,	128};
-
-static unsigned char _a2u[128] = {		/* A- to u-law conversions */
-	1,	3,	5,	7,	9,	11,	13,	15,
-	16,	17,	18,	19,	20,	21,	22,	23,
-	24,	25,	26,	27,	28,	29,	30,	31,
-	32,	32,	33,	33,	34,	34,	35,	35,
-	36,	37,	38,	39,	40,	41,	42,	43,
-	44,	45,	46,	47,	48,	48,	49,	49,
-	50,	51,	52,	53,	54,	55,	56,	57,
-	58,	59,	60,	61,	62,	63,	64,	64,
-	65,	66,	67,	68,	69,	70,	71,	72,
-	73,	74,	75,	76,	77,	78,	79,	79,
-	80,	81,	82,	83,	84,	85,	86,	87,
-	88,	89,	90,	91,	92,	93,	94,	95,
-	96,	97,	98,	99,	100,	101,	102,	103,
-	104,	105,	106,	107,	108,	109,	110,	111,
-	112,	113,	114,	115,	116,	117,	118,	119,
-	120,	121,	122,	123,	124,	125,	126,	127};
-
-static int
-search(
-	int		val,
-	short		*table,
-	int		size)
-{
-	int		i;
-
-	for (i = 0; i < size; i++) {
-		if (val <= *table++)
-			return (i);
-	}
-	return (size);
-}
-
-/*
- * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
- *
- * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
- *
- *		Linear Input Code	Compressed Code
- *	------------------------	---------------
- *	0000000wxyza			000wxyz
- *	0000001wxyza			001wxyz
- *	000001wxyzab			010wxyz
- *	00001wxyzabc			011wxyz
- *	0001wxyzabcd			100wxyz
- *	001wxyzabcde			101wxyz
- *	01wxyzabcdef			110wxyz
- *	1wxyzabcdefg			111wxyz
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-static unsigned char
-linear2alaw(
-	int		pcm_val)	/* 2's complement (16-bit range) */
-{
-	int		mask;
-	int		seg;
-	unsigned char	aval;
-
-	if (pcm_val >= 0) {
-		mask = 0xD5;		/* sign (7th) bit = 1 */
-	} else {
-		mask = 0x55;		/* sign bit = 0 */
-		pcm_val = -pcm_val - 8;
-	}
-
-	/* Convert the scaled magnitude to segment number. */
-	seg = search(pcm_val, seg_end, 8);
-
-	/* Combine the sign, segment, and quantization bits. */
-
-	if (seg >= 8)		/* out of range, return maximum value. */
-		return (0x7F ^ mask);
-	else {
-		aval = seg << SEG_SHIFT;
-		if (seg < 2)
-			aval |= (pcm_val >> 4) & QUANT_MASK;
-		else
-			aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
-		return (aval ^ mask);
-	}
-}
-
-/*
- * alaw2linear() - Convert an A-law value to 16-bit linear PCM
- *
- */
-static int
-alaw2linear(
-	unsigned char	a_val)
-{
-	int		t;
-	int		seg;
-
-	a_val ^= 0x55;
-
-	t = (a_val & QUANT_MASK) << 4;
-	seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
-	switch (seg) {
-	case 0:
-		t += 8;
-		break;
-	case 1:
-		t += 0x108;
-		break;
-	default:
-		t += 0x108;
-		t <<= seg - 1;
-	}
-	return ((a_val & SIGN_BIT) ? t : -t);
-}
-
-#define	BIAS		(0x84)		/* Bias for linear code. */
-
-/*
- * linear2ulaw() - Convert a linear PCM value to u-law
- *
- * In order to simplify the encoding process, the original linear magnitude
- * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
- * (33 - 8191). The result can be seen in the following encoding table:
- *
- *	Biased Linear Input Code	Compressed Code
- *	------------------------	---------------
- *	00000001wxyza			000wxyz
- *	0000001wxyzab			001wxyz
- *	000001wxyzabc			010wxyz
- *	00001wxyzabcd			011wxyz
- *	0001wxyzabcde			100wxyz
- *	001wxyzabcdef			101wxyz
- *	01wxyzabcdefg			110wxyz
- *	1wxyzabcdefgh			111wxyz
- *
- * Each biased linear code has a leading 1 which identifies the segment
- * number. The value of the segment number is equal to 7 minus the number
- * of leading 0's. The quantization interval is directly available as the
- * four bits wxyz.  * The trailing bits (a - h) are ignored.
- *
- * Ordinarily the complement of the resulting code word is used for
- * transmission, and so the code word is complemented before it is returned.
- *
- * For further information see John C. Bellamy's Digital Telephony, 1982,
- * John Wiley & Sons, pps 98-111 and 472-476.
- */
-static unsigned char
-linear2ulaw(
-	int		pcm_val)	/* 2's complement (16-bit range) */
-{
-	int		mask;
-	int		seg;
-	unsigned char	uval;
-
-	/* Get the sign and the magnitude of the value. */
-	if (pcm_val < 0) {
-		pcm_val = BIAS - pcm_val;
-		mask = 0x7F;
-	} else {
-		pcm_val += BIAS;
-		mask = 0xFF;
-	}
-
-	/* Convert the scaled magnitude to segment number. */
-	seg = search(pcm_val, seg_end, 8);
-
-	/*
-	 * Combine the sign, segment, quantization bits;
-	 * and complement the code word.
-	 */
-	if (seg >= 8)		/* out of range, return maximum value. */
-		return (0x7F ^ mask);
-	else {
-		uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
-		return (uval ^ mask);
-	}
-
-}
-
-/*
- * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
- *
- * First, a biased linear code is derived from the code word. An unbiased
- * output can then be obtained by subtracting 33 from the biased code.
- *
- * Note that this function expects to be passed the complement of the
- * original code word. This is in keeping with ISDN conventions.
- */
-static int
-ulaw2linear(
-	unsigned char	u_val)
-{
-	int		t;
-
-	/* Complement to obtain normal u-law value. */
-	u_val = ~u_val;
-
-	/*
-	 * Extract and bias the quantization bits. Then
-	 * shift up by the segment number and subtract out the bias.
-	 */
-	t = ((u_val & QUANT_MASK) << 3) + BIAS;
-	t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
-
-	return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
-}
-
-/* A-law to u-law conversion */
-unsigned char
-alaw2ulaw(
-	unsigned char	aval)
-{
-	aval &= 0xff;
-	return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
-	    (0x7F ^ _a2u[aval ^ 0x55]));
-}
-
-/* u-law to A-law conversion */
-unsigned char
-ulaw2alaw(
-	unsigned char	uval)
-{
-	uval &= 0xff;
-	return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
-	    (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
-}
-
-
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+/* This file contains file from Sun Microsystems, Inc, with the complete 

+ * copyright notice in the second half of this file.

+ */

+#include <pjmedia/codec.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <string.h>	/* memset */

+

+#define G711_BPS	64000

+#define G711_CODEC_CNT	0	/* number of codec to preallocate in memory */

+

+/* These are the only public functions exported to applications */

+PJ_DECL(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *pool);

+PJ_DECL(pj_status_t) g711_deinit_factory (pj_codec_factory *factory);

+

+/* Algorithm prototypes. */

+static unsigned char linear2alaw(int		pcm_val);   /* 2's complement (16-bit range) */

+static int	     alaw2linear(unsigned char	a_val);

+static unsigned char linear2ulaw(int		pcm_val);

+static int	     ulaw2linear(unsigned char	u_val);

+

+/* Prototypes for G711 factory */

+static pj_status_t  g711_match_id( pj_codec_factory *factory, const pj_codec_id *id );

+static pj_status_t  g711_default_attr( pj_codec_factory *factory, const pj_codec_id *id, pj_codec_attr *attr );

+static unsigned	    g711_enum_codecs (pj_codec_factory *factory, unsigned count, pj_codec_id codecs[]);

+static pj_codec*    g711_alloc_codec( pj_codec_factory *factory, const pj_codec_id *id);

+static void	    g711_dealloc_codec( pj_codec_factory *factory, pj_codec *codec );

+

+/* Prototypes for G711 implementation. */

+static pj_status_t  g711_codec_default_attr (pj_codec *codec, pj_codec_attr *attr);

+static pj_status_t  g711_init( pj_codec *codec, pj_pool_t *pool );

+static pj_status_t  g711_open( pj_codec *codec, pj_codec_attr *attr );

+static pj_status_t  g711_close( pj_codec *codec );

+static pj_status_t  g711_encode( pj_codec *codec, const struct pj_audio_frame *input,

+				 unsigned output_buf_len, struct pj_audio_frame *output);

+static pj_status_t  g711_decode( pj_codec *codec, const struct pj_audio_frame *input,

+				 unsigned output_buf_len, struct pj_audio_frame *output);

+

+/* Definition for G711 codec operations. */

+static pj_codec_op g711_op = 

+{

+    &g711_codec_default_attr ,

+    &g711_init,

+    &g711_open,

+    &g711_close,

+    &g711_encode,

+    &g711_decode

+};

+

+/* Definition for G711 codec factory operations. */

+static pj_codec_factory_op g711_factory_op =

+{

+    &g711_match_id,

+    &g711_default_attr,

+    &g711_enum_codecs,

+    &g711_alloc_codec,

+    &g711_dealloc_codec

+};

+

+/* G711 factory private data */

+struct g711_factory_private

+{

+    pj_pool_t  *pool;

+    pj_codec	codec_list;

+};

+

+/* G711 codec private data. */

+struct g711_private

+{

+    unsigned pt;

+};

+

+

+PJ_DEF(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *pool)

+{

+    struct g711_factory_private *priv;

+    //enum { CODEC_MEM_SIZE = sizeof(pj_codec) + sizeof(struct g711_private) + 4 };

+

+    /* Create pool. */

+    /*

+    pool = pj_pool_pool_create_pool(pp, "g711ftry", 

+					G711_CODEC_CNT*CODEC_MEM_SIZE + 

+					sizeof(struct g711_factory_private),

+				        CODEC_MEM_SIZE, NULL);

+    if (!pool)

+	return -1;

+    */

+

+    priv = pj_pool_alloc(pool, sizeof(struct g711_factory_private));

+    if (!priv)

+	return -1;

+

+    factory->factory_data = priv;

+    factory->op = &g711_factory_op;

+

+    priv->pool = pool;

+    pj_list_init(&priv->codec_list);

+    return 0;

+}

+

+PJ_DEF(pj_status_t) g711_deinit_factory (pj_codec_factory *factory)

+{

+    struct g711_factory_private *priv = factory->factory_data;

+

+    /* Invalidate member to help detect errors */

+    priv->pool = NULL;

+    priv->codec_list.next = priv->codec_list.prev = NULL;

+    return 0;

+}

+

+static pj_status_t g711_match_id( pj_codec_factory *factory, const pj_codec_id *id )

+{

+    PJ_UNUSED_ARG(factory)

+

+    /* It's sufficient to check payload type only. */

+    return (id->pt==PJ_RTP_PT_PCMU || id->pt==PJ_RTP_PT_PCMA) ? 0 : -1;

+}

+

+static pj_status_t g711_default_attr (pj_codec_factory *factory, 

+				      const pj_codec_id *id, 

+				      pj_codec_attr *attr )

+{

+    PJ_UNUSED_ARG(factory)

+

+    memset(attr, 0, sizeof(pj_codec_attr));

+    attr->sample_rate = 8000;

+    attr->avg_bps = G711_BPS;

+    attr->pcm_bits_per_sample = 16;

+    attr->ptime = 20;

+    attr->pt = id->pt;

+

+    /* Default all flag bits disabled. */

+

+    return PJ_SUCCESS;

+}

+

+static unsigned	g711_enum_codecs (pj_codec_factory *factory, 

+				  unsigned count, pj_codec_id codecs[])

+{

+    PJ_UNUSED_ARG(factory)

+

+    if (count > 0) {

+	codecs[0].type = PJ_MEDIA_TYPE_AUDIO;

+	codecs[0].pt = PJ_RTP_PT_PCMU;

+	codecs[0].encoding_name = pj_str("PCMU");

+	codecs[0].sample_rate = 8000;

+    }

+    if (count > 1) {

+	codecs[1].type = PJ_MEDIA_TYPE_AUDIO;

+	codecs[1].pt = PJ_RTP_PT_PCMA;

+	codecs[1].encoding_name = pj_str("PCMA");

+	codecs[1].sample_rate = 8000;

+    }

+

+    return 2;

+}

+

+static pj_codec *g711_alloc_codec( pj_codec_factory *factory, const pj_codec_id *id)

+{

+    struct g711_factory_private *priv = factory->factory_data;

+    pj_codec *codec = NULL;

+

+    /* Allocate new codec if no more is available */

+    if (pj_list_empty(&priv->codec_list)) {

+	struct g711_private *codec_priv;

+

+	codec = pj_pool_alloc(priv->pool, sizeof(pj_codec));

+	codec_priv = pj_pool_alloc(priv->pool, sizeof(struct g711_private));

+	if (!codec || !codec_priv)

+	    return NULL;

+

+	codec_priv->pt = id->pt;

+

+	codec->factory = factory;

+	codec->op = &g711_op;

+	codec->codec_data = codec_priv;

+    } else {

+	codec = priv->codec_list.next;

+	pj_list_erase(codec);

+    }

+

+    /* Zero the list, for error detection in g711_dealloc_codec */

+    codec->next = codec->prev = NULL;

+

+    return codec;

+}

+

+static void g711_dealloc_codec( pj_codec_factory *factory, pj_codec *codec )

+{

+    struct g711_factory_private *priv = factory->factory_data;

+

+    /* Check that this node has not been deallocated before */

+    pj_assert (codec->next==NULL && codec->prev==NULL);

+    if (codec->next!=NULL || codec->prev!=NULL) {

+	return;

+    }

+

+    /* Insert at the back of the list */

+    pj_list_insert_before(&priv->codec_list, codec);

+}

+

+static pj_status_t g711_codec_default_attr  (pj_codec *codec, pj_codec_attr *attr)

+{

+    struct g711_private *priv = codec->codec_data;

+    pj_codec_id id;

+

+    id.pt = priv->pt;

+    return g711_default_attr (NULL, &id, attr);

+}

+

+static pj_status_t g711_init( pj_codec *codec, pj_pool_t *pool )

+{

+    /* There's nothing to do here really */

+    PJ_UNUSED_ARG(codec)

+    PJ_UNUSED_ARG(pool)

+

+    return PJ_SUCCESS;

+}

+

+static pj_status_t g711_open( pj_codec *codec, pj_codec_attr *attr )

+{

+    struct g711_private *priv = codec->codec_data;

+    priv->pt = attr->pt;

+    return PJ_SUCCESS;

+}

+

+static pj_status_t g711_close( pj_codec *codec )

+{

+    PJ_UNUSED_ARG(codec);

+    /* Nothing to do */

+    return PJ_SUCCESS;

+}

+

+static pj_status_t  g711_encode( pj_codec *codec, const struct pj_audio_frame *input,

+				 unsigned output_buf_len, struct pj_audio_frame *output)

+{

+    pj_int16_t *samples = (pj_int16_t*) input->buf;

+    struct g711_private *priv = codec->codec_data;

+

+    /* Check output buffer length */

+    if (output_buf_len < input->size / 2)

+	return -1;

+

+    /* Encode */

+    if (priv->pt == PJ_RTP_PT_PCMA) {

+	unsigned i;

+	pj_uint8_t *dst = output->buf;

+

+	for (i=0; i!=input->size/2; ++i, ++dst) {

+	    *dst = linear2alaw(samples[i]);

+	}

+    } else if (priv->pt == PJ_RTP_PT_PCMU) {

+	unsigned i;

+	pj_uint8_t *dst = output->buf;

+

+	for (i=0; i!=input->size/2; ++i, ++dst) {

+	    *dst = linear2ulaw(samples[i]);

+	}

+

+    } else {

+	return -1;

+    }

+

+    output->type = PJ_AUDIO_FRAME_AUDIO;

+    output->size = input->size / 2;

+

+    return 0;

+}

+

+static pj_status_t  g711_decode( pj_codec *codec, const struct pj_audio_frame *input,

+				 unsigned output_buf_len, struct pj_audio_frame *output)

+{

+    struct g711_private *priv = codec->codec_data;

+

+    /* Check output buffer length */

+    if (output_buf_len < input->size * 2)

+	return -1;

+

+    /* Decode */

+    if (priv->pt == PJ_RTP_PT_PCMA) {

+	unsigned i;

+	pj_uint8_t *src = input->buf;

+	pj_uint16_t *dst = output->buf;

+

+	for (i=0; i!=input->size; ++i) {

+	    *dst++ = (pj_uint16_t) alaw2linear(*src++);

+	}

+    } else if (priv->pt == PJ_RTP_PT_PCMU) {

+	unsigned i;

+	pj_uint8_t *src = input->buf;

+	pj_uint16_t *dst = output->buf;

+

+	for (i=0; i!=input->size; ++i) {

+	    *dst++ = (pj_uint16_t) ulaw2linear(*src++);

+	}

+

+    } else {

+	return -1;

+    }

+

+    output->type = PJ_AUDIO_FRAME_AUDIO;

+    output->size = input->size * 2;

+

+    return 0;

+}

+

+

+/*

+ * This source code is a product of Sun Microsystems, Inc. and is provided

+ * for unrestricted use.  Users may copy or modify this source code without

+ * charge.

+ *

+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING

+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR

+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.

+ *

+ * Sun source code is provided with no support and without any obligation on

+ * the part of Sun Microsystems, Inc. to assist in its use, correction,

+ * modification or enhancement.

+ *

+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE

+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE

+ * OR ANY PART THEREOF.

+ *

+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue

+ * or profits or other special, indirect and consequential damages, even if

+ * Sun has been advised of the possibility of such damages.

+ *

+ * Sun Microsystems, Inc.

+ * 2550 Garcia Avenue

+ * Mountain View, California  94043

+ */

+

+

+

+#ifdef _MSC_VER

+#  pragma warning ( disable: 4244 ) /* Conversion from int to char etc */

+#endif

+

+/*

+ * g711.c

+ *

+ * u-law, A-law and linear PCM conversions.

+ */

+#define	SIGN_BIT	(0x80)		/* Sign bit for a A-law byte. */

+#define	QUANT_MASK	(0xf)		/* Quantization field mask. */

+#define	NSEGS		(8)		/* Number of A-law segments. */

+#define	SEG_SHIFT	(4)		/* Left shift for segment number. */

+#define	SEG_MASK	(0x70)		/* Segment field mask. */

+

+static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,

+			    0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};

+

+/* copy from CCITT G.711 specifications */

+static unsigned char _u2a[128] = {		/* u- to A-law conversions */

+	1,	1,	2,	2,	3,	3,	4,	4,

+	5,	5,	6,	6,	7,	7,	8,	8,

+	9,	10,	11,	12,	13,	14,	15,	16,

+	17,	18,	19,	20,	21,	22,	23,	24,

+	25,	27,	29,	31,	33,	34,	35,	36,

+	37,	38,	39,	40,	41,	42,	43,	44,

+	46,	48,	49,	50,	51,	52,	53,	54,

+	55,	56,	57,	58,	59,	60,	61,	62,

+	64,	65,	66,	67,	68,	69,	70,	71,

+	72,	73,	74,	75,	76,	77,	78,	79,

+	81,	82,	83,	84,	85,	86,	87,	88,

+	89,	90,	91,	92,	93,	94,	95,	96,

+	97,	98,	99,	100,	101,	102,	103,	104,

+	105,	106,	107,	108,	109,	110,	111,	112,

+	113,	114,	115,	116,	117,	118,	119,	120,

+	121,	122,	123,	124,	125,	126,	127,	128};

+

+static unsigned char _a2u[128] = {		/* A- to u-law conversions */

+	1,	3,	5,	7,	9,	11,	13,	15,

+	16,	17,	18,	19,	20,	21,	22,	23,

+	24,	25,	26,	27,	28,	29,	30,	31,

+	32,	32,	33,	33,	34,	34,	35,	35,

+	36,	37,	38,	39,	40,	41,	42,	43,

+	44,	45,	46,	47,	48,	48,	49,	49,

+	50,	51,	52,	53,	54,	55,	56,	57,

+	58,	59,	60,	61,	62,	63,	64,	64,

+	65,	66,	67,	68,	69,	70,	71,	72,

+	73,	74,	75,	76,	77,	78,	79,	79,

+	80,	81,	82,	83,	84,	85,	86,	87,

+	88,	89,	90,	91,	92,	93,	94,	95,

+	96,	97,	98,	99,	100,	101,	102,	103,

+	104,	105,	106,	107,	108,	109,	110,	111,

+	112,	113,	114,	115,	116,	117,	118,	119,

+	120,	121,	122,	123,	124,	125,	126,	127};

+

+static int

+search(

+	int		val,

+	short		*table,

+	int		size)

+{

+	int		i;

+

+	for (i = 0; i < size; i++) {

+		if (val <= *table++)

+			return (i);

+	}

+	return (size);

+}

+

+/*

+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law

+ *

+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.

+ *

+ *		Linear Input Code	Compressed Code

+ *	------------------------	---------------

+ *	0000000wxyza			000wxyz

+ *	0000001wxyza			001wxyz

+ *	000001wxyzab			010wxyz

+ *	00001wxyzabc			011wxyz

+ *	0001wxyzabcd			100wxyz

+ *	001wxyzabcde			101wxyz

+ *	01wxyzabcdef			110wxyz

+ *	1wxyzabcdefg			111wxyz

+ *

+ * For further information see John C. Bellamy's Digital Telephony, 1982,

+ * John Wiley & Sons, pps 98-111 and 472-476.

+ */

+static unsigned char

+linear2alaw(

+	int		pcm_val)	/* 2's complement (16-bit range) */

+{

+	int		mask;

+	int		seg;

+	unsigned char	aval;

+

+	if (pcm_val >= 0) {

+		mask = 0xD5;		/* sign (7th) bit = 1 */

+	} else {

+		mask = 0x55;		/* sign bit = 0 */

+		pcm_val = -pcm_val - 8;

+	}

+

+	/* Convert the scaled magnitude to segment number. */

+	seg = search(pcm_val, seg_end, 8);

+

+	/* Combine the sign, segment, and quantization bits. */

+

+	if (seg >= 8)		/* out of range, return maximum value. */

+		return (0x7F ^ mask);

+	else {

+		aval = seg << SEG_SHIFT;

+		if (seg < 2)

+			aval |= (pcm_val >> 4) & QUANT_MASK;

+		else

+			aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;

+		return (aval ^ mask);

+	}

+}

+

+/*

+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM

+ *

+ */

+static int

+alaw2linear(

+	unsigned char	a_val)

+{

+	int		t;

+	int		seg;

+

+	a_val ^= 0x55;

+

+	t = (a_val & QUANT_MASK) << 4;

+	seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;

+	switch (seg) {

+	case 0:

+		t += 8;

+		break;

+	case 1:

+		t += 0x108;

+		break;

+	default:

+		t += 0x108;

+		t <<= seg - 1;

+	}

+	return ((a_val & SIGN_BIT) ? t : -t);

+}

+

+#define	BIAS		(0x84)		/* Bias for linear code. */

+

+/*

+ * linear2ulaw() - Convert a linear PCM value to u-law

+ *

+ * In order to simplify the encoding process, the original linear magnitude

+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to

+ * (33 - 8191). The result can be seen in the following encoding table:

+ *

+ *	Biased Linear Input Code	Compressed Code

+ *	------------------------	---------------

+ *	00000001wxyza			000wxyz

+ *	0000001wxyzab			001wxyz

+ *	000001wxyzabc			010wxyz

+ *	00001wxyzabcd			011wxyz

+ *	0001wxyzabcde			100wxyz

+ *	001wxyzabcdef			101wxyz

+ *	01wxyzabcdefg			110wxyz

+ *	1wxyzabcdefgh			111wxyz

+ *

+ * Each biased linear code has a leading 1 which identifies the segment

+ * number. The value of the segment number is equal to 7 minus the number

+ * of leading 0's. The quantization interval is directly available as the

+ * four bits wxyz.  * The trailing bits (a - h) are ignored.

+ *

+ * Ordinarily the complement of the resulting code word is used for

+ * transmission, and so the code word is complemented before it is returned.

+ *

+ * For further information see John C. Bellamy's Digital Telephony, 1982,

+ * John Wiley & Sons, pps 98-111 and 472-476.

+ */

+static unsigned char

+linear2ulaw(

+	int		pcm_val)	/* 2's complement (16-bit range) */

+{

+	int		mask;

+	int		seg;

+	unsigned char	uval;

+

+	/* Get the sign and the magnitude of the value. */

+	if (pcm_val < 0) {

+		pcm_val = BIAS - pcm_val;

+		mask = 0x7F;

+	} else {

+		pcm_val += BIAS;

+		mask = 0xFF;

+	}

+

+	/* Convert the scaled magnitude to segment number. */

+	seg = search(pcm_val, seg_end, 8);

+

+	/*

+	 * Combine the sign, segment, quantization bits;

+	 * and complement the code word.

+	 */

+	if (seg >= 8)		/* out of range, return maximum value. */

+		return (0x7F ^ mask);

+	else {

+		uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);

+		return (uval ^ mask);

+	}

+

+}

+

+/*

+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM

+ *

+ * First, a biased linear code is derived from the code word. An unbiased

+ * output can then be obtained by subtracting 33 from the biased code.

+ *

+ * Note that this function expects to be passed the complement of the

+ * original code word. This is in keeping with ISDN conventions.

+ */

+static int

+ulaw2linear(

+	unsigned char	u_val)

+{

+	int		t;

+

+	/* Complement to obtain normal u-law value. */

+	u_val = ~u_val;

+

+	/*

+	 * Extract and bias the quantization bits. Then

+	 * shift up by the segment number and subtract out the bias.

+	 */

+	t = ((u_val & QUANT_MASK) << 3) + BIAS;

+	t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;

+

+	return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));

+}

+

+/* A-law to u-law conversion */

+unsigned char

+alaw2ulaw(

+	unsigned char	aval)

+{

+	aval &= 0xff;

+	return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :

+	    (0x7F ^ _a2u[aval ^ 0x55]));

+}

+

+/* u-law to A-law conversion */

+unsigned char

+ulaw2alaw(

+	unsigned char	uval)

+{

+	uval &= 0xff;

+	return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :

+	    (0x55 ^ (_u2a[0x7F ^ uval] - 1)));

+}

+

+

+

diff --git a/pjmedia/src/pjmedia/jbuf.c b/pjmedia/src/pjmedia/jbuf.c
index 0ed2200..d35fad3 100644
--- a/pjmedia/src/pjmedia/jbuf.c
+++ b/pjmedia/src/pjmedia/jbuf.c
@@ -1,406 +1,427 @@
-/* $Id$
- *
- */
-
-#include <pjmedia/jbuf.h>
-#include <pj/log.h>
-#include <pj/pool.h>
-#include <string.h>	/* memset() */
-
-/*
- * At the current state, this is basicly an ugly jitter buffer.
- * It worked before by observing level, bit it doesn't work.
- * Then I used the size, which makes the level obsolete.
- * That's why it's ugly!
- */
-
-#define MAX_SEQ_RANGE	1000	/* Range in which sequence is considered still within session */
-#define UPDATE_DURATION	20	/* Number of frames retrieved before jitter is updated */
-
-#define THIS_FILE   "jbuf"
-
-/* Individual frame in the frame list. */ 
-struct pj_jbframe
-{
-    pj_uint32_t  extseq;
-    void	*buf;
-};
-
-
-/* Jitter buffer state. */ 
-typedef enum jb_state_t
-{
-    JB_PREFETCH,
-    JB_NORMAL,
-} jb_state_t;
-
-
-/* Jitter buffer last operation. */ 
-typedef enum jb_op_t
-{
-    JB_PUT,
-    JB_GET,
-} jb_op_t;
-
-
-/* Short name for convenience. */ 
-typedef struct pj_jitter_buffer JB;
-
-
-/* Initialize framelist. */ 
-static pj_status_t
-pj_framelist_init( pj_jbframelist *lst, pj_pool_t *pool, unsigned maxcount )
-{
-    PJ_LOG(5, (THIS_FILE, "..pj_frame_list_init [lst=%p], maxcount=%d", lst, maxcount));
-
-    memset(lst, 0, sizeof(*lst));
-    lst->maxcount = maxcount;
-    lst->frames = pj_pool_calloc( pool, maxcount, sizeof(*lst->frames) );
-    if (lst->frames == NULL) {
-	PJ_LOG(1,(THIS_FILE, "Unable to allocate frame list!"));
-	return -1;
-    }
-    return 0;    
-}
-
-/* Reset framelist. */
-static void 
-pj_framelist_reset( pj_jbframelist *lst )
-{
-    PJ_LOG(6, (THIS_FILE, "..pj_frame_list_reset [lst=%p]", lst));
-
-    lst->count = 0;
-    lst->head = 0;
-    lst->frames[0].extseq = 0;
-}
-
-/* Put a buffer with the specified sequence into the ordered list. */ 
-static int 
-pj_framelist_put( pj_jbframelist *lst, pj_uint32_t extseq, void *buf )
-{
-    unsigned pos = (unsigned)-1;
-    pj_uint32_t startseq = lst->frames[lst->head].extseq;
-
-    if (lst->count == 0) {
-	/* Empty list. Initialize frame list. */
-	PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_put [lst=%p], empty, seq=%u@pos=%d", 
-		   lst, extseq, lst->head));
-
-	lst->head = 0;
-	lst->count = 1;
-	lst->frames[0].buf = buf;
-	lst->frames[0].extseq = extseq;
-	return 0;
-	
-    } else if (extseq < startseq) {
-	/* The sequence number is lower than our oldest packet. This can mean
-	   two things:
-	    - old packet has been receieved, or
-	    - the sequence number has wrapped around.
-	 */  
-	if (startseq + lst->maxcount <= extseq) {
-	    /* The sequence number has wrapped around, but it is beyond
-	       the capacity of the list (i.e. too soon).
-	     */
-	    PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_SOON! [lst=%p] seq=%u, startseq=%d", 
-		       lst, extseq, startseq));
-	    return PJ_JB_STATUS_TOO_SOON;
-
-	} else if (startseq-extseq > lst->maxcount && startseq+lst->maxcount > extseq) {
-	    /* The sequence number has wrapped around, and it is still inside
-	       the 'window' of the framelist.
-	     */
-	    pos = extseq - startseq;
-	} else {
-	    /* The new frame is too old. */
-	    PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_OLD! [lst=%p] seq=%u, startseq=%d", 
-		       lst, extseq, startseq));
-	    return PJ_JB_STATUS_TOO_OLD;
-	}
-	
-    } else if (extseq > startseq + lst->maxcount) {
-	/* Two possibilities here. Either:
-	    - packet is really too soon, or
-	    - sequence number of startseq has just wrapped around, and old packet
-	      which hasn't wrapped is received.
-	 */
-	if (extseq < MAX_SEQ_RANGE /*approx 20 seconds with 50 fps*/) {
-	    PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_SOON! [lst=%p] seq=%u, startseq=%d", 
-		       lst, extseq, startseq));
-	    return PJ_JB_STATUS_TOO_SOON;
-	} else {
-	    PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_OLD! [lst=%p] seq=%u, startseq=%d", 
-		       lst, extseq, startseq));
-	    return PJ_JB_STATUS_TOO_OLD;
-	}
-    } 
-
-    /* The new frame is within the framelist capacity.
-       Calculate position where to put it in the list.
-     */
-    if (pos == (unsigned)-1)
-	pos = ((extseq - startseq) + lst->head) % lst->maxcount;
-
-    pj_assert(pos < lst->maxcount);
-    
-    /* Update count only if we're not overwriting existing frame. */
-    if (lst->frames[pos].buf == NULL)
-        ++lst->count;
-
-    lst->frames[pos].buf = buf;
-    lst->frames[pos].extseq = extseq;
-
-    PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_put [lst=%p] seq=%u, startseq=%d, head=%d, pos=%d", 
-	       lst, extseq, startseq, lst->head, pos));
-    return 0;
-}
-
-/* Get the first element of the list. */ 
-static int 
-pj_framelist_get( pj_jbframelist *lst, pj_uint32_t *extseq, void **buf )
-{
-    if (lst->count == 0) {
-	/* Empty. */
-	*buf = NULL;
-	*extseq = 0;
-	PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_get [lst=%p], empty!", lst));
-	return -1;
-	
-    } else {
-	*buf = lst->frames[lst->head].buf;
-	*extseq = lst->frames[lst->head].extseq;
-	lst->frames[lst->head].buf = NULL;
-
-	PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_get [lst=%p] seq=%u, head=%d", 
-		   lst, *extseq, lst->head));
-
-	lst->head = (lst->head + 1) % lst->maxcount;
-	--lst->count;
-	return 0;
-    }
-}
-
-
-/*****************************************************************************
- * Reset jitter buffer. 
- ****************************************************************************
-*/
-PJ_DEF(void) pj_jb_reset(JB *jb)
-{
-    PJ_LOG(6, (THIS_FILE, "pj_jb_reset [jb=%p]", jb));
-
-    jb->level = jb->max_level = 1;
-    jb->prefetch = jb->min;
-    jb->get_cnt = 0;
-    jb->lastseq = 0;
-    jb->state = JB_PREFETCH;
-    jb->upd_count = 0;
-    jb->last_op = -1;
-    pj_framelist_reset( &jb->lst );
-}
-
-
-/*****************************************************************************
- * Create jitter buffer.
- *****************************************************************************
- */ 
-PJ_DEF(pj_status_t) pj_jb_init( pj_jitter_buffer *jb, pj_pool_t *pool, 
-			        unsigned min, unsigned max, unsigned maxcount)
-{
-    pj_status_t status;
-
-    if (maxcount <= max) {
-	maxcount = max * 5 / 4;
-	PJ_LOG(3,(THIS_FILE, "Jitter buffer maximum count was adjusted."));
-    }
-
-    jb->min = min;
-    jb->max = max;
-
-    status = pj_framelist_init( &jb->lst, pool, maxcount );
-    if (status != PJ_SUCCESS)
-	return status;
-
-    pj_jb_reset(jb);
-
-    PJ_LOG(4, (THIS_FILE, "pj_jb_init success [jb=%p], min=%d, max=%d, maxcount=%d", 
-			  jb, min, max, maxcount));
-    return PJ_SUCCESS;
-}
-
-
-/*****************************************************************************
- * Put a packet to the jitter buffer.
- *****************************************************************************
- */ 
-PJ_DEF(pj_status_t) pj_jb_put( JB *jb, pj_uint32_t extseq, void *buf )
-{
-    unsigned distance;
-    int status;
-    
-    PJ_LOG(6, (THIS_FILE, "==> pj_jb_put [jb=%p], seq=%u, buf=%p", jb, extseq, buf));
-
-    if (jb->lastseq == 0)
-	jb->lastseq = extseq - 1;
-
-    /* Calculate distance between this packet and last received packet
-       to detect long jump (indicating probably remote has just been
-       restarted.
-     */
-    distance = (extseq > jb->lastseq) ? extseq - jb->lastseq : jb->lastseq - extseq;
-    if (distance > MAX_SEQ_RANGE) {
-	/* Distance is out of range, reset jitter while maintaining current jitter
-	   level.
-	 */
-	int old_level = jb->level;
-	int old_prefetch = jb->prefetch;
-
-	PJ_LOG(4, (THIS_FILE, "    ..[jb=%p] distance out of range, resetting", jb));
-
-	pj_jb_reset(jb);
-	jb->level = old_level;
-	jb->prefetch = old_prefetch;
-	distance = 1;
-	jb->lastseq = extseq - 1;
-    }
-    
-    jb->lastseq = extseq;
-
-    status = pj_framelist_put( &jb->lst, extseq, buf );
-    if (status == PJ_JB_STATUS_TOO_OLD)
-	return -1;
-
-    if (status == PJ_JB_STATUS_TOO_SOON) {
-	/* TODO: discard old packets.. */
-	/* No, don't do it without putting a way to inform application so that
-	   it can free the memory */
-    }
-
-
-    if (jb->last_op != JB_PUT) {
-	if (jb->state != JB_PREFETCH)
-	    jb->level--;
-    } else {
-	jb->level++;
-    }
-
-    if (jb->lst.count > jb->max_level)
-	jb->max_level++;
-
-    jb->last_op = JB_PUT;
-    return 0;
-}
-
-
-/*
- * Update jitter buffer algorithm.
- */
-static void jb_update(JB *jb, int apply, int log_info)
-{
-    unsigned abs_level = jb->max_level > 0 ? jb->max_level : -jb->max_level;
-    unsigned new_prefetch;
-
-    /* Update prefetch count */
-    if (abs_level > jb->prefetch)
-	new_prefetch = (jb->prefetch + abs_level*9 + 1) / 10;
-    else {
-	new_prefetch = (jb->prefetch*4 + abs_level) / 5;
-	pj_assert(new_prefetch <= jb->prefetch);
-    }
-
-    if (log_info) {
-	PJ_LOG(5, (THIS_FILE, "    ..jb_update [jb=%p], level=%d, max_level=%d, old_prefetch=%d, new_prefetch=%d", 
-			      jb, jb->level, jb->max_level, jb->prefetch, new_prefetch));
-    } else {
-	PJ_LOG(6, (THIS_FILE, "    ..jb_update [jb=%p], level=%d, max_level=%d, old_prefetch=%d, new_prefetch=%d", 
-			      jb, jb->level, jb->max_level, jb->prefetch, new_prefetch));
-    }
-
-    if (new_prefetch < jb->min) new_prefetch = jb->min;
-    if (new_prefetch > jb->max) new_prefetch = jb->max;
-
-    /* If jitter buffer is empty, set state to JB_PREFETCH, taking care of the
-       new prefetch setting.
-     */
-    if (jb->lst.count == 0) {
-	jb->state = JB_PREFETCH;
-	jb->get_cnt = 0;
-    } else {
-	/* Check if delay is too long, which in this case probably better to
-	   discard some frames..
-	 */
-	/* No, don't do it without putting a way to inform application so that
-	   it can free the memory */
-    }
-
-
-    if (apply) {
-	jb->prefetch = new_prefetch;
-	if (jb->max_level > 0)
-	    jb->max_level--;
-    } else {
-	jb->level = new_prefetch;
-    }
-}
-
-
-/*****************************************************************************
- * Get the oldest frame from jitter buffer.
- *****************************************************************************
- */ 
-PJ_DEF(pj_status_t) pj_jb_get( JB *jb, pj_uint32_t *extseq, void **buf )
-{
-    pj_status_t status;
-    
-    PJ_LOG(6, (THIS_FILE, "<== pj_jb_get [jb=%p]", jb));
-
-    /*
-     * Check whether we're ready to give frame. When we're in JB_PREFETCH state,
-     * only give frames only when:
-     *	- the buffer has enough frames in it (jb->list.count > jb->prefetch), OR
-     *	- after 'prefetch' attempts, there's still no frame, which in this
-     *	  case PJ_JB_STATUS_FRAME_NULL will be returned by the next check.
-     */
-    if (jb->state == JB_PREFETCH && jb->lst.count <= jb->prefetch && jb->get_cnt < jb->prefetch) {
-	jb->get_cnt++;   
-	jb->last_op = JB_GET;
-	PJ_LOG(5, (THIS_FILE, "    ..[jb=%p] bufferring...", jb));
-	return PJ_JB_STATUS_FRAME_NULL;
-    }
-
-    /* Attempt to get one frame from the list. */
-    status = pj_framelist_get( &jb->lst, extseq, buf );
-    if (status != 0) {
-	PJ_LOG(6, (THIS_FILE, "    ..[jb=%p] no packet!", jb));
-	status = jb->lst.count ? PJ_JB_STATUS_FRAME_MISSING : PJ_JB_STATUS_FRAME_NULL;
-	jb_update(jb, 1, 0);
-	return status;
-    }
-
-    /* Force state to NORMAL */
-    jb->state = JB_NORMAL;
-
-    /* Increase level only when last operation is GET.
-     * This is to prevent level from increasing during silence period, which
-     * no packets is receieved.
-     */
-    if (jb->last_op != JB_GET) {
-	int apply;
-
-	//jb->level++;
-	jb->last_op = JB_GET;
-
-	apply = (++jb->upd_count > UPDATE_DURATION);
-	if (apply)
-	    jb->upd_count = 0;
-
-	jb_update(jb, apply, apply);
-    }
-
-    PJ_LOG(6, (THIS_FILE, "    ..[jb=%p] seq=%u, level=%d, prefetch=%d, size=%u, delay=%d", 
-			  jb, *extseq, jb->level, jb->prefetch, jb->lst.count,
-			  jb->lastseq - *extseq));
-    return 0;
-}
-
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#include <pjmedia/jbuf.h>

+#include <pj/log.h>

+#include <pj/pool.h>

+#include <string.h>	/* memset() */

+

+/*

+ * At the current state, this is basicly an ugly jitter buffer.

+ * It worked before by observing level, bit it doesn't work.

+ * Then I used the size, which makes the level obsolete.

+ * That's why it's ugly!

+ */

+

+#define MAX_SEQ_RANGE	1000	/* Range in which sequence is considered still within session */

+#define UPDATE_DURATION	20	/* Number of frames retrieved before jitter is updated */

+

+#define THIS_FILE   "jbuf"

+

+/* Individual frame in the frame list. */ 

+struct pj_jbframe

+{

+    pj_uint32_t  extseq;

+    void	*buf;

+};

+

+

+/* Jitter buffer state. */ 

+typedef enum jb_state_t

+{

+    JB_PREFETCH,

+    JB_NORMAL,

+} jb_state_t;

+

+

+/* Jitter buffer last operation. */ 

+typedef enum jb_op_t

+{

+    JB_PUT,

+    JB_GET,

+} jb_op_t;

+

+

+/* Short name for convenience. */ 

+typedef struct pj_jitter_buffer JB;

+

+

+/* Initialize framelist. */ 

+static pj_status_t

+pj_framelist_init( pj_jbframelist *lst, pj_pool_t *pool, unsigned maxcount )

+{

+    PJ_LOG(5, (THIS_FILE, "..pj_frame_list_init [lst=%p], maxcount=%d", lst, maxcount));

+

+    memset(lst, 0, sizeof(*lst));

+    lst->maxcount = maxcount;

+    lst->frames = pj_pool_calloc( pool, maxcount, sizeof(*lst->frames) );

+    if (lst->frames == NULL) {

+	PJ_LOG(1,(THIS_FILE, "Unable to allocate frame list!"));

+	return -1;

+    }

+    return 0;    

+}

+

+/* Reset framelist. */

+static void 

+pj_framelist_reset( pj_jbframelist *lst )

+{

+    PJ_LOG(6, (THIS_FILE, "..pj_frame_list_reset [lst=%p]", lst));

+

+    lst->count = 0;

+    lst->head = 0;

+    lst->frames[0].extseq = 0;

+}

+

+/* Put a buffer with the specified sequence into the ordered list. */ 

+static int 

+pj_framelist_put( pj_jbframelist *lst, pj_uint32_t extseq, void *buf )

+{

+    unsigned pos = (unsigned)-1;

+    pj_uint32_t startseq = lst->frames[lst->head].extseq;

+

+    if (lst->count == 0) {

+	/* Empty list. Initialize frame list. */

+	PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_put [lst=%p], empty, seq=%u@pos=%d", 

+		   lst, extseq, lst->head));

+

+	lst->head = 0;

+	lst->count = 1;

+	lst->frames[0].buf = buf;

+	lst->frames[0].extseq = extseq;

+	return 0;

+	

+    } else if (extseq < startseq) {

+	/* The sequence number is lower than our oldest packet. This can mean

+	   two things:

+	    - old packet has been receieved, or

+	    - the sequence number has wrapped around.

+	 */  

+	if (startseq + lst->maxcount <= extseq) {

+	    /* The sequence number has wrapped around, but it is beyond

+	       the capacity of the list (i.e. too soon).

+	     */

+	    PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_SOON! [lst=%p] seq=%u, startseq=%d", 

+		       lst, extseq, startseq));

+	    return PJ_JB_STATUS_TOO_SOON;

+

+	} else if (startseq-extseq > lst->maxcount && startseq+lst->maxcount > extseq) {

+	    /* The sequence number has wrapped around, and it is still inside

+	       the 'window' of the framelist.

+	     */

+	    pos = extseq - startseq;

+	} else {

+	    /* The new frame is too old. */

+	    PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_OLD! [lst=%p] seq=%u, startseq=%d", 

+		       lst, extseq, startseq));

+	    return PJ_JB_STATUS_TOO_OLD;

+	}

+	

+    } else if (extseq > startseq + lst->maxcount) {

+	/* Two possibilities here. Either:

+	    - packet is really too soon, or

+	    - sequence number of startseq has just wrapped around, and old packet

+	      which hasn't wrapped is received.

+	 */

+	if (extseq < MAX_SEQ_RANGE /*approx 20 seconds with 50 fps*/) {

+	    PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_SOON! [lst=%p] seq=%u, startseq=%d", 

+		       lst, extseq, startseq));

+	    return PJ_JB_STATUS_TOO_SOON;

+	} else {

+	    PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_OLD! [lst=%p] seq=%u, startseq=%d", 

+		       lst, extseq, startseq));

+	    return PJ_JB_STATUS_TOO_OLD;

+	}

+    } 

+

+    /* The new frame is within the framelist capacity.

+       Calculate position where to put it in the list.

+     */

+    if (pos == (unsigned)-1)

+	pos = ((extseq - startseq) + lst->head) % lst->maxcount;

+

+    pj_assert(pos < lst->maxcount);

+    

+    /* Update count only if we're not overwriting existing frame. */

+    if (lst->frames[pos].buf == NULL)

+        ++lst->count;

+

+    lst->frames[pos].buf = buf;

+    lst->frames[pos].extseq = extseq;

+

+    PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_put [lst=%p] seq=%u, startseq=%d, head=%d, pos=%d", 

+	       lst, extseq, startseq, lst->head, pos));

+    return 0;

+}

+

+/* Get the first element of the list. */ 

+static int 

+pj_framelist_get( pj_jbframelist *lst, pj_uint32_t *extseq, void **buf )

+{

+    if (lst->count == 0) {

+	/* Empty. */

+	*buf = NULL;

+	*extseq = 0;

+	PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_get [lst=%p], empty!", lst));

+	return -1;

+	

+    } else {

+	*buf = lst->frames[lst->head].buf;

+	*extseq = lst->frames[lst->head].extseq;

+	lst->frames[lst->head].buf = NULL;

+

+	PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_get [lst=%p] seq=%u, head=%d", 

+		   lst, *extseq, lst->head));

+

+	lst->head = (lst->head + 1) % lst->maxcount;

+	--lst->count;

+	return 0;

+    }

+}

+

+

+/*****************************************************************************

+ * Reset jitter buffer. 

+ ****************************************************************************

+*/

+PJ_DEF(void) pj_jb_reset(JB *jb)

+{

+    PJ_LOG(6, (THIS_FILE, "pj_jb_reset [jb=%p]", jb));

+

+    jb->level = jb->max_level = 1;

+    jb->prefetch = jb->min;

+    jb->get_cnt = 0;

+    jb->lastseq = 0;

+    jb->state = JB_PREFETCH;

+    jb->upd_count = 0;

+    jb->last_op = -1;

+    pj_framelist_reset( &jb->lst );

+}

+

+

+/*****************************************************************************

+ * Create jitter buffer.

+ *****************************************************************************

+ */ 

+PJ_DEF(pj_status_t) pj_jb_init( pj_jitter_buffer *jb, pj_pool_t *pool, 

+			        unsigned min, unsigned max, unsigned maxcount)

+{

+    pj_status_t status;

+

+    if (maxcount <= max) {

+	maxcount = max * 5 / 4;

+	PJ_LOG(3,(THIS_FILE, "Jitter buffer maximum count was adjusted."));

+    }

+

+    jb->min = min;

+    jb->max = max;

+

+    status = pj_framelist_init( &jb->lst, pool, maxcount );

+    if (status != PJ_SUCCESS)

+	return status;

+

+    pj_jb_reset(jb);

+

+    PJ_LOG(4, (THIS_FILE, "pj_jb_init success [jb=%p], min=%d, max=%d, maxcount=%d", 

+			  jb, min, max, maxcount));

+    return PJ_SUCCESS;

+}

+

+

+/*****************************************************************************

+ * Put a packet to the jitter buffer.

+ *****************************************************************************

+ */ 

+PJ_DEF(pj_status_t) pj_jb_put( JB *jb, pj_uint32_t extseq, void *buf )

+{

+    unsigned distance;

+    int status;

+    

+    PJ_LOG(6, (THIS_FILE, "==> pj_jb_put [jb=%p], seq=%u, buf=%p", jb, extseq, buf));

+

+    if (jb->lastseq == 0)

+	jb->lastseq = extseq - 1;

+

+    /* Calculate distance between this packet and last received packet

+       to detect long jump (indicating probably remote has just been

+       restarted.

+     */

+    distance = (extseq > jb->lastseq) ? extseq - jb->lastseq : jb->lastseq - extseq;

+    if (distance > MAX_SEQ_RANGE) {

+	/* Distance is out of range, reset jitter while maintaining current jitter

+	   level.

+	 */

+	int old_level = jb->level;

+	int old_prefetch = jb->prefetch;

+

+	PJ_LOG(4, (THIS_FILE, "    ..[jb=%p] distance out of range, resetting", jb));

+

+	pj_jb_reset(jb);

+	jb->level = old_level;

+	jb->prefetch = old_prefetch;

+	distance = 1;

+	jb->lastseq = extseq - 1;

+    }

+    

+    jb->lastseq = extseq;

+

+    status = pj_framelist_put( &jb->lst, extseq, buf );

+    if (status == PJ_JB_STATUS_TOO_OLD)

+	return -1;

+

+    if (status == PJ_JB_STATUS_TOO_SOON) {

+	/* TODO: discard old packets.. */

+	/* No, don't do it without putting a way to inform application so that

+	   it can free the memory */

+    }

+

+

+    if (jb->last_op != JB_PUT) {

+	if (jb->state != JB_PREFETCH)

+	    jb->level--;

+    } else {

+	jb->level++;

+    }

+

+    if (jb->lst.count > jb->max_level)

+	jb->max_level++;

+

+    jb->last_op = JB_PUT;

+    return 0;

+}

+

+

+/*

+ * Update jitter buffer algorithm.

+ */

+static void jb_update(JB *jb, int apply, int log_info)

+{

+    unsigned abs_level = jb->max_level > 0 ? jb->max_level : -jb->max_level;

+    unsigned new_prefetch;

+

+    /* Update prefetch count */

+    if (abs_level > jb->prefetch)

+	new_prefetch = (jb->prefetch + abs_level*9 + 1) / 10;

+    else {

+	new_prefetch = (jb->prefetch*4 + abs_level) / 5;

+	pj_assert(new_prefetch <= jb->prefetch);

+    }

+

+    if (log_info) {

+	PJ_LOG(5, (THIS_FILE, "    ..jb_update [jb=%p], level=%d, max_level=%d, old_prefetch=%d, new_prefetch=%d", 

+			      jb, jb->level, jb->max_level, jb->prefetch, new_prefetch));

+    } else {

+	PJ_LOG(6, (THIS_FILE, "    ..jb_update [jb=%p], level=%d, max_level=%d, old_prefetch=%d, new_prefetch=%d", 

+			      jb, jb->level, jb->max_level, jb->prefetch, new_prefetch));

+    }

+

+    if (new_prefetch < jb->min) new_prefetch = jb->min;

+    if (new_prefetch > jb->max) new_prefetch = jb->max;

+

+    /* If jitter buffer is empty, set state to JB_PREFETCH, taking care of the

+       new prefetch setting.

+     */

+    if (jb->lst.count == 0) {

+	jb->state = JB_PREFETCH;

+	jb->get_cnt = 0;

+    } else {

+	/* Check if delay is too long, which in this case probably better to

+	   discard some frames..

+	 */

+	/* No, don't do it without putting a way to inform application so that

+	   it can free the memory */

+    }

+

+

+    if (apply) {

+	jb->prefetch = new_prefetch;

+	if (jb->max_level > 0)

+	    jb->max_level--;

+    } else {

+	jb->level = new_prefetch;

+    }

+}

+

+

+/*****************************************************************************

+ * Get the oldest frame from jitter buffer.

+ *****************************************************************************

+ */ 

+PJ_DEF(pj_status_t) pj_jb_get( JB *jb, pj_uint32_t *extseq, void **buf )

+{

+    pj_status_t status;

+    

+    PJ_LOG(6, (THIS_FILE, "<== pj_jb_get [jb=%p]", jb));

+

+    /*

+     * Check whether we're ready to give frame. When we're in JB_PREFETCH state,

+     * only give frames only when:

+     *	- the buffer has enough frames in it (jb->list.count > jb->prefetch), OR

+     *	- after 'prefetch' attempts, there's still no frame, which in this

+     *	  case PJ_JB_STATUS_FRAME_NULL will be returned by the next check.

+     */

+    if (jb->state == JB_PREFETCH && jb->lst.count <= jb->prefetch && jb->get_cnt < jb->prefetch) {

+	jb->get_cnt++;   

+	jb->last_op = JB_GET;

+	PJ_LOG(5, (THIS_FILE, "    ..[jb=%p] bufferring...", jb));

+	return PJ_JB_STATUS_FRAME_NULL;

+    }

+

+    /* Attempt to get one frame from the list. */

+    status = pj_framelist_get( &jb->lst, extseq, buf );

+    if (status != 0) {

+	PJ_LOG(6, (THIS_FILE, "    ..[jb=%p] no packet!", jb));

+	status = jb->lst.count ? PJ_JB_STATUS_FRAME_MISSING : PJ_JB_STATUS_FRAME_NULL;

+	jb_update(jb, 1, 0);

+	return status;

+    }

+

+    /* Force state to NORMAL */

+    jb->state = JB_NORMAL;

+

+    /* Increase level only when last operation is GET.

+     * This is to prevent level from increasing during silence period, which

+     * no packets is receieved.

+     */

+    if (jb->last_op != JB_GET) {

+	int apply;

+

+	//jb->level++;

+	jb->last_op = JB_GET;

+

+	apply = (++jb->upd_count > UPDATE_DURATION);

+	if (apply)

+	    jb->upd_count = 0;

+

+	jb_update(jb, apply, apply);

+    }

+

+    PJ_LOG(6, (THIS_FILE, "    ..[jb=%p] seq=%u, level=%d, prefetch=%d, size=%u, delay=%d", 

+			  jb, *extseq, jb->level, jb->prefetch, jb->lst.count,

+			  jb->lastseq - *extseq));

+    return 0;

+}

+

+

diff --git a/pjmedia/src/pjmedia/jbuf.h b/pjmedia/src/pjmedia/jbuf.h
index fc4325b..9229b41 100644
--- a/pjmedia/src/pjmedia/jbuf.h
+++ b/pjmedia/src/pjmedia/jbuf.h
@@ -1,128 +1,149 @@
-/* $Id$
- *
- */
-
-#ifndef __PJMEDIA_JBUF_H__
-#define __PJMEDIA_JBUF_H__
-
-
-/**
- * @file jbuf.h
- * @brief Adaptive jitter buffer implementation.
- */
-/**
- * @defgroup PJMED_JBUF Adaptive jitter buffer
- * @ingroup PJMEDIA
- * @{
- */
-
-#include <pj/types.h>
-
-
-PJ_BEGIN_DECL
-
-
-/**
- * Opaque declaration of internal frame type used by jitter buffer. 
- */
-struct pj_jbframe;
-
-
-/**
- * Miscelaneous operation result/status. 
- */ 
-typedef enum jb_op_status
-{
-    PJ_JB_STATUS_TOO_OLD = -2,		/** The packet is too old. */
-    PJ_JB_STATUS_TOO_SOON = -3,		/** The packet is too soon. */
-    PJ_JB_STATUS_FRAME_NULL = -4,	/** No packet can be retrieved */
-    PJ_JB_STATUS_FRAME_MISSING = -5,	/** The specified packet is missing/lost */
-} jb_op_status;
-
-
-/*
- * Frame list, container abstraction for ordered list with fixed maximum
- * size. It is used internally by the jitter buffer.
- */  
-typedef struct pj_jbframelist
-{
-    unsigned		head, count, maxcount;
-    struct pj_jbframe  *frames;
-} pj_jbframelist;
-
-
-/**
- * Jitter buffer implementation.
- */ 
-typedef struct pj_jitter_buffer
-{
-    pj_jbframelist  lst;	    /** The frame list. */
-    int		    level;	    /** Current, real-time jitter level. */
-    int		    max_level;	    /** Maximum level for the period.	 */
-    unsigned	    prefetch;	    /** Prefetch count currently used. */
-    unsigned	    get_cnt;	    /** Number of get operation during prefetch state. */
-    unsigned	    min;	    /** Minimum jitter size, in packets. */
-    unsigned	    max;	    /** Maximum jitter size, in packets. */
-    pj_uint32_t	    lastseq;	    /** Last sequence number put to jitter buffer. */
-    unsigned	    upd_count;	    /** Internal counter to manage update interval. */
-    int		    state;	    /** Jitter buffer state (1==operational) */
-    int		    last_op;	    /** Last jitter buffer operation. */
-} pj_jitter_buffer;
-
-
-/**
- * Initialize jitter buffer with the specified parameters.
- * This function will allocate internal frame buffer from the specified pool.
- * @param jb The jitter buffer to be initialized.
- * @param pool Pool where memory will be allocated for the frame buffer.
- * @param min The minimum value of jitter buffer, in packets.
- * @param max The maximum value of jitter buffer, in packets.
- * @param maxcount The maximum number of delay, in packets, which must be
- *		   greater than max.
- * @return PJ_SUCCESS on success.
- */
-PJ_DECL(pj_status_t) pj_jb_init(pj_jitter_buffer *jb, pj_pool_t *pool, 
-				unsigned min, unsigned max, unsigned maxcount);
-
-/**
- * Reset jitter buffer according to the parameters specified when the jitter
- * buffer was initialized. Any packets currently in the buffer will be 
- * discarded.
- */
-PJ_DECL(void) pj_jb_reset(pj_jitter_buffer *jb);
-
-/**
- * Put a pointer to the buffer with the specified sequence number. The pointer
- * normally points to a buffer held by application, and this pointer will be
- * returned later on when pj_jb_get() is called. The jitter buffer will not try
- * to interpret the content of this pointer.
- * @return:
- *   - PJ_SUCCESS on success.
- *   - PJ_JB_STATUS_TOO_OLD when the packet is too old.
- *   - PJ_JB_STATUS_TOO_SOON when the packet is too soon.
- */
-PJ_DECL(pj_status_t) pj_jb_put( pj_jitter_buffer *jb, pj_uint32_t extseq, void *buf );
-
-/**
- * Get the earliest data from the jitter buffer. ONLY when the operation succeeds,
- * the function returns both sequence number and a pointer in the parameters.
- * This returned data corresponds to sequence number and pointer that were
- * given to jitter buffer in the previous pj_jb_put operation.
- * @return 
- *  - PJ_SUCCESS on success
- *  - PJ_JB_STATUS_FRAME_NULL when there is no frames to be returned.
- *  - PJ_JB_STATUS_FRAME_MISSING if the jitter buffer detects that the packet 
- *     is lost. Application may run packet concealment algorithm when it 
- *     receives this status.
- */
-PJ_DECL(pj_status_t) pj_jb_get( pj_jitter_buffer *jb, pj_uint32_t *extseq, void **buf );
-
-
-
-PJ_END_DECL
-
-/**
- * @}
- */
-
-#endif	/* __PJMEDIA_JBUF_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJMEDIA_JBUF_H__

+#define __PJMEDIA_JBUF_H__

+

+

+/**

+ * @file jbuf.h

+ * @brief Adaptive jitter buffer implementation.

+ */

+/**

+ * @defgroup PJMED_JBUF Adaptive jitter buffer

+ * @ingroup PJMEDIA

+ * @{

+ */

+

+#include <pj/types.h>

+

+

+PJ_BEGIN_DECL

+

+

+/**

+ * Opaque declaration of internal frame type used by jitter buffer. 

+ */

+struct pj_jbframe;

+

+

+/**

+ * Miscelaneous operation result/status. 

+ */ 

+typedef enum jb_op_status

+{

+    PJ_JB_STATUS_TOO_OLD = -2,		/** The packet is too old. */

+    PJ_JB_STATUS_TOO_SOON = -3,		/** The packet is too soon. */

+    PJ_JB_STATUS_FRAME_NULL = -4,	/** No packet can be retrieved */

+    PJ_JB_STATUS_FRAME_MISSING = -5,	/** The specified packet is missing/lost */

+} jb_op_status;

+

+

+/*

+ * Frame list, container abstraction for ordered list with fixed maximum

+ * size. It is used internally by the jitter buffer.

+ */  

+typedef struct pj_jbframelist

+{

+    unsigned		head, count, maxcount;

+    struct pj_jbframe  *frames;

+} pj_jbframelist;

+

+

+/**

+ * Jitter buffer implementation.

+ */ 

+typedef struct pj_jitter_buffer

+{

+    pj_jbframelist  lst;	    /** The frame list. */

+    int		    level;	    /** Current, real-time jitter level. */

+    int		    max_level;	    /** Maximum level for the period.	 */

+    unsigned	    prefetch;	    /** Prefetch count currently used. */

+    unsigned	    get_cnt;	    /** Number of get operation during prefetch state. */

+    unsigned	    min;	    /** Minimum jitter size, in packets. */

+    unsigned	    max;	    /** Maximum jitter size, in packets. */

+    pj_uint32_t	    lastseq;	    /** Last sequence number put to jitter buffer. */

+    unsigned	    upd_count;	    /** Internal counter to manage update interval. */

+    int		    state;	    /** Jitter buffer state (1==operational) */

+    int		    last_op;	    /** Last jitter buffer operation. */

+} pj_jitter_buffer;

+

+

+/**

+ * Initialize jitter buffer with the specified parameters.

+ * This function will allocate internal frame buffer from the specified pool.

+ * @param jb The jitter buffer to be initialized.

+ * @param pool Pool where memory will be allocated for the frame buffer.

+ * @param min The minimum value of jitter buffer, in packets.

+ * @param max The maximum value of jitter buffer, in packets.

+ * @param maxcount The maximum number of delay, in packets, which must be

+ *		   greater than max.

+ * @return PJ_SUCCESS on success.

+ */

+PJ_DECL(pj_status_t) pj_jb_init(pj_jitter_buffer *jb, pj_pool_t *pool, 

+				unsigned min, unsigned max, unsigned maxcount);

+

+/**

+ * Reset jitter buffer according to the parameters specified when the jitter

+ * buffer was initialized. Any packets currently in the buffer will be 

+ * discarded.

+ */

+PJ_DECL(void) pj_jb_reset(pj_jitter_buffer *jb);

+

+/**

+ * Put a pointer to the buffer with the specified sequence number. The pointer

+ * normally points to a buffer held by application, and this pointer will be

+ * returned later on when pj_jb_get() is called. The jitter buffer will not try

+ * to interpret the content of this pointer.

+ * @return:

+ *   - PJ_SUCCESS on success.

+ *   - PJ_JB_STATUS_TOO_OLD when the packet is too old.

+ *   - PJ_JB_STATUS_TOO_SOON when the packet is too soon.

+ */

+PJ_DECL(pj_status_t) pj_jb_put( pj_jitter_buffer *jb, pj_uint32_t extseq, void *buf );

+

+/**

+ * Get the earliest data from the jitter buffer. ONLY when the operation succeeds,

+ * the function returns both sequence number and a pointer in the parameters.

+ * This returned data corresponds to sequence number and pointer that were

+ * given to jitter buffer in the previous pj_jb_put operation.

+ * @return 

+ *  - PJ_SUCCESS on success

+ *  - PJ_JB_STATUS_FRAME_NULL when there is no frames to be returned.

+ *  - PJ_JB_STATUS_FRAME_MISSING if the jitter buffer detects that the packet 

+ *     is lost. Application may run packet concealment algorithm when it 

+ *     receives this status.

+ */

+PJ_DECL(pj_status_t) pj_jb_get( pj_jitter_buffer *jb, pj_uint32_t *extseq, void **buf );

+

+

+

+PJ_END_DECL

+

+/**

+ * @}

+ */

+

+#endif	/* __PJMEDIA_JBUF_H__ */

diff --git a/pjmedia/src/pjmedia/mediamgr.c b/pjmedia/src/pjmedia/mediamgr.c
index 79fd108..b87d650 100644
--- a/pjmedia/src/pjmedia/mediamgr.c
+++ b/pjmedia/src/pjmedia/mediamgr.c
@@ -1,97 +1,118 @@
-/* $Id$
- *
- */
-#include <pjmedia/mediamgr.h>
-#include <pj/sock.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-
-PJ_DECL(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *pool);
-PJ_DECL(pj_status_t) g711_deinit_factory (pj_codec_factory *factory);
-
-/** Concrete declaration of media manager. */
-struct pj_med_mgr_t
-{
-    /** Pool. */
-    pj_pool_t		 *pool;
-
-    /** Pool factory. */
-    pj_pool_factory	 *pf;
-
-    /** Codec manager. */
-    pj_codec_mgr	  codec_mgr;
-};
-
-/**
- * Initialize and get the instance of media manager.
- */
-PJ_DEF(pj_med_mgr_t*) pj_med_mgr_create ( pj_pool_factory *pf)
-{
-    pj_pool_t *pool;
-    pj_med_mgr_t *mm;
-    pj_codec_factory *cf;
-    pj_status_t status;
-
-    pool = pj_pool_create(pf, "mediamgr", 512, 512, NULL);
-    if (!pool)
-	return NULL;
-
-    mm = pj_pool_calloc(pool, 1, sizeof(struct pj_med_mgr_t));
-    mm->pool = pool;
-    mm->pf = pf;
-
-    /* Sound */
-    pj_snd_init(pf);
-
-    /* Init codec manager. */
-    status = pj_codec_mgr_init(&mm->codec_mgr);
-    if (status != 0) {
-	pj_snd_deinit();
-	goto on_error;
-    }
-
-    /* Init and register G.711 codec. */
-    cf = pj_pool_alloc (mm->pool, sizeof(pj_codec_factory));
-
-    status = g711_init_factory (cf, mm->pool);
-    if (status != 0) {
-	pj_snd_deinit();
-	return NULL;
-    }
-
-    status = pj_codec_mgr_register_factory (&mm->codec_mgr, cf);
-    if (status != 0) 
-	return NULL;
-
-    return mm;
-
-on_error:
-    pj_pool_release(pool);
-    return NULL;
-}
-
-/**
- * Get the codec manager instance.
- */
-PJ_DEF(pj_codec_mgr*) pj_med_mgr_get_codec_mgr (pj_med_mgr_t *mgr)
-{
-    return &mgr->codec_mgr;
-}
-
-/**
- * Deinitialize media manager.
- */
-PJ_DEF(pj_status_t) pj_med_mgr_destroy (pj_med_mgr_t *mgr)
-{
-    pj_snd_deinit();
-    pj_pool_release (mgr->pool);
-    return 0;
-}
-
-/**
- * Get pool factory.
- */
-PJ_DEF(pj_pool_factory*) pj_med_mgr_get_pool_factory (pj_med_mgr_t *mgr)
-{
-    return mgr->pf;
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjmedia/mediamgr.h>

+#include <pj/sock.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+

+PJ_DECL(pj_status_t) g711_init_factory (pj_codec_factory *factory, pj_pool_t *pool);

+PJ_DECL(pj_status_t) g711_deinit_factory (pj_codec_factory *factory);

+

+/** Concrete declaration of media manager. */

+struct pj_med_mgr_t

+{

+    /** Pool. */

+    pj_pool_t		 *pool;

+

+    /** Pool factory. */

+    pj_pool_factory	 *pf;

+

+    /** Codec manager. */

+    pj_codec_mgr	  codec_mgr;

+};

+

+/**

+ * Initialize and get the instance of media manager.

+ */

+PJ_DEF(pj_med_mgr_t*) pj_med_mgr_create ( pj_pool_factory *pf)

+{

+    pj_pool_t *pool;

+    pj_med_mgr_t *mm;

+    pj_codec_factory *cf;

+    pj_status_t status;

+

+    pool = pj_pool_create(pf, "mediamgr", 512, 512, NULL);

+    if (!pool)

+	return NULL;

+

+    mm = pj_pool_calloc(pool, 1, sizeof(struct pj_med_mgr_t));

+    mm->pool = pool;

+    mm->pf = pf;

+

+    /* Sound */

+    pj_snd_init(pf);

+

+    /* Init codec manager. */

+    status = pj_codec_mgr_init(&mm->codec_mgr);

+    if (status != 0) {

+	pj_snd_deinit();

+	goto on_error;

+    }

+

+    /* Init and register G.711 codec. */

+    cf = pj_pool_alloc (mm->pool, sizeof(pj_codec_factory));

+

+    status = g711_init_factory (cf, mm->pool);

+    if (status != 0) {

+	pj_snd_deinit();

+	return NULL;

+    }

+

+    status = pj_codec_mgr_register_factory (&mm->codec_mgr, cf);

+    if (status != 0) 

+	return NULL;

+

+    return mm;

+

+on_error:

+    pj_pool_release(pool);

+    return NULL;

+}

+

+/**

+ * Get the codec manager instance.

+ */

+PJ_DEF(pj_codec_mgr*) pj_med_mgr_get_codec_mgr (pj_med_mgr_t *mgr)

+{

+    return &mgr->codec_mgr;

+}

+

+/**

+ * Deinitialize media manager.

+ */

+PJ_DEF(pj_status_t) pj_med_mgr_destroy (pj_med_mgr_t *mgr)

+{

+    pj_snd_deinit();

+    pj_pool_release (mgr->pool);

+    return 0;

+}

+

+/**

+ * Get pool factory.

+ */

+PJ_DEF(pj_pool_factory*) pj_med_mgr_get_pool_factory (pj_med_mgr_t *mgr)

+{

+    return mgr->pf;

+}

diff --git a/pjmedia/src/pjmedia/mediamgr.h b/pjmedia/src/pjmedia/mediamgr.h
index df4ee63..834cf36 100644
--- a/pjmedia/src/pjmedia/mediamgr.h
+++ b/pjmedia/src/pjmedia/mediamgr.h
@@ -1,86 +1,107 @@
-/* $Id$
- *
- */
-
-#ifndef __PJMEDIA_MEDIAMGR_H__
-#define __PJMEDIA_MEDIAMGR_H__
-
-
-/**
- * @file mediamgr.h
- * @brief Media Manager.
- */
-/**
- * @defgroup PJMED_MGR Media Manager
- * @ingroup PJMEDIA
- * @{
- *
- * The media manager acts as placeholder for endpoint capabilities. Each 
- * media manager will have a codec manager to manage list of codecs installed
- * in the endpoint and a sound device factory.
- *
- * A reference to media manager instance is required when application wants
- * to create a media session (#pj_media_session_create or 
- * #pj_media_session_create_from_sdp).
- */
-
-#include <pjmedia/sound.h>
-#include <pjmedia/codec.h>
-
-
-PJ_BEGIN_DECL
-
-
-/** Opague declaration of media manager. */
-typedef struct pj_med_mgr_t pj_med_mgr_t;
-
-/**
- * Create an instance of media manager.
- *
- * @param pf		Pool factory.
- * @param conn_addr	Connection address to be used by this media manager.
- *
- * @return A new instance of media manager, or NULL if failed.
- */
-PJ_DECL(pj_med_mgr_t*) pj_med_mgr_create (pj_pool_factory *pf);
-
-/**
- * Destroy media manager instance.
- *
- * @param mgr		Media manager instance.
- *
- * @return zero on success.
- */
-PJ_DECL(pj_status_t) pj_med_mgr_destroy (pj_med_mgr_t *mgr);
-
-/**
- * Get pool factory of the media manager as specified when the media
- * manager was created.
- *
- * @param mgr		The media manager instance.
- *
- * @return Pool factory instance of the media manager.
- */
-PJ_DECL(pj_pool_factory*) pj_med_mgr_get_pool_factory (pj_med_mgr_t *mgr);
-
-/**
- * Get the codec manager instance.
- *
- * @param mgr		The media manager instance.
- *
- * @return The instance of codec manager.
- */
-PJ_DECL(pj_codec_mgr*) pj_med_mgr_get_codec_mgr (pj_med_mgr_t *mgr);
-
-
-
-PJ_END_DECL
-
-
-/**
- * @}
- */
-
-
-
-#endif	/* __PJMEDIA_MEDIAMGR_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJMEDIA_MEDIAMGR_H__

+#define __PJMEDIA_MEDIAMGR_H__

+

+

+/**

+ * @file mediamgr.h

+ * @brief Media Manager.

+ */

+/**

+ * @defgroup PJMED_MGR Media Manager

+ * @ingroup PJMEDIA

+ * @{

+ *

+ * The media manager acts as placeholder for endpoint capabilities. Each 

+ * media manager will have a codec manager to manage list of codecs installed

+ * in the endpoint and a sound device factory.

+ *

+ * A reference to media manager instance is required when application wants

+ * to create a media session (#pj_media_session_create or 

+ * #pj_media_session_create_from_sdp).

+ */

+

+#include <pjmedia/sound.h>

+#include <pjmedia/codec.h>

+

+

+PJ_BEGIN_DECL

+

+

+/** Opague declaration of media manager. */

+typedef struct pj_med_mgr_t pj_med_mgr_t;

+

+/**

+ * Create an instance of media manager.

+ *

+ * @param pf		Pool factory.

+ * @param conn_addr	Connection address to be used by this media manager.

+ *

+ * @return A new instance of media manager, or NULL if failed.

+ */

+PJ_DECL(pj_med_mgr_t*) pj_med_mgr_create (pj_pool_factory *pf);

+

+/**

+ * Destroy media manager instance.

+ *

+ * @param mgr		Media manager instance.

+ *

+ * @return zero on success.

+ */

+PJ_DECL(pj_status_t) pj_med_mgr_destroy (pj_med_mgr_t *mgr);

+

+/**

+ * Get pool factory of the media manager as specified when the media

+ * manager was created.

+ *

+ * @param mgr		The media manager instance.

+ *

+ * @return Pool factory instance of the media manager.

+ */

+PJ_DECL(pj_pool_factory*) pj_med_mgr_get_pool_factory (pj_med_mgr_t *mgr);

+

+/**

+ * Get the codec manager instance.

+ *

+ * @param mgr		The media manager instance.

+ *

+ * @return The instance of codec manager.

+ */

+PJ_DECL(pj_codec_mgr*) pj_med_mgr_get_codec_mgr (pj_med_mgr_t *mgr);

+

+

+

+PJ_END_DECL

+

+

+/**

+ * @}

+ */

+

+

+

+#endif	/* __PJMEDIA_MEDIAMGR_H__ */

diff --git a/pjmedia/src/pjmedia/nullsound.c b/pjmedia/src/pjmedia/nullsound.c
index 959b800..dc0b373 100644
--- a/pjmedia/src/pjmedia/nullsound.c
+++ b/pjmedia/src/pjmedia/nullsound.c
@@ -1,112 +1,133 @@
-/* $Id$
- *
- */
-#include <pjmedia/sound.h>
-
-/*
- * Null Factory Operations
- */
-static pj_status_t null_sound_init(void);
-static const char *null_sound_get_name(void);
-static pj_status_t null_sound_destroy(void);
-static pj_status_t null_sound_enum_devices(int *count, char *dev_names[]);
-static pj_status_t null_sound_create_dev(const char *dev_name, pj_snd_dev *dev);
-static pj_status_t null_sound_destroy_dev(pj_snd_dev *dev);
-
-
-/*
- * Null Device Operations
- */
-static pj_status_t null_sound_dev_open( pj_snd_dev *dev, pj_snd_role_t role );
-static pj_status_t null_sound_dev_close( pj_snd_dev *dev );
-static pj_status_t null_sound_dev_play( pj_snd_dev *dev );
-static pj_status_t null_sound_dev_record( pj_snd_dev *dev );
-
-
-static pj_snd_dev_factory null_sound_factory = 
-{
-    &null_sound_init,
-    &null_sound_get_name,
-    &null_sound_destroy,
-    &null_sound_enum_devices,
-    &null_sound_create_dev,
-    &null_sound_destroy_dev
-};
-
-static struct pj_snd_dev_op null_sound_dev_op = 
-{
-    &null_sound_dev_open,
-    &null_sound_dev_close,
-    &null_sound_dev_play,
-    &null_sound_dev_record
-};
-
-PJ_DEF(pj_snd_dev_factory*) pj_nullsound_get_factory()
-{
-    return &null_sound_factory;
-}
-
-static pj_status_t null_sound_init(void)
-{
-    return 0;
-}
-
-static const char *null_sound_get_name(void)
-{
-    return "nullsound";
-}
-
-static pj_status_t null_sound_destroy(void)
-{
-    return 0;
-}
-
-static pj_status_t null_sound_enum_devices(int *count, char *dev_names[])
-{
-    *count = 1;
-    dev_names[0] = "nullsound";
-    return 0;
-}
-
-static pj_status_t null_sound_create_dev(const char *dev_name, pj_snd_dev *dev)
-{
-    PJ_UNUSED_ARG(dev_name);
-    dev->op = &null_sound_dev_op;
-    return 0;
-}
-
-static pj_status_t null_sound_destroy_dev(pj_snd_dev *dev)
-{
-    PJ_UNUSED_ARG(dev);
-    return 0;
-}
-
-
-/*
- * Null Device Operations
- */
-static pj_status_t null_sound_dev_open( pj_snd_dev *dev, pj_snd_role_t role )
-{
-    PJ_UNUSED_ARG(dev);
-    PJ_UNUSED_ARG(role);
-    return 0;
-}
-
-static pj_status_t null_sound_dev_close( pj_snd_dev *dev )
-{
-    PJ_UNUSED_ARG(dev);
-    return 0;
-}
-
-static pj_status_t null_sound_dev_play( pj_snd_dev *dev )
-{
-    PJ_UNUSED_ARG(dev);
-    return 0;
-}
-
-static pj_status_t null_sound_dev_record( pj_snd_dev *dev )
-{
-    PJ_UNUSED_ARG(dev);
-    return 0;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjmedia/sound.h>

+

+/*

+ * Null Factory Operations

+ */

+static pj_status_t null_sound_init(void);

+static const char *null_sound_get_name(void);

+static pj_status_t null_sound_destroy(void);

+static pj_status_t null_sound_enum_devices(int *count, char *dev_names[]);

+static pj_status_t null_sound_create_dev(const char *dev_name, pj_snd_dev *dev);

+static pj_status_t null_sound_destroy_dev(pj_snd_dev *dev);

+

+

+/*

+ * Null Device Operations

+ */

+static pj_status_t null_sound_dev_open( pj_snd_dev *dev, pj_snd_role_t role );

+static pj_status_t null_sound_dev_close( pj_snd_dev *dev );

+static pj_status_t null_sound_dev_play( pj_snd_dev *dev );

+static pj_status_t null_sound_dev_record( pj_snd_dev *dev );

+

+

+static pj_snd_dev_factory null_sound_factory = 

+{

+    &null_sound_init,

+    &null_sound_get_name,

+    &null_sound_destroy,

+    &null_sound_enum_devices,

+    &null_sound_create_dev,

+    &null_sound_destroy_dev

+};

+

+static struct pj_snd_dev_op null_sound_dev_op = 

+{

+    &null_sound_dev_open,

+    &null_sound_dev_close,

+    &null_sound_dev_play,

+    &null_sound_dev_record

+};

+

+PJ_DEF(pj_snd_dev_factory*) pj_nullsound_get_factory()

+{

+    return &null_sound_factory;

+}

+

+static pj_status_t null_sound_init(void)

+{

+    return 0;

+}

+

+static const char *null_sound_get_name(void)

+{

+    return "nullsound";

+}

+

+static pj_status_t null_sound_destroy(void)

+{

+    return 0;

+}

+

+static pj_status_t null_sound_enum_devices(int *count, char *dev_names[])

+{

+    *count = 1;

+    dev_names[0] = "nullsound";

+    return 0;

+}

+

+static pj_status_t null_sound_create_dev(const char *dev_name, pj_snd_dev *dev)

+{

+    PJ_UNUSED_ARG(dev_name);

+    dev->op = &null_sound_dev_op;

+    return 0;

+}

+

+static pj_status_t null_sound_destroy_dev(pj_snd_dev *dev)

+{

+    PJ_UNUSED_ARG(dev);

+    return 0;

+}

+

+

+/*

+ * Null Device Operations

+ */

+static pj_status_t null_sound_dev_open( pj_snd_dev *dev, pj_snd_role_t role )

+{

+    PJ_UNUSED_ARG(dev);

+    PJ_UNUSED_ARG(role);

+    return 0;

+}

+

+static pj_status_t null_sound_dev_close( pj_snd_dev *dev )

+{

+    PJ_UNUSED_ARG(dev);

+    return 0;

+}

+

+static pj_status_t null_sound_dev_play( pj_snd_dev *dev )

+{

+    PJ_UNUSED_ARG(dev);

+    return 0;

+}

+

+static pj_status_t null_sound_dev_record( pj_snd_dev *dev )

+{

+    PJ_UNUSED_ARG(dev);

+    return 0;

+}

+

diff --git a/pjmedia/src/pjmedia/pasound.c b/pjmedia/src/pjmedia/pasound.c
index 60065b3..9eb2f1a 100644
--- a/pjmedia/src/pjmedia/pasound.c
+++ b/pjmedia/src/pjmedia/pasound.c
@@ -1,389 +1,410 @@
-/* $Id$
- *
- */
-#include <pjmedia/sound.h>
-#include <pj/string.h>
-#include <pj/os.h>
-#include <pj/log.h>
-#include <portaudio.h>
-
-#define THIS_FILE	"pasound.c"
-
-static struct snd_mgr
-{
-    pj_pool_factory *factory;
-} snd_mgr;
-
-struct pj_snd_stream
-{
-    pj_pool_t	    *pool;
-    PaStream	    *stream;
-    int		     dev_index;
-    int		     bytes_per_sample;
-    pj_uint32_t	     samples_per_sec;
-    pj_uint32_t	     timestamp;
-    pj_uint32_t	     underflow;
-    pj_uint32_t	     overflow;
-    void	    *user_data;
-    pj_snd_rec_cb    rec_cb;
-    pj_snd_play_cb   play_cb;
-    pj_bool_t	     quit_flag;
-    pj_bool_t	     thread_has_exited;
-    pj_bool_t	     thread_initialized;
-    pj_thread_desc   thread_desc;
-    pj_thread_t	    *thread;
-};
-
-
-static int PaRecorderCallback(const void *input, 
-			      void *output,
-			      unsigned long frameCount,
-			      const PaStreamCallbackTimeInfo* timeInfo,
-			      PaStreamCallbackFlags statusFlags,
-			      void *userData )
-{
-    pj_snd_stream *stream = userData;
-    pj_status_t status;
-
-    PJ_UNUSED_ARG(output)
-    PJ_UNUSED_ARG(timeInfo)
-
-    if (stream->quit_flag)
-	goto on_break;
-
-    if (stream->thread_initialized == 0) {
-	stream->thread = pj_thread_register("pa_rec", stream->thread_desc);
-	stream->thread_initialized = 1;
-    }
-
-    if (statusFlags & paInputUnderflow)
-	++stream->underflow;
-    if (statusFlags & paInputOverflow)
-	++stream->overflow;
-
-    stream->timestamp += frameCount;
-
-    status = (*stream->rec_cb)(stream->user_data, stream->timestamp, 
-			       input, frameCount * stream->bytes_per_sample);
-    
-    if (status==0) 
-	return paContinue;
-
-on_break:
-    stream->thread_has_exited = 1;
-    return paAbort;
-}
-
-static int PaPlayerCallback( const void *input, 
-			     void *output,
-			     unsigned long frameCount,
-			     const PaStreamCallbackTimeInfo* timeInfo,
-			     PaStreamCallbackFlags statusFlags,
-			     void *userData )
-{
-    pj_snd_stream *stream = userData;
-    pj_status_t status;
-    unsigned size = frameCount * stream->bytes_per_sample;
-
-    PJ_UNUSED_ARG(input)
-    PJ_UNUSED_ARG(timeInfo)
-
-    if (stream->quit_flag)
-	goto on_break;
-
-    if (stream->thread_initialized == 0) {
-	stream->thread = pj_thread_register("pa_rec", stream->thread_desc);
-	stream->thread_initialized = 1;
-    }
-
-    if (statusFlags & paInputUnderflow)
-	++stream->underflow;
-    if (statusFlags & paInputOverflow)
-	++stream->overflow;
-
-    stream->timestamp += frameCount;
-
-    status = (*stream->play_cb)(stream->user_data, stream->timestamp, 
-			        output, size);
-    
-    if (status==0) 
-	return paContinue;
-
-on_break:
-    stream->thread_has_exited = 1;
-    return paAbort;
-}
-
-
-/*
- * Init sound library.
- */
-PJ_DEF(pj_status_t) pj_snd_init(pj_pool_factory *factory)
-{
-    int err;
-
-    snd_mgr.factory = factory;
-    err = Pa_Initialize();
-
-    PJ_LOG(4,(THIS_FILE, "PortAudio sound library initialized, status=%d", err));
-
-    return err;
-}
-
-
-/*
- * Get device count.
- */
-PJ_DEF(int) pj_snd_get_dev_count(void)
-{
-    return Pa_GetDeviceCount();
-}
-
-
-/*
- * Get device info.
- */
-PJ_DEF(const pj_snd_dev_info*) pj_snd_get_dev_info(unsigned index)
-{
-    static pj_snd_dev_info info;
-    const PaDeviceInfo *pa_info;
-
-    pa_info = Pa_GetDeviceInfo(index);
-    if (!pa_info)
-	return NULL;
-
-    pj_memset(&info, 0, sizeof(info));
-    strncpy(info.name, pa_info->name, sizeof(info.name));
-    info.name[sizeof(info.name)-1] = '\0';
-    info.input_count = pa_info->maxInputChannels;
-    info.output_count = pa_info->maxOutputChannels;
-    info.default_samples_per_sec = (unsigned)pa_info->defaultSampleRate;
-
-    return &info;
-}
-
-
-/*
- * Open stream.
- */
-PJ_DEF(pj_snd_stream*) pj_snd_open_recorder( int index,
-					     const pj_snd_stream_info *param,
-					     pj_snd_rec_cb rec_cb,
-					     void *user_data)
-{
-    pj_pool_t *pool;
-    pj_snd_stream *stream;
-    PaStreamParameters inputParam;
-    int sampleFormat;
-    const PaDeviceInfo *paDevInfo = NULL;
-    PaError err;
-
-    if (index == -1) {
-	int count = Pa_GetDeviceCount();
-	for (index=0; index<count; ++index) {
-	    paDevInfo = Pa_GetDeviceInfo(index);
-	    if (paDevInfo->maxInputChannels > 0)
-		break;
-	}
-	if (index == count) {
-	    PJ_LOG(2,(THIS_FILE, "Error: unable to find recorder device"));
-	    return NULL;
-	}
-    } else {
-	paDevInfo = Pa_GetDeviceInfo(index);
-	if (!paDevInfo)
-	    return NULL;
-    }
-
-    if (param->bits_per_sample == 8)
-	sampleFormat = paUInt8;
-    else if (param->bits_per_sample == 16)
-	sampleFormat = paInt16;
-    else if (param->bits_per_sample == 32)
-	sampleFormat = paInt32;
-    else
-	return NULL;
-    
-    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
-    if (!pool)
-	return NULL;
-
-    stream = pj_pool_calloc(pool, 1, sizeof(*stream));
-    stream->pool = pool;
-    stream->user_data = user_data;
-    stream->dev_index = index;
-    stream->samples_per_sec = param->samples_per_frame;
-    stream->bytes_per_sample = param->bits_per_sample / 8;
-    stream->rec_cb = rec_cb;
-
-    pj_memset(&inputParam, 0, sizeof(inputParam));
-    inputParam.device = index;
-    inputParam.channelCount = 1;
-    inputParam.hostApiSpecificStreamInfo = NULL;
-    inputParam.sampleFormat = sampleFormat;
-    inputParam.suggestedLatency = paDevInfo->defaultLowInputLatency;
-
-    err = Pa_OpenStream( &stream->stream, &inputParam, NULL,
-			 param->samples_per_sec, 
-			 param->samples_per_frame * param->frames_per_packet, 
-			 0,
-			 &PaRecorderCallback, stream );
-    if (err != paNoError) {
-	pj_pool_release(pool);
-	PJ_LOG(2,(THIS_FILE, "Error opening player: %s", Pa_GetErrorText(err)));
-	return NULL;
-    }
-
-    PJ_LOG(4,(THIS_FILE, "%s opening device %s for recording, sample rate=%d, "
-			 "%d bits per sample, %d samples per buffer",
-			 (err==0 ? "Success" : "Error"),
-			 paDevInfo->name, param->samples_per_sec, 
-			 param->bits_per_sample,
-			 param->samples_per_frame * param->frames_per_packet));
-
-    return stream;
-}
-
-
-PJ_DEF(pj_snd_stream*) pj_snd_open_player(int index,
-					   const pj_snd_stream_info *param,
-					   pj_snd_play_cb play_cb,
-					   void *user_data)
-{
-    pj_pool_t *pool;
-    pj_snd_stream *stream;
-    PaStreamParameters outputParam;
-    int sampleFormat;
-    const PaDeviceInfo *paDevInfo = NULL;
-    PaError err;
-
-    if (index == -1) {
-	int count = Pa_GetDeviceCount();
-	for (index=0; index<count; ++index) {
-	    paDevInfo = Pa_GetDeviceInfo(index);
-	    if (paDevInfo->maxOutputChannels > 0)
-		break;
-	}
-	if (index == count) {
-	    PJ_LOG(2,(THIS_FILE, "Error: unable to find player device"));
-	    return NULL;
-	}
-    } else {
-	paDevInfo = Pa_GetDeviceInfo(index);
-	if (!paDevInfo)
-	    return NULL;
-    }
-
-    if (param->bits_per_sample == 8)
-	sampleFormat = paUInt8;
-    else if (param->bits_per_sample == 16)
-	sampleFormat = paInt16;
-    else if (param->bits_per_sample == 32)
-	sampleFormat = paInt32;
-    else
-	return NULL;
-    
-    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);
-    if (!pool)
-	return NULL;
-
-    stream = pj_pool_calloc(pool, 1, sizeof(*stream));
-    stream->pool = pool;
-    stream->user_data = user_data;
-    stream->samples_per_sec = param->samples_per_frame;
-    stream->bytes_per_sample = param->bits_per_sample / 8;
-    stream->dev_index = index;
-    stream->play_cb = play_cb;
-
-    pj_memset(&outputParam, 0, sizeof(outputParam));
-    outputParam.device = index;
-    outputParam.channelCount = 1;
-    outputParam.hostApiSpecificStreamInfo = NULL;
-    outputParam.sampleFormat = sampleFormat;
-    outputParam.suggestedLatency = paDevInfo->defaultLowInputLatency;
-
-    err = Pa_OpenStream( &stream->stream, NULL, &outputParam,
-			 param->samples_per_sec, 
-			 param->samples_per_frame * param->frames_per_packet, 
-			 0,
-			 &PaPlayerCallback, stream );
-    if (err != paNoError) {
-	pj_pool_release(pool);
-	PJ_LOG(2,(THIS_FILE, "Error opening player: %s", Pa_GetErrorText(err)));
-	return NULL;
-    }
-
-    PJ_LOG(4,(THIS_FILE, "%s opening device %s for playing, sample rate=%d, "
-			 "%d bits per sample, %d samples per buffer",
-			 (err==0 ? "Success" : "Error"),
-			 paDevInfo->name, param->samples_per_sec, 
-		 	 param->bits_per_sample,
-			 param->samples_per_frame * param->frames_per_packet));
-
-    return stream;
-}
-
-
-/*
- * Start stream.
- */
-PJ_DEF(pj_status_t) pj_snd_stream_start(pj_snd_stream *stream)
-{
-    PJ_LOG(4,(THIS_FILE, "Starting stream.."));
-    return Pa_StartStream(stream->stream);
-}
-
-/*
- * Stop stream.
- */
-PJ_DEF(pj_status_t) pj_snd_stream_stop(pj_snd_stream *stream)
-{
-    int i, err;
-
-    stream->quit_flag = 1;
-    for (i=0; !stream->thread_has_exited && i<100; ++i)
-	pj_thread_sleep(10);
-
-    pj_thread_sleep(1);
-
-    PJ_LOG(4,(THIS_FILE, "Stopping stream.."));
-
-    err = Pa_StopStream(stream->stream);
-    return err;
-}
-
-/*
- * Destroy stream.
- */
-PJ_DEF(pj_status_t) pj_snd_stream_close(pj_snd_stream *stream)
-{
-    int i, err;
-    const PaDeviceInfo *paDevInfo;
-
-    stream->quit_flag = 1;
-    for (i=0; !stream->thread_has_exited && i<100; ++i)
-	pj_thread_sleep(10);
-
-    pj_thread_sleep(1);
-
-    paDevInfo = Pa_GetDeviceInfo(stream->dev_index);
-
-    PJ_LOG(4,(THIS_FILE, "Closing %s: %lu underflow, %lu overflow",
-			 paDevInfo->name,
-			 stream->underflow, stream->overflow));
-
-    err = Pa_CloseStream(stream->stream);
-    pj_pool_release(stream->pool);
-    return err;
-}
-
-/*
- * Deinitialize sound library.
- */
-PJ_DEF(pj_status_t) pj_snd_deinit(void)
-{
-    PJ_LOG(4,(THIS_FILE, "PortAudio sound library shutting down.."));
-
-    return Pa_Terminate();
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjmedia/sound.h>

+#include <pj/string.h>

+#include <pj/os.h>

+#include <pj/log.h>

+#include <portaudio.h>

+

+#define THIS_FILE	"pasound.c"

+

+static struct snd_mgr

+{

+    pj_pool_factory *factory;

+} snd_mgr;

+

+struct pj_snd_stream

+{

+    pj_pool_t	    *pool;

+    PaStream	    *stream;

+    int		     dev_index;

+    int		     bytes_per_sample;

+    pj_uint32_t	     samples_per_sec;

+    pj_uint32_t	     timestamp;

+    pj_uint32_t	     underflow;

+    pj_uint32_t	     overflow;

+    void	    *user_data;

+    pj_snd_rec_cb    rec_cb;

+    pj_snd_play_cb   play_cb;

+    pj_bool_t	     quit_flag;

+    pj_bool_t	     thread_has_exited;

+    pj_bool_t	     thread_initialized;

+    pj_thread_desc   thread_desc;

+    pj_thread_t	    *thread;

+};

+

+

+static int PaRecorderCallback(const void *input, 

+			      void *output,

+			      unsigned long frameCount,

+			      const PaStreamCallbackTimeInfo* timeInfo,

+			      PaStreamCallbackFlags statusFlags,

+			      void *userData )

+{

+    pj_snd_stream *stream = userData;

+    pj_status_t status;

+

+    PJ_UNUSED_ARG(output)

+    PJ_UNUSED_ARG(timeInfo)

+

+    if (stream->quit_flag)

+	goto on_break;

+

+    if (stream->thread_initialized == 0) {

+	stream->thread = pj_thread_register("pa_rec", stream->thread_desc);

+	stream->thread_initialized = 1;

+    }

+

+    if (statusFlags & paInputUnderflow)

+	++stream->underflow;

+    if (statusFlags & paInputOverflow)

+	++stream->overflow;

+

+    stream->timestamp += frameCount;

+

+    status = (*stream->rec_cb)(stream->user_data, stream->timestamp, 

+			       input, frameCount * stream->bytes_per_sample);

+    

+    if (status==0) 

+	return paContinue;

+

+on_break:

+    stream->thread_has_exited = 1;

+    return paAbort;

+}

+

+static int PaPlayerCallback( const void *input, 

+			     void *output,

+			     unsigned long frameCount,

+			     const PaStreamCallbackTimeInfo* timeInfo,

+			     PaStreamCallbackFlags statusFlags,

+			     void *userData )

+{

+    pj_snd_stream *stream = userData;

+    pj_status_t status;

+    unsigned size = frameCount * stream->bytes_per_sample;

+

+    PJ_UNUSED_ARG(input)

+    PJ_UNUSED_ARG(timeInfo)

+

+    if (stream->quit_flag)

+	goto on_break;

+

+    if (stream->thread_initialized == 0) {

+	stream->thread = pj_thread_register("pa_rec", stream->thread_desc);

+	stream->thread_initialized = 1;

+    }

+

+    if (statusFlags & paInputUnderflow)

+	++stream->underflow;

+    if (statusFlags & paInputOverflow)

+	++stream->overflow;

+

+    stream->timestamp += frameCount;

+

+    status = (*stream->play_cb)(stream->user_data, stream->timestamp, 

+			        output, size);

+    

+    if (status==0) 

+	return paContinue;

+

+on_break:

+    stream->thread_has_exited = 1;

+    return paAbort;

+}

+

+

+/*

+ * Init sound library.

+ */

+PJ_DEF(pj_status_t) pj_snd_init(pj_pool_factory *factory)

+{

+    int err;

+

+    snd_mgr.factory = factory;

+    err = Pa_Initialize();

+

+    PJ_LOG(4,(THIS_FILE, "PortAudio sound library initialized, status=%d", err));

+

+    return err;

+}

+

+

+/*

+ * Get device count.

+ */

+PJ_DEF(int) pj_snd_get_dev_count(void)

+{

+    return Pa_GetDeviceCount();

+}

+

+

+/*

+ * Get device info.

+ */

+PJ_DEF(const pj_snd_dev_info*) pj_snd_get_dev_info(unsigned index)

+{

+    static pj_snd_dev_info info;

+    const PaDeviceInfo *pa_info;

+

+    pa_info = Pa_GetDeviceInfo(index);

+    if (!pa_info)

+	return NULL;

+

+    pj_memset(&info, 0, sizeof(info));

+    strncpy(info.name, pa_info->name, sizeof(info.name));

+    info.name[sizeof(info.name)-1] = '\0';

+    info.input_count = pa_info->maxInputChannels;

+    info.output_count = pa_info->maxOutputChannels;

+    info.default_samples_per_sec = (unsigned)pa_info->defaultSampleRate;

+

+    return &info;

+}

+

+

+/*

+ * Open stream.

+ */

+PJ_DEF(pj_snd_stream*) pj_snd_open_recorder( int index,

+					     const pj_snd_stream_info *param,

+					     pj_snd_rec_cb rec_cb,

+					     void *user_data)

+{

+    pj_pool_t *pool;

+    pj_snd_stream *stream;

+    PaStreamParameters inputParam;

+    int sampleFormat;

+    const PaDeviceInfo *paDevInfo = NULL;

+    PaError err;

+

+    if (index == -1) {

+	int count = Pa_GetDeviceCount();

+	for (index=0; index<count; ++index) {

+	    paDevInfo = Pa_GetDeviceInfo(index);

+	    if (paDevInfo->maxInputChannels > 0)

+		break;

+	}

+	if (index == count) {

+	    PJ_LOG(2,(THIS_FILE, "Error: unable to find recorder device"));

+	    return NULL;

+	}

+    } else {

+	paDevInfo = Pa_GetDeviceInfo(index);

+	if (!paDevInfo)

+	    return NULL;

+    }

+

+    if (param->bits_per_sample == 8)

+	sampleFormat = paUInt8;

+    else if (param->bits_per_sample == 16)

+	sampleFormat = paInt16;

+    else if (param->bits_per_sample == 32)

+	sampleFormat = paInt32;

+    else

+	return NULL;

+    

+    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);

+    if (!pool)

+	return NULL;

+

+    stream = pj_pool_calloc(pool, 1, sizeof(*stream));

+    stream->pool = pool;

+    stream->user_data = user_data;

+    stream->dev_index = index;

+    stream->samples_per_sec = param->samples_per_frame;

+    stream->bytes_per_sample = param->bits_per_sample / 8;

+    stream->rec_cb = rec_cb;

+

+    pj_memset(&inputParam, 0, sizeof(inputParam));

+    inputParam.device = index;

+    inputParam.channelCount = 1;

+    inputParam.hostApiSpecificStreamInfo = NULL;

+    inputParam.sampleFormat = sampleFormat;

+    inputParam.suggestedLatency = paDevInfo->defaultLowInputLatency;

+

+    err = Pa_OpenStream( &stream->stream, &inputParam, NULL,

+			 param->samples_per_sec, 

+			 param->samples_per_frame * param->frames_per_packet, 

+			 0,

+			 &PaRecorderCallback, stream );

+    if (err != paNoError) {

+	pj_pool_release(pool);

+	PJ_LOG(2,(THIS_FILE, "Error opening player: %s", Pa_GetErrorText(err)));

+	return NULL;

+    }

+

+    PJ_LOG(4,(THIS_FILE, "%s opening device %s for recording, sample rate=%d, "

+			 "%d bits per sample, %d samples per buffer",

+			 (err==0 ? "Success" : "Error"),

+			 paDevInfo->name, param->samples_per_sec, 

+			 param->bits_per_sample,

+			 param->samples_per_frame * param->frames_per_packet));

+

+    return stream;

+}

+

+

+PJ_DEF(pj_snd_stream*) pj_snd_open_player(int index,

+					   const pj_snd_stream_info *param,

+					   pj_snd_play_cb play_cb,

+					   void *user_data)

+{

+    pj_pool_t *pool;

+    pj_snd_stream *stream;

+    PaStreamParameters outputParam;

+    int sampleFormat;

+    const PaDeviceInfo *paDevInfo = NULL;

+    PaError err;

+

+    if (index == -1) {

+	int count = Pa_GetDeviceCount();

+	for (index=0; index<count; ++index) {

+	    paDevInfo = Pa_GetDeviceInfo(index);

+	    if (paDevInfo->maxOutputChannels > 0)

+		break;

+	}

+	if (index == count) {

+	    PJ_LOG(2,(THIS_FILE, "Error: unable to find player device"));

+	    return NULL;

+	}

+    } else {

+	paDevInfo = Pa_GetDeviceInfo(index);

+	if (!paDevInfo)

+	    return NULL;

+    }

+

+    if (param->bits_per_sample == 8)

+	sampleFormat = paUInt8;

+    else if (param->bits_per_sample == 16)

+	sampleFormat = paInt16;

+    else if (param->bits_per_sample == 32)

+	sampleFormat = paInt32;

+    else

+	return NULL;

+    

+    pool = pj_pool_create( snd_mgr.factory, "sndstream", 1024, 1024, NULL);

+    if (!pool)

+	return NULL;

+

+    stream = pj_pool_calloc(pool, 1, sizeof(*stream));

+    stream->pool = pool;

+    stream->user_data = user_data;

+    stream->samples_per_sec = param->samples_per_frame;

+    stream->bytes_per_sample = param->bits_per_sample / 8;

+    stream->dev_index = index;

+    stream->play_cb = play_cb;

+

+    pj_memset(&outputParam, 0, sizeof(outputParam));

+    outputParam.device = index;

+    outputParam.channelCount = 1;

+    outputParam.hostApiSpecificStreamInfo = NULL;

+    outputParam.sampleFormat = sampleFormat;

+    outputParam.suggestedLatency = paDevInfo->defaultLowInputLatency;

+

+    err = Pa_OpenStream( &stream->stream, NULL, &outputParam,

+			 param->samples_per_sec, 

+			 param->samples_per_frame * param->frames_per_packet, 

+			 0,

+			 &PaPlayerCallback, stream );

+    if (err != paNoError) {

+	pj_pool_release(pool);

+	PJ_LOG(2,(THIS_FILE, "Error opening player: %s", Pa_GetErrorText(err)));

+	return NULL;

+    }

+

+    PJ_LOG(4,(THIS_FILE, "%s opening device %s for playing, sample rate=%d, "

+			 "%d bits per sample, %d samples per buffer",

+			 (err==0 ? "Success" : "Error"),

+			 paDevInfo->name, param->samples_per_sec, 

+		 	 param->bits_per_sample,

+			 param->samples_per_frame * param->frames_per_packet));

+

+    return stream;

+}

+

+

+/*

+ * Start stream.

+ */

+PJ_DEF(pj_status_t) pj_snd_stream_start(pj_snd_stream *stream)

+{

+    PJ_LOG(4,(THIS_FILE, "Starting stream.."));

+    return Pa_StartStream(stream->stream);

+}

+

+/*

+ * Stop stream.

+ */

+PJ_DEF(pj_status_t) pj_snd_stream_stop(pj_snd_stream *stream)

+{

+    int i, err;

+

+    stream->quit_flag = 1;

+    for (i=0; !stream->thread_has_exited && i<100; ++i)

+	pj_thread_sleep(10);

+

+    pj_thread_sleep(1);

+

+    PJ_LOG(4,(THIS_FILE, "Stopping stream.."));

+

+    err = Pa_StopStream(stream->stream);

+    return err;

+}

+

+/*

+ * Destroy stream.

+ */

+PJ_DEF(pj_status_t) pj_snd_stream_close(pj_snd_stream *stream)

+{

+    int i, err;

+    const PaDeviceInfo *paDevInfo;

+

+    stream->quit_flag = 1;

+    for (i=0; !stream->thread_has_exited && i<100; ++i)

+	pj_thread_sleep(10);

+

+    pj_thread_sleep(1);

+

+    paDevInfo = Pa_GetDeviceInfo(stream->dev_index);

+

+    PJ_LOG(4,(THIS_FILE, "Closing %s: %lu underflow, %lu overflow",

+			 paDevInfo->name,

+			 stream->underflow, stream->overflow));

+

+    err = Pa_CloseStream(stream->stream);

+    pj_pool_release(stream->pool);

+    return err;

+}

+

+/*

+ * Deinitialize sound library.

+ */

+PJ_DEF(pj_status_t) pj_snd_deinit(void)

+{

+    PJ_LOG(4,(THIS_FILE, "PortAudio sound library shutting down.."));

+

+    return Pa_Terminate();

+}

+

diff --git a/pjmedia/src/pjmedia/portaudio/dsound_wrapper.c b/pjmedia/src/pjmedia/portaudio/dsound_wrapper.c
index 207d287..782e824 100644
--- a/pjmedia/src/pjmedia/portaudio/dsound_wrapper.c
+++ b/pjmedia/src/pjmedia/portaudio/dsound_wrapper.c
@@ -1,616 +1,637 @@
-/*
- * $Id: dsound_wrapper.c,v 1.1.1.1.2.11 2003/09/07 13:04:53 rossbencina Exp $
- * Simplified DirectSound interface.
- *
- * Author: Phil Burk & Robert Marsanyi
- *
- * PortAudio Portable Real-Time Audio Library
- * For more information see: http://www.softsynth.com/portaudio/
- * DirectSound Implementation
- * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "dsound_wrapper.h"
-#include "pa_trace.h"
-
-/*
-    Rather than linking with dxguid.a or using "#define INITGUID" to force a
-    header file to instantiate the required GUID(s), we define them directly
-    below.
-*/
-#include <initguid.h> // needed for the DEFINE_GUID macro
-DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
-
-
-/************************************************************************************/
-DSoundEntryPoints dswDSoundEntryPoints = { 0, 0, 0, 0, 0, 0, 0 };
-/************************************************************************************/
-static HRESULT WINAPI DummyDirectSoundCreate(LPGUID lpcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter)
-{
-    (void)lpcGuidDevice; /* unused parameter */
-    (void)ppDS; /* unused parameter */
-    (void)pUnkOuter; /* unused parameter */
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundEnumerateW(LPDSENUMCALLBACKW lpDSEnumCallback, LPVOID lpContext)
-{
-    (void)lpDSEnumCallback; /* unused parameter */
-    (void)lpContext; /* unused parameter */
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundEnumerateA(LPDSENUMCALLBACKA lpDSEnumCallback, LPVOID lpContext)
-{
-    (void)lpDSEnumCallback; /* unused parameter */
-    (void)lpContext; /* unused parameter */
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundCaptureCreate(LPGUID lpcGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter)
-{
-    (void)lpcGUID; /* unused parameter */
-    (void)lplpDSC; /* unused parameter */
-    (void)pUnkOuter; /* unused parameter */
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW lpDSCEnumCallback, LPVOID lpContext)
-{
-    (void)lpDSCEnumCallback; /* unused parameter */
-    (void)lpContext; /* unused parameter */
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA lpDSCEnumCallback, LPVOID lpContext)
-{
-    (void)lpDSCEnumCallback; /* unused parameter */
-    (void)lpContext; /* unused parameter */
-    return E_NOTIMPL;
-}
-/************************************************************************************/
-void DSW_InitializeDSoundEntryPoints(void)
-{
-    dswDSoundEntryPoints.hInstance_ = LoadLibrary("dsound.dll");
-    if( dswDSoundEntryPoints.hInstance_ != NULL )
-    {
-        dswDSoundEntryPoints.DirectSoundCreate =
-                (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))
-                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCreate" );
-        if( dswDSoundEntryPoints.DirectSoundCreate == NULL )
-            dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
-
-        dswDSoundEntryPoints.DirectSoundEnumerateW =
-                (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
-                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundEnumerateW" );
-        if( dswDSoundEntryPoints.DirectSoundEnumerateW == NULL )
-            dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
-
-        dswDSoundEntryPoints.DirectSoundEnumerateA =
-                (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
-                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundEnumerateA" );
-        if( dswDSoundEntryPoints.DirectSoundEnumerateA == NULL )
-            dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
-
-        dswDSoundEntryPoints.DirectSoundCaptureCreate =
-                (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN))
-                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureCreate" );
-        if( dswDSoundEntryPoints.DirectSoundCaptureCreate == NULL )
-            dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
-
-        dswDSoundEntryPoints.DirectSoundCaptureEnumerateW =
-                (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
-                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateW" );
-        if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateW == NULL )
-            dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
-
-        dswDSoundEntryPoints.DirectSoundCaptureEnumerateA =
-                (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
-                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateA" );
-        if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateA == NULL )
-            dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
-    }
-    else
-    {
-        /* initialize with dummy entry points to make live easy when ds isn't present */
-        dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
-        dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
-        dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
-        dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
-        dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
-        dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
-    }
-}
-/************************************************************************************/
-void DSW_TerminateDSoundEntryPoints(void)
-{
-    if( dswDSoundEntryPoints.hInstance_ != NULL )
-    {
-        FreeLibrary( dswDSoundEntryPoints.hInstance_ );
-        dswDSoundEntryPoints.hInstance_ = NULL;
-        /* ensure that we crash reliably if the entry points arent initialised */
-        dswDSoundEntryPoints.DirectSoundCreate = 0;
-        dswDSoundEntryPoints.DirectSoundEnumerateW = 0;
-        dswDSoundEntryPoints.DirectSoundEnumerateA = 0;
-        dswDSoundEntryPoints.DirectSoundCaptureCreate = 0;
-        dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = 0;
-        dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = 0;
-    }
-}
-/************************************************************************************/
-void DSW_Term( DSoundWrapper *dsw )
-{
-    // Cleanup the sound buffers
-    if (dsw->dsw_OutputBuffer)
-    {
-        IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
-        IDirectSoundBuffer_Release( dsw->dsw_OutputBuffer );
-        dsw->dsw_OutputBuffer = NULL;
-    }
-
-    if (dsw->dsw_InputBuffer)
-    {
-        IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
-        IDirectSoundCaptureBuffer_Release( dsw->dsw_InputBuffer );
-        dsw->dsw_InputBuffer = NULL;
-    }
-
-    if (dsw->dsw_pDirectSoundCapture)
-    {
-        IDirectSoundCapture_Release( dsw->dsw_pDirectSoundCapture );
-        dsw->dsw_pDirectSoundCapture = NULL;
-    }
-
-    if (dsw->dsw_pDirectSound)
-    {
-        IDirectSound_Release( dsw->dsw_pDirectSound );
-        dsw->dsw_pDirectSound = NULL;
-    }
-}
-/************************************************************************************/
-HRESULT DSW_Init( DSoundWrapper *dsw )
-{
-    memset( dsw, 0, sizeof(DSoundWrapper) );
-    return 0;
-}
-/************************************************************************************/
-HRESULT DSW_InitOutputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
-{
-    // Create the DS object
-    HRESULT hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &dsw->dsw_pDirectSound, NULL );
-    if( hr != DS_OK ) return hr;
-    return hr;
-}
-
-/************************************************************************************/
-HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer )
-{
-    DWORD          dwDataLen;
-    DWORD          playCursor;
-    HRESULT        result;
-    LPDIRECTSOUNDBUFFER pPrimaryBuffer;
-    HWND           hWnd;
-    HRESULT        hr;
-    WAVEFORMATEX   wfFormat;
-    DSBUFFERDESC   primaryDesc;
-    DSBUFFERDESC   secondaryDesc;
-    unsigned char* pDSBuffData;
-    LARGE_INTEGER  counterFrequency;
-
-    dsw->dsw_OutputSize = bytesPerBuffer;
-    dsw->dsw_OutputRunning = FALSE;
-    dsw->dsw_OutputUnderflows = 0;
-    dsw->dsw_FramesWritten = 0;
-    dsw->dsw_BytesPerOutputFrame = nChannels * sizeof(short);
-
-    // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the
-    // applications's window. Also if that window is closed before the Buffer is closed
-    // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.)
-    // So we will use GetDesktopWindow() which was suggested by Miller Puckette.
-    // hWnd = GetForegroundWindow();
-    //
-    //  FIXME: The example code I have on the net creates a hidden window that
-    //      is managed by our code - I think we should do that - one hidden
-    //      window for the whole of Pa_DS
-    //
-    hWnd = GetDesktopWindow();
-
-    // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz.
-    // Exclusize also prevents unexpected sounds from other apps during a performance.
-    if ((hr = IDirectSound_SetCooperativeLevel( dsw->dsw_pDirectSound,
-              hWnd, DSSCL_EXCLUSIVE)) != DS_OK)
-    {
-        return hr;
-    }
-
-    // -----------------------------------------------------------------------
-    // Create primary buffer and set format just so we can specify our custom format.
-    // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz.
-    // Setup the primary buffer description
-    ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC));
-    primaryDesc.dwSize        = sizeof(DSBUFFERDESC);
-    primaryDesc.dwFlags       = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth
-    primaryDesc.dwBufferBytes = 0;
-    primaryDesc.lpwfxFormat   = NULL;
-    // Create the buffer
-    if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
-                  &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result;
-    // Define the buffer format
-    wfFormat.wFormatTag = WAVE_FORMAT_PCM;
-    wfFormat.nChannels = nChannels;
-    wfFormat.nSamplesPerSec = nFrameRate;
-    wfFormat.wBitsPerSample = 8 * sizeof(short);
-    wfFormat.nBlockAlign = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
-    wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
-    wfFormat.cbSize = 0;  /* No extended format info. */
-    // Set the primary buffer's format
-    if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result;
-
-    // ----------------------------------------------------------------------
-    // Setup the secondary buffer description
-    ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));
-    secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
-    secondaryDesc.dwFlags =  DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
-    secondaryDesc.dwBufferBytes = bytesPerBuffer;
-    secondaryDesc.lpwfxFormat = &wfFormat;
-    // Create the secondary buffer
-    if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
-                  &secondaryDesc, &dsw->dsw_OutputBuffer, NULL)) != DS_OK) return result;
-    // Lock the DS buffer
-    if ((result = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, 0, dsw->dsw_OutputSize, (LPVOID*)&pDSBuffData,
-                                           &dwDataLen, NULL, 0, 0)) != DS_OK) return result;
-    // Zero the DS buffer
-    ZeroMemory(pDSBuffData, dwDataLen);
-    // Unlock the DS buffer
-    if ((result = IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result;
-    if( QueryPerformanceFrequency( &counterFrequency ) )
-    {
-        int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short));
-        dsw->dsw_CounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate;
-    }
-    else
-    {
-        dsw->dsw_CounterTicksPerBuffer.QuadPart = 0;
-    }
-    // Let DSound set the starting write position because if we set it to zero, it looks like the
-    // buffer is full to begin with. This causes a long pause before sound starts when using large buffers.
-    hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &dsw->dsw_WriteOffset );
-    if( hr != DS_OK )
-    {
-        return hr;
-    }
-    dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerOutputFrame;
-    /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */
-    return DS_OK;
-}
-
-/************************************************************************************/
-HRESULT DSW_StartOutput( DSoundWrapper *dsw )
-{
-    HRESULT        hr;
-    QueryPerformanceCounter( &dsw->dsw_LastPlayTime );
-    dsw->dsw_LastPlayCursor = 0;
-    dsw->dsw_FramesPlayed = 0;
-    hr = IDirectSoundBuffer_SetCurrentPosition( dsw->dsw_OutputBuffer, 0 );
-    if( hr != DS_OK )
-    {
-        return hr;
-    }
-    // Start the buffer playback in a loop.
-    if( dsw->dsw_OutputBuffer != NULL )
-    {
-        hr = IDirectSoundBuffer_Play( dsw->dsw_OutputBuffer, 0, 0, DSBPLAY_LOOPING );
-        if( hr != DS_OK )
-        {
-            return hr;
-        }
-        dsw->dsw_OutputRunning = TRUE;
-    }
-
-    return 0;
-}
-/************************************************************************************/
-HRESULT DSW_StopOutput( DSoundWrapper *dsw )
-{
-    // Stop the buffer playback
-    if( dsw->dsw_OutputBuffer != NULL )
-    {
-        dsw->dsw_OutputRunning = FALSE;
-        return IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
-    }
-    else return 0;
-}
-
-/************************************************************************************/
-HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilledPtr )
-{
-    HRESULT hr;
-    DWORD   playCursor;
-    DWORD   writeCursor;
-    long    bytesFilled;
-    // Query to see where play position is.
-    // We don't need the writeCursor but sometimes DirectSound doesn't handle NULLS correctly
-    // so let's pass a pointer just to be safe.
-    hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
-    if( hr != DS_OK )
-    {
-        return hr;
-    }
-    bytesFilled = dsw->dsw_WriteOffset - playCursor;
-    if( bytesFilled < 0 ) bytesFilled += dsw->dsw_OutputSize; // unwrap offset
-    *bytesFilledPtr = bytesFilled;
-    return hr;
-}
-
-/************************************************************************************
- * Determine how much space can be safely written to in DS buffer.
- * Detect underflows and overflows.
- * Does not allow writing into safety gap maintained by DirectSound.
- */
-HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty )
-{
-    HRESULT hr;
-    DWORD   playCursor;
-    DWORD   writeCursor;
-    long    numBytesEmpty;
-    long    playWriteGap;
-    // Query to see how much room is in buffer.
-    hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
-    if( hr != DS_OK )
-    {
-        return hr;
-    }
-    // Determine size of gap between playIndex and WriteIndex that we cannot write into.
-    playWriteGap = writeCursor - playCursor;
-    if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap
-    /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */
-    /* Attempt to detect playCursor wrap-around and correct it. */
-    if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) )
-    {
-        /* How much time has elapsed since last check. */
-        LARGE_INTEGER   currentTime;
-        LARGE_INTEGER   elapsedTime;
-        long            bytesPlayed;
-        long            bytesExpected;
-        long            buffersWrapped;
-        QueryPerformanceCounter( &currentTime );
-        elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart;
-        dsw->dsw_LastPlayTime = currentTime;
-        /* How many bytes does DirectSound say have been played. */
-        bytesPlayed = playCursor - dsw->dsw_LastPlayCursor;
-        if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap
-        dsw->dsw_LastPlayCursor = playCursor;
-        /* Calculate how many bytes we would have expected to been played by now. */
-        bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart);
-        buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize;
-        if( buffersWrapped > 0 )
-        {
-            playCursor += (buffersWrapped * dsw->dsw_OutputSize);
-            bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize);
-        }
-        /* Maintain frame output cursor. */
-        dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerOutputFrame);
-    }
-    numBytesEmpty = playCursor - dsw->dsw_WriteOffset;
-    if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset
-    /* Have we underflowed? */
-    if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) )
-    {
-        if( dsw->dsw_OutputRunning )
-        {
-            dsw->dsw_OutputUnderflows += 1;
-        }
-        dsw->dsw_WriteOffset = writeCursor;
-        numBytesEmpty = dsw->dsw_OutputSize - playWriteGap;
-    }
-    *bytesEmpty = numBytesEmpty;
-    return hr;
-}
-
-/************************************************************************************/
-HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw )
-{
-    HRESULT hr;
-    LPBYTE lpbuf1 = NULL;
-    LPBYTE lpbuf2 = NULL;
-    DWORD dwsize1 = 0;
-    DWORD dwsize2 = 0;
-    long  bytesEmpty;
-    hr = DSW_QueryOutputSpace( dsw, &bytesEmpty ); // updates dsw_FramesPlayed
-    if (hr != DS_OK) return hr;
-    if( bytesEmpty == 0 ) return DS_OK;
-    // Lock free space in the DS
-    hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesEmpty, (void **) &lpbuf1, &dwsize1,
-                                  (void **) &lpbuf2, &dwsize2, 0);
-    if (hr == DS_OK)
-    {
-        // Copy the buffer into the DS
-        ZeroMemory(lpbuf1, dwsize1);
-        if(lpbuf2 != NULL)
-        {
-            ZeroMemory(lpbuf2, dwsize2);
-        }
-        // Update our buffer offset and unlock sound buffer
-        dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
-        IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
-        dsw->dsw_FramesWritten += bytesEmpty / dsw->dsw_BytesPerOutputFrame;
-    }
-    return hr;
-}
-
-/************************************************************************************/
-HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes )
-{
-    HRESULT hr;
-    LPBYTE lpbuf1 = NULL;
-    LPBYTE lpbuf2 = NULL;
-    DWORD dwsize1 = 0;
-    DWORD dwsize2 = 0;
-    // Lock free space in the DS
-    hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, numBytes, (void **) &lpbuf1, &dwsize1,
-                                  (void **) &lpbuf2, &dwsize2, 0);
-    if (hr == DS_OK)
-    {
-        // Copy the buffer into the DS
-        CopyMemory(lpbuf1, buf, dwsize1);
-        if(lpbuf2 != NULL)
-        {
-            CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
-        }
-        // Update our buffer offset and unlock sound buffer
-        dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
-        IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
-        dsw->dsw_FramesWritten += numBytes / dsw->dsw_BytesPerOutputFrame;
-    }
-    return hr;
-}
-
-/************************************************************************************/
-DWORD DSW_GetOutputStatus( DSoundWrapper *dsw )
-{
-    DWORD status;
-    if (IDirectSoundBuffer_GetStatus( dsw->dsw_OutputBuffer, &status ) != DS_OK)
-        return( DSERR_INVALIDPARAM );
-    else
-        return( status );
-}
-
-/* These routines are used to support audio input.
- * Do NOT compile these calls when using NT4 because it does
- * not support the entry points.
- */
-/************************************************************************************/
-HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
-{
-    HRESULT hr = dswDSoundEntryPoints.DirectSoundCaptureCreate(  lpGUID, &dsw->dsw_pDirectSoundCapture,   NULL );
-    if( hr != DS_OK ) return hr;
-    return hr;
-}
-/************************************************************************************/
-HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer )
-{
-    DSCBUFFERDESC  captureDesc;
-    WAVEFORMATEX   wfFormat;
-    HRESULT        result;
-    
-    dsw->dsw_BytesPerInputFrame = nChannels * sizeof(short);
-
-    // Define the buffer format
-    wfFormat.wFormatTag      = WAVE_FORMAT_PCM;
-    wfFormat.nChannels       = nChannels;
-    wfFormat.nSamplesPerSec  = nFrameRate;
-    wfFormat.wBitsPerSample  = 8 * sizeof(short);
-    wfFormat.nBlockAlign     = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
-    wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
-    wfFormat.cbSize          = 0;   /* No extended format info. */
-    dsw->dsw_InputSize = bytesPerBuffer;
-    // ----------------------------------------------------------------------
-    // Setup the secondary buffer description
-    ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
-    captureDesc.dwSize = sizeof(DSCBUFFERDESC);
-    captureDesc.dwFlags =  0;
-    captureDesc.dwBufferBytes = bytesPerBuffer;
-    captureDesc.lpwfxFormat = &wfFormat;
-    // Create the capture buffer
-    if ((result = IDirectSoundCapture_CreateCaptureBuffer( dsw->dsw_pDirectSoundCapture,
-                  &captureDesc, &dsw->dsw_InputBuffer, NULL)) != DS_OK) return result;
-    dsw->dsw_ReadOffset = 0;  // reset last read position to start of buffer
-    return DS_OK;
-}
-
-/************************************************************************************/
-HRESULT DSW_StartInput( DSoundWrapper *dsw )
-{
-    // Start the buffer playback
-    if( dsw->dsw_InputBuffer != NULL )
-    {
-        return IDirectSoundCaptureBuffer_Start( dsw->dsw_InputBuffer, DSCBSTART_LOOPING );
-    }
-    else return 0;
-}
-
-/************************************************************************************/
-HRESULT DSW_StopInput( DSoundWrapper *dsw )
-{
-    // Stop the buffer playback
-    if( dsw->dsw_InputBuffer != NULL )
-    {
-        return IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
-    }
-    else return 0;
-}
-
-/************************************************************************************/
-HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled )
-{
-    HRESULT hr;
-    DWORD capturePos;
-    DWORD readPos;
-    long  filled;
-    // Query to see how much data is in buffer.
-    // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly
-    // so let's pass a pointer just to be safe.
-    hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos );
-    if( hr != DS_OK )
-    {
-        return hr;
-    }
-    filled = readPos - dsw->dsw_ReadOffset;
-    if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset
-    *bytesFilled = filled;
-    return hr;
-}
-
-/************************************************************************************/
-HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes )
-{
-    HRESULT hr;
-    LPBYTE lpbuf1 = NULL;
-    LPBYTE lpbuf2 = NULL;
-    DWORD dwsize1 = 0;
-    DWORD dwsize2 = 0;
-    // Lock free space in the DS
-    hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1,
-                                          (void **) &lpbuf2, &dwsize2, 0);
-    if (hr == DS_OK)
-    {
-        // Copy from DS to the buffer
-        CopyMemory( buf, lpbuf1, dwsize1);
-        if(lpbuf2 != NULL)
-        {
-            CopyMemory( buf+dwsize1, lpbuf2, dwsize2);
-        }
-        // Update our buffer offset and unlock sound buffer
-        dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize;
-        IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
-    }
-    return hr;
-}
-
+/*

+ * $Id: dsound_wrapper.c,v 1.1.1.1.2.11 2003/09/07 13:04:53 rossbencina Exp $

+ * Simplified DirectSound interface.

+ *

+ * Author: Phil Burk & Robert Marsanyi

+ *

+ * PortAudio Portable Real-Time Audio Library

+ * For more information see: http://www.softsynth.com/portaudio/

+ * DirectSound Implementation

+ * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <stdio.h>

+#include <stdlib.h>

+#include <math.h>

+

+#include "dsound_wrapper.h"

+#include "pa_trace.h"

+

+/*

+    Rather than linking with dxguid.a or using "#define INITGUID" to force a

+    header file to instantiate the required GUID(s), we define them directly

+    below.

+*/

+#include <initguid.h> // needed for the DEFINE_GUID macro

+DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);

+

+

+/************************************************************************************/

+DSoundEntryPoints dswDSoundEntryPoints = { 0, 0, 0, 0, 0, 0, 0 };

+/************************************************************************************/

+static HRESULT WINAPI DummyDirectSoundCreate(LPGUID lpcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter)

+{

+    (void)lpcGuidDevice; /* unused parameter */

+    (void)ppDS; /* unused parameter */

+    (void)pUnkOuter; /* unused parameter */

+    return E_NOTIMPL;

+}

+

+static HRESULT WINAPI DummyDirectSoundEnumerateW(LPDSENUMCALLBACKW lpDSEnumCallback, LPVOID lpContext)

+{

+    (void)lpDSEnumCallback; /* unused parameter */

+    (void)lpContext; /* unused parameter */

+    return E_NOTIMPL;

+}

+

+static HRESULT WINAPI DummyDirectSoundEnumerateA(LPDSENUMCALLBACKA lpDSEnumCallback, LPVOID lpContext)

+{

+    (void)lpDSEnumCallback; /* unused parameter */

+    (void)lpContext; /* unused parameter */

+    return E_NOTIMPL;

+}

+

+static HRESULT WINAPI DummyDirectSoundCaptureCreate(LPGUID lpcGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter)

+{

+    (void)lpcGUID; /* unused parameter */

+    (void)lplpDSC; /* unused parameter */

+    (void)pUnkOuter; /* unused parameter */

+    return E_NOTIMPL;

+}

+

+static HRESULT WINAPI DummyDirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW lpDSCEnumCallback, LPVOID lpContext)

+{

+    (void)lpDSCEnumCallback; /* unused parameter */

+    (void)lpContext; /* unused parameter */

+    return E_NOTIMPL;

+}

+

+static HRESULT WINAPI DummyDirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA lpDSCEnumCallback, LPVOID lpContext)

+{

+    (void)lpDSCEnumCallback; /* unused parameter */

+    (void)lpContext; /* unused parameter */

+    return E_NOTIMPL;

+}

+/************************************************************************************/

+void DSW_InitializeDSoundEntryPoints(void)

+{

+    dswDSoundEntryPoints.hInstance_ = LoadLibrary("dsound.dll");

+    if( dswDSoundEntryPoints.hInstance_ != NULL )

+    {

+        dswDSoundEntryPoints.DirectSoundCreate =

+                (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))

+                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCreate" );

+        if( dswDSoundEntryPoints.DirectSoundCreate == NULL )

+            dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;

+

+        dswDSoundEntryPoints.DirectSoundEnumerateW =

+                (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))

+                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundEnumerateW" );

+        if( dswDSoundEntryPoints.DirectSoundEnumerateW == NULL )

+            dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;

+

+        dswDSoundEntryPoints.DirectSoundEnumerateA =

+                (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))

+                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundEnumerateA" );

+        if( dswDSoundEntryPoints.DirectSoundEnumerateA == NULL )

+            dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;

+

+        dswDSoundEntryPoints.DirectSoundCaptureCreate =

+                (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN))

+                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureCreate" );

+        if( dswDSoundEntryPoints.DirectSoundCaptureCreate == NULL )

+            dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;

+

+        dswDSoundEntryPoints.DirectSoundCaptureEnumerateW =

+                (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))

+                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateW" );

+        if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateW == NULL )

+            dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;

+

+        dswDSoundEntryPoints.DirectSoundCaptureEnumerateA =

+                (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))

+                GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateA" );

+        if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateA == NULL )

+            dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;

+    }

+    else

+    {

+        /* initialize with dummy entry points to make live easy when ds isn't present */

+        dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;

+        dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;

+        dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;

+        dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;

+        dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;

+        dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;

+    }

+}

+/************************************************************************************/

+void DSW_TerminateDSoundEntryPoints(void)

+{

+    if( dswDSoundEntryPoints.hInstance_ != NULL )

+    {

+        FreeLibrary( dswDSoundEntryPoints.hInstance_ );

+        dswDSoundEntryPoints.hInstance_ = NULL;

+        /* ensure that we crash reliably if the entry points arent initialised */

+        dswDSoundEntryPoints.DirectSoundCreate = 0;

+        dswDSoundEntryPoints.DirectSoundEnumerateW = 0;

+        dswDSoundEntryPoints.DirectSoundEnumerateA = 0;

+        dswDSoundEntryPoints.DirectSoundCaptureCreate = 0;

+        dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = 0;

+        dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = 0;

+    }

+}

+/************************************************************************************/

+void DSW_Term( DSoundWrapper *dsw )

+{

+    // Cleanup the sound buffers

+    if (dsw->dsw_OutputBuffer)

+    {

+        IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );

+        IDirectSoundBuffer_Release( dsw->dsw_OutputBuffer );

+        dsw->dsw_OutputBuffer = NULL;

+    }

+

+    if (dsw->dsw_InputBuffer)

+    {

+        IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );

+        IDirectSoundCaptureBuffer_Release( dsw->dsw_InputBuffer );

+        dsw->dsw_InputBuffer = NULL;

+    }

+

+    if (dsw->dsw_pDirectSoundCapture)

+    {

+        IDirectSoundCapture_Release( dsw->dsw_pDirectSoundCapture );

+        dsw->dsw_pDirectSoundCapture = NULL;

+    }

+

+    if (dsw->dsw_pDirectSound)

+    {

+        IDirectSound_Release( dsw->dsw_pDirectSound );

+        dsw->dsw_pDirectSound = NULL;

+    }

+}

+/************************************************************************************/

+HRESULT DSW_Init( DSoundWrapper *dsw )

+{

+    memset( dsw, 0, sizeof(DSoundWrapper) );

+    return 0;

+}

+/************************************************************************************/

+HRESULT DSW_InitOutputDevice( DSoundWrapper *dsw, LPGUID lpGUID )

+{

+    // Create the DS object

+    HRESULT hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &dsw->dsw_pDirectSound, NULL );

+    if( hr != DS_OK ) return hr;

+    return hr;

+}

+

+/************************************************************************************/

+HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer )

+{

+    DWORD          dwDataLen;

+    DWORD          playCursor;

+    HRESULT        result;

+    LPDIRECTSOUNDBUFFER pPrimaryBuffer;

+    HWND           hWnd;

+    HRESULT        hr;

+    WAVEFORMATEX   wfFormat;

+    DSBUFFERDESC   primaryDesc;

+    DSBUFFERDESC   secondaryDesc;

+    unsigned char* pDSBuffData;

+    LARGE_INTEGER  counterFrequency;

+

+    dsw->dsw_OutputSize = bytesPerBuffer;

+    dsw->dsw_OutputRunning = FALSE;

+    dsw->dsw_OutputUnderflows = 0;

+    dsw->dsw_FramesWritten = 0;

+    dsw->dsw_BytesPerOutputFrame = nChannels * sizeof(short);

+

+    // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the

+    // applications's window. Also if that window is closed before the Buffer is closed

+    // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.)

+    // So we will use GetDesktopWindow() which was suggested by Miller Puckette.

+    // hWnd = GetForegroundWindow();

+    //

+    //  FIXME: The example code I have on the net creates a hidden window that

+    //      is managed by our code - I think we should do that - one hidden

+    //      window for the whole of Pa_DS

+    //

+    hWnd = GetDesktopWindow();

+

+    // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz.

+    // Exclusize also prevents unexpected sounds from other apps during a performance.

+    if ((hr = IDirectSound_SetCooperativeLevel( dsw->dsw_pDirectSound,

+              hWnd, DSSCL_EXCLUSIVE)) != DS_OK)

+    {

+        return hr;

+    }

+

+    // -----------------------------------------------------------------------

+    // Create primary buffer and set format just so we can specify our custom format.

+    // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz.

+    // Setup the primary buffer description

+    ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC));

+    primaryDesc.dwSize        = sizeof(DSBUFFERDESC);

+    primaryDesc.dwFlags       = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth

+    primaryDesc.dwBufferBytes = 0;

+    primaryDesc.lpwfxFormat   = NULL;

+    // Create the buffer

+    if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,

+                  &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result;

+    // Define the buffer format

+    wfFormat.wFormatTag = WAVE_FORMAT_PCM;

+    wfFormat.nChannels = nChannels;

+    wfFormat.nSamplesPerSec = nFrameRate;

+    wfFormat.wBitsPerSample = 8 * sizeof(short);

+    wfFormat.nBlockAlign = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));

+    wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;

+    wfFormat.cbSize = 0;  /* No extended format info. */

+    // Set the primary buffer's format

+    if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result;

+

+    // ----------------------------------------------------------------------

+    // Setup the secondary buffer description

+    ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));

+    secondaryDesc.dwSize = sizeof(DSBUFFERDESC);

+    secondaryDesc.dwFlags =  DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;

+    secondaryDesc.dwBufferBytes = bytesPerBuffer;

+    secondaryDesc.lpwfxFormat = &wfFormat;

+    // Create the secondary buffer

+    if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,

+                  &secondaryDesc, &dsw->dsw_OutputBuffer, NULL)) != DS_OK) return result;

+    // Lock the DS buffer

+    if ((result = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, 0, dsw->dsw_OutputSize, (LPVOID*)&pDSBuffData,

+                                           &dwDataLen, NULL, 0, 0)) != DS_OK) return result;

+    // Zero the DS buffer

+    ZeroMemory(pDSBuffData, dwDataLen);

+    // Unlock the DS buffer

+    if ((result = IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result;

+    if( QueryPerformanceFrequency( &counterFrequency ) )

+    {

+        int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short));

+        dsw->dsw_CounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate;

+    }

+    else

+    {

+        dsw->dsw_CounterTicksPerBuffer.QuadPart = 0;

+    }

+    // Let DSound set the starting write position because if we set it to zero, it looks like the

+    // buffer is full to begin with. This causes a long pause before sound starts when using large buffers.

+    hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &dsw->dsw_WriteOffset );

+    if( hr != DS_OK )

+    {

+        return hr;

+    }

+    dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerOutputFrame;

+    /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */

+    return DS_OK;

+}

+

+/************************************************************************************/

+HRESULT DSW_StartOutput( DSoundWrapper *dsw )

+{

+    HRESULT        hr;

+    QueryPerformanceCounter( &dsw->dsw_LastPlayTime );

+    dsw->dsw_LastPlayCursor = 0;

+    dsw->dsw_FramesPlayed = 0;

+    hr = IDirectSoundBuffer_SetCurrentPosition( dsw->dsw_OutputBuffer, 0 );

+    if( hr != DS_OK )

+    {

+        return hr;

+    }

+    // Start the buffer playback in a loop.

+    if( dsw->dsw_OutputBuffer != NULL )

+    {

+        hr = IDirectSoundBuffer_Play( dsw->dsw_OutputBuffer, 0, 0, DSBPLAY_LOOPING );

+        if( hr != DS_OK )

+        {

+            return hr;

+        }

+        dsw->dsw_OutputRunning = TRUE;

+    }

+

+    return 0;

+}

+/************************************************************************************/

+HRESULT DSW_StopOutput( DSoundWrapper *dsw )

+{

+    // Stop the buffer playback

+    if( dsw->dsw_OutputBuffer != NULL )

+    {

+        dsw->dsw_OutputRunning = FALSE;

+        return IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );

+    }

+    else return 0;

+}

+

+/************************************************************************************/

+HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilledPtr )

+{

+    HRESULT hr;

+    DWORD   playCursor;

+    DWORD   writeCursor;

+    long    bytesFilled;

+    // Query to see where play position is.

+    // We don't need the writeCursor but sometimes DirectSound doesn't handle NULLS correctly

+    // so let's pass a pointer just to be safe.

+    hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );

+    if( hr != DS_OK )

+    {

+        return hr;

+    }

+    bytesFilled = dsw->dsw_WriteOffset - playCursor;

+    if( bytesFilled < 0 ) bytesFilled += dsw->dsw_OutputSize; // unwrap offset

+    *bytesFilledPtr = bytesFilled;

+    return hr;

+}

+

+/************************************************************************************

+ * Determine how much space can be safely written to in DS buffer.

+ * Detect underflows and overflows.

+ * Does not allow writing into safety gap maintained by DirectSound.

+ */

+HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty )

+{

+    HRESULT hr;

+    DWORD   playCursor;

+    DWORD   writeCursor;

+    long    numBytesEmpty;

+    long    playWriteGap;

+    // Query to see how much room is in buffer.

+    hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );

+    if( hr != DS_OK )

+    {

+        return hr;

+    }

+    // Determine size of gap between playIndex and WriteIndex that we cannot write into.

+    playWriteGap = writeCursor - playCursor;

+    if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap

+    /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */

+    /* Attempt to detect playCursor wrap-around and correct it. */

+    if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) )

+    {

+        /* How much time has elapsed since last check. */

+        LARGE_INTEGER   currentTime;

+        LARGE_INTEGER   elapsedTime;

+        long            bytesPlayed;

+        long            bytesExpected;

+        long            buffersWrapped;

+        QueryPerformanceCounter( &currentTime );

+        elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart;

+        dsw->dsw_LastPlayTime = currentTime;

+        /* How many bytes does DirectSound say have been played. */

+        bytesPlayed = playCursor - dsw->dsw_LastPlayCursor;

+        if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap

+        dsw->dsw_LastPlayCursor = playCursor;

+        /* Calculate how many bytes we would have expected to been played by now. */

+        bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart);

+        buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize;

+        if( buffersWrapped > 0 )

+        {

+            playCursor += (buffersWrapped * dsw->dsw_OutputSize);

+            bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize);

+        }

+        /* Maintain frame output cursor. */

+        dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerOutputFrame);

+    }

+    numBytesEmpty = playCursor - dsw->dsw_WriteOffset;

+    if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset

+    /* Have we underflowed? */

+    if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) )

+    {

+        if( dsw->dsw_OutputRunning )

+        {

+            dsw->dsw_OutputUnderflows += 1;

+        }

+        dsw->dsw_WriteOffset = writeCursor;

+        numBytesEmpty = dsw->dsw_OutputSize - playWriteGap;

+    }

+    *bytesEmpty = numBytesEmpty;

+    return hr;

+}

+

+/************************************************************************************/

+HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw )

+{

+    HRESULT hr;

+    LPBYTE lpbuf1 = NULL;

+    LPBYTE lpbuf2 = NULL;

+    DWORD dwsize1 = 0;

+    DWORD dwsize2 = 0;

+    long  bytesEmpty;

+    hr = DSW_QueryOutputSpace( dsw, &bytesEmpty ); // updates dsw_FramesPlayed

+    if (hr != DS_OK) return hr;

+    if( bytesEmpty == 0 ) return DS_OK;

+    // Lock free space in the DS

+    hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesEmpty, (void **) &lpbuf1, &dwsize1,

+                                  (void **) &lpbuf2, &dwsize2, 0);

+    if (hr == DS_OK)

+    {

+        // Copy the buffer into the DS

+        ZeroMemory(lpbuf1, dwsize1);

+        if(lpbuf2 != NULL)

+        {

+            ZeroMemory(lpbuf2, dwsize2);

+        }

+        // Update our buffer offset and unlock sound buffer

+        dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;

+        IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);

+        dsw->dsw_FramesWritten += bytesEmpty / dsw->dsw_BytesPerOutputFrame;

+    }

+    return hr;

+}

+

+/************************************************************************************/

+HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes )

+{

+    HRESULT hr;

+    LPBYTE lpbuf1 = NULL;

+    LPBYTE lpbuf2 = NULL;

+    DWORD dwsize1 = 0;

+    DWORD dwsize2 = 0;

+    // Lock free space in the DS

+    hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, numBytes, (void **) &lpbuf1, &dwsize1,

+                                  (void **) &lpbuf2, &dwsize2, 0);

+    if (hr == DS_OK)

+    {

+        // Copy the buffer into the DS

+        CopyMemory(lpbuf1, buf, dwsize1);

+        if(lpbuf2 != NULL)

+        {

+            CopyMemory(lpbuf2, buf+dwsize1, dwsize2);

+        }

+        // Update our buffer offset and unlock sound buffer

+        dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;

+        IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);

+        dsw->dsw_FramesWritten += numBytes / dsw->dsw_BytesPerOutputFrame;

+    }

+    return hr;

+}

+

+/************************************************************************************/

+DWORD DSW_GetOutputStatus( DSoundWrapper *dsw )

+{

+    DWORD status;

+    if (IDirectSoundBuffer_GetStatus( dsw->dsw_OutputBuffer, &status ) != DS_OK)

+        return( DSERR_INVALIDPARAM );

+    else

+        return( status );

+}

+

+/* These routines are used to support audio input.

+ * Do NOT compile these calls when using NT4 because it does

+ * not support the entry points.

+ */

+/************************************************************************************/

+HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID )

+{

+    HRESULT hr = dswDSoundEntryPoints.DirectSoundCaptureCreate(  lpGUID, &dsw->dsw_pDirectSoundCapture,   NULL );

+    if( hr != DS_OK ) return hr;

+    return hr;

+}

+/************************************************************************************/

+HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer )

+{

+    DSCBUFFERDESC  captureDesc;

+    WAVEFORMATEX   wfFormat;

+    HRESULT        result;

+    

+    dsw->dsw_BytesPerInputFrame = nChannels * sizeof(short);

+

+    // Define the buffer format

+    wfFormat.wFormatTag      = WAVE_FORMAT_PCM;

+    wfFormat.nChannels       = nChannels;

+    wfFormat.nSamplesPerSec  = nFrameRate;

+    wfFormat.wBitsPerSample  = 8 * sizeof(short);

+    wfFormat.nBlockAlign     = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));

+    wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;

+    wfFormat.cbSize          = 0;   /* No extended format info. */

+    dsw->dsw_InputSize = bytesPerBuffer;

+    // ----------------------------------------------------------------------

+    // Setup the secondary buffer description

+    ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));

+    captureDesc.dwSize = sizeof(DSCBUFFERDESC);

+    captureDesc.dwFlags =  0;

+    captureDesc.dwBufferBytes = bytesPerBuffer;

+    captureDesc.lpwfxFormat = &wfFormat;

+    // Create the capture buffer

+    if ((result = IDirectSoundCapture_CreateCaptureBuffer( dsw->dsw_pDirectSoundCapture,

+                  &captureDesc, &dsw->dsw_InputBuffer, NULL)) != DS_OK) return result;

+    dsw->dsw_ReadOffset = 0;  // reset last read position to start of buffer

+    return DS_OK;

+}

+

+/************************************************************************************/

+HRESULT DSW_StartInput( DSoundWrapper *dsw )

+{

+    // Start the buffer playback

+    if( dsw->dsw_InputBuffer != NULL )

+    {

+        return IDirectSoundCaptureBuffer_Start( dsw->dsw_InputBuffer, DSCBSTART_LOOPING );

+    }

+    else return 0;

+}

+

+/************************************************************************************/

+HRESULT DSW_StopInput( DSoundWrapper *dsw )

+{

+    // Stop the buffer playback

+    if( dsw->dsw_InputBuffer != NULL )

+    {

+        return IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );

+    }

+    else return 0;

+}

+

+/************************************************************************************/

+HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled )

+{

+    HRESULT hr;

+    DWORD capturePos;

+    DWORD readPos;

+    long  filled;

+    // Query to see how much data is in buffer.

+    // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly

+    // so let's pass a pointer just to be safe.

+    hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos );

+    if( hr != DS_OK )

+    {

+        return hr;

+    }

+    filled = readPos - dsw->dsw_ReadOffset;

+    if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset

+    *bytesFilled = filled;

+    return hr;

+}

+

+/************************************************************************************/

+HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes )

+{

+    HRESULT hr;

+    LPBYTE lpbuf1 = NULL;

+    LPBYTE lpbuf2 = NULL;

+    DWORD dwsize1 = 0;

+    DWORD dwsize2 = 0;

+    // Lock free space in the DS

+    hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1,

+                                          (void **) &lpbuf2, &dwsize2, 0);

+    if (hr == DS_OK)

+    {

+        // Copy from DS to the buffer

+        CopyMemory( buf, lpbuf1, dwsize1);

+        if(lpbuf2 != NULL)

+        {

+            CopyMemory( buf+dwsize1, lpbuf2, dwsize2);

+        }

+        // Update our buffer offset and unlock sound buffer

+        dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize;

+        IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);

+    }

+    return hr;

+}

+

diff --git a/pjmedia/src/pjmedia/portaudio/dsound_wrapper.h b/pjmedia/src/pjmedia/portaudio/dsound_wrapper.h
index 9e3f565..e8954c1 100644
--- a/pjmedia/src/pjmedia/portaudio/dsound_wrapper.h
+++ b/pjmedia/src/pjmedia/portaudio/dsound_wrapper.h
@@ -1,130 +1,151 @@
-#ifndef __DSOUND_WRAPPER_H
-#define __DSOUND_WRAPPER_H
-/*
- * $Id: dsound_wrapper.h,v 1.1.1.1.2.8 2005/01/16 20:48:37 rossbencina Exp $
- * Simplified DirectSound interface.
- *
- * Author: Phil Burk & Robert Marsanyi
- *
- * For PortAudio Portable Real-Time Audio Library
- * For more information see: http://www.softsynth.com/portaudio/
- * DirectSound Implementation
- * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-/* on Borland compilers, WIN32 doesn't seem to be defined by default, which
-    breaks DSound.h. Adding the define here fixes the problem. - rossb. */
-#ifdef __BORLANDC__
-#if !defined(WIN32)
-#define WIN32
-#endif
-#endif
-
-/*
-  We are only using DX3 in here, no need to polute the namespace - davidv
-*/
-#define DIRECTSOUND_VERSION 0x0300
-
-#include <DSound.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-typedef struct
-{
-    HINSTANCE hInstance_;
-    
-    HRESULT (WINAPI *DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
-    HRESULT (WINAPI *DirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
-    HRESULT (WINAPI *DirectSoundEnumerateA)(LPDSENUMCALLBACKA, LPVOID);
-
-    HRESULT (WINAPI *DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN);
-    HRESULT (WINAPI *DirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
-    HRESULT (WINAPI *DirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA, LPVOID);
-}DSoundEntryPoints;
-
-extern DSoundEntryPoints dswDSoundEntryPoints;
-
-void DSW_InitializeDSoundEntryPoints(void);
-void DSW_TerminateDSoundEntryPoints(void);
-
-#define DSW_NUM_POSITIONS     (4)
-#define DSW_NUM_EVENTS        (5)
-#define DSW_TERMINATION_EVENT     (DSW_NUM_POSITIONS)
-
-typedef struct
-{
-/* Output */
-    LPDIRECTSOUND        dsw_pDirectSound;
-    LPDIRECTSOUNDBUFFER  dsw_OutputBuffer;
-    DWORD                dsw_WriteOffset;     /* last write position */
-    INT                  dsw_OutputSize;
-    INT                  dsw_BytesPerOutputFrame;
-    /* Try to detect play buffer underflows. */
-    LARGE_INTEGER        dsw_CounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */
-    LARGE_INTEGER        dsw_LastPlayTime;
-    UINT                 dsw_LastPlayCursor;
-    UINT                 dsw_OutputUnderflows;
-    BOOL                 dsw_OutputRunning;
-    /* use double which lets us can play for several thousand years with enough precision */
-    double               dsw_FramesWritten;
-    double               dsw_FramesPlayed;
-/* Input */
-    INT                  dsw_BytesPerInputFrame;
-    LPDIRECTSOUNDCAPTURE dsw_pDirectSoundCapture;
-    LPDIRECTSOUNDCAPTUREBUFFER   dsw_InputBuffer;
-    UINT                 dsw_ReadOffset;      /* last read position */
-    UINT                 dsw_InputSize;
-} DSoundWrapper;
-
-HRESULT DSW_Init( DSoundWrapper *dsw );
-void DSW_Term( DSoundWrapper *dsw );
-HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,
-                              WORD nChannels, int bufSize );
-HRESULT DSW_StartOutput( DSoundWrapper *dsw );
-HRESULT DSW_StopOutput( DSoundWrapper *dsw );
-DWORD   DSW_GetOutputStatus( DSoundWrapper *dsw );
-HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes );
-HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw );
-HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty );
-HRESULT DSW_Enumerate( DSoundWrapper *dsw );
-
-HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,
-                             WORD nChannels, int bufSize );
-HRESULT DSW_StartInput( DSoundWrapper *dsw );
-HRESULT DSW_StopInput( DSoundWrapper *dsw );
-HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes );
-HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled );
-HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilled );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif  /* __DSOUND_WRAPPER_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef __DSOUND_WRAPPER_H

+#define __DSOUND_WRAPPER_H

+/*

+ * $Id: dsound_wrapper.h,v 1.1.1.1.2.8 2005/01/16 20:48:37 rossbencina Exp $

+ * Simplified DirectSound interface.

+ *

+ * Author: Phil Burk & Robert Marsanyi

+ *

+ * For PortAudio Portable Real-Time Audio Library

+ * For more information see: http://www.softsynth.com/portaudio/

+ * DirectSound Implementation

+ * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ *

+ */

+

+/* on Borland compilers, WIN32 doesn't seem to be defined by default, which

+    breaks DSound.h. Adding the define here fixes the problem. - rossb. */

+#ifdef __BORLANDC__

+#if !defined(WIN32)

+#define WIN32

+#endif

+#endif

+

+/*

+  We are only using DX3 in here, no need to polute the namespace - davidv

+*/

+#define DIRECTSOUND_VERSION 0x0300

+

+#include <DSound.h>

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+typedef struct

+{

+    HINSTANCE hInstance_;

+    

+    HRESULT (WINAPI *DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);

+    HRESULT (WINAPI *DirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);

+    HRESULT (WINAPI *DirectSoundEnumerateA)(LPDSENUMCALLBACKA, LPVOID);

+

+    HRESULT (WINAPI *DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN);

+    HRESULT (WINAPI *DirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID);

+    HRESULT (WINAPI *DirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA, LPVOID);

+}DSoundEntryPoints;

+

+extern DSoundEntryPoints dswDSoundEntryPoints;

+

+void DSW_InitializeDSoundEntryPoints(void);

+void DSW_TerminateDSoundEntryPoints(void);

+

+#define DSW_NUM_POSITIONS     (4)

+#define DSW_NUM_EVENTS        (5)

+#define DSW_TERMINATION_EVENT     (DSW_NUM_POSITIONS)

+

+typedef struct

+{

+/* Output */

+    LPDIRECTSOUND        dsw_pDirectSound;

+    LPDIRECTSOUNDBUFFER  dsw_OutputBuffer;

+    DWORD                dsw_WriteOffset;     /* last write position */

+    INT                  dsw_OutputSize;

+    INT                  dsw_BytesPerOutputFrame;

+    /* Try to detect play buffer underflows. */

+    LARGE_INTEGER        dsw_CounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */

+    LARGE_INTEGER        dsw_LastPlayTime;

+    UINT                 dsw_LastPlayCursor;

+    UINT                 dsw_OutputUnderflows;

+    BOOL                 dsw_OutputRunning;

+    /* use double which lets us can play for several thousand years with enough precision */

+    double               dsw_FramesWritten;

+    double               dsw_FramesPlayed;

+/* Input */

+    INT                  dsw_BytesPerInputFrame;

+    LPDIRECTSOUNDCAPTURE dsw_pDirectSoundCapture;

+    LPDIRECTSOUNDCAPTUREBUFFER   dsw_InputBuffer;

+    UINT                 dsw_ReadOffset;      /* last read position */

+    UINT                 dsw_InputSize;

+} DSoundWrapper;

+

+HRESULT DSW_Init( DSoundWrapper *dsw );

+void DSW_Term( DSoundWrapper *dsw );

+HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,

+                              WORD nChannels, int bufSize );

+HRESULT DSW_StartOutput( DSoundWrapper *dsw );

+HRESULT DSW_StopOutput( DSoundWrapper *dsw );

+DWORD   DSW_GetOutputStatus( DSoundWrapper *dsw );

+HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes );

+HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw );

+HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty );

+HRESULT DSW_Enumerate( DSoundWrapper *dsw );

+

+HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,

+                             WORD nChannels, int bufSize );

+HRESULT DSW_StartInput( DSoundWrapper *dsw );

+HRESULT DSW_StopInput( DSoundWrapper *dsw );

+HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes );

+HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled );

+HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilled );

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif  /* __DSOUND_WRAPPER_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_allocation.c b/pjmedia/src/pjmedia/portaudio/pa_allocation.c
index 035b4d0..d9f068c 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_allocation.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_allocation.c
@@ -1,234 +1,255 @@
-/*
- * $Id: pa_allocation.c,v 1.1.2.6 2004/12/20 12:07:51 rossbencina Exp $
- * Portable Audio I/O Library allocation group implementation
- * memory allocation group for tracking allocation groups
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Allocation Group implementation.
-*/
-
-
-#include "pa_allocation.h"
-#include "pa_util.h"
-
-
-/*
-    Maintain 3 singly linked lists...
-    linkBlocks: the buffers used to allocate the links
-    spareLinks: links available for use in the allocations list
-    allocations: the buffers currently allocated using PaUtil_ContextAllocateMemory()
-
-    Link block size is doubled every time new links are allocated.
-*/
-
-
-#define PA_INITIAL_LINK_COUNT_    16
-
-struct PaUtilAllocationGroupLink
-{
-    struct PaUtilAllocationGroupLink *next;
-    void *buffer;
-};
-
-/*
-    Allocate a block of links. The first link will have it's buffer member
-    pointing to the block, and it's next member set to <nextBlock>. The remaining
-    links will have NULL buffer members, and each link will point to
-    the next link except the last, which will point to <nextSpare>
-*/
-static struct PaUtilAllocationGroupLink *AllocateLinks( long count,
-        struct PaUtilAllocationGroupLink *nextBlock,
-        struct PaUtilAllocationGroupLink *nextSpare )
-{
-    struct PaUtilAllocationGroupLink *result;
-    int i;
-    
-    result = (struct PaUtilAllocationGroupLink *)PaUtil_AllocateMemory(
-            sizeof(struct PaUtilAllocationGroupLink) * count );
-    if( result )
-    {
-        /* the block link */
-        result[0].buffer = result;
-        result[0].next = nextBlock;
-
-        /* the spare links */
-        for( i=1; i<count; ++i )
-        {
-            result[i].buffer = 0;
-            result[i].next = &result[i+1];
-        }
-        result[count-1].next = nextSpare;
-    }
-    
-    return result;
-}
-
-
-PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void )
-{
-    PaUtilAllocationGroup* result = 0;
-    struct PaUtilAllocationGroupLink *links;
-
-
-    links = AllocateLinks( PA_INITIAL_LINK_COUNT_, 0, 0 );
-    if( links != 0 )
-    {
-        result = (PaUtilAllocationGroup*)PaUtil_AllocateMemory( sizeof(PaUtilAllocationGroup) );
-        if( result )
-        {
-            result->linkCount = PA_INITIAL_LINK_COUNT_;
-            result->linkBlocks = &links[0];
-            result->spareLinks = &links[1];
-            result->allocations = 0;
-        }
-        else
-        {
-            PaUtil_FreeMemory( links );
-        }
-    }
-
-    return result;
-}
-
-
-void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group )
-{
-    struct PaUtilAllocationGroupLink *current = group->linkBlocks;
-    struct PaUtilAllocationGroupLink *next;
-
-    while( current )
-    {
-        next = current->next;
-        PaUtil_FreeMemory( current->buffer );
-        current = next;
-    }
-
-    PaUtil_FreeMemory( group );
-}
-
-
-void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size )
-{
-    struct PaUtilAllocationGroupLink *links, *link;
-    void *result = 0;
-    
-    /* allocate more links if necessary */
-    if( !group->spareLinks )
-    {
-        /* double the link count on each block allocation */
-        links = AllocateLinks( group->linkCount, group->linkBlocks, group->spareLinks );
-        if( links )
-        {
-            group->linkCount += group->linkCount;
-            group->linkBlocks = &links[0];
-            group->spareLinks = &links[1];
-        }
-    }
-
-    if( group->spareLinks )
-    {
-        result = PaUtil_AllocateMemory( size );
-        if( result )
-        {
-            link = group->spareLinks;
-            group->spareLinks = link->next;
-
-            link->buffer = result;
-            link->next = group->allocations;
-
-            group->allocations = link;
-        }
-    }
-
-    return result;    
-}
-
-
-void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer )
-{
-    struct PaUtilAllocationGroupLink *current = group->allocations;
-    struct PaUtilAllocationGroupLink *previous = 0;
-
-    if( buffer == 0 )
-        return;
-
-    /* find the right link and remove it */
-    while( current )
-    {
-        if( current->buffer == buffer )
-        {
-            if( previous )
-            {
-                previous->next = current->next;
-            }
-            else
-            {
-                group->allocations = current->next;
-            }
-
-            current->buffer = 0;
-            current->next = group->spareLinks;
-            group->spareLinks = current;
-
-            break;
-        }
-        
-        previous = current;
-        current = current->next;
-    }
-
-    PaUtil_FreeMemory( buffer ); /* free the memory whether we found it in the list or not */
-}
-
-
-void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group )
-{
-    struct PaUtilAllocationGroupLink *current = group->allocations;
-    struct PaUtilAllocationGroupLink *previous = 0;
-
-    /* free all buffers in the allocations list */
-    while( current )
-    {
-        PaUtil_FreeMemory( current->buffer );
-        current->buffer = 0;
-
-        previous = current;
-        current = current->next;
-    }
-
-    /* link the former allocations list onto the front of the spareLinks list */
-    if( previous )
-    {
-        previous->next = group->spareLinks;
-        group->spareLinks = group->allocations;
-        group->allocations = 0;
-    }
-}
-
+/*

+ * $Id: pa_allocation.c,v 1.1.2.6 2004/12/20 12:07:51 rossbencina Exp $

+ * Portable Audio I/O Library allocation group implementation

+ * memory allocation group for tracking allocation groups

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+ @brief Allocation Group implementation.

+*/

+

+

+#include "pa_allocation.h"

+#include "pa_util.h"

+

+

+/*

+    Maintain 3 singly linked lists...

+    linkBlocks: the buffers used to allocate the links

+    spareLinks: links available for use in the allocations list

+    allocations: the buffers currently allocated using PaUtil_ContextAllocateMemory()

+

+    Link block size is doubled every time new links are allocated.

+*/

+

+

+#define PA_INITIAL_LINK_COUNT_    16

+

+struct PaUtilAllocationGroupLink

+{

+    struct PaUtilAllocationGroupLink *next;

+    void *buffer;

+};

+

+/*

+    Allocate a block of links. The first link will have it's buffer member

+    pointing to the block, and it's next member set to <nextBlock>. The remaining

+    links will have NULL buffer members, and each link will point to

+    the next link except the last, which will point to <nextSpare>

+*/

+static struct PaUtilAllocationGroupLink *AllocateLinks( long count,

+        struct PaUtilAllocationGroupLink *nextBlock,

+        struct PaUtilAllocationGroupLink *nextSpare )

+{

+    struct PaUtilAllocationGroupLink *result;

+    int i;

+    

+    result = (struct PaUtilAllocationGroupLink *)PaUtil_AllocateMemory(

+            sizeof(struct PaUtilAllocationGroupLink) * count );

+    if( result )

+    {

+        /* the block link */

+        result[0].buffer = result;

+        result[0].next = nextBlock;

+

+        /* the spare links */

+        for( i=1; i<count; ++i )

+        {

+            result[i].buffer = 0;

+            result[i].next = &result[i+1];

+        }

+        result[count-1].next = nextSpare;

+    }

+    

+    return result;

+}

+

+

+PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void )

+{

+    PaUtilAllocationGroup* result = 0;

+    struct PaUtilAllocationGroupLink *links;

+

+

+    links = AllocateLinks( PA_INITIAL_LINK_COUNT_, 0, 0 );

+    if( links != 0 )

+    {

+        result = (PaUtilAllocationGroup*)PaUtil_AllocateMemory( sizeof(PaUtilAllocationGroup) );

+        if( result )

+        {

+            result->linkCount = PA_INITIAL_LINK_COUNT_;

+            result->linkBlocks = &links[0];

+            result->spareLinks = &links[1];

+            result->allocations = 0;

+        }

+        else

+        {

+            PaUtil_FreeMemory( links );

+        }

+    }

+

+    return result;

+}

+

+

+void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group )

+{

+    struct PaUtilAllocationGroupLink *current = group->linkBlocks;

+    struct PaUtilAllocationGroupLink *next;

+

+    while( current )

+    {

+        next = current->next;

+        PaUtil_FreeMemory( current->buffer );

+        current = next;

+    }

+

+    PaUtil_FreeMemory( group );

+}

+

+

+void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size )

+{

+    struct PaUtilAllocationGroupLink *links, *link;

+    void *result = 0;

+    

+    /* allocate more links if necessary */

+    if( !group->spareLinks )

+    {

+        /* double the link count on each block allocation */

+        links = AllocateLinks( group->linkCount, group->linkBlocks, group->spareLinks );

+        if( links )

+        {

+            group->linkCount += group->linkCount;

+            group->linkBlocks = &links[0];

+            group->spareLinks = &links[1];

+        }

+    }

+

+    if( group->spareLinks )

+    {

+        result = PaUtil_AllocateMemory( size );

+        if( result )

+        {

+            link = group->spareLinks;

+            group->spareLinks = link->next;

+

+            link->buffer = result;

+            link->next = group->allocations;

+

+            group->allocations = link;

+        }

+    }

+

+    return result;    

+}

+

+

+void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer )

+{

+    struct PaUtilAllocationGroupLink *current = group->allocations;

+    struct PaUtilAllocationGroupLink *previous = 0;

+

+    if( buffer == 0 )

+        return;

+

+    /* find the right link and remove it */

+    while( current )

+    {

+        if( current->buffer == buffer )

+        {

+            if( previous )

+            {

+                previous->next = current->next;

+            }

+            else

+            {

+                group->allocations = current->next;

+            }

+

+            current->buffer = 0;

+            current->next = group->spareLinks;

+            group->spareLinks = current;

+

+            break;

+        }

+        

+        previous = current;

+        current = current->next;

+    }

+

+    PaUtil_FreeMemory( buffer ); /* free the memory whether we found it in the list or not */

+}

+

+

+void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group )

+{

+    struct PaUtilAllocationGroupLink *current = group->allocations;

+    struct PaUtilAllocationGroupLink *previous = 0;

+

+    /* free all buffers in the allocations list */

+    while( current )

+    {

+        PaUtil_FreeMemory( current->buffer );

+        current->buffer = 0;

+

+        previous = current;

+        current = current->next;

+    }

+

+    /* link the former allocations list onto the front of the spareLinks list */

+    if( previous )

+    {

+        previous->next = group->spareLinks;

+        group->spareLinks = group->allocations;

+        group->allocations = 0;

+    }

+}

+

diff --git a/pjmedia/src/pjmedia/portaudio/pa_allocation.h b/pjmedia/src/pjmedia/portaudio/pa_allocation.h
index fb9321a..788a8ae 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_allocation.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_allocation.h
@@ -1,95 +1,116 @@
-#ifndef PA_ALLOCATION_H
-#define PA_ALLOCATION_H
-/*
- * $Id: pa_allocation.h,v 1.1.2.4 2003/09/20 21:04:44 rossbencina Exp $
- * Portable Audio I/O Library allocation context header
- * memory allocation context for tracking allocation groups
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Allocation Group prototypes. An Allocation Group makes it easy to
- allocate multiple blocks of memory and free them all simultanously.
- 
- An allocation group is useful for keeping track of multiple blocks
- of memory which are allocated at the same time (such as during initialization)
- and need to be deallocated at the same time. The allocation group maintains
- a list of allocated blocks, and can deallocate them all simultaneously which
- can be usefull for cleaning up after a partially initialized object fails.
-
- The allocation group implementation is built on top of the lower
- level allocation functions defined in pa_util.h
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-typedef struct
-{
-    long linkCount;
-    struct PaUtilAllocationGroupLink *linkBlocks;
-    struct PaUtilAllocationGroupLink *spareLinks;
-    struct PaUtilAllocationGroupLink *allocations;
-}PaUtilAllocationGroup;
-
-
-
-/** Create an allocation group.
-*/
-PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void );
-
-/** Destroy an allocation group, but not the memory allocated through the group.
-*/
-void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group );
-
-/** Allocate a block of memory though an allocation group.
-*/
-void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size );
-
-/** Free a block of memory that was previously allocated though an allocation
- group. Calling this function is a relatively time consuming operation.
- Under normal circumstances clients should call PaUtil_FreeAllAllocations to
- free all allocated blocks simultaneously.
- @see PaUtil_FreeAllAllocations
-*/
-void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer );
-
-/** Free all blocks of memory which have been allocated through the allocation
- group. This function doesn't destroy the group itself.
-*/
-void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group );
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_ALLOCATION_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_ALLOCATION_H

+#define PA_ALLOCATION_H

+/*

+ * $Id: pa_allocation.h,v 1.1.2.4 2003/09/20 21:04:44 rossbencina Exp $

+ * Portable Audio I/O Library allocation context header

+ * memory allocation context for tracking allocation groups

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+ @brief Allocation Group prototypes. An Allocation Group makes it easy to

+ allocate multiple blocks of memory and free them all simultanously.

+ 

+ An allocation group is useful for keeping track of multiple blocks

+ of memory which are allocated at the same time (such as during initialization)

+ and need to be deallocated at the same time. The allocation group maintains

+ a list of allocated blocks, and can deallocate them all simultaneously which

+ can be usefull for cleaning up after a partially initialized object fails.

+

+ The allocation group implementation is built on top of the lower

+ level allocation functions defined in pa_util.h

+*/

+

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+typedef struct

+{

+    long linkCount;

+    struct PaUtilAllocationGroupLink *linkBlocks;

+    struct PaUtilAllocationGroupLink *spareLinks;

+    struct PaUtilAllocationGroupLink *allocations;

+}PaUtilAllocationGroup;

+

+

+

+/** Create an allocation group.

+*/

+PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void );

+

+/** Destroy an allocation group, but not the memory allocated through the group.

+*/

+void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group );

+

+/** Allocate a block of memory though an allocation group.

+*/

+void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size );

+

+/** Free a block of memory that was previously allocated though an allocation

+ group. Calling this function is a relatively time consuming operation.

+ Under normal circumstances clients should call PaUtil_FreeAllAllocations to

+ free all allocated blocks simultaneously.

+ @see PaUtil_FreeAllAllocations

+*/

+void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer );

+

+/** Free all blocks of memory which have been allocated through the allocation

+ group. This function doesn't destroy the group itself.

+*/

+void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group );

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PA_ALLOCATION_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_converters.c b/pjmedia/src/pjmedia/portaudio/pa_converters.c
index 4ee73c9..33fe6a8 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_converters.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_converters.c
@@ -1,1926 +1,1947 @@
-/*
- * $Id: pa_converters.c,v 1.1.2.26 2004/12/11 16:32:38 aknudsen Exp $
- * Portable Audio I/O Library sample conversion mechanism
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Conversion functions implementations.
- 
- If the C9x function lrintf() is available, define PA_USE_C99_LRINTF to use it
-
- @todo Consider whether functions which dither but don't clip should exist,
- V18 automatically enabled clipping whenever dithering was selected. Perhaps
- we should do the same.
-
- @todo implement the converters marked IMPLEMENT ME: Float32_To_UInt8_Dither,
- Float32_To_UInt8_Clip, Float32_To_UInt8_DitherClip, Int32_To_Int24_Dither,
- Int32_To_UInt8_Dither, Int24_To_Int16_Dither, Int24_To_Int8_Dither, 
- Int24_To_UInt8_Dither, Int16_To_Int8_Dither, Int16_To_UInt8_Dither,
-
- @todo review the converters marked REVIEW: Float32_To_Int32,
- Float32_To_Int32_Dither, Float32_To_Int32_Clip, Float32_To_Int32_DitherClip,
- Int32_To_Int16_Dither, Int32_To_Int8_Dither, Int16_To_Int32
-*/
-
-
-#include "pa_converters.h"
-#include "pa_dither.h"
-#include "pa_endianness.h"
-#include "pa_types.h"
-
-
-PaSampleFormat PaUtil_SelectClosestAvailableFormat(
-        PaSampleFormat availableFormats, PaSampleFormat format )
-{
-    PaSampleFormat result;
-
-    format &= ~paNonInterleaved;
-    availableFormats &= ~paNonInterleaved;
-    
-    if( (format & availableFormats) == 0 )
-    {
-        /* NOTE: this code depends on the sample format constants being in
-            descending order of quality - ie best quality is 0
-            FIXME: should write an assert which checks that all of the
-            known constants conform to that requirement.
-        */
-
-        if( format != 0x01 )
-        {
-            /* scan for better formats */
-            result = format;
-            do
-            {
-                result >>= 1;
-            }
-            while( (result & availableFormats) == 0 && result != 0 );
-        }
-        else
-        {
-            result = 0;
-        }
-        
-        if( result == 0 ){
-            /* scan for worse formats */
-            result = format;
-            do
-            {
-                result <<= 1;
-            }
-            while( (result & availableFormats) == 0 && result != paCustomFormat );
-
-            if( (result & availableFormats) == 0 )
-                result = paSampleFormatNotSupported;
-        }
-        
-    }else{
-        result = format;
-    }
-
-    return result;
-}
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_SELECT_FORMAT_( format, float32, int32, int24, int16, int8, uint8 ) \
-    switch( format & ~paNonInterleaved ){                                      \
-    case paFloat32:                                                            \
-        float32                                                                \
-    case paInt32:                                                              \
-        int32                                                                  \
-    case paInt24:                                                              \
-        int24                                                                  \
-    case paInt16:                                                              \
-        int16                                                                  \
-    case paInt8:                                                               \
-        int8                                                                   \
-    case paUInt8:                                                              \
-        uint8                                                                  \
-    default: return 0;                                                         \
-    }
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_SELECT_CONVERTER_DITHER_CLIP_( flags, source, destination )         \
-    if( flags & paClipOff ){ /* no clip */                                     \
-        if( flags & paDitherOff ){ /* no dither */                             \
-            return paConverters. source ## _To_ ## destination;                \
-        }else{ /* dither */                                                    \
-            return paConverters. source ## _To_ ## destination ## _Dither;     \
-        }                                                                      \
-    }else{ /* clip */                                                          \
-        if( flags & paDitherOff ){ /* no dither */                             \
-            return paConverters. source ## _To_ ## destination ## _Clip;       \
-        }else{ /* dither */                                                    \
-            return paConverters. source ## _To_ ## destination ## _DitherClip; \
-        }                                                                      \
-    }
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_SELECT_CONVERTER_DITHER_( flags, source, destination )              \
-    if( flags & paDitherOff ){ /* no dither */                                 \
-        return paConverters. source ## _To_ ## destination;                    \
-    }else{ /* dither */                                                        \
-        return paConverters. source ## _To_ ## destination ## _Dither;         \
-    }
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_USE_CONVERTER_( source, destination )\
-    return paConverters. source ## _To_ ## destination;
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_UNITY_CONVERSION_( wordlength )\
-    return paConverters. Copy_ ## wordlength ## _To_ ## wordlength;
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,
-        PaSampleFormat destinationFormat, PaStreamFlags flags )
-{
-    PA_SELECT_FORMAT_( sourceFormat,
-                       /* paFloat32: */
-                       PA_SELECT_FORMAT_( destinationFormat,
-                                          /* paFloat32: */        PA_UNITY_CONVERSION_( 32 ),
-                                          /* paInt32: */          PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int32 ),
-                                          /* paInt24: */          PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int24 ),
-                                          /* paInt16: */          PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int16 ),
-                                          /* paInt8: */           PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int8 ),
-                                          /* paUInt8: */          PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, UInt8 )
-                                        ),
-                       /* paInt32: */
-                       PA_SELECT_FORMAT_( destinationFormat,
-                                          /* paFloat32: */        PA_USE_CONVERTER_( Int32, Float32 ),
-                                          /* paInt32: */          PA_UNITY_CONVERSION_( 32 ),
-                                          /* paInt24: */          PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int24 ),
-                                          /* paInt16: */          PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int16 ),
-                                          /* paInt8: */           PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int8 ),
-                                          /* paUInt8: */          PA_SELECT_CONVERTER_DITHER_( flags, Int32, UInt8 )
-                                        ),
-                       /* paInt24: */
-                       PA_SELECT_FORMAT_( destinationFormat,
-                                          /* paFloat32: */        PA_USE_CONVERTER_( Int24, Float32 ),
-                                          /* paInt32: */          PA_USE_CONVERTER_( Int24, Int32 ),
-                                          /* paInt24: */          PA_UNITY_CONVERSION_( 24 ),
-                                          /* paInt16: */          PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int16 ),
-                                          /* paInt8: */           PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int8 ),
-                                          /* paUInt8: */          PA_SELECT_CONVERTER_DITHER_( flags, Int24, UInt8 )
-                                        ),
-                       /* paInt16: */
-                       PA_SELECT_FORMAT_( destinationFormat,
-                                          /* paFloat32: */        PA_USE_CONVERTER_( Int16, Float32 ),
-                                          /* paInt32: */          PA_USE_CONVERTER_( Int16, Int32 ),
-                                          /* paInt24: */          PA_USE_CONVERTER_( Int16, Int24 ),
-                                          /* paInt16: */          PA_UNITY_CONVERSION_( 16 ),
-                                          /* paInt8: */           PA_SELECT_CONVERTER_DITHER_( flags, Int16, Int8 ),
-                                          /* paUInt8: */          PA_SELECT_CONVERTER_DITHER_( flags, Int16, UInt8 )
-                                        ),
-                       /* paInt8: */
-                       PA_SELECT_FORMAT_( destinationFormat,
-                                          /* paFloat32: */        PA_USE_CONVERTER_( Int8, Float32 ),
-                                          /* paInt32: */          PA_USE_CONVERTER_( Int8, Int32 ),
-                                          /* paInt24: */          PA_USE_CONVERTER_( Int8, Int24 ),
-                                          /* paInt16: */          PA_USE_CONVERTER_( Int8, Int16 ),
-                                          /* paInt8: */           PA_UNITY_CONVERSION_( 8 ),
-                                          /* paUInt8: */          PA_USE_CONVERTER_( Int8, UInt8 )
-                                        ),
-                       /* paUInt8: */
-                       PA_SELECT_FORMAT_( destinationFormat,
-                                          /* paFloat32: */        PA_USE_CONVERTER_( UInt8, Float32 ),
-                                          /* paInt32: */          PA_USE_CONVERTER_( UInt8, Int32 ),
-                                          /* paInt24: */          PA_USE_CONVERTER_( UInt8, Int24 ),
-                                          /* paInt16: */          PA_USE_CONVERTER_( UInt8, Int16 ),
-                                          /* paInt8: */           PA_USE_CONVERTER_( UInt8, Int8 ),
-                                          /* paUInt8: */          PA_UNITY_CONVERSION_( 8 )
-                                        )
-                     )
-}
-
-/* -------------------------------------------------------------------------- */
-
-#ifdef PA_NO_STANDARD_CONVERTERS
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilConverterTable paConverters = {
-    0, /* PaUtilConverter *Float32_To_Int32; */
-    0, /* PaUtilConverter *Float32_To_Int32_Dither; */
-    0, /* PaUtilConverter *Float32_To_Int32_Clip; */
-    0, /* PaUtilConverter *Float32_To_Int32_DitherClip; */
-
-    0, /* PaUtilConverter *Float32_To_Int24; */
-    0, /* PaUtilConverter *Float32_To_Int24_Dither; */
-    0, /* PaUtilConverter *Float32_To_Int24_Clip; */
-    0, /* PaUtilConverter *Float32_To_Int24_DitherClip; */
-
-    0, /* PaUtilConverter *Float32_To_Int16; */
-    0, /* PaUtilConverter *Float32_To_Int16_Dither; */
-    0, /* PaUtilConverter *Float32_To_Int16_Clip; */
-    0, /* PaUtilConverter *Float32_To_Int16_DitherClip; */
-
-    0, /* PaUtilConverter *Float32_To_Int8; */
-    0, /* PaUtilConverter *Float32_To_Int8_Dither; */
-    0, /* PaUtilConverter *Float32_To_Int8_Clip; */
-    0, /* PaUtilConverter *Float32_To_Int8_DitherClip; */
-
-    0, /* PaUtilConverter *Float32_To_UInt8; */
-    0, /* PaUtilConverter *Float32_To_UInt8_Dither; */
-    0, /* PaUtilConverter *Float32_To_UInt8_Clip; */
-    0, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */
-
-    0, /* PaUtilConverter *Int32_To_Float32; */
-    0, /* PaUtilConverter *Int32_To_Int24; */
-    0, /* PaUtilConverter *Int32_To_Int24_Dither; */
-    0, /* PaUtilConverter *Int32_To_Int16; */
-    0, /* PaUtilConverter *Int32_To_Int16_Dither; */
-    0, /* PaUtilConverter *Int32_To_Int8; */
-    0, /* PaUtilConverter *Int32_To_Int8_Dither; */
-    0, /* PaUtilConverter *Int32_To_UInt8; */
-    0, /* PaUtilConverter *Int32_To_UInt8_Dither; */
-
-    0, /* PaUtilConverter *Int24_To_Float32; */
-    0, /* PaUtilConverter *Int24_To_Int32; */
-    0, /* PaUtilConverter *Int24_To_Int16; */
-    0, /* PaUtilConverter *Int24_To_Int16_Dither; */
-    0, /* PaUtilConverter *Int24_To_Int8; */
-    0, /* PaUtilConverter *Int24_To_Int8_Dither; */
-    0, /* PaUtilConverter *Int24_To_UInt8; */
-    0, /* PaUtilConverter *Int24_To_UInt8_Dither; */
-    
-    0, /* PaUtilConverter *Int16_To_Float32; */
-    0, /* PaUtilConverter *Int16_To_Int32; */
-    0, /* PaUtilConverter *Int16_To_Int24; */
-    0, /* PaUtilConverter *Int16_To_Int8; */
-    0, /* PaUtilConverter *Int16_To_Int8_Dither; */
-    0, /* PaUtilConverter *Int16_To_UInt8; */
-    0, /* PaUtilConverter *Int16_To_UInt8_Dither; */
-
-    0, /* PaUtilConverter *Int8_To_Float32; */
-    0, /* PaUtilConverter *Int8_To_Int32; */
-    0, /* PaUtilConverter *Int8_To_Int24 */
-    0, /* PaUtilConverter *Int8_To_Int16; */
-    0, /* PaUtilConverter *Int8_To_UInt8; */
-
-    0, /* PaUtilConverter *UInt8_To_Float32; */
-    0, /* PaUtilConverter *UInt8_To_Int32; */
-    0, /* PaUtilConverter *UInt8_To_Int24; */
-    0, /* PaUtilConverter *UInt8_To_Int16; */
-    0, /* PaUtilConverter *UInt8_To_Int8; */
-
-    0, /* PaUtilConverter *Copy_8_To_8; */
-    0, /* PaUtilConverter *Copy_16_To_16; */
-    0, /* PaUtilConverter *Copy_24_To_24; */
-    0  /* PaUtilConverter *Copy_32_To_32; */
-};
-
-/* -------------------------------------------------------------------------- */
-
-#else /* PA_NO_STANDARD_CONVERTERS is not defined */
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_CLIP_( val, min, max )\
-    { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
-
-
-static const float const_1_div_128_ = 1.0f / 128.0f;  /* 8 bit multiplier */
-
-static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */
-
-static const double const_1_div_2147483648_ = 1.0 / 2147483648.0; /* 32 bit multiplier */
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        /* REVIEW */
-#ifdef PA_USE_C99_LRINTF
-        float scaled = *src * 0x7FFFFFFF;
-        *dest = lrintf(scaled-0.5f);
-#else
-        double scaled = *src * 0x7FFFFFFF;
-        *dest = (signed long) scaled;        
-#endif
-        
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-
-    while( count-- )
-    {
-        /* REVIEW */
-#ifdef PA_USE_C99_LRINTF
-        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        float dithered = ((float)*src * (2147483646.0f)) + dither;
-        *dest = lrintf(dithered - 0.5f);
-#else
-        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        double dithered = ((double)*src * (2147483646.0)) + dither;
-        *dest = (signed long) dithered;
-#endif
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_Clip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-    (void) ditherGenerator; /* unused parameter */
-    
-    while( count-- )
-    {
-        /* REVIEW */
-#ifdef PA_USE_C99_LRINTF
-        float scaled = *src * 0x7FFFFFFF;
-        PA_CLIP_( scaled, -2147483648.f, 2147483647.f  );
-        *dest = lrintf(scaled-0.5f);
-#else
-        double scaled = *src * 0x7FFFFFFF;
-        PA_CLIP_( scaled, -2147483648., 2147483647.  );
-        *dest = (signed long) scaled;
-#endif
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_DitherClip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-
-    while( count-- )
-    {
-        /* REVIEW */
-#ifdef PA_USE_C99_LRINTF
-        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        float dithered = ((float)*src * (2147483646.0f)) + dither;
-        PA_CLIP_( dithered, -2147483648.f, 2147483647.f  );
-        *dest = lrintf(dithered-0.5f);
-#else
-        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        double dithered = ((double)*src * (2147483646.0)) + dither;
-        PA_CLIP_( dithered, -2147483648., 2147483647.  );
-        *dest = (signed long) dithered;
-#endif
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    signed long temp;
-
-    (void) ditherGenerator; /* unused parameter */
-    
-    while( count-- )
-    {
-        /* convert to 32 bit and drop the low 8 bits */
-        double scaled = *src * 0x7FFFFFFF;
-        temp = (signed long) scaled;
-        
-#if defined(PA_LITTLE_ENDIAN)
-        dest[0] = (unsigned char)(temp >> 8);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 24);
-#elif defined(PA_BIG_ENDIAN)
-        dest[0] = (unsigned char)(temp >> 24);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 8);
-#endif
-
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    signed long temp;
-
-    while( count-- )
-    {
-        /* convert to 32 bit and drop the low 8 bits */
-
-        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        double dithered = ((double)*src * (2147483646.0)) + dither;
-        
-        temp = (signed long) dithered;
-
-#if defined(PA_LITTLE_ENDIAN)
-        dest[0] = (unsigned char)(temp >> 8);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 24);
-#elif defined(PA_BIG_ENDIAN)
-        dest[0] = (unsigned char)(temp >> 24);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 8);
-#endif
-
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_Clip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    signed long temp;
-
-    (void) ditherGenerator; /* unused parameter */
-    
-    while( count-- )
-    {
-        /* convert to 32 bit and drop the low 8 bits */
-        double scaled = *src * 0x7FFFFFFF;
-        PA_CLIP_( scaled, -2147483648., 2147483647.  );
-        temp = (signed long) scaled;
-
-#if defined(PA_LITTLE_ENDIAN)
-        dest[0] = (unsigned char)(temp >> 8);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 24);
-#elif defined(PA_BIG_ENDIAN)
-        dest[0] = (unsigned char)(temp >> 24);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 8);
-#endif
-
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_DitherClip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    signed long temp;
-    
-    while( count-- )
-    {
-        /* convert to 32 bit and drop the low 8 bits */
-        
-        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        double dithered = ((double)*src * (2147483646.0)) + dither;
-        PA_CLIP_( dithered, -2147483648., 2147483647.  );
-        
-        temp = (signed long) dithered;
-
-#if defined(PA_LITTLE_ENDIAN)
-        dest[0] = (unsigned char)(temp >> 8);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 24);
-#elif defined(PA_BIG_ENDIAN)
-        dest[0] = (unsigned char)(temp >> 24);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 8);
-#endif
-
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-#ifdef PA_USE_C99_LRINTF
-        float tempf = (*src * (32767.0f)) ;
-        *dest = lrintf(tempf-0.5f);
-#else
-        short samp = (short) (*src * (32767.0f));
-        *dest = samp;
-#endif
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed short *dest = (signed short*)destinationBuffer;
-
-    while( count-- )
-    {
-
-        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        float dithered = (*src * (32766.0f)) + dither;
-
-#ifdef PA_USE_C99_LRINTF
-        *dest = lrintf(dithered-0.5f);
-#else
-        *dest = (signed short) dithered;
-#endif
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_Clip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-#ifdef PA_USE_C99_LRINTF
-        long samp = lrintf((*src * (32767.0f)) -0.5f);
-#else
-        long samp = (signed long) (*src * (32767.0f));
-#endif
-        PA_CLIP_( samp, -0x8000, 0x7FFF );
-        *dest = (signed short) samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_DitherClip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-
-        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        float dithered = (*src * (32766.0f)) + dither;
-        signed long samp = (signed long) dithered;
-        PA_CLIP_( samp, -0x8000, 0x7FFF );
-#ifdef PA_USE_C99_LRINTF
-        *dest = lrintf(samp-0.5f);
-#else
-        *dest = (signed short) samp;
-#endif
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed char *dest =  (signed char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        signed char samp = (signed char) (*src * (127.0f));
-        *dest = samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int8_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed char *dest =  (signed char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        float dithered = (*src * (126.0f)) + dither;
-        signed long samp = (signed long) dithered;
-        *dest = (signed char) samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int8_Clip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed char *dest =  (signed char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        signed long samp = (signed long)(*src * (127.0f));
-        PA_CLIP_( samp, -0x80, 0x7F );
-        *dest = (signed char) samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int8_DitherClip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    signed char *dest =  (signed char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        /* use smaller scaler to prevent overflow when we add the dither */
-        float dithered = (*src * (126.0f)) + dither;
-        signed long samp = (signed long) dithered;
-        PA_CLIP_( samp, -0x80, 0x7F );
-        *dest = (signed char) samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_UInt8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        unsigned char samp = (unsigned char)(128 + ((unsigned char) (*src * (127.0f))));
-        *dest = samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_UInt8_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        /* IMPLEMENT ME */
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_UInt8_Clip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        /* IMPLEMENT ME */
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_UInt8_DitherClip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        /* IMPLEMENT ME */
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Float32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed long *src = (signed long*)sourceBuffer;
-    float *dest =  (float*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        *dest = (float) ((double)*src * const_1_div_2147483648_);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int24(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed long *src    = (signed long*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    (void) ditherGenerator; /* unused parameter */
-    
-	while( count-- )
-    {
-		/* REVIEW */
-#if defined(PA_LITTLE_ENDIAN)
-        dest[0] = (unsigned char)(*src >> 8);
-        dest[1] = (unsigned char)(*src >> 16);
-        dest[2] = (unsigned char)(*src >> 24);
-#elif defined(PA_BIG_ENDIAN)
-        dest[0] = (unsigned char)(*src >> 24);
-        dest[1] = (unsigned char)(*src >> 16);
-        dest[2] = (unsigned char)(*src >> 8);
-#endif
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int24_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    (void) destinationBuffer; /* unused parameters */
-    (void) destinationStride; /* unused parameters */
-    (void) sourceBuffer; /* unused parameters */
-    (void) sourceStride; /* unused parameters */
-    (void) count; /* unused parameters */
-    (void) ditherGenerator; /* unused parameters */
-    /* IMPLEMENT ME */
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int16(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed long *src = (signed long*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        *dest = (signed short) ((*src) >> 16);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int16_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed long *src = (signed long*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    signed long dither;
-
-    while( count-- )
-    {
-        /* REVIEW */
-        dither = PaUtil_Generate16BitTriangularDither( ditherGenerator );
-        *dest = (signed short) ((((*src)>>1) + dither) >> 15);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed long *src = (signed long*)sourceBuffer;
-    signed char *dest =  (signed char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        *dest = (signed char) ((*src) >> 24);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int8_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed long *src = (signed long*)sourceBuffer;
-    signed char *dest =  (signed char*)destinationBuffer;
-    signed long dither;
-
-    while( count-- )
-    {
-        /* REVIEW */
-        dither = PaUtil_Generate16BitTriangularDither( ditherGenerator );
-        *dest = (signed char) ((((*src)>>1) + dither) >> 23);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_UInt8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed long *src = (signed long*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-		(*dest) = (unsigned char)(((*src) >> 24) + 128); 
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_UInt8_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed long *src = (signed long*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        /* IMPLEMENT ME */
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Float32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    float *dest = (float*)destinationBuffer;
-    signed long temp;
-
-    (void) ditherGenerator; /* unused parameter */
-    
-    while( count-- )
-    {
-
-#if defined(PA_LITTLE_ENDIAN)
-        temp = (((long)src[0]) << 8);  
-        temp = temp | (((long)src[1]) << 16);
-        temp = temp | (((long)src[2]) << 24);
-#elif defined(PA_BIG_ENDIAN)
-        temp = (((long)src[0]) << 24);
-        temp = temp | (((long)src[1]) << 16);
-        temp = temp | (((long)src[2]) << 8);
-#endif
-
-        *dest = (float) ((double)temp * const_1_div_2147483648_);
-
-        src += sourceStride * 3;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src  = (unsigned char*)sourceBuffer;
-    signed long   *dest = (signed long*)  destinationBuffer;
-    signed long temp;
-
-    (void) ditherGenerator; /* unused parameter */
-    
-    while( count-- )
-    {
-
-#if defined(PA_LITTLE_ENDIAN)
-        temp = (((long)src[0]) << 8);  
-        temp = temp | (((long)src[1]) << 16);
-        temp = temp | (((long)src[2]) << 24);
-#elif defined(PA_BIG_ENDIAN)
-        temp = (((long)src[0]) << 24);
-        temp = temp | (((long)src[1]) << 16);
-        temp = temp | (((long)src[2]) << 8);
-#endif
-
-        *dest = temp;
-
-        src += sourceStride * 3;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int16(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    signed short *dest = (signed short*)destinationBuffer;
-    
-	signed short temp;
-
-    (void) ditherGenerator; /* unused parameter */
-        
-    while( count-- )
-    {
-		
-#if defined(PA_LITTLE_ENDIAN)
-		/* src[0] is discarded */
-        temp = (((signed short)src[1]));
-        temp = temp | (signed short)(((signed short)src[2]) << 8);
-#elif defined(PA_BIG_ENDIAN)
-		/* src[2] is discarded */
-        temp = (signed short)(((signed short)src[0]) << 8);
-        temp = temp | (((signed short)src[1]));
-#endif
-
-        *dest = temp;
-
-        src += sourceStride * 3;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int16_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    (void) destinationBuffer; /* unused parameters */
-    (void) destinationStride; /* unused parameters */
-    (void) sourceBuffer; /* unused parameters */
-    (void) sourceStride; /* unused parameters */
-    (void) count; /* unused parameters */
-    (void) ditherGenerator; /* unused parameters */
-    /* IMPLEMENT ME */
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    signed char  *dest = (signed char*)destinationBuffer;
-    
-    (void) ditherGenerator; /* unused parameter */
-        
-    while( count-- )
-    {	
-	
-#if defined(PA_LITTLE_ENDIAN)
-		/* src[0] is discarded */
-		/* src[1] is discarded */
-        *dest = src[2];
-#elif defined(PA_BIG_ENDIAN)
-		/* src[2] is discarded */
-		/* src[1] is discarded */
-		*dest = src[0];
-#endif
-
-        src += sourceStride * 3;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int8_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    (void) destinationBuffer; /* unused parameters */
-    (void) destinationStride; /* unused parameters */
-    (void) sourceBuffer; /* unused parameters */
-    (void) sourceStride; /* unused parameters */
-    (void) count; /* unused parameters */
-    (void) ditherGenerator; /* unused parameters */
-    /* IMPLEMENT ME */
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_UInt8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    
-    (void) ditherGenerator; /* unused parameter */
-        
-    while( count-- )
-    {
-		
-#if defined(PA_LITTLE_ENDIAN)
-		/* src[0] is discarded */
-		/* src[1] is discarded */
-        *dest = (unsigned char)(src[2] + 128);
-#elif defined(PA_BIG_ENDIAN)
-        *dest = (unsigned char)(src[0] + 128);
-		/* src[1] is discarded */
-		/* src[2] is discarded */		
-#endif
-
-        src += sourceStride * 3;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_UInt8_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    (void) destinationBuffer; /* unused parameters */
-    (void) destinationStride; /* unused parameters */
-    (void) sourceBuffer; /* unused parameters */
-    (void) sourceStride; /* unused parameters */
-    (void) count; /* unused parameters */
-    (void) ditherGenerator; /* unused parameters */
-    /* IMPLEMENT ME */
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Float32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed short *src = (signed short*)sourceBuffer;
-    float *dest =  (float*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        float samp = *src * const_1_div_32768_; /* FIXME: i'm concerned about this being asymetrical with float->int16 -rb */
-        *dest = samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Int32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed short *src = (signed short*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        /* REVIEW: we should consider something like
-            (*src << 16) | (*src & 0xFFFF)
-        */
-        
-        *dest = *src << 16;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Int24(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed short *src   = (signed short*) sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    signed short temp;
-
-    (void) ditherGenerator; /* unused parameter */
-    
-    while( count-- )
-    {
-        temp = *src;
-        
-#if defined(PA_LITTLE_ENDIAN)
-        dest[0] = 0;
-        dest[1] = (unsigned char)(temp);
-        dest[2] = (unsigned char)(temp >> 8);
-#elif defined(PA_BIG_ENDIAN)
-        dest[0] = (unsigned char)(temp >> 8);
-        dest[1] = (unsigned char)(temp);
-        dest[2] = 0;
-#endif
-
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Int8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed short *src = (signed short*)sourceBuffer;
-    signed char *dest =  (signed char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        (*dest) = (signed char)((*src) >> 8);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Int8_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed short *src = (signed short*)sourceBuffer;
-    signed char *dest =  (signed char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        /* IMPLEMENT ME */
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_UInt8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed short *src = (signed short*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-		(*dest) = (unsigned char)(((*src) >> 8) + 128); 
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_UInt8_Dither(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed short *src = (signed short*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        /* IMPLEMENT ME */
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_Float32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed char *src = (signed char*)sourceBuffer;
-    float *dest =  (float*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        float samp = *src * const_1_div_128_;
-        *dest = samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_Int32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed char *src = (signed char*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-		(*dest) = (*src) << 24;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_Int24(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed char *src = (signed char*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-
-#if defined(PA_LITTLE_ENDIAN)
-        dest[0] = 0;
-        dest[1] = 0;
-        dest[2] = (*src);
-#elif defined(PA_BIG_ENDIAN)
-        dest[0] = (*src);
-        dest[1] = 0;
-        dest[2] = 0;
-#endif
-
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_Int16(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed char *src = (signed char*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-		(*dest) = (signed short)((*src) << 8);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_UInt8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    signed char *src = (signed char*)sourceBuffer;
-    unsigned char *dest =  (unsigned char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        (*dest) = (unsigned char)(*src + 128);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Float32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    float *dest =  (float*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        float samp = (*src - 128) * const_1_div_128_;
-        *dest = samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Int32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-		(*dest) = (*src - 128) << 24;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Int24(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-	unsigned char *src  = (unsigned char*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    (void) ditherGenerator; /* unused parameters */
-    
-	while( count-- )
-    {
-
-#if defined(PA_LITTLE_ENDIAN)
-        dest[0] = 0;
-        dest[1] = 0;
-        dest[2] = (unsigned char)(*src - 128);
-#elif defined(PA_BIG_ENDIAN)
-        dest[0] = (unsigned char)(*src - 128);
-        dest[1] = 0;
-        dest[2] = 0;
-#endif
-		
-        src += sourceStride;
-        dest += destinationStride * 3;    
-	}
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Int16(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-		(*dest) = (signed short)((*src - 128) << 8);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Int8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    signed char  *dest = (signed char*)destinationBuffer;
-    (void)ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        (*dest) = (signed char)(*src - 128);
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Copy_8_To_8(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-                                                      
-    (void) ditherGenerator; /* unused parameter */
-
-    while( count-- )
-    {
-        *dest = *src;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Copy_16_To_16(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    PaUint16 *src = (PaUint16 *)sourceBuffer;
-    PaUint16 *dest = (PaUint16 *)destinationBuffer;
-                                                        
-    (void) ditherGenerator; /* unused parameter */
-    
-    while( count-- )
-    {
-        *dest = *src;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Copy_24_To_24(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    unsigned char *src = (unsigned char*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-
-    (void) ditherGenerator; /* unused parameter */
-    
-    while( count-- )
-    {
-        dest[0] = src[0];
-        dest[1] = src[1];
-        dest[2] = src[2];
-
-        src += sourceStride * 3;
-        dest += destinationStride * 3;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Copy_32_To_32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    PaUint32 *dest = (PaUint32 *)destinationBuffer;
-    PaUint32 *src = (PaUint32 *)sourceBuffer;
-
-    (void) ditherGenerator; /* unused parameter */
-    
-    while( count-- )
-    {
-        *dest = *src;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilConverterTable paConverters = {
-    Float32_To_Int32,              /* PaUtilConverter *Float32_To_Int32; */
-    Float32_To_Int32_Dither,       /* PaUtilConverter *Float32_To_Int32_Dither; */
-    Float32_To_Int32_Clip,         /* PaUtilConverter *Float32_To_Int32_Clip; */
-    Float32_To_Int32_DitherClip,   /* PaUtilConverter *Float32_To_Int32_DitherClip; */
-
-    Float32_To_Int24,              /* PaUtilConverter *Float32_To_Int24; */
-    Float32_To_Int24_Dither,       /* PaUtilConverter *Float32_To_Int24_Dither; */
-    Float32_To_Int24_Clip,         /* PaUtilConverter *Float32_To_Int24_Clip; */
-    Float32_To_Int24_DitherClip,   /* PaUtilConverter *Float32_To_Int24_DitherClip; */
-    
-    Float32_To_Int16,              /* PaUtilConverter *Float32_To_Int16; */
-    Float32_To_Int16_Dither,       /* PaUtilConverter *Float32_To_Int16_Dither; */
-    Float32_To_Int16_Clip,         /* PaUtilConverter *Float32_To_Int16_Clip; */
-    Float32_To_Int16_DitherClip,   /* PaUtilConverter *Float32_To_Int16_DitherClip; */
-
-    Float32_To_Int8,               /* PaUtilConverter *Float32_To_Int8; */
-    Float32_To_Int8_Dither,        /* PaUtilConverter *Float32_To_Int8_Dither; */
-    Float32_To_Int8_Clip,          /* PaUtilConverter *Float32_To_Int8_Clip; */
-    Float32_To_Int8_DitherClip,    /* PaUtilConverter *Float32_To_Int8_DitherClip; */
-
-    Float32_To_UInt8,              /* PaUtilConverter *Float32_To_UInt8; */
-    Float32_To_UInt8_Dither,       /* PaUtilConverter *Float32_To_UInt8_Dither; */
-    Float32_To_UInt8_Clip,         /* PaUtilConverter *Float32_To_UInt8_Clip; */
-    Float32_To_UInt8_DitherClip,   /* PaUtilConverter *Float32_To_UInt8_DitherClip; */
-
-    Int32_To_Float32,              /* PaUtilConverter *Int32_To_Float32; */
-    Int32_To_Int24,                /* PaUtilConverter *Int32_To_Int24; */
-    Int32_To_Int24_Dither,         /* PaUtilConverter *Int32_To_Int24_Dither; */
-    Int32_To_Int16,                /* PaUtilConverter *Int32_To_Int16; */
-    Int32_To_Int16_Dither,         /* PaUtilConverter *Int32_To_Int16_Dither; */
-    Int32_To_Int8,                 /* PaUtilConverter *Int32_To_Int8; */
-    Int32_To_Int8_Dither,          /* PaUtilConverter *Int32_To_Int8_Dither; */
-    Int32_To_UInt8,                /* PaUtilConverter *Int32_To_UInt8; */
-    Int32_To_UInt8_Dither,         /* PaUtilConverter *Int32_To_UInt8_Dither; */
-
-    Int24_To_Float32,              /* PaUtilConverter *Int24_To_Float32; */
-    Int24_To_Int32,                /* PaUtilConverter *Int24_To_Int32; */
-    Int24_To_Int16,                /* PaUtilConverter *Int24_To_Int16; */
-    Int24_To_Int16_Dither,         /* PaUtilConverter *Int24_To_Int16_Dither; */
-    Int24_To_Int8,                 /* PaUtilConverter *Int24_To_Int8; */
-    Int24_To_Int8_Dither,          /* PaUtilConverter *Int24_To_Int8_Dither; */
-    Int24_To_UInt8,                /* PaUtilConverter *Int24_To_UInt8; */
-    Int24_To_UInt8_Dither,         /* PaUtilConverter *Int24_To_UInt8_Dither; */
-
-    Int16_To_Float32,              /* PaUtilConverter *Int16_To_Float32; */
-    Int16_To_Int32,                /* PaUtilConverter *Int16_To_Int32; */
-    Int16_To_Int24,                /* PaUtilConverter *Int16_To_Int24; */
-    Int16_To_Int8,                 /* PaUtilConverter *Int16_To_Int8; */
-    Int16_To_Int8_Dither,          /* PaUtilConverter *Int16_To_Int8_Dither; */
-    Int16_To_UInt8,                /* PaUtilConverter *Int16_To_UInt8; */
-    Int16_To_UInt8_Dither,         /* PaUtilConverter *Int16_To_UInt8_Dither; */
-
-    Int8_To_Float32,               /* PaUtilConverter *Int8_To_Float32; */
-    Int8_To_Int32,                 /* PaUtilConverter *Int8_To_Int32; */
-    Int8_To_Int24,                 /* PaUtilConverter *Int8_To_Int24 */
-    Int8_To_Int16,                 /* PaUtilConverter *Int8_To_Int16; */
-    Int8_To_UInt8,                 /* PaUtilConverter *Int8_To_UInt8; */
-
-    UInt8_To_Float32,              /* PaUtilConverter *UInt8_To_Float32; */
-    UInt8_To_Int32,                /* PaUtilConverter *UInt8_To_Int32; */
-    UInt8_To_Int24,                /* PaUtilConverter *UInt8_To_Int24; */
-    UInt8_To_Int16,                /* PaUtilConverter *UInt8_To_Int16; */
-    UInt8_To_Int8,                 /* PaUtilConverter *UInt8_To_Int8; */
-
-    Copy_8_To_8,                   /* PaUtilConverter *Copy_8_To_8; */
-    Copy_16_To_16,                 /* PaUtilConverter *Copy_16_To_16; */
-    Copy_24_To_24,                 /* PaUtilConverter *Copy_24_To_24; */
-    Copy_32_To_32                  /* PaUtilConverter *Copy_32_To_32; */
-};
-
-/* -------------------------------------------------------------------------- */
-
-#endif /* PA_NO_STANDARD_CONVERTERS */
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat )
-{
-    switch( destinationFormat & ~paNonInterleaved ){
-    case paFloat32:
-        return paZeroers.Zero32;
-    case paInt32:
-        return paZeroers.Zero32;
-    case paInt24:
-        return paZeroers.Zero24;
-    case paInt16:
-        return paZeroers.Zero16;
-    case paInt8:
-        return paZeroers.Zero8;
-    case paUInt8:
-        return paZeroers.ZeroU8;
-    default: return 0;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-#ifdef PA_NO_STANDARD_ZEROERS
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilZeroerTable paZeroers = {
-    0,  /* PaUtilZeroer *ZeroU8; */
-    0,  /* PaUtilZeroer *Zero8; */
-    0,  /* PaUtilZeroer *Zero16; */
-    0,  /* PaUtilZeroer *Zero24; */
-    0,  /* PaUtilZeroer *Zero32; */
-};
-
-/* -------------------------------------------------------------------------- */
-
-#else /* PA_NO_STANDARD_ZEROERS is not defined */
-
-/* -------------------------------------------------------------------------- */
-
-static void ZeroU8( void *destinationBuffer, signed int destinationStride,
-        unsigned int count )
-{
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-
-    while( count-- )
-    {
-        *dest = 128;
-
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Zero8( void *destinationBuffer, signed int destinationStride,
-        unsigned int count )
-{
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-
-    while( count-- )
-    {
-        *dest = 0;
-
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Zero16( void *destinationBuffer, signed int destinationStride,
-        unsigned int count )
-{
-    PaUint16 *dest = (PaUint16 *)destinationBuffer;
-
-    while( count-- )
-    {
-        *dest = 0;
-
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Zero24( void *destinationBuffer, signed int destinationStride,
-        unsigned int count )
-{
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-
-    while( count-- )
-    {
-        dest[0] = 0;
-        dest[1] = 0;
-        dest[2] = 0;
-
-        dest += destinationStride * 3;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Zero32( void *destinationBuffer, signed int destinationStride,
-        unsigned int count )
-{
-    PaUint32 *dest = (PaUint32 *)destinationBuffer;
-
-    while( count-- )
-    {
-        *dest = 0;
-
-        dest += destinationStride;
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilZeroerTable paZeroers = {
-    ZeroU8,  /* PaUtilZeroer *ZeroU8; */
-    Zero8,  /* PaUtilZeroer *Zero8; */
-    Zero16,  /* PaUtilZeroer *Zero16; */
-    Zero24,  /* PaUtilZeroer *Zero24; */
-    Zero32,  /* PaUtilZeroer *Zero32; */
-};
-
-/* -------------------------------------------------------------------------- */
-
-#endif /* PA_NO_STANDARD_ZEROERS */
+/*

+ * $Id: pa_converters.c,v 1.1.2.26 2004/12/11 16:32:38 aknudsen Exp $

+ * Portable Audio I/O Library sample conversion mechanism

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+ @brief Conversion functions implementations.

+ 

+ If the C9x function lrintf() is available, define PA_USE_C99_LRINTF to use it

+

+ @todo Consider whether functions which dither but don't clip should exist,

+ V18 automatically enabled clipping whenever dithering was selected. Perhaps

+ we should do the same.

+

+ @todo implement the converters marked IMPLEMENT ME: Float32_To_UInt8_Dither,

+ Float32_To_UInt8_Clip, Float32_To_UInt8_DitherClip, Int32_To_Int24_Dither,

+ Int32_To_UInt8_Dither, Int24_To_Int16_Dither, Int24_To_Int8_Dither, 

+ Int24_To_UInt8_Dither, Int16_To_Int8_Dither, Int16_To_UInt8_Dither,

+

+ @todo review the converters marked REVIEW: Float32_To_Int32,

+ Float32_To_Int32_Dither, Float32_To_Int32_Clip, Float32_To_Int32_DitherClip,

+ Int32_To_Int16_Dither, Int32_To_Int8_Dither, Int16_To_Int32

+*/

+

+

+#include "pa_converters.h"

+#include "pa_dither.h"

+#include "pa_endianness.h"

+#include "pa_types.h"

+

+

+PaSampleFormat PaUtil_SelectClosestAvailableFormat(

+        PaSampleFormat availableFormats, PaSampleFormat format )

+{

+    PaSampleFormat result;

+

+    format &= ~paNonInterleaved;

+    availableFormats &= ~paNonInterleaved;

+    

+    if( (format & availableFormats) == 0 )

+    {

+        /* NOTE: this code depends on the sample format constants being in

+            descending order of quality - ie best quality is 0

+            FIXME: should write an assert which checks that all of the

+            known constants conform to that requirement.

+        */

+

+        if( format != 0x01 )

+        {

+            /* scan for better formats */

+            result = format;

+            do

+            {

+                result >>= 1;

+            }

+            while( (result & availableFormats) == 0 && result != 0 );

+        }

+        else

+        {

+            result = 0;

+        }

+        

+        if( result == 0 ){

+            /* scan for worse formats */

+            result = format;

+            do

+            {

+                result <<= 1;

+            }

+            while( (result & availableFormats) == 0 && result != paCustomFormat );

+

+            if( (result & availableFormats) == 0 )

+                result = paSampleFormatNotSupported;

+        }

+        

+    }else{

+        result = format;

+    }

+

+    return result;

+}

+

+/* -------------------------------------------------------------------------- */

+

+#define PA_SELECT_FORMAT_( format, float32, int32, int24, int16, int8, uint8 ) \

+    switch( format & ~paNonInterleaved ){                                      \

+    case paFloat32:                                                            \

+        float32                                                                \

+    case paInt32:                                                              \

+        int32                                                                  \

+    case paInt24:                                                              \

+        int24                                                                  \

+    case paInt16:                                                              \

+        int16                                                                  \

+    case paInt8:                                                               \

+        int8                                                                   \

+    case paUInt8:                                                              \

+        uint8                                                                  \

+    default: return 0;                                                         \

+    }

+

+/* -------------------------------------------------------------------------- */

+

+#define PA_SELECT_CONVERTER_DITHER_CLIP_( flags, source, destination )         \

+    if( flags & paClipOff ){ /* no clip */                                     \

+        if( flags & paDitherOff ){ /* no dither */                             \

+            return paConverters. source ## _To_ ## destination;                \

+        }else{ /* dither */                                                    \

+            return paConverters. source ## _To_ ## destination ## _Dither;     \

+        }                                                                      \

+    }else{ /* clip */                                                          \

+        if( flags & paDitherOff ){ /* no dither */                             \

+            return paConverters. source ## _To_ ## destination ## _Clip;       \

+        }else{ /* dither */                                                    \

+            return paConverters. source ## _To_ ## destination ## _DitherClip; \

+        }                                                                      \

+    }

+

+/* -------------------------------------------------------------------------- */

+

+#define PA_SELECT_CONVERTER_DITHER_( flags, source, destination )              \

+    if( flags & paDitherOff ){ /* no dither */                                 \

+        return paConverters. source ## _To_ ## destination;                    \

+    }else{ /* dither */                                                        \

+        return paConverters. source ## _To_ ## destination ## _Dither;         \

+    }

+

+/* -------------------------------------------------------------------------- */

+

+#define PA_USE_CONVERTER_( source, destination )\

+    return paConverters. source ## _To_ ## destination;

+

+/* -------------------------------------------------------------------------- */

+

+#define PA_UNITY_CONVERSION_( wordlength )\

+    return paConverters. Copy_ ## wordlength ## _To_ ## wordlength;

+

+/* -------------------------------------------------------------------------- */

+

+PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,

+        PaSampleFormat destinationFormat, PaStreamFlags flags )

+{

+    PA_SELECT_FORMAT_( sourceFormat,

+                       /* paFloat32: */

+                       PA_SELECT_FORMAT_( destinationFormat,

+                                          /* paFloat32: */        PA_UNITY_CONVERSION_( 32 ),

+                                          /* paInt32: */          PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int32 ),

+                                          /* paInt24: */          PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int24 ),

+                                          /* paInt16: */          PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int16 ),

+                                          /* paInt8: */           PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int8 ),

+                                          /* paUInt8: */          PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, UInt8 )

+                                        ),

+                       /* paInt32: */

+                       PA_SELECT_FORMAT_( destinationFormat,

+                                          /* paFloat32: */        PA_USE_CONVERTER_( Int32, Float32 ),

+                                          /* paInt32: */          PA_UNITY_CONVERSION_( 32 ),

+                                          /* paInt24: */          PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int24 ),

+                                          /* paInt16: */          PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int16 ),

+                                          /* paInt8: */           PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int8 ),

+                                          /* paUInt8: */          PA_SELECT_CONVERTER_DITHER_( flags, Int32, UInt8 )

+                                        ),

+                       /* paInt24: */

+                       PA_SELECT_FORMAT_( destinationFormat,

+                                          /* paFloat32: */        PA_USE_CONVERTER_( Int24, Float32 ),

+                                          /* paInt32: */          PA_USE_CONVERTER_( Int24, Int32 ),

+                                          /* paInt24: */          PA_UNITY_CONVERSION_( 24 ),

+                                          /* paInt16: */          PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int16 ),

+                                          /* paInt8: */           PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int8 ),

+                                          /* paUInt8: */          PA_SELECT_CONVERTER_DITHER_( flags, Int24, UInt8 )

+                                        ),

+                       /* paInt16: */

+                       PA_SELECT_FORMAT_( destinationFormat,

+                                          /* paFloat32: */        PA_USE_CONVERTER_( Int16, Float32 ),

+                                          /* paInt32: */          PA_USE_CONVERTER_( Int16, Int32 ),

+                                          /* paInt24: */          PA_USE_CONVERTER_( Int16, Int24 ),

+                                          /* paInt16: */          PA_UNITY_CONVERSION_( 16 ),

+                                          /* paInt8: */           PA_SELECT_CONVERTER_DITHER_( flags, Int16, Int8 ),

+                                          /* paUInt8: */          PA_SELECT_CONVERTER_DITHER_( flags, Int16, UInt8 )

+                                        ),

+                       /* paInt8: */

+                       PA_SELECT_FORMAT_( destinationFormat,

+                                          /* paFloat32: */        PA_USE_CONVERTER_( Int8, Float32 ),

+                                          /* paInt32: */          PA_USE_CONVERTER_( Int8, Int32 ),

+                                          /* paInt24: */          PA_USE_CONVERTER_( Int8, Int24 ),

+                                          /* paInt16: */          PA_USE_CONVERTER_( Int8, Int16 ),

+                                          /* paInt8: */           PA_UNITY_CONVERSION_( 8 ),

+                                          /* paUInt8: */          PA_USE_CONVERTER_( Int8, UInt8 )

+                                        ),

+                       /* paUInt8: */

+                       PA_SELECT_FORMAT_( destinationFormat,

+                                          /* paFloat32: */        PA_USE_CONVERTER_( UInt8, Float32 ),

+                                          /* paInt32: */          PA_USE_CONVERTER_( UInt8, Int32 ),

+                                          /* paInt24: */          PA_USE_CONVERTER_( UInt8, Int24 ),

+                                          /* paInt16: */          PA_USE_CONVERTER_( UInt8, Int16 ),

+                                          /* paInt8: */           PA_USE_CONVERTER_( UInt8, Int8 ),

+                                          /* paUInt8: */          PA_UNITY_CONVERSION_( 8 )

+                                        )

+                     )

+}

+

+/* -------------------------------------------------------------------------- */

+

+#ifdef PA_NO_STANDARD_CONVERTERS

+

+/* -------------------------------------------------------------------------- */

+

+PaUtilConverterTable paConverters = {

+    0, /* PaUtilConverter *Float32_To_Int32; */

+    0, /* PaUtilConverter *Float32_To_Int32_Dither; */

+    0, /* PaUtilConverter *Float32_To_Int32_Clip; */

+    0, /* PaUtilConverter *Float32_To_Int32_DitherClip; */

+

+    0, /* PaUtilConverter *Float32_To_Int24; */

+    0, /* PaUtilConverter *Float32_To_Int24_Dither; */

+    0, /* PaUtilConverter *Float32_To_Int24_Clip; */

+    0, /* PaUtilConverter *Float32_To_Int24_DitherClip; */

+

+    0, /* PaUtilConverter *Float32_To_Int16; */

+    0, /* PaUtilConverter *Float32_To_Int16_Dither; */

+    0, /* PaUtilConverter *Float32_To_Int16_Clip; */

+    0, /* PaUtilConverter *Float32_To_Int16_DitherClip; */

+

+    0, /* PaUtilConverter *Float32_To_Int8; */

+    0, /* PaUtilConverter *Float32_To_Int8_Dither; */

+    0, /* PaUtilConverter *Float32_To_Int8_Clip; */

+    0, /* PaUtilConverter *Float32_To_Int8_DitherClip; */

+

+    0, /* PaUtilConverter *Float32_To_UInt8; */

+    0, /* PaUtilConverter *Float32_To_UInt8_Dither; */

+    0, /* PaUtilConverter *Float32_To_UInt8_Clip; */

+    0, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */

+

+    0, /* PaUtilConverter *Int32_To_Float32; */

+    0, /* PaUtilConverter *Int32_To_Int24; */

+    0, /* PaUtilConverter *Int32_To_Int24_Dither; */

+    0, /* PaUtilConverter *Int32_To_Int16; */

+    0, /* PaUtilConverter *Int32_To_Int16_Dither; */

+    0, /* PaUtilConverter *Int32_To_Int8; */

+    0, /* PaUtilConverter *Int32_To_Int8_Dither; */

+    0, /* PaUtilConverter *Int32_To_UInt8; */

+    0, /* PaUtilConverter *Int32_To_UInt8_Dither; */

+

+    0, /* PaUtilConverter *Int24_To_Float32; */

+    0, /* PaUtilConverter *Int24_To_Int32; */

+    0, /* PaUtilConverter *Int24_To_Int16; */

+    0, /* PaUtilConverter *Int24_To_Int16_Dither; */

+    0, /* PaUtilConverter *Int24_To_Int8; */

+    0, /* PaUtilConverter *Int24_To_Int8_Dither; */

+    0, /* PaUtilConverter *Int24_To_UInt8; */

+    0, /* PaUtilConverter *Int24_To_UInt8_Dither; */

+    

+    0, /* PaUtilConverter *Int16_To_Float32; */

+    0, /* PaUtilConverter *Int16_To_Int32; */

+    0, /* PaUtilConverter *Int16_To_Int24; */

+    0, /* PaUtilConverter *Int16_To_Int8; */

+    0, /* PaUtilConverter *Int16_To_Int8_Dither; */

+    0, /* PaUtilConverter *Int16_To_UInt8; */

+    0, /* PaUtilConverter *Int16_To_UInt8_Dither; */

+

+    0, /* PaUtilConverter *Int8_To_Float32; */

+    0, /* PaUtilConverter *Int8_To_Int32; */

+    0, /* PaUtilConverter *Int8_To_Int24 */

+    0, /* PaUtilConverter *Int8_To_Int16; */

+    0, /* PaUtilConverter *Int8_To_UInt8; */

+

+    0, /* PaUtilConverter *UInt8_To_Float32; */

+    0, /* PaUtilConverter *UInt8_To_Int32; */

+    0, /* PaUtilConverter *UInt8_To_Int24; */

+    0, /* PaUtilConverter *UInt8_To_Int16; */

+    0, /* PaUtilConverter *UInt8_To_Int8; */

+

+    0, /* PaUtilConverter *Copy_8_To_8; */

+    0, /* PaUtilConverter *Copy_16_To_16; */

+    0, /* PaUtilConverter *Copy_24_To_24; */

+    0  /* PaUtilConverter *Copy_32_To_32; */

+};

+

+/* -------------------------------------------------------------------------- */

+

+#else /* PA_NO_STANDARD_CONVERTERS is not defined */

+

+/* -------------------------------------------------------------------------- */

+

+#define PA_CLIP_( val, min, max )\

+    { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }

+

+

+static const float const_1_div_128_ = 1.0f / 128.0f;  /* 8 bit multiplier */

+

+static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */

+

+static const double const_1_div_2147483648_ = 1.0 / 2147483648.0; /* 32 bit multiplier */

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        /* REVIEW */

+#ifdef PA_USE_C99_LRINTF

+        float scaled = *src * 0x7FFFFFFF;

+        *dest = lrintf(scaled-0.5f);

+#else

+        double scaled = *src * 0x7FFFFFFF;

+        *dest = (signed long) scaled;        

+#endif

+        

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int32_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+

+    while( count-- )

+    {

+        /* REVIEW */

+#ifdef PA_USE_C99_LRINTF

+        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        float dithered = ((float)*src * (2147483646.0f)) + dither;

+        *dest = lrintf(dithered - 0.5f);

+#else

+        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        double dithered = ((double)*src * (2147483646.0)) + dither;

+        *dest = (signed long) dithered;

+#endif

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int32_Clip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+    (void) ditherGenerator; /* unused parameter */

+    

+    while( count-- )

+    {

+        /* REVIEW */

+#ifdef PA_USE_C99_LRINTF

+        float scaled = *src * 0x7FFFFFFF;

+        PA_CLIP_( scaled, -2147483648.f, 2147483647.f  );

+        *dest = lrintf(scaled-0.5f);

+#else

+        double scaled = *src * 0x7FFFFFFF;

+        PA_CLIP_( scaled, -2147483648., 2147483647.  );

+        *dest = (signed long) scaled;

+#endif

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int32_DitherClip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+

+    while( count-- )

+    {

+        /* REVIEW */

+#ifdef PA_USE_C99_LRINTF

+        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        float dithered = ((float)*src * (2147483646.0f)) + dither;

+        PA_CLIP_( dithered, -2147483648.f, 2147483647.f  );

+        *dest = lrintf(dithered-0.5f);

+#else

+        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        double dithered = ((double)*src * (2147483646.0)) + dither;

+        PA_CLIP_( dithered, -2147483648., 2147483647.  );

+        *dest = (signed long) dithered;

+#endif

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int24(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    signed long temp;

+

+    (void) ditherGenerator; /* unused parameter */

+    

+    while( count-- )

+    {

+        /* convert to 32 bit and drop the low 8 bits */

+        double scaled = *src * 0x7FFFFFFF;

+        temp = (signed long) scaled;

+        

+#if defined(PA_LITTLE_ENDIAN)

+        dest[0] = (unsigned char)(temp >> 8);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 24);

+#elif defined(PA_BIG_ENDIAN)

+        dest[0] = (unsigned char)(temp >> 24);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 8);

+#endif

+

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int24_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    signed long temp;

+

+    while( count-- )

+    {

+        /* convert to 32 bit and drop the low 8 bits */

+

+        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        double dithered = ((double)*src * (2147483646.0)) + dither;

+        

+        temp = (signed long) dithered;

+

+#if defined(PA_LITTLE_ENDIAN)

+        dest[0] = (unsigned char)(temp >> 8);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 24);

+#elif defined(PA_BIG_ENDIAN)

+        dest[0] = (unsigned char)(temp >> 24);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 8);

+#endif

+

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int24_Clip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    signed long temp;

+

+    (void) ditherGenerator; /* unused parameter */

+    

+    while( count-- )

+    {

+        /* convert to 32 bit and drop the low 8 bits */

+        double scaled = *src * 0x7FFFFFFF;

+        PA_CLIP_( scaled, -2147483648., 2147483647.  );

+        temp = (signed long) scaled;

+

+#if defined(PA_LITTLE_ENDIAN)

+        dest[0] = (unsigned char)(temp >> 8);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 24);

+#elif defined(PA_BIG_ENDIAN)

+        dest[0] = (unsigned char)(temp >> 24);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 8);

+#endif

+

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int24_DitherClip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    signed long temp;

+    

+    while( count-- )

+    {

+        /* convert to 32 bit and drop the low 8 bits */

+        

+        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        double dithered = ((double)*src * (2147483646.0)) + dither;

+        PA_CLIP_( dithered, -2147483648., 2147483647.  );

+        

+        temp = (signed long) dithered;

+

+#if defined(PA_LITTLE_ENDIAN)

+        dest[0] = (unsigned char)(temp >> 8);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 24);

+#elif defined(PA_BIG_ENDIAN)

+        dest[0] = (unsigned char)(temp >> 24);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 8);

+#endif

+

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int16(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+#ifdef PA_USE_C99_LRINTF

+        float tempf = (*src * (32767.0f)) ;

+        *dest = lrintf(tempf-0.5f);

+#else

+        short samp = (short) (*src * (32767.0f));

+        *dest = samp;

+#endif

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int16_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed short *dest = (signed short*)destinationBuffer;

+

+    while( count-- )

+    {

+

+        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        float dithered = (*src * (32766.0f)) + dither;

+

+#ifdef PA_USE_C99_LRINTF

+        *dest = lrintf(dithered-0.5f);

+#else

+        *dest = (signed short) dithered;

+#endif

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int16_Clip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+#ifdef PA_USE_C99_LRINTF

+        long samp = lrintf((*src * (32767.0f)) -0.5f);

+#else

+        long samp = (signed long) (*src * (32767.0f));

+#endif

+        PA_CLIP_( samp, -0x8000, 0x7FFF );

+        *dest = (signed short) samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int16_DitherClip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+

+        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        float dithered = (*src * (32766.0f)) + dither;

+        signed long samp = (signed long) dithered;

+        PA_CLIP_( samp, -0x8000, 0x7FFF );

+#ifdef PA_USE_C99_LRINTF

+        *dest = lrintf(samp-0.5f);

+#else

+        *dest = (signed short) samp;

+#endif

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed char *dest =  (signed char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        signed char samp = (signed char) (*src * (127.0f));

+        *dest = samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int8_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed char *dest =  (signed char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        float dithered = (*src * (126.0f)) + dither;

+        signed long samp = (signed long) dithered;

+        *dest = (signed char) samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int8_Clip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed char *dest =  (signed char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        signed long samp = (signed long)(*src * (127.0f));

+        PA_CLIP_( samp, -0x80, 0x7F );

+        *dest = (signed char) samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int8_DitherClip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    signed char *dest =  (signed char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        /* use smaller scaler to prevent overflow when we add the dither */

+        float dithered = (*src * (126.0f)) + dither;

+        signed long samp = (signed long) dithered;

+        PA_CLIP_( samp, -0x80, 0x7F );

+        *dest = (signed char) samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_UInt8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        unsigned char samp = (unsigned char)(128 + ((unsigned char) (*src * (127.0f))));

+        *dest = samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_UInt8_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        /* IMPLEMENT ME */

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_UInt8_Clip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        /* IMPLEMENT ME */

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_UInt8_DitherClip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        /* IMPLEMENT ME */

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int32_To_Float32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed long *src = (signed long*)sourceBuffer;

+    float *dest =  (float*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        *dest = (float) ((double)*src * const_1_div_2147483648_);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int32_To_Int24(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed long *src    = (signed long*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    (void) ditherGenerator; /* unused parameter */

+    

+	while( count-- )

+    {

+		/* REVIEW */

+#if defined(PA_LITTLE_ENDIAN)

+        dest[0] = (unsigned char)(*src >> 8);

+        dest[1] = (unsigned char)(*src >> 16);

+        dest[2] = (unsigned char)(*src >> 24);

+#elif defined(PA_BIG_ENDIAN)

+        dest[0] = (unsigned char)(*src >> 24);

+        dest[1] = (unsigned char)(*src >> 16);

+        dest[2] = (unsigned char)(*src >> 8);

+#endif

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int32_To_Int24_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    (void) destinationBuffer; /* unused parameters */

+    (void) destinationStride; /* unused parameters */

+    (void) sourceBuffer; /* unused parameters */

+    (void) sourceStride; /* unused parameters */

+    (void) count; /* unused parameters */

+    (void) ditherGenerator; /* unused parameters */

+    /* IMPLEMENT ME */

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int32_To_Int16(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed long *src = (signed long*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        *dest = (signed short) ((*src) >> 16);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int32_To_Int16_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed long *src = (signed long*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    signed long dither;

+

+    while( count-- )

+    {

+        /* REVIEW */

+        dither = PaUtil_Generate16BitTriangularDither( ditherGenerator );

+        *dest = (signed short) ((((*src)>>1) + dither) >> 15);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int32_To_Int8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed long *src = (signed long*)sourceBuffer;

+    signed char *dest =  (signed char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        *dest = (signed char) ((*src) >> 24);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int32_To_Int8_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed long *src = (signed long*)sourceBuffer;

+    signed char *dest =  (signed char*)destinationBuffer;

+    signed long dither;

+

+    while( count-- )

+    {

+        /* REVIEW */

+        dither = PaUtil_Generate16BitTriangularDither( ditherGenerator );

+        *dest = (signed char) ((((*src)>>1) + dither) >> 23);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int32_To_UInt8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed long *src = (signed long*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+		(*dest) = (unsigned char)(((*src) >> 24) + 128); 

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int32_To_UInt8_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed long *src = (signed long*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        /* IMPLEMENT ME */

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int24_To_Float32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    float *dest = (float*)destinationBuffer;

+    signed long temp;

+

+    (void) ditherGenerator; /* unused parameter */

+    

+    while( count-- )

+    {

+

+#if defined(PA_LITTLE_ENDIAN)

+        temp = (((long)src[0]) << 8);  

+        temp = temp | (((long)src[1]) << 16);

+        temp = temp | (((long)src[2]) << 24);

+#elif defined(PA_BIG_ENDIAN)

+        temp = (((long)src[0]) << 24);

+        temp = temp | (((long)src[1]) << 16);

+        temp = temp | (((long)src[2]) << 8);

+#endif

+

+        *dest = (float) ((double)temp * const_1_div_2147483648_);

+

+        src += sourceStride * 3;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int24_To_Int32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src  = (unsigned char*)sourceBuffer;

+    signed long   *dest = (signed long*)  destinationBuffer;

+    signed long temp;

+

+    (void) ditherGenerator; /* unused parameter */

+    

+    while( count-- )

+    {

+

+#if defined(PA_LITTLE_ENDIAN)

+        temp = (((long)src[0]) << 8);  

+        temp = temp | (((long)src[1]) << 16);

+        temp = temp | (((long)src[2]) << 24);

+#elif defined(PA_BIG_ENDIAN)

+        temp = (((long)src[0]) << 24);

+        temp = temp | (((long)src[1]) << 16);

+        temp = temp | (((long)src[2]) << 8);

+#endif

+

+        *dest = temp;

+

+        src += sourceStride * 3;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int24_To_Int16(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    signed short *dest = (signed short*)destinationBuffer;

+    

+	signed short temp;

+

+    (void) ditherGenerator; /* unused parameter */

+        

+    while( count-- )

+    {

+		

+#if defined(PA_LITTLE_ENDIAN)

+		/* src[0] is discarded */

+        temp = (((signed short)src[1]));

+        temp = temp | (signed short)(((signed short)src[2]) << 8);

+#elif defined(PA_BIG_ENDIAN)

+		/* src[2] is discarded */

+        temp = (signed short)(((signed short)src[0]) << 8);

+        temp = temp | (((signed short)src[1]));

+#endif

+

+        *dest = temp;

+

+        src += sourceStride * 3;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int24_To_Int16_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    (void) destinationBuffer; /* unused parameters */

+    (void) destinationStride; /* unused parameters */

+    (void) sourceBuffer; /* unused parameters */

+    (void) sourceStride; /* unused parameters */

+    (void) count; /* unused parameters */

+    (void) ditherGenerator; /* unused parameters */

+    /* IMPLEMENT ME */

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int24_To_Int8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    signed char  *dest = (signed char*)destinationBuffer;

+    

+    (void) ditherGenerator; /* unused parameter */

+        

+    while( count-- )

+    {	

+	

+#if defined(PA_LITTLE_ENDIAN)

+		/* src[0] is discarded */

+		/* src[1] is discarded */

+        *dest = src[2];

+#elif defined(PA_BIG_ENDIAN)

+		/* src[2] is discarded */

+		/* src[1] is discarded */

+		*dest = src[0];

+#endif

+

+        src += sourceStride * 3;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int24_To_Int8_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    (void) destinationBuffer; /* unused parameters */

+    (void) destinationStride; /* unused parameters */

+    (void) sourceBuffer; /* unused parameters */

+    (void) sourceStride; /* unused parameters */

+    (void) count; /* unused parameters */

+    (void) ditherGenerator; /* unused parameters */

+    /* IMPLEMENT ME */

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int24_To_UInt8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    

+    (void) ditherGenerator; /* unused parameter */

+        

+    while( count-- )

+    {

+		

+#if defined(PA_LITTLE_ENDIAN)

+		/* src[0] is discarded */

+		/* src[1] is discarded */

+        *dest = (unsigned char)(src[2] + 128);

+#elif defined(PA_BIG_ENDIAN)

+        *dest = (unsigned char)(src[0] + 128);

+		/* src[1] is discarded */

+		/* src[2] is discarded */		

+#endif

+

+        src += sourceStride * 3;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int24_To_UInt8_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    (void) destinationBuffer; /* unused parameters */

+    (void) destinationStride; /* unused parameters */

+    (void) sourceBuffer; /* unused parameters */

+    (void) sourceStride; /* unused parameters */

+    (void) count; /* unused parameters */

+    (void) ditherGenerator; /* unused parameters */

+    /* IMPLEMENT ME */

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int16_To_Float32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed short *src = (signed short*)sourceBuffer;

+    float *dest =  (float*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        float samp = *src * const_1_div_32768_; /* FIXME: i'm concerned about this being asymetrical with float->int16 -rb */

+        *dest = samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int16_To_Int32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed short *src = (signed short*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        /* REVIEW: we should consider something like

+            (*src << 16) | (*src & 0xFFFF)

+        */

+        

+        *dest = *src << 16;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int16_To_Int24(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed short *src   = (signed short*) sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    signed short temp;

+

+    (void) ditherGenerator; /* unused parameter */

+    

+    while( count-- )

+    {

+        temp = *src;

+        

+#if defined(PA_LITTLE_ENDIAN)

+        dest[0] = 0;

+        dest[1] = (unsigned char)(temp);

+        dest[2] = (unsigned char)(temp >> 8);

+#elif defined(PA_BIG_ENDIAN)

+        dest[0] = (unsigned char)(temp >> 8);

+        dest[1] = (unsigned char)(temp);

+        dest[2] = 0;

+#endif

+

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int16_To_Int8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed short *src = (signed short*)sourceBuffer;

+    signed char *dest =  (signed char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        (*dest) = (signed char)((*src) >> 8);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int16_To_Int8_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed short *src = (signed short*)sourceBuffer;

+    signed char *dest =  (signed char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        /* IMPLEMENT ME */

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int16_To_UInt8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed short *src = (signed short*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+		(*dest) = (unsigned char)(((*src) >> 8) + 128); 

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int16_To_UInt8_Dither(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed short *src = (signed short*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        /* IMPLEMENT ME */

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int8_To_Float32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed char *src = (signed char*)sourceBuffer;

+    float *dest =  (float*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        float samp = *src * const_1_div_128_;

+        *dest = samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int8_To_Int32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed char *src = (signed char*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+		(*dest) = (*src) << 24;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int8_To_Int24(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed char *src = (signed char*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+

+#if defined(PA_LITTLE_ENDIAN)

+        dest[0] = 0;

+        dest[1] = 0;

+        dest[2] = (*src);

+#elif defined(PA_BIG_ENDIAN)

+        dest[0] = (*src);

+        dest[1] = 0;

+        dest[2] = 0;

+#endif

+

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int8_To_Int16(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed char *src = (signed char*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+		(*dest) = (signed short)((*src) << 8);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Int8_To_UInt8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    signed char *src = (signed char*)sourceBuffer;

+    unsigned char *dest =  (unsigned char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        (*dest) = (unsigned char)(*src + 128);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void UInt8_To_Float32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    float *dest =  (float*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        float samp = (*src - 128) * const_1_div_128_;

+        *dest = samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void UInt8_To_Int32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+		(*dest) = (*src - 128) << 24;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void UInt8_To_Int24(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+	unsigned char *src  = (unsigned char*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    (void) ditherGenerator; /* unused parameters */

+    

+	while( count-- )

+    {

+

+#if defined(PA_LITTLE_ENDIAN)

+        dest[0] = 0;

+        dest[1] = 0;

+        dest[2] = (unsigned char)(*src - 128);

+#elif defined(PA_BIG_ENDIAN)

+        dest[0] = (unsigned char)(*src - 128);

+        dest[1] = 0;

+        dest[2] = 0;

+#endif

+		

+        src += sourceStride;

+        dest += destinationStride * 3;    

+	}

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void UInt8_To_Int16(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+		(*dest) = (signed short)((*src - 128) << 8);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void UInt8_To_Int8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    signed char  *dest = (signed char*)destinationBuffer;

+    (void)ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        (*dest) = (signed char)(*src - 128);

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Copy_8_To_8(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+                                                      

+    (void) ditherGenerator; /* unused parameter */

+

+    while( count-- )

+    {

+        *dest = *src;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Copy_16_To_16(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    PaUint16 *src = (PaUint16 *)sourceBuffer;

+    PaUint16 *dest = (PaUint16 *)destinationBuffer;

+                                                        

+    (void) ditherGenerator; /* unused parameter */

+    

+    while( count-- )

+    {

+        *dest = *src;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Copy_24_To_24(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    unsigned char *src = (unsigned char*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+

+    (void) ditherGenerator; /* unused parameter */

+    

+    while( count-- )

+    {

+        dest[0] = src[0];

+        dest[1] = src[1];

+        dest[2] = src[2];

+

+        src += sourceStride * 3;

+        dest += destinationStride * 3;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Copy_32_To_32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    PaUint32 *dest = (PaUint32 *)destinationBuffer;

+    PaUint32 *src = (PaUint32 *)sourceBuffer;

+

+    (void) ditherGenerator; /* unused parameter */

+    

+    while( count-- )

+    {

+        *dest = *src;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+PaUtilConverterTable paConverters = {

+    Float32_To_Int32,              /* PaUtilConverter *Float32_To_Int32; */

+    Float32_To_Int32_Dither,       /* PaUtilConverter *Float32_To_Int32_Dither; */

+    Float32_To_Int32_Clip,         /* PaUtilConverter *Float32_To_Int32_Clip; */

+    Float32_To_Int32_DitherClip,   /* PaUtilConverter *Float32_To_Int32_DitherClip; */

+

+    Float32_To_Int24,              /* PaUtilConverter *Float32_To_Int24; */

+    Float32_To_Int24_Dither,       /* PaUtilConverter *Float32_To_Int24_Dither; */

+    Float32_To_Int24_Clip,         /* PaUtilConverter *Float32_To_Int24_Clip; */

+    Float32_To_Int24_DitherClip,   /* PaUtilConverter *Float32_To_Int24_DitherClip; */

+    

+    Float32_To_Int16,              /* PaUtilConverter *Float32_To_Int16; */

+    Float32_To_Int16_Dither,       /* PaUtilConverter *Float32_To_Int16_Dither; */

+    Float32_To_Int16_Clip,         /* PaUtilConverter *Float32_To_Int16_Clip; */

+    Float32_To_Int16_DitherClip,   /* PaUtilConverter *Float32_To_Int16_DitherClip; */

+

+    Float32_To_Int8,               /* PaUtilConverter *Float32_To_Int8; */

+    Float32_To_Int8_Dither,        /* PaUtilConverter *Float32_To_Int8_Dither; */

+    Float32_To_Int8_Clip,          /* PaUtilConverter *Float32_To_Int8_Clip; */

+    Float32_To_Int8_DitherClip,    /* PaUtilConverter *Float32_To_Int8_DitherClip; */

+

+    Float32_To_UInt8,              /* PaUtilConverter *Float32_To_UInt8; */

+    Float32_To_UInt8_Dither,       /* PaUtilConverter *Float32_To_UInt8_Dither; */

+    Float32_To_UInt8_Clip,         /* PaUtilConverter *Float32_To_UInt8_Clip; */

+    Float32_To_UInt8_DitherClip,   /* PaUtilConverter *Float32_To_UInt8_DitherClip; */

+

+    Int32_To_Float32,              /* PaUtilConverter *Int32_To_Float32; */

+    Int32_To_Int24,                /* PaUtilConverter *Int32_To_Int24; */

+    Int32_To_Int24_Dither,         /* PaUtilConverter *Int32_To_Int24_Dither; */

+    Int32_To_Int16,                /* PaUtilConverter *Int32_To_Int16; */

+    Int32_To_Int16_Dither,         /* PaUtilConverter *Int32_To_Int16_Dither; */

+    Int32_To_Int8,                 /* PaUtilConverter *Int32_To_Int8; */

+    Int32_To_Int8_Dither,          /* PaUtilConverter *Int32_To_Int8_Dither; */

+    Int32_To_UInt8,                /* PaUtilConverter *Int32_To_UInt8; */

+    Int32_To_UInt8_Dither,         /* PaUtilConverter *Int32_To_UInt8_Dither; */

+

+    Int24_To_Float32,              /* PaUtilConverter *Int24_To_Float32; */

+    Int24_To_Int32,                /* PaUtilConverter *Int24_To_Int32; */

+    Int24_To_Int16,                /* PaUtilConverter *Int24_To_Int16; */

+    Int24_To_Int16_Dither,         /* PaUtilConverter *Int24_To_Int16_Dither; */

+    Int24_To_Int8,                 /* PaUtilConverter *Int24_To_Int8; */

+    Int24_To_Int8_Dither,          /* PaUtilConverter *Int24_To_Int8_Dither; */

+    Int24_To_UInt8,                /* PaUtilConverter *Int24_To_UInt8; */

+    Int24_To_UInt8_Dither,         /* PaUtilConverter *Int24_To_UInt8_Dither; */

+

+    Int16_To_Float32,              /* PaUtilConverter *Int16_To_Float32; */

+    Int16_To_Int32,                /* PaUtilConverter *Int16_To_Int32; */

+    Int16_To_Int24,                /* PaUtilConverter *Int16_To_Int24; */

+    Int16_To_Int8,                 /* PaUtilConverter *Int16_To_Int8; */

+    Int16_To_Int8_Dither,          /* PaUtilConverter *Int16_To_Int8_Dither; */

+    Int16_To_UInt8,                /* PaUtilConverter *Int16_To_UInt8; */

+    Int16_To_UInt8_Dither,         /* PaUtilConverter *Int16_To_UInt8_Dither; */

+

+    Int8_To_Float32,               /* PaUtilConverter *Int8_To_Float32; */

+    Int8_To_Int32,                 /* PaUtilConverter *Int8_To_Int32; */

+    Int8_To_Int24,                 /* PaUtilConverter *Int8_To_Int24 */

+    Int8_To_Int16,                 /* PaUtilConverter *Int8_To_Int16; */

+    Int8_To_UInt8,                 /* PaUtilConverter *Int8_To_UInt8; */

+

+    UInt8_To_Float32,              /* PaUtilConverter *UInt8_To_Float32; */

+    UInt8_To_Int32,                /* PaUtilConverter *UInt8_To_Int32; */

+    UInt8_To_Int24,                /* PaUtilConverter *UInt8_To_Int24; */

+    UInt8_To_Int16,                /* PaUtilConverter *UInt8_To_Int16; */

+    UInt8_To_Int8,                 /* PaUtilConverter *UInt8_To_Int8; */

+

+    Copy_8_To_8,                   /* PaUtilConverter *Copy_8_To_8; */

+    Copy_16_To_16,                 /* PaUtilConverter *Copy_16_To_16; */

+    Copy_24_To_24,                 /* PaUtilConverter *Copy_24_To_24; */

+    Copy_32_To_32                  /* PaUtilConverter *Copy_32_To_32; */

+};

+

+/* -------------------------------------------------------------------------- */

+

+#endif /* PA_NO_STANDARD_CONVERTERS */

+

+/* -------------------------------------------------------------------------- */

+

+PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat )

+{

+    switch( destinationFormat & ~paNonInterleaved ){

+    case paFloat32:

+        return paZeroers.Zero32;

+    case paInt32:

+        return paZeroers.Zero32;

+    case paInt24:

+        return paZeroers.Zero24;

+    case paInt16:

+        return paZeroers.Zero16;

+    case paInt8:

+        return paZeroers.Zero8;

+    case paUInt8:

+        return paZeroers.ZeroU8;

+    default: return 0;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+#ifdef PA_NO_STANDARD_ZEROERS

+

+/* -------------------------------------------------------------------------- */

+

+PaUtilZeroerTable paZeroers = {

+    0,  /* PaUtilZeroer *ZeroU8; */

+    0,  /* PaUtilZeroer *Zero8; */

+    0,  /* PaUtilZeroer *Zero16; */

+    0,  /* PaUtilZeroer *Zero24; */

+    0,  /* PaUtilZeroer *Zero32; */

+};

+

+/* -------------------------------------------------------------------------- */

+

+#else /* PA_NO_STANDARD_ZEROERS is not defined */

+

+/* -------------------------------------------------------------------------- */

+

+static void ZeroU8( void *destinationBuffer, signed int destinationStride,

+        unsigned int count )

+{

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+

+    while( count-- )

+    {

+        *dest = 128;

+

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Zero8( void *destinationBuffer, signed int destinationStride,

+        unsigned int count )

+{

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+

+    while( count-- )

+    {

+        *dest = 0;

+

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Zero16( void *destinationBuffer, signed int destinationStride,

+        unsigned int count )

+{

+    PaUint16 *dest = (PaUint16 *)destinationBuffer;

+

+    while( count-- )

+    {

+        *dest = 0;

+

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Zero24( void *destinationBuffer, signed int destinationStride,

+        unsigned int count )

+{

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+

+    while( count-- )

+    {

+        dest[0] = 0;

+        dest[1] = 0;

+        dest[2] = 0;

+

+        dest += destinationStride * 3;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Zero32( void *destinationBuffer, signed int destinationStride,

+        unsigned int count )

+{

+    PaUint32 *dest = (PaUint32 *)destinationBuffer;

+

+    while( count-- )

+    {

+        *dest = 0;

+

+        dest += destinationStride;

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+PaUtilZeroerTable paZeroers = {

+    ZeroU8,  /* PaUtilZeroer *ZeroU8; */

+    Zero8,  /* PaUtilZeroer *Zero8; */

+    Zero16,  /* PaUtilZeroer *Zero16; */

+    Zero24,  /* PaUtilZeroer *Zero24; */

+    Zero32,  /* PaUtilZeroer *Zero32; */

+};

+

+/* -------------------------------------------------------------------------- */

+

+#endif /* PA_NO_STANDARD_ZEROERS */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_converters.h b/pjmedia/src/pjmedia/portaudio/pa_converters.h
index 831c9c6..b196293 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_converters.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_converters.h
@@ -1,254 +1,275 @@
-#ifndef PA_CONVERTERS_H
-#define PA_CONVERTERS_H
-/*
- * $Id: pa_converters.h,v 1.1.2.9 2003/09/20 21:05:14 rossbencina Exp $
- * Portable Audio I/O Library sample conversion mechanism
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Conversion functions used to convert buffers of samples from one
- format to another.
-*/
-
-
-#include "portaudio.h"  /* for PaSampleFormat */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-struct PaUtilTriangularDitherGenerator;
-
-
-/** Choose an available sample format which is most appropriate for
- representing the requested format. If the requested format is not available
- higher quality formats are considered before lower quality formates.
- @param availableFormats A variable containing the logical OR of all available
- formats.
- @param format The desired format.
- @return The most appropriate available format for representing the requested
- format.
-*/
-PaSampleFormat PaUtil_SelectClosestAvailableFormat(
-        PaSampleFormat availableFormats, PaSampleFormat format );
-
-
-/* high level conversions functions for use by implementations */
-
-
-/** The generic sample converter prototype. Sample converters convert count
-    samples from sourceBuffer to destinationBuffer. The actual type of the data
-    pointed to by these parameters varys for different converter functions.
-    @param destinationBuffer A pointer to the first sample of the destination.
-    @param destinationStride An offset between successive destination samples
-    expressed in samples (not bytes.) It may be negative.
-    @param sourceBuffer A pointer to the first sample of the source.
-    @param sourceStride An offset between successive source samples
-    expressed in samples (not bytes.) It may be negative.
-    @param count The number of samples to convert.
-    @param ditherState State information used to calculate dither. Converters
-    that do not perform dithering will ignore this parameter, in which case
-    NULL or invalid dither state may be passed.
-*/
-typedef void PaUtilConverter(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator );
-
-
-/** Find a sample converter function for the given source and destinations
-    formats and flags (clip and dither.)
-    @return
-    A pointer to a PaUtilConverter which will perform the requested
-    conversion, or NULL if the given format conversion is not supported.
-    For conversions where clipping or dithering is not necessary, the
-    clip and dither flags are ignored and a non-clipping or dithering
-    version is returned.
-    If the source and destination formats are the same, a function which
-    copies data of the appropriate size will be returned.
-*/
-PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,
-        PaSampleFormat destinationFormat, PaStreamFlags flags );
-
-
-/** The generic buffer zeroer prototype. Buffer zeroers copy count zeros to
-    destinationBuffer. The actual type of the data pointed to varys for
-    different zeroer functions.
-    @param destinationBuffer A pointer to the first sample of the destination.
-    @param destinationStride An offset between successive destination samples
-    expressed in samples (not bytes.) It may be negative.
-    @param count The number of samples to zero.
-*/
-typedef void PaUtilZeroer(
-    void *destinationBuffer, signed int destinationStride, unsigned int count );
-
-    
-/** Find a buffer zeroer function for the given destination format.
-    @return
-    A pointer to a PaUtilZeroer which will perform the requested
-    zeroing.
-*/
-PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat );
-
-/*----------------------------------------------------------------------------*/
-/* low level functions and data structures which may be used for
-    substituting conversion functions */
-
-
-/** The type used to store all sample conversion functions.
-    @see paConverters;
-*/
-typedef struct{
-    PaUtilConverter *Float32_To_Int32;
-    PaUtilConverter *Float32_To_Int32_Dither;
-    PaUtilConverter *Float32_To_Int32_Clip;
-    PaUtilConverter *Float32_To_Int32_DitherClip;
-
-    PaUtilConverter *Float32_To_Int24;
-    PaUtilConverter *Float32_To_Int24_Dither;
-    PaUtilConverter *Float32_To_Int24_Clip;
-    PaUtilConverter *Float32_To_Int24_DitherClip;
-    
-    PaUtilConverter *Float32_To_Int16;
-    PaUtilConverter *Float32_To_Int16_Dither;
-    PaUtilConverter *Float32_To_Int16_Clip;
-    PaUtilConverter *Float32_To_Int16_DitherClip;
-
-    PaUtilConverter *Float32_To_Int8;
-    PaUtilConverter *Float32_To_Int8_Dither;
-    PaUtilConverter *Float32_To_Int8_Clip;
-    PaUtilConverter *Float32_To_Int8_DitherClip;
-
-    PaUtilConverter *Float32_To_UInt8;
-    PaUtilConverter *Float32_To_UInt8_Dither;
-    PaUtilConverter *Float32_To_UInt8_Clip;
-    PaUtilConverter *Float32_To_UInt8_DitherClip;
-
-    PaUtilConverter *Int32_To_Float32;
-    PaUtilConverter *Int32_To_Int24;
-    PaUtilConverter *Int32_To_Int24_Dither;
-    PaUtilConverter *Int32_To_Int16;
-    PaUtilConverter *Int32_To_Int16_Dither;
-    PaUtilConverter *Int32_To_Int8;
-    PaUtilConverter *Int32_To_Int8_Dither;
-    PaUtilConverter *Int32_To_UInt8;
-    PaUtilConverter *Int32_To_UInt8_Dither;
-
-    PaUtilConverter *Int24_To_Float32;
-    PaUtilConverter *Int24_To_Int32;
-    PaUtilConverter *Int24_To_Int16;
-    PaUtilConverter *Int24_To_Int16_Dither;
-    PaUtilConverter *Int24_To_Int8;
-    PaUtilConverter *Int24_To_Int8_Dither;
-    PaUtilConverter *Int24_To_UInt8;
-    PaUtilConverter *Int24_To_UInt8_Dither;
-
-    PaUtilConverter *Int16_To_Float32;
-    PaUtilConverter *Int16_To_Int32;
-    PaUtilConverter *Int16_To_Int24;
-    PaUtilConverter *Int16_To_Int8;
-    PaUtilConverter *Int16_To_Int8_Dither;
-    PaUtilConverter *Int16_To_UInt8;
-    PaUtilConverter *Int16_To_UInt8_Dither;
-
-    PaUtilConverter *Int8_To_Float32;
-    PaUtilConverter *Int8_To_Int32;
-    PaUtilConverter *Int8_To_Int24;
-    PaUtilConverter *Int8_To_Int16;
-    PaUtilConverter *Int8_To_UInt8;
-    
-    PaUtilConverter *UInt8_To_Float32;
-    PaUtilConverter *UInt8_To_Int32;
-    PaUtilConverter *UInt8_To_Int24;
-    PaUtilConverter *UInt8_To_Int16;
-    PaUtilConverter *UInt8_To_Int8;
-
-    PaUtilConverter *Copy_8_To_8;       /* copy without any conversion */
-    PaUtilConverter *Copy_16_To_16;     /* copy without any conversion */
-    PaUtilConverter *Copy_24_To_24;     /* copy without any conversion */
-    PaUtilConverter *Copy_32_To_32;     /* copy without any conversion */
-} PaUtilConverterTable;
-
-
-/** A table of pointers to all required converter functions.
-    PaUtil_SelectConverter() uses this table to lookup the appropriate
-    conversion functions. The fields of this structure are initialized
-    with default conversion functions. Fields may be NULL, indicating that
-    no conversion function is available. User code may substitue optimised
-    conversion functions by assigning different function pointers to
-    these fields.
-
-    @note
-    If the PA_NO_STANDARD_CONVERTERS preprocessor variable is defined,
-    PortAudio's standard converters will not be compiled, and all fields
-    of this structure will be initialized to NULL. In such cases, users
-    should supply their own conversion functions if the require PortAudio
-    to open a stream that requires sample conversion.
-
-    @see PaUtilConverterTable, PaUtilConverter, PaUtil_SelectConverter
-*/
-extern PaUtilConverterTable paConverters;
-
-
-/** The type used to store all buffer zeroing functions.
-    @see paZeroers;
-*/
-typedef struct{
-    PaUtilZeroer *ZeroU8; /* unsigned 8 bit, zero == 128 */
-    PaUtilZeroer *Zero8;
-    PaUtilZeroer *Zero16;
-    PaUtilZeroer *Zero24;
-    PaUtilZeroer *Zero32;
-} PaUtilZeroerTable;
-
-
-/** A table of pointers to all required zeroer functions.
-    PaUtil_SelectZeroer() uses this table to lookup the appropriate
-    conversion functions. The fields of this structure are initialized
-    with default conversion functions. User code may substitue optimised
-    conversion functions by assigning different function pointers to
-    these fields.
-
-    @note
-    If the PA_NO_STANDARD_ZEROERS preprocessor variable is defined,
-    PortAudio's standard zeroers will not be compiled, and all fields
-    of this structure will be initialized to NULL. In such cases, users
-    should supply their own zeroing functions for the sample sizes which
-    they intend to use.
-
-    @see PaUtilZeroerTable, PaUtilZeroer, PaUtil_SelectZeroer
-*/
-extern PaUtilZeroerTable paZeroers;
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_CONVERTERS_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_CONVERTERS_H

+#define PA_CONVERTERS_H

+/*

+ * $Id: pa_converters.h,v 1.1.2.9 2003/09/20 21:05:14 rossbencina Exp $

+ * Portable Audio I/O Library sample conversion mechanism

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+ @brief Conversion functions used to convert buffers of samples from one

+ format to another.

+*/

+

+

+#include "portaudio.h"  /* for PaSampleFormat */

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+struct PaUtilTriangularDitherGenerator;

+

+

+/** Choose an available sample format which is most appropriate for

+ representing the requested format. If the requested format is not available

+ higher quality formats are considered before lower quality formates.

+ @param availableFormats A variable containing the logical OR of all available

+ formats.

+ @param format The desired format.

+ @return The most appropriate available format for representing the requested

+ format.

+*/

+PaSampleFormat PaUtil_SelectClosestAvailableFormat(

+        PaSampleFormat availableFormats, PaSampleFormat format );

+

+

+/* high level conversions functions for use by implementations */

+

+

+/** The generic sample converter prototype. Sample converters convert count

+    samples from sourceBuffer to destinationBuffer. The actual type of the data

+    pointed to by these parameters varys for different converter functions.

+    @param destinationBuffer A pointer to the first sample of the destination.

+    @param destinationStride An offset between successive destination samples

+    expressed in samples (not bytes.) It may be negative.

+    @param sourceBuffer A pointer to the first sample of the source.

+    @param sourceStride An offset between successive source samples

+    expressed in samples (not bytes.) It may be negative.

+    @param count The number of samples to convert.

+    @param ditherState State information used to calculate dither. Converters

+    that do not perform dithering will ignore this parameter, in which case

+    NULL or invalid dither state may be passed.

+*/

+typedef void PaUtilConverter(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator );

+

+

+/** Find a sample converter function for the given source and destinations

+    formats and flags (clip and dither.)

+    @return

+    A pointer to a PaUtilConverter which will perform the requested

+    conversion, or NULL if the given format conversion is not supported.

+    For conversions where clipping or dithering is not necessary, the

+    clip and dither flags are ignored and a non-clipping or dithering

+    version is returned.

+    If the source and destination formats are the same, a function which

+    copies data of the appropriate size will be returned.

+*/

+PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,

+        PaSampleFormat destinationFormat, PaStreamFlags flags );

+

+

+/** The generic buffer zeroer prototype. Buffer zeroers copy count zeros to

+    destinationBuffer. The actual type of the data pointed to varys for

+    different zeroer functions.

+    @param destinationBuffer A pointer to the first sample of the destination.

+    @param destinationStride An offset between successive destination samples

+    expressed in samples (not bytes.) It may be negative.

+    @param count The number of samples to zero.

+*/

+typedef void PaUtilZeroer(

+    void *destinationBuffer, signed int destinationStride, unsigned int count );

+

+    

+/** Find a buffer zeroer function for the given destination format.

+    @return

+    A pointer to a PaUtilZeroer which will perform the requested

+    zeroing.

+*/

+PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat );

+

+/*----------------------------------------------------------------------------*/

+/* low level functions and data structures which may be used for

+    substituting conversion functions */

+

+

+/** The type used to store all sample conversion functions.

+    @see paConverters;

+*/

+typedef struct{

+    PaUtilConverter *Float32_To_Int32;

+    PaUtilConverter *Float32_To_Int32_Dither;

+    PaUtilConverter *Float32_To_Int32_Clip;

+    PaUtilConverter *Float32_To_Int32_DitherClip;

+

+    PaUtilConverter *Float32_To_Int24;

+    PaUtilConverter *Float32_To_Int24_Dither;

+    PaUtilConverter *Float32_To_Int24_Clip;

+    PaUtilConverter *Float32_To_Int24_DitherClip;

+    

+    PaUtilConverter *Float32_To_Int16;

+    PaUtilConverter *Float32_To_Int16_Dither;

+    PaUtilConverter *Float32_To_Int16_Clip;

+    PaUtilConverter *Float32_To_Int16_DitherClip;

+

+    PaUtilConverter *Float32_To_Int8;

+    PaUtilConverter *Float32_To_Int8_Dither;

+    PaUtilConverter *Float32_To_Int8_Clip;

+    PaUtilConverter *Float32_To_Int8_DitherClip;

+

+    PaUtilConverter *Float32_To_UInt8;

+    PaUtilConverter *Float32_To_UInt8_Dither;

+    PaUtilConverter *Float32_To_UInt8_Clip;

+    PaUtilConverter *Float32_To_UInt8_DitherClip;

+

+    PaUtilConverter *Int32_To_Float32;

+    PaUtilConverter *Int32_To_Int24;

+    PaUtilConverter *Int32_To_Int24_Dither;

+    PaUtilConverter *Int32_To_Int16;

+    PaUtilConverter *Int32_To_Int16_Dither;

+    PaUtilConverter *Int32_To_Int8;

+    PaUtilConverter *Int32_To_Int8_Dither;

+    PaUtilConverter *Int32_To_UInt8;

+    PaUtilConverter *Int32_To_UInt8_Dither;

+

+    PaUtilConverter *Int24_To_Float32;

+    PaUtilConverter *Int24_To_Int32;

+    PaUtilConverter *Int24_To_Int16;

+    PaUtilConverter *Int24_To_Int16_Dither;

+    PaUtilConverter *Int24_To_Int8;

+    PaUtilConverter *Int24_To_Int8_Dither;

+    PaUtilConverter *Int24_To_UInt8;

+    PaUtilConverter *Int24_To_UInt8_Dither;

+

+    PaUtilConverter *Int16_To_Float32;

+    PaUtilConverter *Int16_To_Int32;

+    PaUtilConverter *Int16_To_Int24;

+    PaUtilConverter *Int16_To_Int8;

+    PaUtilConverter *Int16_To_Int8_Dither;

+    PaUtilConverter *Int16_To_UInt8;

+    PaUtilConverter *Int16_To_UInt8_Dither;

+

+    PaUtilConverter *Int8_To_Float32;

+    PaUtilConverter *Int8_To_Int32;

+    PaUtilConverter *Int8_To_Int24;

+    PaUtilConverter *Int8_To_Int16;

+    PaUtilConverter *Int8_To_UInt8;

+    

+    PaUtilConverter *UInt8_To_Float32;

+    PaUtilConverter *UInt8_To_Int32;

+    PaUtilConverter *UInt8_To_Int24;

+    PaUtilConverter *UInt8_To_Int16;

+    PaUtilConverter *UInt8_To_Int8;

+

+    PaUtilConverter *Copy_8_To_8;       /* copy without any conversion */

+    PaUtilConverter *Copy_16_To_16;     /* copy without any conversion */

+    PaUtilConverter *Copy_24_To_24;     /* copy without any conversion */

+    PaUtilConverter *Copy_32_To_32;     /* copy without any conversion */

+} PaUtilConverterTable;

+

+

+/** A table of pointers to all required converter functions.

+    PaUtil_SelectConverter() uses this table to lookup the appropriate

+    conversion functions. The fields of this structure are initialized

+    with default conversion functions. Fields may be NULL, indicating that

+    no conversion function is available. User code may substitue optimised

+    conversion functions by assigning different function pointers to

+    these fields.

+

+    @note

+    If the PA_NO_STANDARD_CONVERTERS preprocessor variable is defined,

+    PortAudio's standard converters will not be compiled, and all fields

+    of this structure will be initialized to NULL. In such cases, users

+    should supply their own conversion functions if the require PortAudio

+    to open a stream that requires sample conversion.

+

+    @see PaUtilConverterTable, PaUtilConverter, PaUtil_SelectConverter

+*/

+extern PaUtilConverterTable paConverters;

+

+

+/** The type used to store all buffer zeroing functions.

+    @see paZeroers;

+*/

+typedef struct{

+    PaUtilZeroer *ZeroU8; /* unsigned 8 bit, zero == 128 */

+    PaUtilZeroer *Zero8;

+    PaUtilZeroer *Zero16;

+    PaUtilZeroer *Zero24;

+    PaUtilZeroer *Zero32;

+} PaUtilZeroerTable;

+

+

+/** A table of pointers to all required zeroer functions.

+    PaUtil_SelectZeroer() uses this table to lookup the appropriate

+    conversion functions. The fields of this structure are initialized

+    with default conversion functions. User code may substitue optimised

+    conversion functions by assigning different function pointers to

+    these fields.

+

+    @note

+    If the PA_NO_STANDARD_ZEROERS preprocessor variable is defined,

+    PortAudio's standard zeroers will not be compiled, and all fields

+    of this structure will be initialized to NULL. In such cases, users

+    should supply their own zeroing functions for the sample sizes which

+    they intend to use.

+

+    @see PaUtilZeroerTable, PaUtilZeroer, PaUtil_SelectZeroer

+*/

+extern PaUtilZeroerTable paZeroers;

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PA_CONVERTERS_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_cpuload.c b/pjmedia/src/pjmedia/portaudio/pa_cpuload.c
index e70fbf4..2def09d 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_cpuload.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_cpuload.c
@@ -1,96 +1,117 @@
-/*
- * $Id: pa_cpuload.c,v 1.1.2.14 2004/01/08 22:01:12 rossbencina Exp $
- * Portable Audio I/O Library CPU Load measurement functions
- * Portable CPU load measurement facility.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 2002 Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Functions to assist in measuring the CPU utilization of a callback
- stream. Used to implement the Pa_GetStreamCpuLoad() function.
-
- @todo Dynamically calculate the coefficients used to smooth the CPU Load
- Measurements over time to provide a uniform characterisation of CPU Load
- independent of rate at which PaUtil_BeginCpuLoadMeasurement /
- PaUtil_EndCpuLoadMeasurement are called.
-*/
-
-
-#include "pa_cpuload.h"
-
-#include <assert.h>
-
-#include "pa_util.h"   /* for PaUtil_GetTime() */
-
-
-void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate )
-{
-    assert( sampleRate > 0 );
-
-    measurer->samplingPeriod = 1. / sampleRate;
-    measurer->averageLoad = 0.;
-}
-
-void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer )
-{
-    measurer->averageLoad = 0.;
-}
-
-void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer )
-{
-    measurer->measurementStartTime = PaUtil_GetTime();
-}
-
-
-void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed )
-{
-    double measurementEndTime, secondsFor100Percent, measuredLoad;
-
-    if( framesProcessed > 0 ){
-        measurementEndTime = PaUtil_GetTime();
-
-        assert( framesProcessed > 0 );
-        secondsFor100Percent = framesProcessed * measurer->samplingPeriod;
-
-        measuredLoad = (measurementEndTime - measurer->measurementStartTime) / secondsFor100Percent;
-
-        /* Low pass filter the calculated CPU load to reduce jitter using a simple IIR low pass filter. */
-        /** FIXME @todo these coefficients shouldn't be hardwired */
-#define LOWPASS_COEFFICIENT_0   (0.9)
-#define LOWPASS_COEFFICIENT_1   (0.99999 - LOWPASS_COEFFICIENT_0)
-
-        measurer->averageLoad = (LOWPASS_COEFFICIENT_0 * measurer->averageLoad) +
-                               (LOWPASS_COEFFICIENT_1 * measuredLoad);
-    }
-}
-
-
-double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer )
-{
-    return measurer->averageLoad;
-}
+/*

+ * $Id: pa_cpuload.c,v 1.1.2.14 2004/01/08 22:01:12 rossbencina Exp $

+ * Portable Audio I/O Library CPU Load measurement functions

+ * Portable CPU load measurement facility.

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 2002 Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+ @brief Functions to assist in measuring the CPU utilization of a callback

+ stream. Used to implement the Pa_GetStreamCpuLoad() function.

+

+ @todo Dynamically calculate the coefficients used to smooth the CPU Load

+ Measurements over time to provide a uniform characterisation of CPU Load

+ independent of rate at which PaUtil_BeginCpuLoadMeasurement /

+ PaUtil_EndCpuLoadMeasurement are called.

+*/

+

+

+#include "pa_cpuload.h"

+

+#include <assert.h>

+

+#include "pa_util.h"   /* for PaUtil_GetTime() */

+

+

+void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate )

+{

+    assert( sampleRate > 0 );

+

+    measurer->samplingPeriod = 1. / sampleRate;

+    measurer->averageLoad = 0.;

+}

+

+void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer )

+{

+    measurer->averageLoad = 0.;

+}

+

+void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer )

+{

+    measurer->measurementStartTime = PaUtil_GetTime();

+}

+

+

+void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed )

+{

+    double measurementEndTime, secondsFor100Percent, measuredLoad;

+

+    if( framesProcessed > 0 ){

+        measurementEndTime = PaUtil_GetTime();

+

+        assert( framesProcessed > 0 );

+        secondsFor100Percent = framesProcessed * measurer->samplingPeriod;

+

+        measuredLoad = (measurementEndTime - measurer->measurementStartTime) / secondsFor100Percent;

+

+        /* Low pass filter the calculated CPU load to reduce jitter using a simple IIR low pass filter. */

+        /** FIXME @todo these coefficients shouldn't be hardwired */

+#define LOWPASS_COEFFICIENT_0   (0.9)

+#define LOWPASS_COEFFICIENT_1   (0.99999 - LOWPASS_COEFFICIENT_0)

+

+        measurer->averageLoad = (LOWPASS_COEFFICIENT_0 * measurer->averageLoad) +

+                               (LOWPASS_COEFFICIENT_1 * measuredLoad);

+    }

+}

+

+

+double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer )

+{

+    return measurer->averageLoad;

+}

diff --git a/pjmedia/src/pjmedia/portaudio/pa_cpuload.h b/pjmedia/src/pjmedia/portaudio/pa_cpuload.h
index f77d919..fd7988b 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_cpuload.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_cpuload.h
@@ -1,63 +1,84 @@
-#ifndef PA_CPULOAD_H
-#define PA_CPULOAD_H
-/*
- * $Id: pa_cpuload.h,v 1.1.2.10 2004/01/08 22:01:12 rossbencina Exp $
- * Portable Audio I/O Library CPU Load measurement functions
- * Portable CPU load measurement facility.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 2002 Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Functions to assist in measuring the CPU utilization of a callback
- stream. Used to implement the Pa_GetStreamCpuLoad() function.
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-typedef struct {
-    double samplingPeriod;
-    double measurementStartTime;
-    double averageLoad;
-} PaUtilCpuLoadMeasurer; /**< @todo need better name than measurer */
-
-void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate );
-void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer );
-void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed );
-void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer );
-double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer );
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */     
-#endif /* PA_CPULOAD_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_CPULOAD_H

+#define PA_CPULOAD_H

+/*

+ * $Id: pa_cpuload.h,v 1.1.2.10 2004/01/08 22:01:12 rossbencina Exp $

+ * Portable Audio I/O Library CPU Load measurement functions

+ * Portable CPU load measurement facility.

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 2002 Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+ @brief Functions to assist in measuring the CPU utilization of a callback

+ stream. Used to implement the Pa_GetStreamCpuLoad() function.

+*/

+

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+typedef struct {

+    double samplingPeriod;

+    double measurementStartTime;

+    double averageLoad;

+} PaUtilCpuLoadMeasurer; /**< @todo need better name than measurer */

+

+void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate );

+void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer );

+void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed );

+void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer );

+double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer );

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */     

+#endif /* PA_CPULOAD_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_dither.c b/pjmedia/src/pjmedia/portaudio/pa_dither.c
index 0600db6..0c20a95 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_dither.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_dither.c
@@ -1,204 +1,225 @@
-/*
- * $Id: pa_dither.c,v 1.1.2.6 2005/05/28 22:49:02 rossbencina Exp $
- * Portable Audio I/O Library triangular dither generator
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Functions for generating dither noise
-*/
-
-
-#include "pa_dither.h"
-#include "pa_types.h"
-
-#define PA_DITHER_BITS_   (15)
-
-
-void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *state )
-{
-    state->previous = 0;
-    state->randSeed1 = 22222;
-    state->randSeed2 = 5555555;
-}
-
-
-signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state )
-{
-    signed long current, highPass;
-
-    /* Generate two random numbers. */
-    state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;
-    state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;
-
-    /* Generate triangular distribution about 0.
-     * Shift before adding to prevent overflow which would skew the distribution.
-     * Also shift an extra bit for the high pass filter. 
-     */
-#define DITHER_SHIFT_  ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)
-    current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
-              (((signed long)state->randSeed2)>>DITHER_SHIFT_);
-
-    /* High pass filter to reduce audibility. */
-    highPass = current - state->previous;
-    state->previous = current;
-    return highPass;
-}
-
-
-/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */
-#define PA_FLOAT_DITHER_SCALE_  (1.0f / ((1<<PA_DITHER_BITS_)-1))
-static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_;
-
-float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *state )
-{
-    signed long current, highPass;
-
-    /* Generate two random numbers. */
-    state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;
-    state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;
-
-    /* Generate triangular distribution about 0.
-     * Shift before adding to prevent overflow which would skew the distribution.
-     * Also shift an extra bit for the high pass filter. 
-     */
-#define DITHER_SHIFT_  ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)
-    current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
-              (((signed long)state->randSeed2)>>DITHER_SHIFT_);
-
-    /* High pass filter to reduce audibility. */
-    highPass = current - state->previous;
-    state->previous = current;
-    return ((float)highPass) * const_float_dither_scale_;
-}
-
-
-/*
-The following alternate dither algorithms (from musicdsp.org) could be
-considered
-*/
-
-/*Noise shaped dither  (March 2000)
--------------------
-
-This is a simple implementation of highpass triangular-PDF dither with
-2nd-order noise shaping, for use when truncating floating point audio
-data to fixed point.
-
-The noise shaping lowers the noise floor by 11dB below 5kHz (@ 44100Hz
-sample rate) compared to triangular-PDF dither. The code below assumes
-input data is in the range +1 to -1 and doesn't check for overloads!
-
-To save time when generating dither for multiple channels you can do
-things like this:  r3=(r1 & 0x7F)<<8; instead of calling rand() again.
-
-
-
-  int   r1, r2;                //rectangular-PDF random numbers
-  float s1, s2;                //error feedback buffers
-  float s = 0.5f;              //set to 0.0f for no noise shaping
-  float w = pow(2.0,bits-1);   //word length (usually bits=16)
-  float wi= 1.0f/w;            
-  float d = wi / RAND_MAX;     //dither amplitude (2 lsb)
-  float o = wi * 0.5f;         //remove dc offset
-  float in, tmp;
-  int   out;
-
-
-//for each sample...
-
-  r2=r1;                               //can make HP-TRI dither by
-  r1=rand();                           //subtracting previous rand()
-    
-  in += s * (s1 + s1 - s2);            //error feedback
-  tmp = in + o + d * (float)(r1 - r2); //dc offset and dither 
-  
-  out = (int)(w * tmp);                //truncate downwards
-  if(tmp<0.0f) out--;                  //this is faster than floor()
-
-  s2 = s1;                            
-  s1 = in - wi * (float)out;           //error
-
-
-
--- 
-paul.kellett@maxim.abel.co.uk
-http://www.maxim.abel.co.uk
-*/
-
-
-/*
-16-to-8-bit first-order dither
-
-Type : First order error feedforward dithering code
-References : Posted by Jon Watte
-
-Notes : 
-This is about as simple a dithering algorithm as you can implement, but it's
-likely to sound better than just truncating to N bits.
-
-Note that you might not want to carry forward the full difference for infinity.
-It's probably likely that the worst performance hit comes from the saturation
-conditionals, which can be avoided with appropriate instructions on many DSPs
-and integer SIMD type instructions, or CMOV.
-
-Last, if sound quality is paramount (such as when going from > 16 bits to 16
-bits) you probably want to use a higher-order dither function found elsewhere
-on this site. 
-
-
-Code : 
-// This code will down-convert and dither a 16-bit signed short 
-// mono signal into an 8-bit unsigned char signal, using a first 
-// order forward-feeding error term dither. 
-
-#define uchar unsigned char 
-
-void dither_one_channel_16_to_8( short * input, uchar * output, int count, int * memory ) 
-{ 
-  int m = *memory; 
-  while( count-- > 0 ) { 
-    int i = *input++; 
-    i += m; 
-    int j = i + 32768 - 128; 
-    uchar o; 
-    if( j < 0 ) { 
-      o = 0; 
-    } 
-    else if( j > 65535 ) { 
-      o = 255; 
-    } 
-    else { 
-      o = (uchar)((j>>8)&0xff); 
-    } 
-    m = ((j-32768+128)-i); 
-    *output++ = o; 
-  } 
-  *memory = m; 
-} 
-*/
+/*

+ * $Id: pa_dither.c,v 1.1.2.6 2005/05/28 22:49:02 rossbencina Exp $

+ * Portable Audio I/O Library triangular dither generator

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+ @brief Functions for generating dither noise

+*/

+

+

+#include "pa_dither.h"

+#include "pa_types.h"

+

+#define PA_DITHER_BITS_   (15)

+

+

+void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *state )

+{

+    state->previous = 0;

+    state->randSeed1 = 22222;

+    state->randSeed2 = 5555555;

+}

+

+

+signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state )

+{

+    signed long current, highPass;

+

+    /* Generate two random numbers. */

+    state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;

+    state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;

+

+    /* Generate triangular distribution about 0.

+     * Shift before adding to prevent overflow which would skew the distribution.

+     * Also shift an extra bit for the high pass filter. 

+     */

+#define DITHER_SHIFT_  ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)

+    current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +

+              (((signed long)state->randSeed2)>>DITHER_SHIFT_);

+

+    /* High pass filter to reduce audibility. */

+    highPass = current - state->previous;

+    state->previous = current;

+    return highPass;

+}

+

+

+/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */

+#define PA_FLOAT_DITHER_SCALE_  (1.0f / ((1<<PA_DITHER_BITS_)-1))

+static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_;

+

+float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *state )

+{

+    signed long current, highPass;

+

+    /* Generate two random numbers. */

+    state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;

+    state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;

+

+    /* Generate triangular distribution about 0.

+     * Shift before adding to prevent overflow which would skew the distribution.

+     * Also shift an extra bit for the high pass filter. 

+     */

+#define DITHER_SHIFT_  ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)

+    current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +

+              (((signed long)state->randSeed2)>>DITHER_SHIFT_);

+

+    /* High pass filter to reduce audibility. */

+    highPass = current - state->previous;

+    state->previous = current;

+    return ((float)highPass) * const_float_dither_scale_;

+}

+

+

+/*

+The following alternate dither algorithms (from musicdsp.org) could be

+considered

+*/

+

+/*Noise shaped dither  (March 2000)

+-------------------

+

+This is a simple implementation of highpass triangular-PDF dither with

+2nd-order noise shaping, for use when truncating floating point audio

+data to fixed point.

+

+The noise shaping lowers the noise floor by 11dB below 5kHz (@ 44100Hz

+sample rate) compared to triangular-PDF dither. The code below assumes

+input data is in the range +1 to -1 and doesn't check for overloads!

+

+To save time when generating dither for multiple channels you can do

+things like this:  r3=(r1 & 0x7F)<<8; instead of calling rand() again.

+

+

+

+  int   r1, r2;                //rectangular-PDF random numbers

+  float s1, s2;                //error feedback buffers

+  float s = 0.5f;              //set to 0.0f for no noise shaping

+  float w = pow(2.0,bits-1);   //word length (usually bits=16)

+  float wi= 1.0f/w;            

+  float d = wi / RAND_MAX;     //dither amplitude (2 lsb)

+  float o = wi * 0.5f;         //remove dc offset

+  float in, tmp;

+  int   out;

+

+

+//for each sample...

+

+  r2=r1;                               //can make HP-TRI dither by

+  r1=rand();                           //subtracting previous rand()

+    

+  in += s * (s1 + s1 - s2);            //error feedback

+  tmp = in + o + d * (float)(r1 - r2); //dc offset and dither 

+  

+  out = (int)(w * tmp);                //truncate downwards

+  if(tmp<0.0f) out--;                  //this is faster than floor()

+

+  s2 = s1;                            

+  s1 = in - wi * (float)out;           //error

+

+

+

+-- 

+paul.kellett@maxim.abel.co.uk

+http://www.maxim.abel.co.uk

+*/

+

+

+/*

+16-to-8-bit first-order dither

+

+Type : First order error feedforward dithering code

+References : Posted by Jon Watte

+

+Notes : 

+This is about as simple a dithering algorithm as you can implement, but it's

+likely to sound better than just truncating to N bits.

+

+Note that you might not want to carry forward the full difference for infinity.

+It's probably likely that the worst performance hit comes from the saturation

+conditionals, which can be avoided with appropriate instructions on many DSPs

+and integer SIMD type instructions, or CMOV.

+

+Last, if sound quality is paramount (such as when going from > 16 bits to 16

+bits) you probably want to use a higher-order dither function found elsewhere

+on this site. 

+

+

+Code : 

+// This code will down-convert and dither a 16-bit signed short 

+// mono signal into an 8-bit unsigned char signal, using a first 

+// order forward-feeding error term dither. 

+

+#define uchar unsigned char 

+

+void dither_one_channel_16_to_8( short * input, uchar * output, int count, int * memory ) 

+{ 

+  int m = *memory; 

+  while( count-- > 0 ) { 

+    int i = *input++; 

+    i += m; 

+    int j = i + 32768 - 128; 

+    uchar o; 

+    if( j < 0 ) { 

+      o = 0; 

+    } 

+    else if( j > 65535 ) { 

+      o = 255; 

+    } 

+    else { 

+      o = (uchar)((j>>8)&0xff); 

+    } 

+    m = ((j-32768+128)-i); 

+    *output++ = o; 

+  } 

+  *memory = m; 

+} 

+*/

diff --git a/pjmedia/src/pjmedia/portaudio/pa_dither.h b/pjmedia/src/pjmedia/portaudio/pa_dither.h
index 70369e1..24bbe2a 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_dither.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_dither.h
@@ -1,91 +1,112 @@
-#ifndef PA_DITHER_H
-#define PA_DITHER_H
-/*
- * $Id: pa_dither.h,v 1.1.2.4 2003/09/20 21:06:19 rossbencina Exp $
- * Portable Audio I/O Library triangular dither generator
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Functions for generating dither noise
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/** @brief State needed to generate a dither signal */
-typedef struct PaUtilTriangularDitherGenerator{
-    unsigned long previous;
-    unsigned long randSeed1;
-    unsigned long randSeed2;
-} PaUtilTriangularDitherGenerator;
-
-
-/** @brief Initialize dither state */
-void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState );
-
-
-/**
- @brief Calculate 2 LSB dither signal with a triangular distribution.
- Ranged for adding to a 1 bit right-shifted 32 bit integer
- prior to >>15. eg:
-<pre>
-    signed long in = *
-    signed long dither = PaUtil_Generate16BitTriangularDither( ditherState );
-    signed short out = (signed short)(((in>>1) + dither) >> 15);
-</pre>
- @return
- A signed long with a range of +32767 to -32768
-*/
-signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
-
-
-/**
- @brief Calculate 2 LSB dither signal with a triangular distribution.
- Ranged for adding to a pre-scaled float.
-<pre>
-    float in = *
-    float dither = PaUtil_GenerateFloatTriangularDither( ditherState );
-    // use smaller scaler to prevent overflow when we add the dither
-    signed short out = (signed short)(in*(32766.0f) + dither );
-</pre>
- @return
- A float with a range of -2.0 to +1.99999.
-*/
-float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
-
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_DITHER_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_DITHER_H

+#define PA_DITHER_H

+/*

+ * $Id: pa_dither.h,v 1.1.2.4 2003/09/20 21:06:19 rossbencina Exp $

+ * Portable Audio I/O Library triangular dither generator

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+ @brief Functions for generating dither noise

+*/

+

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+/** @brief State needed to generate a dither signal */

+typedef struct PaUtilTriangularDitherGenerator{

+    unsigned long previous;

+    unsigned long randSeed1;

+    unsigned long randSeed2;

+} PaUtilTriangularDitherGenerator;

+

+

+/** @brief Initialize dither state */

+void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState );

+

+

+/**

+ @brief Calculate 2 LSB dither signal with a triangular distribution.

+ Ranged for adding to a 1 bit right-shifted 32 bit integer

+ prior to >>15. eg:

+<pre>

+    signed long in = *

+    signed long dither = PaUtil_Generate16BitTriangularDither( ditherState );

+    signed short out = (signed short)(((in>>1) + dither) >> 15);

+</pre>

+ @return

+ A signed long with a range of +32767 to -32768

+*/

+signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState );

+

+

+/**

+ @brief Calculate 2 LSB dither signal with a triangular distribution.

+ Ranged for adding to a pre-scaled float.

+<pre>

+    float in = *

+    float dither = PaUtil_GenerateFloatTriangularDither( ditherState );

+    // use smaller scaler to prevent overflow when we add the dither

+    signed short out = (signed short)(in*(32766.0f) + dither );

+</pre>

+ @return

+ A float with a range of -2.0 to +1.99999.

+*/

+float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState );

+

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PA_DITHER_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_endianness.h b/pjmedia/src/pjmedia/portaudio/pa_endianness.h
index 052bced..2b546c3 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_endianness.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_endianness.h
@@ -1,111 +1,132 @@
-#ifndef PA_ENDIANNESS_H
-#define PA_ENDIANNESS_H
-/*
- * $Id: pa_endianness.h,v 1.1.2.3 2003/09/20 21:06:19 rossbencina Exp $
- * Portable Audio I/O Library current platform endianness macros
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Configure endianness symbols for the target processor.
-
- Arrange for either the PA_LITTLE_ENDIAN or PA_BIG_ENDIAN preprocessor symbols
- to be defined. The one that is defined reflects the endianness of the target
- platform and may be used to implement conditional compilation of byte-order
- dependent code.
-
- If either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN is defined already, then no attempt
- is made to override that setting. This may be useful if you have a better way
- of determining the platform's endianness. The autoconf mechanism uses this for
- example.
-
- A PA_VALIDATE_ENDIANNESS macro is provided to compare the compile time
- and runtime endiannes and raise an assertion if they don't match.
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-#if defined(PA_LITTLE_ENDIAN) || defined(PA_BIG_ENDIAN)
-    /* endianness define has been set externally, such as by autoconf */
-
-    #if defined(PA_LITTLE_ENDIAN) && defined(PA_BIG_ENDIAN)
-    #error both PA_LITTLE_ENDIAN and PA_BIG_ENDIAN have been defined externally to pa_endianness.h - only one endianness at a time please
-    #endif
-
-#else
-    /* endianness define has not been set externally */
-
-    /* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */
-
-    #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
-
-    #define PA_LITTLE_ENDIAN /* win32, assume intel byte order */
-
-    #else
-
-#endif
-
-    #if !defined(PA_LITTLE_ENDIAN) && !defined(PA_BIG_ENDIAN)
-    /*
-     If the following error is raised, you either need to modify the code above
-     to automatically determine the endianness from other symbols defined on your
-     platform, or define either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN externally.
-    */
-    #error pa_endianness.h was unable to automatically determine the endianness of the target platform
-    #endif
-    
-#endif
-
-/* PA_VALIDATE_ENDIANNESS compares the compile time and runtime endianness,
- and raises an assertion if they don't match. <assert.h> must be included in
- the context in which this macro is used.
-*/
-#if defined(PA_LITTLE_ENDIAN)
-    #define PA_VALIDATE_ENDIANNESS \
-    { \
-        const long nativeOne = 1; \
-        assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 1 ); \
-    }
-#elif defined(PA_BIG_ENDIAN)
-    #define PA_VALIDATE_ENDIANNESS \
-    { \
-        const long nativeOne = 1; \
-        assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \
-    }
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_ENDIANNESS_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_ENDIANNESS_H

+#define PA_ENDIANNESS_H

+/*

+ * $Id: pa_endianness.h,v 1.1.2.3 2003/09/20 21:06:19 rossbencina Exp $

+ * Portable Audio I/O Library current platform endianness macros

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+ @brief Configure endianness symbols for the target processor.

+

+ Arrange for either the PA_LITTLE_ENDIAN or PA_BIG_ENDIAN preprocessor symbols

+ to be defined. The one that is defined reflects the endianness of the target

+ platform and may be used to implement conditional compilation of byte-order

+ dependent code.

+

+ If either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN is defined already, then no attempt

+ is made to override that setting. This may be useful if you have a better way

+ of determining the platform's endianness. The autoconf mechanism uses this for

+ example.

+

+ A PA_VALIDATE_ENDIANNESS macro is provided to compare the compile time

+ and runtime endiannes and raise an assertion if they don't match.

+*/

+

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+#if defined(PA_LITTLE_ENDIAN) || defined(PA_BIG_ENDIAN)

+    /* endianness define has been set externally, such as by autoconf */

+

+    #if defined(PA_LITTLE_ENDIAN) && defined(PA_BIG_ENDIAN)

+    #error both PA_LITTLE_ENDIAN and PA_BIG_ENDIAN have been defined externally to pa_endianness.h - only one endianness at a time please

+    #endif

+

+#else

+    /* endianness define has not been set externally */

+

+    /* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */

+

+    #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)

+

+    #define PA_LITTLE_ENDIAN /* win32, assume intel byte order */

+

+    #else

+

+#endif

+

+    #if !defined(PA_LITTLE_ENDIAN) && !defined(PA_BIG_ENDIAN)

+    /*

+     If the following error is raised, you either need to modify the code above

+     to automatically determine the endianness from other symbols defined on your

+     platform, or define either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN externally.

+    */

+    #error pa_endianness.h was unable to automatically determine the endianness of the target platform

+    #endif

+    

+#endif

+

+/* PA_VALIDATE_ENDIANNESS compares the compile time and runtime endianness,

+ and raises an assertion if they don't match. <assert.h> must be included in

+ the context in which this macro is used.

+*/

+#if defined(PA_LITTLE_ENDIAN)

+    #define PA_VALIDATE_ENDIANNESS \

+    { \

+        const long nativeOne = 1; \

+        assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 1 ); \

+    }

+#elif defined(PA_BIG_ENDIAN)

+    #define PA_VALIDATE_ENDIANNESS \

+    { \

+        const long nativeOne = 1; \

+        assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \

+    }

+#endif

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PA_ENDIANNESS_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_front.c b/pjmedia/src/pjmedia/portaudio/pa_front.c
index 3a267bb..1790582 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_front.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_front.c
@@ -1,1976 +1,1997 @@
-/*
- * $Id: pa_front.c,v 1.1.2.51 2005/02/05 15:52:12 rossbencina Exp $
- * Portable Audio I/O Library Multi-Host API front end
- * Validate function parameters and manage multiple host APIs.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/* doxygen index page */
-/** @mainpage
-
-PortAudio is an open-source cross-platform †CË library for audio input
-and output. It is designed to simplify the porting of audio applications
-between various platforms, and also to simplify the development of audio
-software in general by hiding the complexities of device interfacing.
-
-See the PortAudio website for further information http://www.portaudio.com/
-
-This documentation pertains to PortAudio V19, API version 2.0 which is
-currently under development. API version 2.0 differs in a number of ways from
-previous versions, please consult the enhancement proposals for further details:
-http://www.portaudio.com/docs/proposals/index.html
-
-This documentation is under construction. Things you might be interested in
-include:
-
-- The PortAudio API 2.0, as documented in portaudio.h
-
-- The <a href="todo.html">TODO List</a>
-
-Feel free to pick an item off TODO list and fix/implement it. You may want to
-enquire about status on the PortAudio mailing list first.
-*/
-
-
-/** @file
- @brief Implements public PortAudio API, checks some errors, forwards to
- host API implementations.
- 
- Implements the functions defined in the PortAudio API, checks for
- some parameter and state inconsistencies and forwards API requests to
- specific Host API implementations (via the interface declared in
- pa_hostapi.h), and Streams (via the interface declared in pa_stream.h).
-
- This file handles initialization and termination of Host API
- implementations via initializers stored in the paHostApiInitializers
- global variable.
-
- Some utility functions declared in pa_util.h are implemented in this file.
-
- All PortAudio API functions can be conditionally compiled with logging code.
- To compile with logging, define the PA_LOG_API_CALLS precompiler symbol.
-
-    @todo Consider adding host API specific error text in Pa_GetErrorText() for
-    paUnanticipatedHostError
-
-    @todo Consider adding a new error code for when (inputParameters == NULL)
-    && (outputParameters == NULL)
-
-    @todo review whether Pa_CloseStream() should call the interface's
-    CloseStream function if aborting the stream returns an error code.
-
-    @todo Create new error codes if a NULL buffer pointer, or a
-    zero frame count is passed to Pa_ReadStream or Pa_WriteStream.
-*/
-
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <memory.h>
-#include <string.h>
-#include <assert.h> /* needed by PA_VALIDATE_ENDIANNESS */
-
-#include "portaudio.h"
-#include "pa_util.h"
-#include "pa_endianness.h"
-#include "pa_types.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-
-#include "pa_trace.h"
-
-
-#define PA_VERSION_  1899
-#define PA_VERSION_TEXT_ "PortAudio V19-devel"
-
-
-
-/* #define PA_LOG_API_CALLS */
-
-/*
-    The basic format for log messages is described below. If you need to
-    add any log messages, please follow this format.
- 
-    Function entry (void function):
- 
-        "FunctionName called.\n"
- 
-    Function entry (non void function):
- 
-        "FunctionName called:\n"
-        "\tParam1Type param1: param1Value\n"
-        "\tParam2Type param2: param2Value\n"      (etc...)
- 
- 
-    Function exit (no return value):
- 
-        "FunctionName returned.\n"
- 
-    Function exit (simple return value):
- 
-        "FunctionName returned:\n"
-        "\tReturnType: returnValue\n\n"
- 
-    If the return type is an error code, the error text is displayed in ()
- 
-    If the return type is not an error code, but has taken a special value
-    because an error occurred, then the reason for the error is shown in []
- 
-    If the return type is a struct ptr, the struct is dumped.
- 
-    See the code below for examples
-*/
-
-
-int Pa_GetVersion( void )
-{
-    return PA_VERSION_;
-}
-
-
-const char* Pa_GetVersionText( void )
-{
-    return PA_VERSION_TEXT_;
-}
-
-
-
-#define PA_LAST_HOST_ERROR_TEXT_LENGTH_  1024
-
-static char lastHostErrorText_[ PA_LAST_HOST_ERROR_TEXT_LENGTH_ + 1 ] = {0};
-
-static PaHostErrorInfo lastHostErrorInfo_ = { (PaHostApiTypeId)-1, 0, lastHostErrorText_ };
-
-
-void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
-        const char *errorText )
-{
-    lastHostErrorInfo_.hostApiType = hostApiType;
-    lastHostErrorInfo_.errorCode = errorCode;
-
-    strncpy( lastHostErrorText_, errorText, PA_LAST_HOST_ERROR_TEXT_LENGTH_ );
-}
-
-
-void PaUtil_DebugPrint( const char *format, ... )
-{
-    va_list ap;
-
-    va_start( ap, format );
-    vfprintf( stderr, format, ap );
-    va_end( ap );
-
-    fflush( stderr );
-}
-
-
-static PaUtilHostApiRepresentation **hostApis_ = 0;
-static int hostApisCount_ = 0;
-static int initializationCount_ = 0;
-static int deviceCount_ = 0;
-
-PaUtilStreamRepresentation *firstOpenStream_ = NULL;
-
-
-#define PA_IS_INITIALISED_ (initializationCount_ != 0)
-
-
-static int CountHostApiInitializers( void )
-{
-    int result = 0;
-
-    while( paHostApiInitializers[ result ] != 0 )
-        ++result;
-    return result;
-}
-
-
-static void TerminateHostApis( void )
-{
-    /* terminate in reverse order from initialization */
-
-    while( hostApisCount_ > 0 )
-    {
-        --hostApisCount_;
-        hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] );
-    }
-    hostApisCount_ = 0;
-    deviceCount_ = 0;
-
-    if( hostApis_ != 0 )
-        PaUtil_FreeMemory( hostApis_ );
-    hostApis_ = 0;
-}
-
-
-static PaError InitializeHostApis( void )
-{
-    PaError result = paNoError;
-    int i, initializerCount, baseDeviceIndex;
-
-    initializerCount = CountHostApiInitializers();
-
-    hostApis_ = (PaUtilHostApiRepresentation**)PaUtil_AllocateMemory(
-            sizeof(PaUtilHostApiRepresentation*) * initializerCount );
-    if( !hostApis_ )
-    {
-        result = paInsufficientMemory;
-        goto error; 
-    }
-
-    hostApisCount_ = 0;
-    deviceCount_ = 0;
-    baseDeviceIndex = 0;
-
-    for( i=0; i< initializerCount; ++i )
-    {
-        hostApis_[hostApisCount_] = NULL;
-        result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ );
-        if( result != paNoError )
-            goto error;
-
-        if( hostApis_[hostApisCount_] )
-        {
-
-            hostApis_[hostApisCount_]->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
-
-            if( hostApis_[hostApisCount_]->info.defaultInputDevice != paNoDevice )
-                hostApis_[hostApisCount_]->info.defaultInputDevice += baseDeviceIndex;
-
-            if( hostApis_[hostApisCount_]->info.defaultOutputDevice != paNoDevice )
-                hostApis_[hostApisCount_]->info.defaultOutputDevice += baseDeviceIndex;
-
-            baseDeviceIndex += hostApis_[hostApisCount_]->info.deviceCount;
-            deviceCount_ += hostApis_[hostApisCount_]->info.deviceCount;
-
-            ++hostApisCount_;
-        }
-    }
-
-    return result;
-
-error:
-    TerminateHostApis();
-    return result;
-}
-
-
-/*
-    FindHostApi() finds the index of the host api to which
-    <device> belongs and returns it. if <hostSpecificDeviceIndex> is
-    non-null, the host specific device index is returned in it.
-    returns -1 if <device> is out of range.
- 
-*/
-static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex )
-{
-    int i=0;
-
-    if( !PA_IS_INITIALISED_ )
-        return -1;
-
-    if( device < 0 )
-        return -1;
-
-    while( i < hostApisCount_
-            && device >= hostApis_[i]->info.deviceCount )
-    {
-
-        device -= hostApis_[i]->info.deviceCount;
-        ++i;
-    }
-
-    if( i >= hostApisCount_ )
-        return -1;
-
-    if( hostSpecificDeviceIndex )
-        *hostSpecificDeviceIndex = device;
-
-    return i;
-}
-
-
-static void AddOpenStream( PaStream* stream )
-{
-    ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_;
-    firstOpenStream_ = (PaUtilStreamRepresentation*)stream;
-}
-
-
-static void RemoveOpenStream( PaStream* stream )
-{
-    PaUtilStreamRepresentation *previous = NULL;
-    PaUtilStreamRepresentation *current = firstOpenStream_;
-
-    while( current != NULL )
-    {
-        if( ((PaStream*)current) == stream )
-        {
-            if( previous == NULL )
-            {
-                firstOpenStream_ = current->nextOpenStream;
-            }
-            else
-            {
-                previous->nextOpenStream = current->nextOpenStream;
-            }
-            return;
-        }
-        else
-        {
-            previous = current;
-            current = current->nextOpenStream;
-        }
-    }
-}
-
-
-static void CloseOpenStreams( void )
-{
-    /* we call Pa_CloseStream() here to ensure that the same destruction
-        logic is used for automatically closed streams */
-
-    while( firstOpenStream_ != NULL )
-        Pa_CloseStream( firstOpenStream_ );
-}
-
-
-PaError Pa_Initialize( void )
-{
-    PaError result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint( "Pa_Initialize called.\n" );
-#endif
-
-    if( PA_IS_INITIALISED_ )
-    {
-        ++initializationCount_;
-        result = paNoError;
-    }
-    else
-    {
-        PA_VALIDATE_TYPE_SIZES;
-        PA_VALIDATE_ENDIANNESS;
-        
-        PaUtil_InitializeClock();
-        PaUtil_ResetTraceMessages();
-
-        result = InitializeHostApis();
-        if( result == paNoError )
-            ++initializationCount_;
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint( "Pa_Initialize returned:\n" );
-    PaUtil_DebugPrint( "\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError Pa_Terminate( void )
-{
-    PaError result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_Terminate called.\n" );
-#endif
-
-    if( PA_IS_INITIALISED_ )
-    {
-        if( --initializationCount_ == 0 )
-        {
-            CloseOpenStreams();
-
-            TerminateHostApis();
-
-            PaUtil_DumpTraceMessages();
-        }
-        result = paNoError;
-    }
-    else
-    {
-        result=  paNotInitialized;
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_Terminate returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void )
-{
-    return &lastHostErrorInfo_;
-}
-
-
-const char *Pa_GetErrorText( PaError errorCode )
-{
-    const char *result;
-
-    switch( errorCode )
-    {
-    case paNoError:                  result = "Success"; break;
-    case paNotInitialized:           result = "PortAudio not initialized"; break;
-    /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError */
-    case paUnanticipatedHostError:   result = "Unanticipated host error"; break;
-    case paInvalidChannelCount:      result = "Invalid number of channels"; break;
-    case paInvalidSampleRate:        result = "Invalid sample rate"; break;
-    case paInvalidDevice:            result = "Invalid device"; break;
-    case paInvalidFlag:              result = "Invalid flag"; break;
-    case paSampleFormatNotSupported: result = "Sample format not supported"; break;
-    case paBadIODeviceCombination:   result = "Illegal combination of I/O devices"; break;
-    case paInsufficientMemory:       result = "Insufficient memory"; break;
-    case paBufferTooBig:             result = "Buffer too big"; break;
-    case paBufferTooSmall:           result = "Buffer too small"; break;
-    case paNullCallback:             result = "No callback routine specified"; break;
-    case paBadStreamPtr:             result = "Invalid stream pointer"; break;
-    case paTimedOut:                 result = "Wait timed out"; break;
-    case paInternalError:            result = "Internal PortAudio error"; break;
-    case paDeviceUnavailable:        result = "Device unavailable"; break;
-    case paIncompatibleHostApiSpecificStreamInfo:   result = "Incompatible host API specific stream info"; break;
-    case paStreamIsStopped:          result = "Stream is stopped"; break;
-    case paStreamIsNotStopped:       result = "Stream is not stopped"; break;
-    case paInputOverflowed:          result = "Input overflowed"; break;
-    case paOutputUnderflowed:        result = "Output underflowed"; break;
-    case paHostApiNotFound:          result = "Host API not found"; break;
-    case paInvalidHostApi:           result = "Invalid host API"; break;
-    case paCanNotReadFromACallbackStream:       result = "Can't read from a callback stream"; break;
-    case paCanNotWriteToACallbackStream:        result = "Can't write to a callback stream"; break;
-    case paCanNotReadFromAnOutputOnlyStream:    result = "Can't read from an output only stream"; break;
-    case paCanNotWriteToAnInputOnlyStream:      result = "Can't write to an input only stream"; break;
-    default:                         result = "Illegal error number"; break;
-    }
-    return result;
-}
-
-
-PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type )
-{
-    PaHostApiIndex result;
-    int i;
-    
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex called:\n" );
-    PaUtil_DebugPrint("\tPaHostApiTypeId type: %d\n", type );
-#endif
-
-    if( !PA_IS_INITIALISED_ )
-    {
-        result = paNotInitialized;
-    }
-    else
-    {
-        result = paHostApiNotFound;
-        
-        for( i=0; i < hostApisCount_; ++i )
-        {
-            if( hostApis_[i]->info.type == type )
-            {
-                result = i;
-                break;
-            }         
-        }
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex returned:\n" );
-    if( result < 0 )
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-    else
-        PaUtil_DebugPrint("\tPaHostApiIndex: %d\n\n", result );
-#endif
-
-    return result;
-}
-
-
-PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,
-        PaHostApiTypeId type )
-{
-    PaError result;
-    int i;
-    
-    if( !PA_IS_INITIALISED_ )
-    {
-        result = paNotInitialized;
-    }
-    else
-    {
-        result = paHostApiNotFound;
-                
-        for( i=0; i < hostApisCount_; ++i )
-        {
-            if( hostApis_[i]->info.type == type )
-            {
-                *hostApi = hostApis_[i];
-                result = paNoError;
-                break;
-            }
-        }
-    }
-
-    return result;
-}
-
-
-PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
-        PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi )
-{
-    PaError result;
-    PaDeviceIndex x;
-    
-    x = device - hostApi->privatePaFrontInfo.baseDeviceIndex;
-
-    if( x < 0 || x >= hostApi->info.deviceCount )
-    {
-        result = paInvalidDevice;
-    }
-    else
-    {
-        *hostApiDevice = x;
-        result = paNoError;
-    }
-
-    return result;
-}
-
-
-PaHostApiIndex Pa_GetHostApiCount( void )
-{
-    int result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetHostApiCount called.\n" );
-#endif
-
-    if( !PA_IS_INITIALISED_ )
-    {
-        result = paNotInitialized;
-    }
-    else
-    {
-        result = hostApisCount_;
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetHostApiCount returned:\n" );
-    if( result < 0 )
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-    else
-        PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", result );
-#endif
-
-    return result;
-}
-
-
-PaHostApiIndex Pa_GetDefaultHostApi( void )
-{
-    int result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetDefaultHostApi called.\n" );
-#endif
-
-    if( !PA_IS_INITIALISED_ )
-    {
-        result = paNotInitialized;
-    }
-    else
-    {
-        result = paDefaultHostApiIndex;
-
-        /* internal consistency check: make sure that the default host api
-         index is within range */
-
-        if( result < 0 || result >= hostApisCount_ )
-        {
-            result = paInternalError;
-        }
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" );
-    if( result < 0 )
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-    else
-        PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", result );
-#endif
-
-    return result;
-}
-
-
-const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi )
-{
-    PaHostApiInfo *info;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetHostApiInfo called:\n" );
-    PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );
-#endif
-
-    if( !PA_IS_INITIALISED_ )
-    {
-        info = NULL;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
-        PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n\n" );
-#endif
-
-    }
-    else if( hostApi < 0 || hostApi >= hostApisCount_ )
-    {
-        info = NULL;
-        
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
-        PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n\n" );
-#endif
-
-    }
-    else
-    {
-        info = &hostApis_[hostApi]->info;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
-        PaUtil_DebugPrint("\tPaHostApiInfo*: 0x%p\n", info );
-        PaUtil_DebugPrint("\t{" );
-        PaUtil_DebugPrint("\t\tint structVersion: %d\n", info->structVersion );
-        PaUtil_DebugPrint("\t\tPaHostApiTypeId type: %d\n", info->type );
-        PaUtil_DebugPrint("\t\tconst char *name: %s\n\n", info->name );
-        PaUtil_DebugPrint("\t}\n\n" );
-#endif
-
-    }
-
-     return info;
-}
-
-
-PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex )
-{
-    PaDeviceIndex result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex called:\n" );
-    PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );
-    PaUtil_DebugPrint("\tint hostApiDeviceIndex: %d\n", hostApiDeviceIndex );
-#endif
-
-    if( !PA_IS_INITIALISED_ )
-    {
-        result = paNotInitialized;
-    }
-    else
-    {
-        if( hostApi < 0 || hostApi >= hostApisCount_ )
-        {
-            result = paInvalidHostApi;
-        }
-        else
-        {
-            if( hostApiDeviceIndex < 0 ||
-                    hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount )
-            {
-                result = paInvalidDevice;
-            }
-            else
-            {
-                result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex;
-            }
-        }
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
-    if( result < 0 )
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-    else
-        PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
-#endif
-
-    return result;
-}
-
-
-PaDeviceIndex Pa_GetDeviceCount( void )
-{
-    PaDeviceIndex result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetDeviceCount called.\n" );
-#endif
-
-    if( !PA_IS_INITIALISED_ )
-    {
-        result = paNotInitialized;
-    }
-    else
-    {
-        result = deviceCount_;
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetDeviceCount returned:\n" );
-    if( result < 0 )
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-    else
-        PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
-#endif
-
-    return result;
-}
-
-
-PaDeviceIndex Pa_GetDefaultInputDevice( void )
-{
-    PaHostApiIndex hostApi;
-    PaDeviceIndex result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetDefaultInputDevice called.\n" );
-#endif
-
-    hostApi = Pa_GetDefaultHostApi();
-    if( hostApi < 0 )
-    {
-        result = paNoDevice;
-    }
-    else
-    {
-        result = hostApis_[hostApi]->info.defaultInputDevice;
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetDefaultInputDevice returned:\n" );
-    PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
-#endif
-
-    return result;
-}
-
-
-PaDeviceIndex Pa_GetDefaultOutputDevice( void )
-{
-    PaHostApiIndex hostApi;
-    PaDeviceIndex result;
-    
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetDefaultOutputDevice called.\n" );
-#endif
-
-    hostApi = Pa_GetDefaultHostApi();
-    if( hostApi < 0 )
-    {
-        result = paNoDevice;
-    }
-    else
-    {
-        result = hostApis_[hostApi]->info.defaultOutputDevice;
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetDefaultOutputDevice returned:\n" );
-    PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
-#endif
-
-    return result;
-}
-
-
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
-{
-    int hostSpecificDeviceIndex;
-    int hostApiIndex = FindHostApi( device, &hostSpecificDeviceIndex );
-    PaDeviceInfo *result;
-
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetDeviceInfo called:\n" );
-    PaUtil_DebugPrint("\tPaDeviceIndex device: %d\n", device );
-#endif
-
-    if( hostApiIndex < 0 )
-    {
-        result = NULL;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );
-        PaUtil_DebugPrint("\tPaDeviceInfo* NULL [ invalid device index ]\n\n" );
-#endif
-
-    }
-    else
-    {
-        result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ];
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );
-        PaUtil_DebugPrint("\tPaDeviceInfo*: 0x%p:\n", result );
-        PaUtil_DebugPrint("\t{\n" );
-
-        PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );
-        PaUtil_DebugPrint("\t\tconst char *name: %s\n", result->name );
-        PaUtil_DebugPrint("\t\tPaHostApiIndex hostApi: %d\n", result->hostApi );
-        PaUtil_DebugPrint("\t\tint maxInputChannels: %d\n", result->maxInputChannels );
-        PaUtil_DebugPrint("\t\tint maxOutputChannels: %d\n", result->maxOutputChannels );
-        PaUtil_DebugPrint("\t}\n\n" );
-#endif
-
-    }
-
-    return result;
-}
-
-
-/*
-    SampleFormatIsValid() returns 1 if sampleFormat is a sample format
-    defined in portaudio.h, or 0 otherwise.
-*/
-static int SampleFormatIsValid( PaSampleFormat format )
-{
-    switch( format & ~paNonInterleaved )
-    {
-    case paFloat32: return 1;
-    case paInt16: return 1;
-    case paInt32: return 1;
-    case paInt24: return 1;
-    case paInt8: return 1;
-    case paUInt8: return 1;
-    case paCustomFormat: return 1;
-    default: return 0;
-    }
-}
-
-/*
-    NOTE: make sure this validation list is kept syncronised with the one in
-            pa_hostapi.h
-
-    ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream()
-    conform to the expected values as described below. This function is
-    also designed to be used with the proposed Pa_IsFormatSupported() function.
-    
-    There are basically two types of validation that could be performed:
-    Generic conformance validation, and device capability mismatch
-    validation. This function performs only generic conformance validation.
-    Validation that would require knowledge of device capabilities is
-    not performed because of potentially complex relationships between
-    combinations of parameters - for example, even if the sampleRate
-    seems ok, it might not be for a duplex stream - we have no way of
-    checking this in an API-neutral way, so we don't try.
- 
-    On success the function returns PaNoError and fills in hostApi,
-    hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure
-    the function returns an error code indicating the first encountered
-    parameter error.
- 
- 
-    If ValidateOpenStreamParameters() returns paNoError, the following
-    assertions are guaranteed to be true.
- 
-    - at least one of inputParameters & outputParmeters is valid (not NULL)
-
-    - if inputParameters & outputParmeters are both valid, that
-        inputParameters->device & outputParmeters->device  both use the same host api
- 
-    PaDeviceIndex inputParameters->device
-        - is within range (0 to Pa_GetDeviceCount-1) Or:
-        - is paUseHostApiSpecificDeviceSpecification and
-            inputParameters->hostApiSpecificStreamInfo is non-NULL and refers
-            to a valid host api
-
-    int inputParameters->channelCount
-        - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0
-        - upper bound is NOT validated against device capabilities
- 
-    PaSampleFormat inputParameters->sampleFormat
-        - is one of the sample formats defined in portaudio.h
-
-    void *inputParameters->hostApiSpecificStreamInfo
-        - if supplied its hostApi field matches the input device's host Api
- 
-    PaDeviceIndex outputParmeters->device
-        - is within range (0 to Pa_GetDeviceCount-1)
- 
-    int outputParmeters->channelCount
-        - if inputDevice is valid, channelCount is > 0
-        - upper bound is NOT validated against device capabilities
- 
-    PaSampleFormat outputParmeters->sampleFormat
-        - is one of the sample formats defined in portaudio.h
-        
-    void *outputParmeters->hostApiSpecificStreamInfo
-        - if supplied its hostApi field matches the output device's host Api
- 
-    double sampleRate
-        - is not an 'absurd' rate (less than 1000. or greater than 200000.)
-        - sampleRate is NOT validated against device capabilities
- 
-    PaStreamFlags streamFlags
-        - unused platform neutral flags are zero
-        - paNeverDropInput is only used for full-duplex callback streams with
-            variable buffer size (paFramesPerBufferUnspecified)
-*/
-static PaError ValidateOpenStreamParameters(
-    const PaStreamParameters *inputParameters,
-    const PaStreamParameters *outputParameters,
-    double sampleRate,
-    unsigned long framesPerBuffer,
-    PaStreamFlags streamFlags,
-    PaStreamCallback *streamCallback,
-    PaUtilHostApiRepresentation **hostApi,
-    PaDeviceIndex *hostApiInputDevice,
-    PaDeviceIndex *hostApiOutputDevice )
-{
-    int inputHostApiIndex  = -1, /* Surpress uninitialised var warnings: compiler does */
-        outputHostApiIndex = -1; /* not see that if inputParameters and outputParame-  */
-                                 /* ters are both nonzero, these indices are set.      */
-
-    if( (inputParameters == NULL) && (outputParameters == NULL) )
-    {
-        return paInvalidDevice; /** @todo should be a new error code "invalid device parameters" or something */
-    }
-    else
-    {
-        if( inputParameters == NULL )
-        {
-            *hostApiInputDevice = paNoDevice;
-        }
-        else if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
-        {
-            if( inputParameters->hostApiSpecificStreamInfo )
-            {
-                inputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
-                        ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType );
-
-                if( inputHostApiIndex != -1 )
-                {
-                    *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification;
-                    *hostApi = hostApis_[inputHostApiIndex];
-                }
-                else
-                {
-                    return paInvalidDevice;
-                }
-            }
-            else
-            {
-                return paInvalidDevice;
-            }
-        }
-        else
-        {
-            if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ )
-                return paInvalidDevice;
-
-            inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice );
-            if( inputHostApiIndex < 0 )
-                return paInternalError;
-
-            *hostApi = hostApis_[inputHostApiIndex];
-
-            if( inputParameters->channelCount <= 0 )
-                return paInvalidChannelCount;
-
-            if( !SampleFormatIsValid( inputParameters->sampleFormat ) )
-                return paSampleFormatNotSupported;
-
-            if( inputParameters->hostApiSpecificStreamInfo != NULL )
-            {
-                if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType
-                        != (*hostApi)->info.type )
-                    return paIncompatibleHostApiSpecificStreamInfo;
-            }
-        }
-
-        if( outputParameters == NULL )
-        {
-            *hostApiOutputDevice = paNoDevice;
-        }
-        else if( outputParameters->device == paUseHostApiSpecificDeviceSpecification  )
-        {
-            if( outputParameters->hostApiSpecificStreamInfo )
-            {
-                outputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
-                        ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType );
-
-                if( outputHostApiIndex != -1 )
-                {
-                    *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification;
-                    *hostApi = hostApis_[outputHostApiIndex];
-                }
-                else
-                {
-                    return paInvalidDevice;
-                }
-            }
-            else
-            {
-                return paInvalidDevice;
-            }
-        }
-        else
-        {
-            if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ )
-                return paInvalidDevice;
-
-            outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice );
-            if( outputHostApiIndex < 0 )
-                return paInternalError;
-
-            *hostApi = hostApis_[outputHostApiIndex];
-
-            if( outputParameters->channelCount <= 0 )
-                return paInvalidChannelCount;
-
-            if( !SampleFormatIsValid( outputParameters->sampleFormat ) )
-                return paSampleFormatNotSupported;
-
-            if( outputParameters->hostApiSpecificStreamInfo != NULL )
-            {
-                if( ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType
-                        != (*hostApi)->info.type )
-                    return paIncompatibleHostApiSpecificStreamInfo;
-            }
-        }   
-
-        if( (inputParameters != NULL) && (outputParameters != NULL) )
-        {
-            /* ensure that both devices use the same API */
-            if( inputHostApiIndex != outputHostApiIndex )
-                return paBadIODeviceCombination;
-        }
-    }
-    
-    
-    /* Check for absurd sample rates. */
-    if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
-        return paInvalidSampleRate;
-
-    if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 )
-        return paInvalidFlag;
-
-    if( streamFlags & paNeverDropInput )
-    {
-        /* must be a callback stream */
-        if( !streamCallback )
-             return paInvalidFlag;
-
-        /* must be a full duplex stream */
-        if( (inputParameters == NULL) || (outputParameters == NULL) )
-            return paInvalidFlag;
-
-        /* must use paFramesPerBufferUnspecified */
-        if( framesPerBuffer != paFramesPerBufferUnspecified )
-            return paInvalidFlag;
-    }
-    
-    return paNoError;
-}
-
-
-PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
-                              const PaStreamParameters *outputParameters,
-                              double sampleRate )
-{
-    PaError result;
-    PaUtilHostApiRepresentation *hostApi;
-    PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;
-    PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
-    PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
-
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_IsFormatSupported called:\n" );
-
-    if( inputParameters == NULL ){
-        PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: NULL\n" );
-    }else{
-        PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters );
-        PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );
-        PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );
-        PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );
-        PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );
-        PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );
-    }
-
-    if( outputParameters == NULL ){
-        PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: NULL\n" );
-    }else{
-        PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters );
-        PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );
-        PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );
-        PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );
-        PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );
-        PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );
-    }
-    
-    PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
-#endif
-
-    if( !PA_IS_INITIALISED_ )
-    {
-        result = paNotInitialized;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-        return result;
-    }
-
-    result = ValidateOpenStreamParameters( inputParameters,
-                                           outputParameters,
-                                           sampleRate, 0, paNoFlag, 0,
-                                           &hostApi,
-                                           &hostApiInputDevice,
-                                           &hostApiOutputDevice );
-    if( result != paNoError )
-    {
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-        return result;
-    }
-    
-
-    if( inputParameters )
-    {
-        hostApiInputParameters.device = hostApiInputDevice;
-        hostApiInputParameters.channelCount = inputParameters->channelCount;
-        hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
-        hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
-        hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
-        hostApiInputParametersPtr = &hostApiInputParameters;
-    }
-    else
-    {
-        hostApiInputParametersPtr = NULL;
-    }
-
-    if( outputParameters )
-    {
-        hostApiOutputParameters.device = hostApiOutputDevice;
-        hostApiOutputParameters.channelCount = outputParameters->channelCount;
-        hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
-        hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
-        hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
-        hostApiOutputParametersPtr = &hostApiOutputParameters;
-    }
-    else
-    {
-        hostApiOutputParametersPtr = NULL;
-    }
-
-    result = hostApi->IsFormatSupported( hostApi,
-                                  hostApiInputParametersPtr, hostApiOutputParametersPtr,
-                                  sampleRate );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
-    if( result == paFormatIsSupported )
-        PaUtil_DebugPrint("\tPaError: 0 [ paFormatIsSupported ]\n\n" );
-    else
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError Pa_OpenStream( PaStream** stream,
-                       const PaStreamParameters *inputParameters,
-                       const PaStreamParameters *outputParameters,
-                       double sampleRate,
-                       unsigned long framesPerBuffer,
-                       PaStreamFlags streamFlags,
-                       PaStreamCallback *streamCallback,
-                       void *userData )
-{
-    PaError result;
-    PaUtilHostApiRepresentation *hostApi;
-    PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;
-    PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
-    PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
-
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_OpenStream called:\n" );
-    PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );
-
-    if( inputParameters == NULL ){
-        PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: NULL\n" );
-    }else{
-        PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters );
-        PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );
-        PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );
-        PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );
-        PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );
-        PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );
-    }
-
-    if( outputParameters == NULL ){
-        PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: NULL\n" );
-    }else{
-        PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters );
-        PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );
-        PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );
-        PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );
-        PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );
-        PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );
-    }
-    
-    PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
-    PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );
-    PaUtil_DebugPrint("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags );
-    PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );
-    PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );
-#endif
-
-    if( !PA_IS_INITIALISED_ )
-    {
-        result = paNotInitialized;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
-        PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-        return result;
-    }
-
-    /* Check for parameter errors.
-        NOTE: make sure this validation list is kept syncronised with the one
-        in pa_hostapi.h
-    */
-
-    if( stream == NULL )
-    {
-        result = paBadStreamPtr;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
-        PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-        return result;
-    }
-
-    result = ValidateOpenStreamParameters( inputParameters,
-                                           outputParameters,
-                                           sampleRate, framesPerBuffer,
-                                           streamFlags, streamCallback,
-                                           &hostApi,
-                                           &hostApiInputDevice,
-                                           &hostApiOutputDevice );
-    if( result != paNoError )
-    {
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
-        PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-        return result;
-    }
-    
-
-    if( inputParameters )
-    {
-        hostApiInputParameters.device = hostApiInputDevice;
-        hostApiInputParameters.channelCount = inputParameters->channelCount;
-        hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
-        hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
-        hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
-        hostApiInputParametersPtr = &hostApiInputParameters;
-    }
-    else
-    {
-        hostApiInputParametersPtr = NULL;
-    }
-
-    if( outputParameters )
-    {
-        hostApiOutputParameters.device = hostApiOutputDevice;
-        hostApiOutputParameters.channelCount = outputParameters->channelCount;
-        hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
-        hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
-        hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
-        hostApiOutputParametersPtr = &hostApiOutputParameters;
-    }
-    else
-    {
-        hostApiOutputParametersPtr = NULL;
-    }
-
-    result = hostApi->OpenStream( hostApi, stream,
-                                  hostApiInputParametersPtr, hostApiOutputParametersPtr,
-                                  sampleRate, framesPerBuffer, streamFlags, streamCallback, userData );
-
-    if( result == paNoError )
-        AddOpenStream( *stream );
-
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
-    PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p\n", *stream );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError Pa_OpenDefaultStream( PaStream** stream,
-                              int inputChannelCount,
-                              int outputChannelCount,
-                              PaSampleFormat sampleFormat,
-                              double sampleRate,
-                              unsigned long framesPerBuffer,
-                              PaStreamCallback *streamCallback,
-                              void *userData )
-{
-    PaError result;
-    PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
-    PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_OpenDefaultStream called:\n" );
-    PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );
-    PaUtil_DebugPrint("\tint inputChannelCount: %d\n", inputChannelCount );
-    PaUtil_DebugPrint("\tint outputChannelCount: %d\n", outputChannelCount );
-    PaUtil_DebugPrint("\tPaSampleFormat sampleFormat: %d\n", sampleFormat );
-    PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
-    PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );
-    PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );
-    PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );
-#endif
-
-
-    if( inputChannelCount > 0 )
-    {
-        hostApiInputParameters.device = Pa_GetDefaultInputDevice();
-        hostApiInputParameters.channelCount = inputChannelCount;
-        hostApiInputParameters.sampleFormat = sampleFormat;
-        /* defaultHighInputLatency is used below instead of
-           defaultLowInputLatency because it is more important for the default
-           stream to work reliably than it is for it to work with the lowest
-           latency.
-         */
-        hostApiInputParameters.suggestedLatency = 
-             Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency;
-        hostApiInputParameters.hostApiSpecificStreamInfo = NULL;
-        hostApiInputParametersPtr = &hostApiInputParameters;
-    }
-    else
-    {
-        hostApiInputParametersPtr = NULL;
-    }
-
-    if( outputChannelCount > 0 )
-    {
-        hostApiOutputParameters.device = Pa_GetDefaultOutputDevice();
-        hostApiOutputParameters.channelCount = outputChannelCount;
-        hostApiOutputParameters.sampleFormat = sampleFormat;
-        /* defaultHighOutputLatency is used below instead of
-           defaultLowOutputLatency because it is more important for the default
-           stream to work reliably than it is for it to work with the lowest
-           latency.
-         */
-        hostApiOutputParameters.suggestedLatency =
-             Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency;
-        hostApiOutputParameters.hostApiSpecificStreamInfo = NULL;
-        hostApiOutputParametersPtr = &hostApiOutputParameters;
-    }
-    else
-    {
-        hostApiOutputParametersPtr = NULL;
-    }
-
-
-    result = Pa_OpenStream(
-                 stream, hostApiInputParametersPtr, hostApiOutputParametersPtr,
-                 sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_OpenDefaultStream returned:\n" );
-    PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p", *stream );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError PaUtil_ValidateStreamPointer( PaStream* stream )
-{
-    if( !PA_IS_INITIALISED_ ) return paNotInitialized;
-
-    if( stream == NULL ) return paBadStreamPtr;
-
-    if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC )
-        return paBadStreamPtr;
-
-    return paNoError;
-}
-
-
-PaError Pa_CloseStream( PaStream* stream )
-{
-    PaUtilStreamInterface *interface;
-    PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_CloseStream called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    /* always remove the open stream from our list, even if this function
-        eventually returns an error. Otherwise CloseOpenStreams() will
-        get stuck in an infinite loop */
-    RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */
-
-    if( result == paNoError )
-    {
-        interface = PA_STREAM_INTERFACE(stream);
-
-        /* abort the stream if it isn't stopped */
-        result = interface->IsStopped( stream );
-        if( result == 1 )
-            result = paNoError;
-        else if( result == 0 )
-            result = interface->Abort( stream );
-
-        if( result == paNoError )                 /** @todo REVIEW: shouldn't we close anyway? */
-            result = interface->Close( stream );
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_CloseStream returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback )
-{
-    PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_SetStreamFinishedCallback called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-    PaUtil_DebugPrint("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback );
-#endif
-
-    if( result == paNoError )
-    {
-        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
-        if( result == 0 )
-        {
-            result = paStreamIsNotStopped ;
-        }
-        if( result == 1 )
-        {
-            PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback;
-            result = paNoError;
-        }
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_SetStreamFinishedCallback returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-
-}
-
-
-PaError Pa_StartStream( PaStream *stream )
-{
-    PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_StartStream called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( result == paNoError )
-    {
-        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
-        if( result == 0 )
-        {
-            result = paStreamIsNotStopped ;
-        }
-        else if( result == 1 )
-        {
-            result = PA_STREAM_INTERFACE(stream)->Start( stream );
-        }
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_StartStream returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError Pa_StopStream( PaStream *stream )
-{
-    PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_StopStream called\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( result == paNoError )
-    {
-        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
-        if( result == 0 )
-        {
-            result = PA_STREAM_INTERFACE(stream)->Stop( stream );
-        }
-        else if( result == 1 )
-        {
-            result = paStreamIsStopped;
-        }
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_StopStream returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError Pa_AbortStream( PaStream *stream )
-{
-    PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_AbortStream called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( result == paNoError )
-    {
-        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
-        if( result == 0 )
-        {
-            result = PA_STREAM_INTERFACE(stream)->Abort( stream );
-        }
-        else if( result == 1 )
-        {
-            result = paStreamIsStopped;
-        }
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_AbortStream returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError Pa_IsStreamStopped( PaStream *stream )
-{
-    PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_IsStreamStopped called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( result == paNoError )
-        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_IsStreamStopped returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError Pa_IsStreamActive( PaStream *stream )
-{
-    PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_IsStreamActive called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( result == paNoError )
-        result = PA_STREAM_INTERFACE(stream)->IsActive( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_IsStreamActive returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream )
-{
-    PaError error = PaUtil_ValidateStreamPointer( stream );
-    const PaStreamInfo *result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetStreamInfo called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( error != paNoError )
-    {
-        result = 0;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );
-        PaUtil_DebugPrint("\tconst PaStreamInfo*: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );
-#endif
-
-    }
-    else
-    {
-        result = &PA_STREAM_REP( stream )->streamInfo;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );
-        PaUtil_DebugPrint("\tconst PaStreamInfo*: 0x%p:\n", result );
-        PaUtil_DebugPrint("\t{" );
-
-        PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );
-        PaUtil_DebugPrint("\t\tPaTime inputLatency: %f\n", result->inputLatency );
-        PaUtil_DebugPrint("\t\tPaTime outputLatency: %f\n", result->outputLatency );
-        PaUtil_DebugPrint("\t\tdouble sampleRate: %f\n", result->sampleRate );
-        PaUtil_DebugPrint("\t}\n\n" );
-#endif
-
-    }
-
-    return result;
-}
-
-
-PaTime Pa_GetStreamTime( PaStream *stream )
-{
-    PaError error = PaUtil_ValidateStreamPointer( stream );
-    PaTime result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetStreamTime called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( error != paNoError )
-    {
-        result = 0;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );
-        PaUtil_DebugPrint("\tPaTime: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );
-#endif
-
-    }
-    else
-    {
-        result = PA_STREAM_INTERFACE(stream)->GetTime( stream );
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );
-        PaUtil_DebugPrint("\tPaTime: %g\n\n", result );
-#endif
-
-    }
-
-    return result;
-}
-
-
-double Pa_GetStreamCpuLoad( PaStream* stream )
-{
-    PaError error = PaUtil_ValidateStreamPointer( stream );
-    double result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetStreamCpuLoad called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( error != paNoError )
-    {
-
-        result = 0.0;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );
-        PaUtil_DebugPrint("\tdouble: 0.0 [PaError error: %d ( %s )]\n\n", error, Pa_GetErrorText( error ) );
-#endif
-
-    }
-    else
-    {
-        result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream );
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );
-        PaUtil_DebugPrint("\tdouble: %g\n\n", result );
-#endif
-
-    }
-
-    return result;
-}
-
-
-PaError Pa_ReadStream( PaStream* stream,
-                       void *buffer,
-                       unsigned long frames )
-{
-    PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_ReadStream called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( result == paNoError )
-    {
-        if( frames == 0 )
-        {
-            result = paInternalError; /** @todo should return a different error code */
-        }
-        else if( buffer == 0 )
-        {
-            result = paInternalError; /** @todo should return a different error code */
-        }
-        else
-        {
-            result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
-            if( result == 0 )
-            {
-                result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames );
-            }
-            else if( result == 1 )
-            {
-                result = paStreamIsStopped;
-            }
-        }
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_ReadStream returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-
-PaError Pa_WriteStream( PaStream* stream,
-                        const void *buffer,
-                        unsigned long frames )
-{
-    PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_WriteStream called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( result == paNoError )
-    {
-        if( frames == 0 )
-        {
-            result = paInternalError; /** @todo should return a different error code */
-        }
-        else if( buffer == 0 )
-        {
-            result = paInternalError; /** @todo should return a different error code */
-        }
-        else
-        {
-            result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
-            if( result == 0 )
-            {
-                result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames );
-            }
-            else if( result == 1 )
-            {
-                result = paStreamIsStopped;
-            }  
-        }
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_WriteStream returned:\n" );
-    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return result;
-}
-
-signed long Pa_GetStreamReadAvailable( PaStream* stream )
-{
-    PaError error = PaUtil_ValidateStreamPointer( stream );
-    signed long result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetStreamReadAvailable called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( error != paNoError )
-    {
-        result = 0;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );
-        PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );
-#endif
-
-    }
-    else
-    {
-        result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream );
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    }
-
-    return result;
-}
-
-
-signed long Pa_GetStreamWriteAvailable( PaStream* stream )
-{
-    PaError error = PaUtil_ValidateStreamPointer( stream );
-    signed long result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetStreamWriteAvailable called:\n" );
-    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
-    if( error != paNoError )
-    {
-        result = 0;
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );
-        PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );
-#endif
-
-    }
-    else
-    {
-        result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream );
-
-#ifdef PA_LOG_API_CALLS
-        PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    }
-
-    return result;
-}
-
-
-PaError Pa_GetSampleSize( PaSampleFormat format )
-{
-    int result;
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetSampleSize called:\n" );
-    PaUtil_DebugPrint("\tPaSampleFormat format: %d\n", format );
-#endif
-
-    switch( format & ~paNonInterleaved )
-    {
-
-    case paUInt8:
-    case paInt8:
-        result = 1;
-        break;
-
-    case paInt16:
-        result = 2;
-        break;
-
-    case paInt24:
-        result = 3;
-        break;
-
-    case paFloat32:
-    case paInt32:
-        result = 4;
-        break;
-
-    default:
-        result = paSampleFormatNotSupported;
-        break;
-    }
-
-#ifdef PA_LOG_API_CALLS
-    PaUtil_DebugPrint("Pa_GetSampleSize returned:\n" );
-    if( result > 0 )
-        PaUtil_DebugPrint("\tint: %d\n\n", result );
-    else
-        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
-    return (PaError) result;
-}
-
+/*

+ * $Id: pa_front.c,v 1.1.2.51 2005/02/05 15:52:12 rossbencina Exp $

+ * Portable Audio I/O Library Multi-Host API front end

+ * Validate function parameters and manage multiple host APIs.

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/* doxygen index page */

+/** @mainpage

+

+PortAudio is an open-source cross-platform †CË library for audio input

+and output. It is designed to simplify the porting of audio applications

+between various platforms, and also to simplify the development of audio

+software in general by hiding the complexities of device interfacing.

+

+See the PortAudio website for further information http://www.portaudio.com/

+

+This documentation pertains to PortAudio V19, API version 2.0 which is

+currently under development. API version 2.0 differs in a number of ways from

+previous versions, please consult the enhancement proposals for further details:

+http://www.portaudio.com/docs/proposals/index.html

+

+This documentation is under construction. Things you might be interested in

+include:

+

+- The PortAudio API 2.0, as documented in portaudio.h

+

+- The <a href="todo.html">TODO List</a>

+

+Feel free to pick an item off TODO list and fix/implement it. You may want to

+enquire about status on the PortAudio mailing list first.

+*/

+

+

+/** @file

+ @brief Implements public PortAudio API, checks some errors, forwards to

+ host API implementations.

+ 

+ Implements the functions defined in the PortAudio API, checks for

+ some parameter and state inconsistencies and forwards API requests to

+ specific Host API implementations (via the interface declared in

+ pa_hostapi.h), and Streams (via the interface declared in pa_stream.h).

+

+ This file handles initialization and termination of Host API

+ implementations via initializers stored in the paHostApiInitializers

+ global variable.

+

+ Some utility functions declared in pa_util.h are implemented in this file.

+

+ All PortAudio API functions can be conditionally compiled with logging code.

+ To compile with logging, define the PA_LOG_API_CALLS precompiler symbol.

+

+    @todo Consider adding host API specific error text in Pa_GetErrorText() for

+    paUnanticipatedHostError

+

+    @todo Consider adding a new error code for when (inputParameters == NULL)

+    && (outputParameters == NULL)

+

+    @todo review whether Pa_CloseStream() should call the interface's

+    CloseStream function if aborting the stream returns an error code.

+

+    @todo Create new error codes if a NULL buffer pointer, or a

+    zero frame count is passed to Pa_ReadStream or Pa_WriteStream.

+*/

+

+

+#include <stdio.h>

+#include <stdarg.h>

+#include <memory.h>

+#include <string.h>

+#include <assert.h> /* needed by PA_VALIDATE_ENDIANNESS */

+

+#include "portaudio.h"

+#include "pa_util.h"

+#include "pa_endianness.h"

+#include "pa_types.h"

+#include "pa_hostapi.h"

+#include "pa_stream.h"

+

+#include "pa_trace.h"

+

+

+#define PA_VERSION_  1899

+#define PA_VERSION_TEXT_ "PortAudio V19-devel"

+

+

+

+/* #define PA_LOG_API_CALLS */

+

+/*

+    The basic format for log messages is described below. If you need to

+    add any log messages, please follow this format.

+ 

+    Function entry (void function):

+ 

+        "FunctionName called.\n"

+ 

+    Function entry (non void function):

+ 

+        "FunctionName called:\n"

+        "\tParam1Type param1: param1Value\n"

+        "\tParam2Type param2: param2Value\n"      (etc...)

+ 

+ 

+    Function exit (no return value):

+ 

+        "FunctionName returned.\n"

+ 

+    Function exit (simple return value):

+ 

+        "FunctionName returned:\n"

+        "\tReturnType: returnValue\n\n"

+ 

+    If the return type is an error code, the error text is displayed in ()

+ 

+    If the return type is not an error code, but has taken a special value

+    because an error occurred, then the reason for the error is shown in []

+ 

+    If the return type is a struct ptr, the struct is dumped.

+ 

+    See the code below for examples

+*/

+

+

+int Pa_GetVersion( void )

+{

+    return PA_VERSION_;

+}

+

+

+const char* Pa_GetVersionText( void )

+{

+    return PA_VERSION_TEXT_;

+}

+

+

+

+#define PA_LAST_HOST_ERROR_TEXT_LENGTH_  1024

+

+static char lastHostErrorText_[ PA_LAST_HOST_ERROR_TEXT_LENGTH_ + 1 ] = {0};

+

+static PaHostErrorInfo lastHostErrorInfo_ = { (PaHostApiTypeId)-1, 0, lastHostErrorText_ };

+

+

+void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,

+        const char *errorText )

+{

+    lastHostErrorInfo_.hostApiType = hostApiType;

+    lastHostErrorInfo_.errorCode = errorCode;

+

+    strncpy( lastHostErrorText_, errorText, PA_LAST_HOST_ERROR_TEXT_LENGTH_ );

+}

+

+

+void PaUtil_DebugPrint( const char *format, ... )

+{

+    va_list ap;

+

+    va_start( ap, format );

+    vfprintf( stderr, format, ap );

+    va_end( ap );

+

+    fflush( stderr );

+}

+

+

+static PaUtilHostApiRepresentation **hostApis_ = 0;

+static int hostApisCount_ = 0;

+static int initializationCount_ = 0;

+static int deviceCount_ = 0;

+

+PaUtilStreamRepresentation *firstOpenStream_ = NULL;

+

+

+#define PA_IS_INITIALISED_ (initializationCount_ != 0)

+

+

+static int CountHostApiInitializers( void )

+{

+    int result = 0;

+

+    while( paHostApiInitializers[ result ] != 0 )

+        ++result;

+    return result;

+}

+

+

+static void TerminateHostApis( void )

+{

+    /* terminate in reverse order from initialization */

+

+    while( hostApisCount_ > 0 )

+    {

+        --hostApisCount_;

+        hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] );

+    }

+    hostApisCount_ = 0;

+    deviceCount_ = 0;

+

+    if( hostApis_ != 0 )

+        PaUtil_FreeMemory( hostApis_ );

+    hostApis_ = 0;

+}

+

+

+static PaError InitializeHostApis( void )

+{

+    PaError result = paNoError;

+    int i, initializerCount, baseDeviceIndex;

+

+    initializerCount = CountHostApiInitializers();

+

+    hostApis_ = (PaUtilHostApiRepresentation**)PaUtil_AllocateMemory(

+            sizeof(PaUtilHostApiRepresentation*) * initializerCount );

+    if( !hostApis_ )

+    {

+        result = paInsufficientMemory;

+        goto error; 

+    }

+

+    hostApisCount_ = 0;

+    deviceCount_ = 0;

+    baseDeviceIndex = 0;

+

+    for( i=0; i< initializerCount; ++i )

+    {

+        hostApis_[hostApisCount_] = NULL;

+        result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ );

+        if( result != paNoError )

+            goto error;

+

+        if( hostApis_[hostApisCount_] )

+        {

+

+            hostApis_[hostApisCount_]->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;

+

+            if( hostApis_[hostApisCount_]->info.defaultInputDevice != paNoDevice )

+                hostApis_[hostApisCount_]->info.defaultInputDevice += baseDeviceIndex;

+

+            if( hostApis_[hostApisCount_]->info.defaultOutputDevice != paNoDevice )

+                hostApis_[hostApisCount_]->info.defaultOutputDevice += baseDeviceIndex;

+

+            baseDeviceIndex += hostApis_[hostApisCount_]->info.deviceCount;

+            deviceCount_ += hostApis_[hostApisCount_]->info.deviceCount;

+

+            ++hostApisCount_;

+        }

+    }

+

+    return result;

+

+error:

+    TerminateHostApis();

+    return result;

+}

+

+

+/*

+    FindHostApi() finds the index of the host api to which

+    <device> belongs and returns it. if <hostSpecificDeviceIndex> is

+    non-null, the host specific device index is returned in it.

+    returns -1 if <device> is out of range.

+ 

+*/

+static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex )

+{

+    int i=0;

+

+    if( !PA_IS_INITIALISED_ )

+        return -1;

+

+    if( device < 0 )

+        return -1;

+

+    while( i < hostApisCount_

+            && device >= hostApis_[i]->info.deviceCount )

+    {

+

+        device -= hostApis_[i]->info.deviceCount;

+        ++i;

+    }

+

+    if( i >= hostApisCount_ )

+        return -1;

+

+    if( hostSpecificDeviceIndex )

+        *hostSpecificDeviceIndex = device;

+

+    return i;

+}

+

+

+static void AddOpenStream( PaStream* stream )

+{

+    ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_;

+    firstOpenStream_ = (PaUtilStreamRepresentation*)stream;

+}

+

+

+static void RemoveOpenStream( PaStream* stream )

+{

+    PaUtilStreamRepresentation *previous = NULL;

+    PaUtilStreamRepresentation *current = firstOpenStream_;

+

+    while( current != NULL )

+    {

+        if( ((PaStream*)current) == stream )

+        {

+            if( previous == NULL )

+            {

+                firstOpenStream_ = current->nextOpenStream;

+            }

+            else

+            {

+                previous->nextOpenStream = current->nextOpenStream;

+            }

+            return;

+        }

+        else

+        {

+            previous = current;

+            current = current->nextOpenStream;

+        }

+    }

+}

+

+

+static void CloseOpenStreams( void )

+{

+    /* we call Pa_CloseStream() here to ensure that the same destruction

+        logic is used for automatically closed streams */

+

+    while( firstOpenStream_ != NULL )

+        Pa_CloseStream( firstOpenStream_ );

+}

+

+

+PaError Pa_Initialize( void )

+{

+    PaError result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint( "Pa_Initialize called.\n" );

+#endif

+

+    if( PA_IS_INITIALISED_ )

+    {

+        ++initializationCount_;

+        result = paNoError;

+    }

+    else

+    {

+        PA_VALIDATE_TYPE_SIZES;

+        PA_VALIDATE_ENDIANNESS;

+        

+        PaUtil_InitializeClock();

+        PaUtil_ResetTraceMessages();

+

+        result = InitializeHostApis();

+        if( result == paNoError )

+            ++initializationCount_;

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint( "Pa_Initialize returned:\n" );

+    PaUtil_DebugPrint( "\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError Pa_Terminate( void )

+{

+    PaError result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_Terminate called.\n" );

+#endif

+

+    if( PA_IS_INITIALISED_ )

+    {

+        if( --initializationCount_ == 0 )

+        {

+            CloseOpenStreams();

+

+            TerminateHostApis();

+

+            PaUtil_DumpTraceMessages();

+        }

+        result = paNoError;

+    }

+    else

+    {

+        result=  paNotInitialized;

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_Terminate returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void )

+{

+    return &lastHostErrorInfo_;

+}

+

+

+const char *Pa_GetErrorText( PaError errorCode )

+{

+    const char *result;

+

+    switch( errorCode )

+    {

+    case paNoError:                  result = "Success"; break;

+    case paNotInitialized:           result = "PortAudio not initialized"; break;

+    /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError */

+    case paUnanticipatedHostError:   result = "Unanticipated host error"; break;

+    case paInvalidChannelCount:      result = "Invalid number of channels"; break;

+    case paInvalidSampleRate:        result = "Invalid sample rate"; break;

+    case paInvalidDevice:            result = "Invalid device"; break;

+    case paInvalidFlag:              result = "Invalid flag"; break;

+    case paSampleFormatNotSupported: result = "Sample format not supported"; break;

+    case paBadIODeviceCombination:   result = "Illegal combination of I/O devices"; break;

+    case paInsufficientMemory:       result = "Insufficient memory"; break;

+    case paBufferTooBig:             result = "Buffer too big"; break;

+    case paBufferTooSmall:           result = "Buffer too small"; break;

+    case paNullCallback:             result = "No callback routine specified"; break;

+    case paBadStreamPtr:             result = "Invalid stream pointer"; break;

+    case paTimedOut:                 result = "Wait timed out"; break;

+    case paInternalError:            result = "Internal PortAudio error"; break;

+    case paDeviceUnavailable:        result = "Device unavailable"; break;

+    case paIncompatibleHostApiSpecificStreamInfo:   result = "Incompatible host API specific stream info"; break;

+    case paStreamIsStopped:          result = "Stream is stopped"; break;

+    case paStreamIsNotStopped:       result = "Stream is not stopped"; break;

+    case paInputOverflowed:          result = "Input overflowed"; break;

+    case paOutputUnderflowed:        result = "Output underflowed"; break;

+    case paHostApiNotFound:          result = "Host API not found"; break;

+    case paInvalidHostApi:           result = "Invalid host API"; break;

+    case paCanNotReadFromACallbackStream:       result = "Can't read from a callback stream"; break;

+    case paCanNotWriteToACallbackStream:        result = "Can't write to a callback stream"; break;

+    case paCanNotReadFromAnOutputOnlyStream:    result = "Can't read from an output only stream"; break;

+    case paCanNotWriteToAnInputOnlyStream:      result = "Can't write to an input only stream"; break;

+    default:                         result = "Illegal error number"; break;

+    }

+    return result;

+}

+

+

+PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type )

+{

+    PaHostApiIndex result;

+    int i;

+    

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex called:\n" );

+    PaUtil_DebugPrint("\tPaHostApiTypeId type: %d\n", type );

+#endif

+

+    if( !PA_IS_INITIALISED_ )

+    {

+        result = paNotInitialized;

+    }

+    else

+    {

+        result = paHostApiNotFound;

+        

+        for( i=0; i < hostApisCount_; ++i )

+        {

+            if( hostApis_[i]->info.type == type )

+            {

+                result = i;

+                break;

+            }         

+        }

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex returned:\n" );

+    if( result < 0 )

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+    else

+        PaUtil_DebugPrint("\tPaHostApiIndex: %d\n\n", result );

+#endif

+

+    return result;

+}

+

+

+PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,

+        PaHostApiTypeId type )

+{

+    PaError result;

+    int i;

+    

+    if( !PA_IS_INITIALISED_ )

+    {

+        result = paNotInitialized;

+    }

+    else

+    {

+        result = paHostApiNotFound;

+                

+        for( i=0; i < hostApisCount_; ++i )

+        {

+            if( hostApis_[i]->info.type == type )

+            {

+                *hostApi = hostApis_[i];

+                result = paNoError;

+                break;

+            }

+        }

+    }

+

+    return result;

+}

+

+

+PaError PaUtil_DeviceIndexToHostApiDeviceIndex(

+        PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi )

+{

+    PaError result;

+    PaDeviceIndex x;

+    

+    x = device - hostApi->privatePaFrontInfo.baseDeviceIndex;

+

+    if( x < 0 || x >= hostApi->info.deviceCount )

+    {

+        result = paInvalidDevice;

+    }

+    else

+    {

+        *hostApiDevice = x;

+        result = paNoError;

+    }

+

+    return result;

+}

+

+

+PaHostApiIndex Pa_GetHostApiCount( void )

+{

+    int result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetHostApiCount called.\n" );

+#endif

+

+    if( !PA_IS_INITIALISED_ )

+    {

+        result = paNotInitialized;

+    }

+    else

+    {

+        result = hostApisCount_;

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetHostApiCount returned:\n" );

+    if( result < 0 )

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+    else

+        PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", result );

+#endif

+

+    return result;

+}

+

+

+PaHostApiIndex Pa_GetDefaultHostApi( void )

+{

+    int result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetDefaultHostApi called.\n" );

+#endif

+

+    if( !PA_IS_INITIALISED_ )

+    {

+        result = paNotInitialized;

+    }

+    else

+    {

+        result = paDefaultHostApiIndex;

+

+        /* internal consistency check: make sure that the default host api

+         index is within range */

+

+        if( result < 0 || result >= hostApisCount_ )

+        {

+            result = paInternalError;

+        }

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" );

+    if( result < 0 )

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+    else

+        PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", result );

+#endif

+

+    return result;

+}

+

+

+const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi )

+{

+    PaHostApiInfo *info;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetHostApiInfo called:\n" );

+    PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );

+#endif

+

+    if( !PA_IS_INITIALISED_ )

+    {

+        info = NULL;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );

+        PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n\n" );

+#endif

+

+    }

+    else if( hostApi < 0 || hostApi >= hostApisCount_ )

+    {

+        info = NULL;

+        

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );

+        PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n\n" );

+#endif

+

+    }

+    else

+    {

+        info = &hostApis_[hostApi]->info;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );

+        PaUtil_DebugPrint("\tPaHostApiInfo*: 0x%p\n", info );

+        PaUtil_DebugPrint("\t{" );

+        PaUtil_DebugPrint("\t\tint structVersion: %d\n", info->structVersion );

+        PaUtil_DebugPrint("\t\tPaHostApiTypeId type: %d\n", info->type );

+        PaUtil_DebugPrint("\t\tconst char *name: %s\n\n", info->name );

+        PaUtil_DebugPrint("\t}\n\n" );

+#endif

+

+    }

+

+     return info;

+}

+

+

+PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex )

+{

+    PaDeviceIndex result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex called:\n" );

+    PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );

+    PaUtil_DebugPrint("\tint hostApiDeviceIndex: %d\n", hostApiDeviceIndex );

+#endif

+

+    if( !PA_IS_INITIALISED_ )

+    {

+        result = paNotInitialized;

+    }

+    else

+    {

+        if( hostApi < 0 || hostApi >= hostApisCount_ )

+        {

+            result = paInvalidHostApi;

+        }

+        else

+        {

+            if( hostApiDeviceIndex < 0 ||

+                    hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount )

+            {

+                result = paInvalidDevice;

+            }

+            else

+            {

+                result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex;

+            }

+        }

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );

+    if( result < 0 )

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+    else

+        PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );

+#endif

+

+    return result;

+}

+

+

+PaDeviceIndex Pa_GetDeviceCount( void )

+{

+    PaDeviceIndex result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetDeviceCount called.\n" );

+#endif

+

+    if( !PA_IS_INITIALISED_ )

+    {

+        result = paNotInitialized;

+    }

+    else

+    {

+        result = deviceCount_;

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetDeviceCount returned:\n" );

+    if( result < 0 )

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+    else

+        PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );

+#endif

+

+    return result;

+}

+

+

+PaDeviceIndex Pa_GetDefaultInputDevice( void )

+{

+    PaHostApiIndex hostApi;

+    PaDeviceIndex result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetDefaultInputDevice called.\n" );

+#endif

+

+    hostApi = Pa_GetDefaultHostApi();

+    if( hostApi < 0 )

+    {

+        result = paNoDevice;

+    }

+    else

+    {

+        result = hostApis_[hostApi]->info.defaultInputDevice;

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetDefaultInputDevice returned:\n" );

+    PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );

+#endif

+

+    return result;

+}

+

+

+PaDeviceIndex Pa_GetDefaultOutputDevice( void )

+{

+    PaHostApiIndex hostApi;

+    PaDeviceIndex result;

+    

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetDefaultOutputDevice called.\n" );

+#endif

+

+    hostApi = Pa_GetDefaultHostApi();

+    if( hostApi < 0 )

+    {

+        result = paNoDevice;

+    }

+    else

+    {

+        result = hostApis_[hostApi]->info.defaultOutputDevice;

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetDefaultOutputDevice returned:\n" );

+    PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );

+#endif

+

+    return result;

+}

+

+

+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )

+{

+    int hostSpecificDeviceIndex;

+    int hostApiIndex = FindHostApi( device, &hostSpecificDeviceIndex );

+    PaDeviceInfo *result;

+

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetDeviceInfo called:\n" );

+    PaUtil_DebugPrint("\tPaDeviceIndex device: %d\n", device );

+#endif

+

+    if( hostApiIndex < 0 )

+    {

+        result = NULL;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );

+        PaUtil_DebugPrint("\tPaDeviceInfo* NULL [ invalid device index ]\n\n" );

+#endif

+

+    }

+    else

+    {

+        result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ];

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );

+        PaUtil_DebugPrint("\tPaDeviceInfo*: 0x%p:\n", result );

+        PaUtil_DebugPrint("\t{\n" );

+

+        PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );

+        PaUtil_DebugPrint("\t\tconst char *name: %s\n", result->name );

+        PaUtil_DebugPrint("\t\tPaHostApiIndex hostApi: %d\n", result->hostApi );

+        PaUtil_DebugPrint("\t\tint maxInputChannels: %d\n", result->maxInputChannels );

+        PaUtil_DebugPrint("\t\tint maxOutputChannels: %d\n", result->maxOutputChannels );

+        PaUtil_DebugPrint("\t}\n\n" );

+#endif

+

+    }

+

+    return result;

+}

+

+

+/*

+    SampleFormatIsValid() returns 1 if sampleFormat is a sample format

+    defined in portaudio.h, or 0 otherwise.

+*/

+static int SampleFormatIsValid( PaSampleFormat format )

+{

+    switch( format & ~paNonInterleaved )

+    {

+    case paFloat32: return 1;

+    case paInt16: return 1;

+    case paInt32: return 1;

+    case paInt24: return 1;

+    case paInt8: return 1;

+    case paUInt8: return 1;

+    case paCustomFormat: return 1;

+    default: return 0;

+    }

+}

+

+/*

+    NOTE: make sure this validation list is kept syncronised with the one in

+            pa_hostapi.h

+

+    ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream()

+    conform to the expected values as described below. This function is

+    also designed to be used with the proposed Pa_IsFormatSupported() function.

+    

+    There are basically two types of validation that could be performed:

+    Generic conformance validation, and device capability mismatch

+    validation. This function performs only generic conformance validation.

+    Validation that would require knowledge of device capabilities is

+    not performed because of potentially complex relationships between

+    combinations of parameters - for example, even if the sampleRate

+    seems ok, it might not be for a duplex stream - we have no way of

+    checking this in an API-neutral way, so we don't try.

+ 

+    On success the function returns PaNoError and fills in hostApi,

+    hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure

+    the function returns an error code indicating the first encountered

+    parameter error.

+ 

+ 

+    If ValidateOpenStreamParameters() returns paNoError, the following

+    assertions are guaranteed to be true.

+ 

+    - at least one of inputParameters & outputParmeters is valid (not NULL)

+

+    - if inputParameters & outputParmeters are both valid, that

+        inputParameters->device & outputParmeters->device  both use the same host api

+ 

+    PaDeviceIndex inputParameters->device

+        - is within range (0 to Pa_GetDeviceCount-1) Or:

+        - is paUseHostApiSpecificDeviceSpecification and

+            inputParameters->hostApiSpecificStreamInfo is non-NULL and refers

+            to a valid host api

+

+    int inputParameters->channelCount

+        - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0

+        - upper bound is NOT validated against device capabilities

+ 

+    PaSampleFormat inputParameters->sampleFormat

+        - is one of the sample formats defined in portaudio.h

+

+    void *inputParameters->hostApiSpecificStreamInfo

+        - if supplied its hostApi field matches the input device's host Api

+ 

+    PaDeviceIndex outputParmeters->device

+        - is within range (0 to Pa_GetDeviceCount-1)

+ 

+    int outputParmeters->channelCount

+        - if inputDevice is valid, channelCount is > 0

+        - upper bound is NOT validated against device capabilities

+ 

+    PaSampleFormat outputParmeters->sampleFormat

+        - is one of the sample formats defined in portaudio.h

+        

+    void *outputParmeters->hostApiSpecificStreamInfo

+        - if supplied its hostApi field matches the output device's host Api

+ 

+    double sampleRate

+        - is not an 'absurd' rate (less than 1000. or greater than 200000.)

+        - sampleRate is NOT validated against device capabilities

+ 

+    PaStreamFlags streamFlags

+        - unused platform neutral flags are zero

+        - paNeverDropInput is only used for full-duplex callback streams with

+            variable buffer size (paFramesPerBufferUnspecified)

+*/

+static PaError ValidateOpenStreamParameters(

+    const PaStreamParameters *inputParameters,

+    const PaStreamParameters *outputParameters,

+    double sampleRate,

+    unsigned long framesPerBuffer,

+    PaStreamFlags streamFlags,

+    PaStreamCallback *streamCallback,

+    PaUtilHostApiRepresentation **hostApi,

+    PaDeviceIndex *hostApiInputDevice,

+    PaDeviceIndex *hostApiOutputDevice )

+{

+    int inputHostApiIndex  = -1, /* Surpress uninitialised var warnings: compiler does */

+        outputHostApiIndex = -1; /* not see that if inputParameters and outputParame-  */

+                                 /* ters are both nonzero, these indices are set.      */

+

+    if( (inputParameters == NULL) && (outputParameters == NULL) )

+    {

+        return paInvalidDevice; /** @todo should be a new error code "invalid device parameters" or something */

+    }

+    else

+    {

+        if( inputParameters == NULL )

+        {

+            *hostApiInputDevice = paNoDevice;

+        }

+        else if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )

+        {

+            if( inputParameters->hostApiSpecificStreamInfo )

+            {

+                inputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(

+                        ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType );

+

+                if( inputHostApiIndex != -1 )

+                {

+                    *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification;

+                    *hostApi = hostApis_[inputHostApiIndex];

+                }

+                else

+                {

+                    return paInvalidDevice;

+                }

+            }

+            else

+            {

+                return paInvalidDevice;

+            }

+        }

+        else

+        {

+            if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ )

+                return paInvalidDevice;

+

+            inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice );

+            if( inputHostApiIndex < 0 )

+                return paInternalError;

+

+            *hostApi = hostApis_[inputHostApiIndex];

+

+            if( inputParameters->channelCount <= 0 )

+                return paInvalidChannelCount;

+

+            if( !SampleFormatIsValid( inputParameters->sampleFormat ) )

+                return paSampleFormatNotSupported;

+

+            if( inputParameters->hostApiSpecificStreamInfo != NULL )

+            {

+                if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType

+                        != (*hostApi)->info.type )

+                    return paIncompatibleHostApiSpecificStreamInfo;

+            }

+        }

+

+        if( outputParameters == NULL )

+        {

+            *hostApiOutputDevice = paNoDevice;

+        }

+        else if( outputParameters->device == paUseHostApiSpecificDeviceSpecification  )

+        {

+            if( outputParameters->hostApiSpecificStreamInfo )

+            {

+                outputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(

+                        ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType );

+

+                if( outputHostApiIndex != -1 )

+                {

+                    *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification;

+                    *hostApi = hostApis_[outputHostApiIndex];

+                }

+                else

+                {

+                    return paInvalidDevice;

+                }

+            }

+            else

+            {

+                return paInvalidDevice;

+            }

+        }

+        else

+        {

+            if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ )

+                return paInvalidDevice;

+

+            outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice );

+            if( outputHostApiIndex < 0 )

+                return paInternalError;

+

+            *hostApi = hostApis_[outputHostApiIndex];

+

+            if( outputParameters->channelCount <= 0 )

+                return paInvalidChannelCount;

+

+            if( !SampleFormatIsValid( outputParameters->sampleFormat ) )

+                return paSampleFormatNotSupported;

+

+            if( outputParameters->hostApiSpecificStreamInfo != NULL )

+            {

+                if( ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType

+                        != (*hostApi)->info.type )

+                    return paIncompatibleHostApiSpecificStreamInfo;

+            }

+        }   

+

+        if( (inputParameters != NULL) && (outputParameters != NULL) )

+        {

+            /* ensure that both devices use the same API */

+            if( inputHostApiIndex != outputHostApiIndex )

+                return paBadIODeviceCombination;

+        }

+    }

+    

+    

+    /* Check for absurd sample rates. */

+    if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )

+        return paInvalidSampleRate;

+

+    if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 )

+        return paInvalidFlag;

+

+    if( streamFlags & paNeverDropInput )

+    {

+        /* must be a callback stream */

+        if( !streamCallback )

+             return paInvalidFlag;

+

+        /* must be a full duplex stream */

+        if( (inputParameters == NULL) || (outputParameters == NULL) )

+            return paInvalidFlag;

+

+        /* must use paFramesPerBufferUnspecified */

+        if( framesPerBuffer != paFramesPerBufferUnspecified )

+            return paInvalidFlag;

+    }

+    

+    return paNoError;

+}

+

+

+PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,

+                              const PaStreamParameters *outputParameters,

+                              double sampleRate )

+{

+    PaError result;

+    PaUtilHostApiRepresentation *hostApi;

+    PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;

+    PaStreamParameters hostApiInputParameters, hostApiOutputParameters;

+    PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;

+

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_IsFormatSupported called:\n" );

+

+    if( inputParameters == NULL ){

+        PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: NULL\n" );

+    }else{

+        PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters );

+        PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );

+        PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );

+        PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );

+        PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );

+        PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );

+    }

+

+    if( outputParameters == NULL ){

+        PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: NULL\n" );

+    }else{

+        PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters );

+        PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );

+        PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );

+        PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );

+        PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );

+        PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );

+    }

+    

+    PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );

+#endif

+

+    if( !PA_IS_INITIALISED_ )

+    {

+        result = paNotInitialized;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+        return result;

+    }

+

+    result = ValidateOpenStreamParameters( inputParameters,

+                                           outputParameters,

+                                           sampleRate, 0, paNoFlag, 0,

+                                           &hostApi,

+                                           &hostApiInputDevice,

+                                           &hostApiOutputDevice );

+    if( result != paNoError )

+    {

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+        return result;

+    }

+    

+

+    if( inputParameters )

+    {

+        hostApiInputParameters.device = hostApiInputDevice;

+        hostApiInputParameters.channelCount = inputParameters->channelCount;

+        hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;

+        hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;

+        hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;

+        hostApiInputParametersPtr = &hostApiInputParameters;

+    }

+    else

+    {

+        hostApiInputParametersPtr = NULL;

+    }

+

+    if( outputParameters )

+    {

+        hostApiOutputParameters.device = hostApiOutputDevice;

+        hostApiOutputParameters.channelCount = outputParameters->channelCount;

+        hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;

+        hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;

+        hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;

+        hostApiOutputParametersPtr = &hostApiOutputParameters;

+    }

+    else

+    {

+        hostApiOutputParametersPtr = NULL;

+    }

+

+    result = hostApi->IsFormatSupported( hostApi,

+                                  hostApiInputParametersPtr, hostApiOutputParametersPtr,

+                                  sampleRate );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_OpenStream returned:\n" );

+    if( result == paFormatIsSupported )

+        PaUtil_DebugPrint("\tPaError: 0 [ paFormatIsSupported ]\n\n" );

+    else

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError Pa_OpenStream( PaStream** stream,

+                       const PaStreamParameters *inputParameters,

+                       const PaStreamParameters *outputParameters,

+                       double sampleRate,

+                       unsigned long framesPerBuffer,

+                       PaStreamFlags streamFlags,

+                       PaStreamCallback *streamCallback,

+                       void *userData )

+{

+    PaError result;

+    PaUtilHostApiRepresentation *hostApi;

+    PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;

+    PaStreamParameters hostApiInputParameters, hostApiOutputParameters;

+    PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;

+

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_OpenStream called:\n" );

+    PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );

+

+    if( inputParameters == NULL ){

+        PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: NULL\n" );

+    }else{

+        PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters );

+        PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );

+        PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );

+        PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );

+        PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );

+        PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );

+    }

+

+    if( outputParameters == NULL ){

+        PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: NULL\n" );

+    }else{

+        PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters );

+        PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );

+        PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );

+        PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );

+        PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );

+        PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );

+    }

+    

+    PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );

+    PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );

+    PaUtil_DebugPrint("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags );

+    PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );

+    PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );

+#endif

+

+    if( !PA_IS_INITIALISED_ )

+    {

+        result = paNotInitialized;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_OpenStream returned:\n" );

+        PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+        return result;

+    }

+

+    /* Check for parameter errors.

+        NOTE: make sure this validation list is kept syncronised with the one

+        in pa_hostapi.h

+    */

+

+    if( stream == NULL )

+    {

+        result = paBadStreamPtr;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_OpenStream returned:\n" );

+        PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+        return result;

+    }

+

+    result = ValidateOpenStreamParameters( inputParameters,

+                                           outputParameters,

+                                           sampleRate, framesPerBuffer,

+                                           streamFlags, streamCallback,

+                                           &hostApi,

+                                           &hostApiInputDevice,

+                                           &hostApiOutputDevice );

+    if( result != paNoError )

+    {

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_OpenStream returned:\n" );

+        PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+        return result;

+    }

+    

+

+    if( inputParameters )

+    {

+        hostApiInputParameters.device = hostApiInputDevice;

+        hostApiInputParameters.channelCount = inputParameters->channelCount;

+        hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;

+        hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;

+        hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;

+        hostApiInputParametersPtr = &hostApiInputParameters;

+    }

+    else

+    {

+        hostApiInputParametersPtr = NULL;

+    }

+

+    if( outputParameters )

+    {

+        hostApiOutputParameters.device = hostApiOutputDevice;

+        hostApiOutputParameters.channelCount = outputParameters->channelCount;

+        hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;

+        hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;

+        hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;

+        hostApiOutputParametersPtr = &hostApiOutputParameters;

+    }

+    else

+    {

+        hostApiOutputParametersPtr = NULL;

+    }

+

+    result = hostApi->OpenStream( hostApi, stream,

+                                  hostApiInputParametersPtr, hostApiOutputParametersPtr,

+                                  sampleRate, framesPerBuffer, streamFlags, streamCallback, userData );

+

+    if( result == paNoError )

+        AddOpenStream( *stream );

+

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_OpenStream returned:\n" );

+    PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p\n", *stream );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError Pa_OpenDefaultStream( PaStream** stream,

+                              int inputChannelCount,

+                              int outputChannelCount,

+                              PaSampleFormat sampleFormat,

+                              double sampleRate,

+                              unsigned long framesPerBuffer,

+                              PaStreamCallback *streamCallback,

+                              void *userData )

+{

+    PaError result;

+    PaStreamParameters hostApiInputParameters, hostApiOutputParameters;

+    PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_OpenDefaultStream called:\n" );

+    PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );

+    PaUtil_DebugPrint("\tint inputChannelCount: %d\n", inputChannelCount );

+    PaUtil_DebugPrint("\tint outputChannelCount: %d\n", outputChannelCount );

+    PaUtil_DebugPrint("\tPaSampleFormat sampleFormat: %d\n", sampleFormat );

+    PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );

+    PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );

+    PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );

+    PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );

+#endif

+

+

+    if( inputChannelCount > 0 )

+    {

+        hostApiInputParameters.device = Pa_GetDefaultInputDevice();

+        hostApiInputParameters.channelCount = inputChannelCount;

+        hostApiInputParameters.sampleFormat = sampleFormat;

+        /* defaultHighInputLatency is used below instead of

+           defaultLowInputLatency because it is more important for the default

+           stream to work reliably than it is for it to work with the lowest

+           latency.

+         */

+        hostApiInputParameters.suggestedLatency = 

+             Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency;

+        hostApiInputParameters.hostApiSpecificStreamInfo = NULL;

+        hostApiInputParametersPtr = &hostApiInputParameters;

+    }

+    else

+    {

+        hostApiInputParametersPtr = NULL;

+    }

+

+    if( outputChannelCount > 0 )

+    {

+        hostApiOutputParameters.device = Pa_GetDefaultOutputDevice();

+        hostApiOutputParameters.channelCount = outputChannelCount;

+        hostApiOutputParameters.sampleFormat = sampleFormat;

+        /* defaultHighOutputLatency is used below instead of

+           defaultLowOutputLatency because it is more important for the default

+           stream to work reliably than it is for it to work with the lowest

+           latency.

+         */

+        hostApiOutputParameters.suggestedLatency =

+             Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency;

+        hostApiOutputParameters.hostApiSpecificStreamInfo = NULL;

+        hostApiOutputParametersPtr = &hostApiOutputParameters;

+    }

+    else

+    {

+        hostApiOutputParametersPtr = NULL;

+    }

+

+

+    result = Pa_OpenStream(

+                 stream, hostApiInputParametersPtr, hostApiOutputParametersPtr,

+                 sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_OpenDefaultStream returned:\n" );

+    PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p", *stream );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError PaUtil_ValidateStreamPointer( PaStream* stream )

+{

+    if( !PA_IS_INITIALISED_ ) return paNotInitialized;

+

+    if( stream == NULL ) return paBadStreamPtr;

+

+    if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC )

+        return paBadStreamPtr;

+

+    return paNoError;

+}

+

+

+PaError Pa_CloseStream( PaStream* stream )

+{

+    PaUtilStreamInterface *interface;

+    PaError result = PaUtil_ValidateStreamPointer( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_CloseStream called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    /* always remove the open stream from our list, even if this function

+        eventually returns an error. Otherwise CloseOpenStreams() will

+        get stuck in an infinite loop */

+    RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */

+

+    if( result == paNoError )

+    {

+        interface = PA_STREAM_INTERFACE(stream);

+

+        /* abort the stream if it isn't stopped */

+        result = interface->IsStopped( stream );

+        if( result == 1 )

+            result = paNoError;

+        else if( result == 0 )

+            result = interface->Abort( stream );

+

+        if( result == paNoError )                 /** @todo REVIEW: shouldn't we close anyway? */

+            result = interface->Close( stream );

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_CloseStream returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback )

+{

+    PaError result = PaUtil_ValidateStreamPointer( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_SetStreamFinishedCallback called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+    PaUtil_DebugPrint("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback );

+#endif

+

+    if( result == paNoError )

+    {

+        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );

+        if( result == 0 )

+        {

+            result = paStreamIsNotStopped ;

+        }

+        if( result == 1 )

+        {

+            PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback;

+            result = paNoError;

+        }

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_SetStreamFinishedCallback returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+

+}

+

+

+PaError Pa_StartStream( PaStream *stream )

+{

+    PaError result = PaUtil_ValidateStreamPointer( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_StartStream called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( result == paNoError )

+    {

+        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );

+        if( result == 0 )

+        {

+            result = paStreamIsNotStopped ;

+        }

+        else if( result == 1 )

+        {

+            result = PA_STREAM_INTERFACE(stream)->Start( stream );

+        }

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_StartStream returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError Pa_StopStream( PaStream *stream )

+{

+    PaError result = PaUtil_ValidateStreamPointer( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_StopStream called\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( result == paNoError )

+    {

+        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );

+        if( result == 0 )

+        {

+            result = PA_STREAM_INTERFACE(stream)->Stop( stream );

+        }

+        else if( result == 1 )

+        {

+            result = paStreamIsStopped;

+        }

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_StopStream returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError Pa_AbortStream( PaStream *stream )

+{

+    PaError result = PaUtil_ValidateStreamPointer( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_AbortStream called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( result == paNoError )

+    {

+        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );

+        if( result == 0 )

+        {

+            result = PA_STREAM_INTERFACE(stream)->Abort( stream );

+        }

+        else if( result == 1 )

+        {

+            result = paStreamIsStopped;

+        }

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_AbortStream returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError Pa_IsStreamStopped( PaStream *stream )

+{

+    PaError result = PaUtil_ValidateStreamPointer( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_IsStreamStopped called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( result == paNoError )

+        result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_IsStreamStopped returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError Pa_IsStreamActive( PaStream *stream )

+{

+    PaError result = PaUtil_ValidateStreamPointer( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_IsStreamActive called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( result == paNoError )

+        result = PA_STREAM_INTERFACE(stream)->IsActive( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_IsStreamActive returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream )

+{

+    PaError error = PaUtil_ValidateStreamPointer( stream );

+    const PaStreamInfo *result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetStreamInfo called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( error != paNoError )

+    {

+        result = 0;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );

+        PaUtil_DebugPrint("\tconst PaStreamInfo*: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );

+#endif

+

+    }

+    else

+    {

+        result = &PA_STREAM_REP( stream )->streamInfo;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );

+        PaUtil_DebugPrint("\tconst PaStreamInfo*: 0x%p:\n", result );

+        PaUtil_DebugPrint("\t{" );

+

+        PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );

+        PaUtil_DebugPrint("\t\tPaTime inputLatency: %f\n", result->inputLatency );

+        PaUtil_DebugPrint("\t\tPaTime outputLatency: %f\n", result->outputLatency );

+        PaUtil_DebugPrint("\t\tdouble sampleRate: %f\n", result->sampleRate );

+        PaUtil_DebugPrint("\t}\n\n" );

+#endif

+

+    }

+

+    return result;

+}

+

+

+PaTime Pa_GetStreamTime( PaStream *stream )

+{

+    PaError error = PaUtil_ValidateStreamPointer( stream );

+    PaTime result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetStreamTime called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( error != paNoError )

+    {

+        result = 0;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );

+        PaUtil_DebugPrint("\tPaTime: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );

+#endif

+

+    }

+    else

+    {

+        result = PA_STREAM_INTERFACE(stream)->GetTime( stream );

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );

+        PaUtil_DebugPrint("\tPaTime: %g\n\n", result );

+#endif

+

+    }

+

+    return result;

+}

+

+

+double Pa_GetStreamCpuLoad( PaStream* stream )

+{

+    PaError error = PaUtil_ValidateStreamPointer( stream );

+    double result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetStreamCpuLoad called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( error != paNoError )

+    {

+

+        result = 0.0;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );

+        PaUtil_DebugPrint("\tdouble: 0.0 [PaError error: %d ( %s )]\n\n", error, Pa_GetErrorText( error ) );

+#endif

+

+    }

+    else

+    {

+        result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream );

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );

+        PaUtil_DebugPrint("\tdouble: %g\n\n", result );

+#endif

+

+    }

+

+    return result;

+}

+

+

+PaError Pa_ReadStream( PaStream* stream,

+                       void *buffer,

+                       unsigned long frames )

+{

+    PaError result = PaUtil_ValidateStreamPointer( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_ReadStream called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( result == paNoError )

+    {

+        if( frames == 0 )

+        {

+            result = paInternalError; /** @todo should return a different error code */

+        }

+        else if( buffer == 0 )

+        {

+            result = paInternalError; /** @todo should return a different error code */

+        }

+        else

+        {

+            result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );

+            if( result == 0 )

+            {

+                result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames );

+            }

+            else if( result == 1 )

+            {

+                result = paStreamIsStopped;

+            }

+        }

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_ReadStream returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+

+PaError Pa_WriteStream( PaStream* stream,

+                        const void *buffer,

+                        unsigned long frames )

+{

+    PaError result = PaUtil_ValidateStreamPointer( stream );

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_WriteStream called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( result == paNoError )

+    {

+        if( frames == 0 )

+        {

+            result = paInternalError; /** @todo should return a different error code */

+        }

+        else if( buffer == 0 )

+        {

+            result = paInternalError; /** @todo should return a different error code */

+        }

+        else

+        {

+            result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );

+            if( result == 0 )

+            {

+                result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames );

+            }

+            else if( result == 1 )

+            {

+                result = paStreamIsStopped;

+            }  

+        }

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_WriteStream returned:\n" );

+    PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return result;

+}

+

+signed long Pa_GetStreamReadAvailable( PaStream* stream )

+{

+    PaError error = PaUtil_ValidateStreamPointer( stream );

+    signed long result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetStreamReadAvailable called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( error != paNoError )

+    {

+        result = 0;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );

+        PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );

+#endif

+

+    }

+    else

+    {

+        result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream );

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    }

+

+    return result;

+}

+

+

+signed long Pa_GetStreamWriteAvailable( PaStream* stream )

+{

+    PaError error = PaUtil_ValidateStreamPointer( stream );

+    signed long result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetStreamWriteAvailable called:\n" );

+    PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );

+#endif

+

+    if( error != paNoError )

+    {

+        result = 0;

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );

+        PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );

+#endif

+

+    }

+    else

+    {

+        result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream );

+

+#ifdef PA_LOG_API_CALLS

+        PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    }

+

+    return result;

+}

+

+

+PaError Pa_GetSampleSize( PaSampleFormat format )

+{

+    int result;

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetSampleSize called:\n" );

+    PaUtil_DebugPrint("\tPaSampleFormat format: %d\n", format );

+#endif

+

+    switch( format & ~paNonInterleaved )

+    {

+

+    case paUInt8:

+    case paInt8:

+        result = 1;

+        break;

+

+    case paInt16:

+        result = 2;

+        break;

+

+    case paInt24:

+        result = 3;

+        break;

+

+    case paFloat32:

+    case paInt32:

+        result = 4;

+        break;

+

+    default:

+        result = paSampleFormatNotSupported;

+        break;

+    }

+

+#ifdef PA_LOG_API_CALLS

+    PaUtil_DebugPrint("Pa_GetSampleSize returned:\n" );

+    if( result > 0 )

+        PaUtil_DebugPrint("\tint: %d\n\n", result );

+    else

+        PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );

+#endif

+

+    return (PaError) result;

+}

+

diff --git a/pjmedia/src/pjmedia/portaudio/pa_hostapi.h b/pjmedia/src/pjmedia/portaudio/pa_hostapi.h
index d055070..aee0635 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_hostapi.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_hostapi.h
@@ -1,244 +1,265 @@
-#ifndef PA_HOSTAPI_H
-#define PA_HOSTAPI_H
-/*
- * $Id: pa_hostapi.h,v 1.1.2.14 2004/01/08 22:01:12 rossbencina Exp $
- * Portable Audio I/O Library
- * host api representation
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Interface used by pa_front to virtualize functions which operate on
- host APIs.
-*/
-
-
-#include "portaudio.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/** **FOR THE USE OF pa_front.c ONLY**
-    Do NOT use fields in this structure, they my change at any time.
-    Use functions defined in pa_util.h if you think you need functionality
-    which can be derived from here.
-*/
-typedef struct PaUtilPrivatePaFrontHostApiInfo {
-
-
-    unsigned long baseDeviceIndex;
-}PaUtilPrivatePaFrontHostApiInfo;
-
-
-/** The common header for all data structures whose pointers are passed through
- the hostApiSpecificStreamInfo field of the PaStreamParameters structure.
- Note that in order to keep the public PortAudio interface clean, this structure
- is not used explicitly when declaring hostApiSpecificStreamInfo data structures.
- However, some code in pa_front depends on the first 3 members being equivalent
- with this structure.
- @see PaStreamParameters
-*/
-typedef struct PaUtilHostApiSpecificStreamInfoHeader
-{
-    unsigned long size;             /**< size of whole structure including this header */
-    PaHostApiTypeId hostApiType;    /**< host API for which this data is intended */
-    unsigned long version;          /**< structure version */
-} PaUtilHostApiSpecificStreamInfoHeader;
-
-
-
-/** A structure representing the interface to a host API. Contains both
- concrete data and pointers to functions which implement the interface.
-*/
-typedef struct PaUtilHostApiRepresentation {
-    PaUtilPrivatePaFrontHostApiInfo privatePaFrontInfo;
-
-    /** The host api implementation should populate the info field. In the
-        case of info.defaultInputDevice and info.defaultOutputDevice the
-        values stored should be 0 based indices within the host api's own
-        device index range (0 to deviceCount). These values will be converted
-        to global device indices by pa_front after PaUtilHostApiInitializer()
-        returns.
-    */
-    PaHostApiInfo info;
-
-    PaDeviceInfo** deviceInfos;
-
-    /**
-        (*Terminate)() is guaranteed to be called with a valid <hostApi>
-        parameter, which was previously returned from the same implementation's
-        initializer.
-    */
-    void (*Terminate)( struct PaUtilHostApiRepresentation *hostApi );
-
-    /**
-        The inputParameters and outputParameters pointers should not be saved
-        as they will not remain valid after OpenStream is called.
-
-        
-        The following guarantees are made about parameters to (*OpenStream)():
-
-            [NOTE: the following list up to *END PA FRONT VALIDATIONS* should be
-                kept in sync with the one for ValidateOpenStreamParameters and
-                Pa_OpenStream in pa_front.c]
-                
-            PaHostApiRepresentation *hostApi
-                - is valid for this implementation
-
-            PaStream** stream
-                - is non-null
-
-            - at least one of inputParameters & outputParmeters is valid (not NULL)
-
-            - if inputParameters & outputParmeters are both valid, that
-                inputParameters->device & outputParmeters->device  both use the same host api
- 
-            PaDeviceIndex inputParameters->device
-                - is within range (0 to Pa_CountDevices-1) Or:
-                - is paUseHostApiSpecificDeviceSpecification and
-                    inputParameters->hostApiSpecificStreamInfo is non-NULL and refers
-                    to a valid host api
-
-            int inputParameters->numChannels
-                - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, numInputChannels is > 0
-                - upper bound is NOT validated against device capabilities
- 
-            PaSampleFormat inputParameters->sampleFormat
-                - is one of the sample formats defined in portaudio.h
-
-            void *inputParameters->hostApiSpecificStreamInfo
-                - if supplied its hostApi field matches the input device's host Api
- 
-            PaDeviceIndex outputParmeters->device
-                - is within range (0 to Pa_CountDevices-1)
- 
-            int outputParmeters->numChannels
-                - if inputDevice is valid, numInputChannels is > 0
-                - upper bound is NOT validated against device capabilities
- 
-            PaSampleFormat outputParmeters->sampleFormat
-                - is one of the sample formats defined in portaudio.h
-        
-            void *outputParmeters->hostApiSpecificStreamInfo
-                - if supplied its hostApi field matches the output device's host Api
- 
-            double sampleRate
-                - is not an 'absurd' rate (less than 1000. or greater than 200000.)
-                - sampleRate is NOT validated against device capabilities
- 
-            PaStreamFlags streamFlags
-                - unused platform neutral flags are zero
-                - paNeverDropInput is only used for full-duplex callback streams
-                    with variable buffer size (paFramesPerBufferUnspecified)
-
-            [*END PA FRONT VALIDATIONS*]
-
-
-        The following validations MUST be performed by (*OpenStream)():
-
-            - check that input device can support numInputChannels
-            
-            - check that input device can support inputSampleFormat, or that
-                we have the capability to convert from outputSampleFormat to
-                a native format
-
-            - if inputStreamInfo is supplied, validate its contents,
-                or return an error if no inputStreamInfo is expected
-
-            - check that output device can support numOutputChannels
-            
-            - check that output device can support outputSampleFormat, or that
-                we have the capability to convert from outputSampleFormat to
-                a native format
-
-            - if outputStreamInfo is supplied, validate its contents,
-                or return an error if no outputStreamInfo is expected
-
-            - if a full duplex stream is requested, check that the combination
-                of input and output parameters is supported
-
-            - check that the device supports sampleRate
-
-            - alter sampleRate to a close allowable rate if necessary
-
-            - validate inputLatency and outputLatency
-
-            - validate any platform specific flags, if flags are supplied they
-                must be valid.
-    */
-    PaError (*OpenStream)( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** stream,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerCallback,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *streamCallback,
-                           void *userData );
-
-
-    PaError (*IsFormatSupported)( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate );
-} PaUtilHostApiRepresentation;
-
-
-/** Prototype for the initialization function which must be implemented by every
- host API.
- 
- @see paHostApiInitializers
-*/
-typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex );
-
-
-/** paHostApiInitializers is a NULL-terminated array of host API initialization
- functions. These functions are called by pa_front to initialize the host APIs
- when the client calls Pa_Initialize().
-
- There is a platform specific file which defines paHostApiInitializers for that
- platform, pa_win/pa_win_hostapis.c contains the Win32 definitions for example.
-*/
-extern PaUtilHostApiInitializer *paHostApiInitializers[];
-
-
-/** The index of the default host API in the paHostApiInitializers array.
- 
- There is a platform specific file which defines paDefaultHostApiIndex for that
- platform, see pa_win/pa_win_hostapis.c for example.
-*/
-extern int paDefaultHostApiIndex;
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_HOSTAPI_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_HOSTAPI_H

+#define PA_HOSTAPI_H

+/*

+ * $Id: pa_hostapi.h,v 1.1.2.14 2004/01/08 22:01:12 rossbencina Exp $

+ * Portable Audio I/O Library

+ * host api representation

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+ @brief Interface used by pa_front to virtualize functions which operate on

+ host APIs.

+*/

+

+

+#include "portaudio.h"

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+/** **FOR THE USE OF pa_front.c ONLY**

+    Do NOT use fields in this structure, they my change at any time.

+    Use functions defined in pa_util.h if you think you need functionality

+    which can be derived from here.

+*/

+typedef struct PaUtilPrivatePaFrontHostApiInfo {

+

+

+    unsigned long baseDeviceIndex;

+}PaUtilPrivatePaFrontHostApiInfo;

+

+

+/** The common header for all data structures whose pointers are passed through

+ the hostApiSpecificStreamInfo field of the PaStreamParameters structure.

+ Note that in order to keep the public PortAudio interface clean, this structure

+ is not used explicitly when declaring hostApiSpecificStreamInfo data structures.

+ However, some code in pa_front depends on the first 3 members being equivalent

+ with this structure.

+ @see PaStreamParameters

+*/

+typedef struct PaUtilHostApiSpecificStreamInfoHeader

+{

+    unsigned long size;             /**< size of whole structure including this header */

+    PaHostApiTypeId hostApiType;    /**< host API for which this data is intended */

+    unsigned long version;          /**< structure version */

+} PaUtilHostApiSpecificStreamInfoHeader;

+

+

+

+/** A structure representing the interface to a host API. Contains both

+ concrete data and pointers to functions which implement the interface.

+*/

+typedef struct PaUtilHostApiRepresentation {

+    PaUtilPrivatePaFrontHostApiInfo privatePaFrontInfo;

+

+    /** The host api implementation should populate the info field. In the

+        case of info.defaultInputDevice and info.defaultOutputDevice the

+        values stored should be 0 based indices within the host api's own

+        device index range (0 to deviceCount). These values will be converted

+        to global device indices by pa_front after PaUtilHostApiInitializer()

+        returns.

+    */

+    PaHostApiInfo info;

+

+    PaDeviceInfo** deviceInfos;

+

+    /**

+        (*Terminate)() is guaranteed to be called with a valid <hostApi>

+        parameter, which was previously returned from the same implementation's

+        initializer.

+    */

+    void (*Terminate)( struct PaUtilHostApiRepresentation *hostApi );

+

+    /**

+        The inputParameters and outputParameters pointers should not be saved

+        as they will not remain valid after OpenStream is called.

+

+        

+        The following guarantees are made about parameters to (*OpenStream)():

+

+            [NOTE: the following list up to *END PA FRONT VALIDATIONS* should be

+                kept in sync with the one for ValidateOpenStreamParameters and

+                Pa_OpenStream in pa_front.c]

+                

+            PaHostApiRepresentation *hostApi

+                - is valid for this implementation

+

+            PaStream** stream

+                - is non-null

+

+            - at least one of inputParameters & outputParmeters is valid (not NULL)

+

+            - if inputParameters & outputParmeters are both valid, that

+                inputParameters->device & outputParmeters->device  both use the same host api

+ 

+            PaDeviceIndex inputParameters->device

+                - is within range (0 to Pa_CountDevices-1) Or:

+                - is paUseHostApiSpecificDeviceSpecification and

+                    inputParameters->hostApiSpecificStreamInfo is non-NULL and refers

+                    to a valid host api

+

+            int inputParameters->numChannels

+                - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, numInputChannels is > 0

+                - upper bound is NOT validated against device capabilities

+ 

+            PaSampleFormat inputParameters->sampleFormat

+                - is one of the sample formats defined in portaudio.h

+

+            void *inputParameters->hostApiSpecificStreamInfo

+                - if supplied its hostApi field matches the input device's host Api

+ 

+            PaDeviceIndex outputParmeters->device

+                - is within range (0 to Pa_CountDevices-1)

+ 

+            int outputParmeters->numChannels

+                - if inputDevice is valid, numInputChannels is > 0

+                - upper bound is NOT validated against device capabilities

+ 

+            PaSampleFormat outputParmeters->sampleFormat

+                - is one of the sample formats defined in portaudio.h

+        

+            void *outputParmeters->hostApiSpecificStreamInfo

+                - if supplied its hostApi field matches the output device's host Api

+ 

+            double sampleRate

+                - is not an 'absurd' rate (less than 1000. or greater than 200000.)

+                - sampleRate is NOT validated against device capabilities

+ 

+            PaStreamFlags streamFlags

+                - unused platform neutral flags are zero

+                - paNeverDropInput is only used for full-duplex callback streams

+                    with variable buffer size (paFramesPerBufferUnspecified)

+

+            [*END PA FRONT VALIDATIONS*]

+

+

+        The following validations MUST be performed by (*OpenStream)():

+

+            - check that input device can support numInputChannels

+            

+            - check that input device can support inputSampleFormat, or that

+                we have the capability to convert from outputSampleFormat to

+                a native format

+

+            - if inputStreamInfo is supplied, validate its contents,

+                or return an error if no inputStreamInfo is expected

+

+            - check that output device can support numOutputChannels

+            

+            - check that output device can support outputSampleFormat, or that

+                we have the capability to convert from outputSampleFormat to

+                a native format

+

+            - if outputStreamInfo is supplied, validate its contents,

+                or return an error if no outputStreamInfo is expected

+

+            - if a full duplex stream is requested, check that the combination

+                of input and output parameters is supported

+

+            - check that the device supports sampleRate

+

+            - alter sampleRate to a close allowable rate if necessary

+

+            - validate inputLatency and outputLatency

+

+            - validate any platform specific flags, if flags are supplied they

+                must be valid.

+    */

+    PaError (*OpenStream)( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** stream,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerCallback,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *streamCallback,

+                           void *userData );

+

+

+    PaError (*IsFormatSupported)( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate );

+} PaUtilHostApiRepresentation;

+

+

+/** Prototype for the initialization function which must be implemented by every

+ host API.

+ 

+ @see paHostApiInitializers

+*/

+typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex );

+

+

+/** paHostApiInitializers is a NULL-terminated array of host API initialization

+ functions. These functions are called by pa_front to initialize the host APIs

+ when the client calls Pa_Initialize().

+

+ There is a platform specific file which defines paHostApiInitializers for that

+ platform, pa_win/pa_win_hostapis.c contains the Win32 definitions for example.

+*/

+extern PaUtilHostApiInitializer *paHostApiInitializers[];

+

+

+/** The index of the default host API in the paHostApiInitializers array.

+ 

+ There is a platform specific file which defines paDefaultHostApiIndex for that

+ platform, see pa_win/pa_win_hostapis.c for example.

+*/

+extern int paDefaultHostApiIndex;

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PA_HOSTAPI_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.c b/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.c
index 3b04716..405ada1 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.c
@@ -1,3272 +1,3293 @@
-/*
- * $Id: pa_linux_alsa.c,v 1.1.2.71 2005/04/15 18:20:18 aknudsen Exp $
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- * ALSA implementation by Joshua Haberman and Arve Knudsen
- *
- * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
- * Copyright (c) 2005 Arve Knudsen <aknuds-1@broadpark.no>
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#define ALSA_PCM_NEW_SW_PARAMS_API
-#include <alsa/asoundlib.h>
-#undef ALSA_PCM_NEW_HW_PARAMS_API
-#undef ALSA_PCM_NEW_SW_PARAMS_API
-
-#include <sys/poll.h>
-#include <string.h> /* strlen() */
-#include <limits.h>
-#include <math.h>
-#include <pthread.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/mman.h>
-#include <signal.h> /* For sig_atomic_t */
-
-#include "portaudio.h"
-#include "pa_util.h"
-#include "pa_unix_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
-#include "pa_linux_alsa.h"
-
-/* Check return value of ALSA function, and map it to PaError */
-#define ENSURE_(expr, code) \
-    do { \
-        if( UNLIKELY( (aErr_ = (expr)) < 0 ) ) \
-        { \
-            /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
-            if( (code) == paUnanticipatedHostError && pthread_self() != callbackThread_ ) \
-            { \
-                PaUtil_SetLastHostErrorInfo( paALSA, aErr_, snd_strerror( aErr_ ) ); \
-            } \
-            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
-            result = (code); \
-            goto error; \
-        } \
-    } while( 0 );
-
-#define ASSERT_CALL_(expr, success) \
-    aErr_ = (expr); \
-    assert( aErr_ == success );
-
-static int aErr_;               /* Used with ENSURE_ */
-static pthread_t callbackThread_;
-
-typedef enum
-{
-    StreamDirection_In,
-    StreamDirection_Out
-} StreamDirection;
-
-/* Threading utility struct */
-typedef struct PaAlsaThreading
-{
-    pthread_t watchdogThread;
-    pthread_t callbackThread;
-    int watchdogRunning;
-    int rtSched;
-    int rtPrio;
-    int useWatchdog;
-    unsigned long throttledSleepTime;
-    volatile PaTime callbackTime;
-    volatile PaTime callbackCpuTime;
-    PaUtilCpuLoadMeasurer *cpuLoadMeasurer;
-} PaAlsaThreading;
-
-typedef struct
-{
-    PaSampleFormat hostSampleFormat;
-    unsigned long framesPerBuffer;
-    int numUserChannels, numHostChannels;
-    int userInterleaved, hostInterleaved;
-
-    snd_pcm_t *pcm;
-    snd_pcm_uframes_t bufferSize;
-    snd_pcm_format_t nativeFormat;
-    unsigned int nfds;
-    int ready;  /* Marked ready from poll */
-    void **userBuffers;
-    snd_pcm_uframes_t offset;
-    StreamDirection streamDir;
-
-    snd_pcm_channel_area_t *channelAreas;  /* Needed for channel adaption */
-} PaAlsaStreamComponent;
-
-/* Implementation specific stream structure */
-typedef struct PaAlsaStream
-{
-    PaUtilStreamRepresentation streamRepresentation;
-    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
-    PaUtilBufferProcessor bufferProcessor;
-    PaAlsaThreading threading;
-
-    unsigned long framesPerUserBuffer;
-
-    int primeBuffers;
-    int callbackMode;              /* bool: are we running in callback mode? */
-    int pcmsSynced;	            /* Have we successfully synced pcms */
-
-    /* the callback thread uses these to poll the sound device(s), waiting
-     * for data to be ready/available */
-    struct pollfd *pfds;
-    int pollTimeout;
-
-    /* Used in communication between threads */
-    volatile sig_atomic_t callback_finished; /* bool: are we in the "callback finished" state? */
-    volatile sig_atomic_t callbackAbort;    /* Drop frames? */
-    volatile sig_atomic_t callbackStop;     /* Signal a stop */
-    volatile sig_atomic_t isActive;         /* Is stream in active state? (Between StartStream and StopStream || !paContinue) */
-    pthread_mutex_t stateMtx;               /* Used to synchronize access to stream state */
-    pthread_mutex_t startMtx;               /* Used to synchronize stream start in callback mode */
-    pthread_cond_t startCond;               /* Wait untill audio is started in callback thread */
-
-    int neverDropInput;
-
-    PaTime underrun;
-    PaTime overrun;
-
-    PaAlsaStreamComponent capture, playback;
-}
-PaAlsaStream;
-
-/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct PaAlsaHostApiRepresentation
-{
-    PaUtilHostApiRepresentation commonHostApiRep;
-    PaUtilStreamInterface callbackStreamInterface;
-    PaUtilStreamInterface blockingStreamInterface;
-
-    PaUtilAllocationGroup *allocations;
-
-    PaHostApiIndex hostApiIndex;
-}
-PaAlsaHostApiRepresentation;
-
-typedef struct PaAlsaDeviceInfo
-{
-    PaDeviceInfo commonDeviceInfo;
-    char *alsaName;
-    int isPlug;
-    int minInputChannels;
-    int minOutputChannels;
-}
-PaAlsaDeviceInfo;
-
-/* Threading utilities */
-
-static void InitializeThreading( PaAlsaThreading *th, PaUtilCpuLoadMeasurer *clm )
-{
-    th->watchdogRunning = 0;
-    th->rtSched = 0;
-    th->callbackTime = 0;
-    th->callbackCpuTime = 0;
-    th->useWatchdog = 1;
-    th->throttledSleepTime = 0;
-    th->cpuLoadMeasurer = clm;
-
-    th->rtPrio = (sched_get_priority_max( SCHED_FIFO ) - sched_get_priority_min( SCHED_FIFO )) / 2
-            + sched_get_priority_min( SCHED_FIFO );
-}
-
-static PaError KillCallbackThread( PaAlsaThreading *th, int wait, PaError *exitResult, PaError *watchdogExitResult )
-{
-    PaError result = paNoError;
-    void *pret;
-
-    if( exitResult )
-        *exitResult = paNoError;
-    if( watchdogExitResult )
-        *watchdogExitResult = paNoError;
-
-    if( th->watchdogRunning )
-    {
-        pthread_cancel( th->watchdogThread );
-        ASSERT_CALL_( pthread_join( th->watchdogThread, &pret ), 0 );
-
-        if( pret && pret != PTHREAD_CANCELED )
-        {
-            if( watchdogExitResult )
-                *watchdogExitResult = *(PaError *) pret;
-            free( pret );
-        }
-    }
-
-    /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
-    /* TODO: Make join time out */
-    if( !wait )
-        pthread_cancel( th->callbackThread );   /* XXX: Safe to call this if the thread has exited on its own? */
-    ASSERT_CALL_( pthread_join( th->callbackThread, &pret ), 0 );
-
-    if( pret && pret != PTHREAD_CANCELED )
-    {
-        if( exitResult )
-            *exitResult = *(PaError *) pret;
-        free( pret );
-    }
-
-    return result;
-}
-
-static void OnWatchdogExit( void *userData )
-{
-    PaAlsaThreading *th = (PaAlsaThreading *) userData;
-    struct sched_param spm = { 0 };
-    assert( th );
-
-    ASSERT_CALL_( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 );    /* Lower before exiting */
-    PA_DEBUG(( "Watchdog exiting\n" ));
-}
-
-static PaError BoostPriority( PaAlsaThreading *th )
-{
-    PaError result = paNoError;
-    struct sched_param spm = { 0 };
-    spm.sched_priority = th->rtPrio;
-
-    assert( th );
-
-    if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )
-    {
-        PA_UNLESS( errno == EPERM, paInternalError );  /* Lack permission to raise priority */
-        PA_DEBUG(( "Failed bumping priority\n" ));
-        result = 0;
-    }
-    else
-        result = 1; /* Success */
-error:
-    return result;
-}
-
-static void *WatchdogFunc( void *userData )
-{
-    PaError result = paNoError, *pres = NULL;
-    int err;
-    PaAlsaThreading *th = (PaAlsaThreading *) userData;
-    unsigned intervalMsec = 500;
-    const PaTime maxSeconds = 3.;   /* Max seconds between callbacks */
-    PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed;
-    double cpuLoad, avgCpuLoad = 0.;
-    int throttled = 0;
-
-    assert( th );
-
-    pthread_cleanup_push( &OnWatchdogExit, th );	/* Execute OnWatchdogExit when exiting */
-
-    /* Boost priority of callback thread */
-    PA_ENSURE( result = BoostPriority( th ) );
-    if( !result )
-    {
-        pthread_exit( NULL );   /* Boost failed, might as well exit */
-    }
-
-    cpuTimeThen = th->callbackCpuTime;
-    {
-        int policy;
-        struct sched_param spm = { 0 };
-        pthread_getschedparam( pthread_self(), &policy, &spm );
-        PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority ));
-    }
-
-    while( 1 )
-    {
-        double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff;
-        
-        /* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */
-        pthread_testcancel();
-        Pa_Sleep( intervalMsec );
-        pthread_testcancel();
-
-        if( PaUtil_GetTime() - th->callbackTime > maxSeconds )
-        {
-            PA_DEBUG(( "Watchdog: Terminating callback thread\n" ));
-            /* Tell thread to terminate */
-            err = pthread_kill( th->callbackThread, SIGKILL );
-            pthread_exit( NULL );
-        }
-
-        PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) ));
-
-        /* Check if we should throttle, or unthrottle :P */
-        cpuTimeNow = th->callbackCpuTime;
-        cpuTimeElapsed = cpuTimeNow - cpuTimeThen;
-        cpuTimeThen = cpuTimeNow;
-
-        timeNow = PaUtil_GetTime();
-        timeElapsed = timeNow - timeThen;
-        timeThen = timeNow;
-        cpuLoad = cpuTimeElapsed / timeElapsed;
-        avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1;
-        /*
-        if( throttled )
-            PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed ));
-            */
-        if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 )
-        {
-            static int policy;
-            static struct sched_param spm = { 0 };
-            static const struct sched_param defaultSpm = { 0 };
-            PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority ));
-
-            pthread_getschedparam( th->callbackThread, &policy, &spm );
-            if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) )
-            {
-                throttled = 1;
-            }
-            else
-                PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) ));
-
-            /* Give other processes a go, before raising priority again */
-            PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime ));
-            Pa_Sleep( th->throttledSleepTime );
-
-            /* Reset callback priority */
-            if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )
-            {
-                PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) ));
-            }
-
-            if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 )
-                intervalMsec = 50;
-            else
-                intervalMsec = 100;
-
-            /*
-            lowpassCoeff = .97;
-            lowpassCoeff1 = .99999 - lowpassCoeff;
-            */
-        }
-        else if( throttled && avgCpuLoad < .8 )
-        {
-            intervalMsec = 500;
-            throttled = 0;
-
-            /*
-            lowpassCoeff = .9;
-            lowpassCoeff1 = .99999 - lowpassCoeff;
-            */
-        }
-    }
-
-    pthread_cleanup_pop( 1 );   /* Execute cleanup on exit */
-
-error:
-    /* Shouldn't get here in the normal case */
-
-    /* Pass on error code */
-    pres = malloc( sizeof (PaError) );
-    *pres = result;
-    
-    pthread_exit( pres );
-}
-
-static PaError CreateCallbackThread( PaAlsaThreading *th, void *(*callbackThreadFunc)( void * ), PaStream *s )
-{
-    PaError result = paNoError;
-    pthread_attr_t attr;
-    int started = 0;
-
-#if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)
-    if( th->rtSched )
-    {
-        if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 )
-        {
-            int savedErrno = errno;             /* In case errno gets overwritten */
-            assert( savedErrno != EINVAL );     /* Most likely a programmer error */
-            PA_UNLESS( (savedErrno == EPERM), paInternalError );
-            PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ ));
-        }
-        else
-            PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ ));
-    }
-#endif
-
-    PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
-    /* Priority relative to other processes */
-    PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );   
-
-    PA_UNLESS( !pthread_create( &th->callbackThread, &attr, callbackThreadFunc, s ), paInternalError );
-    started = 1;
-
-    if( th->rtSched )
-    {
-        if( th->useWatchdog )
-        {
-            int err;
-            struct sched_param wdSpm = { 0 };
-            /* Launch watchdog, watchdog sets callback thread priority */
-            int prio = PA_MIN( th->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) );
-            wdSpm.sched_priority = prio;
-
-            PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
-            PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError );
-            PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
-            PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError );
-            PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError );
-            if( (err = pthread_create( &th->watchdogThread, &attr, &WatchdogFunc, th )) )
-            {
-                PA_UNLESS( err == EPERM, paInternalError );
-                /* Permission error, go on without realtime privileges */
-                PA_DEBUG(( "Failed bumping priority\n" ));
-            }
-            else
-            {
-                int policy;
-                th->watchdogRunning = 1;
-                ASSERT_CALL_( pthread_getschedparam( th->watchdogThread, &policy, &wdSpm ), 0 );
-                /* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */
-                if( wdSpm.sched_priority != prio )
-                {
-                    PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority ));
-                    PA_ENSURE( paInternalError );
-                }
-            }
-        }
-        else
-            PA_ENSURE( BoostPriority( th ) );
-    }
-
-end:
-    return result;
-error:
-    if( started )
-        KillCallbackThread( th, 0, NULL, NULL );
-
-    goto end;
-}
-
-static void CallbackUpdate( PaAlsaThreading *th )
-{
-    th->callbackTime = PaUtil_GetTime();
-    th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer );
-}
-
-/* prototypes for functions declared in this file */
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** s,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *callback,
-                           void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );
-static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate );
-static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate );
-
-/* Callback prototypes */
-static void *CallbackThreadFunc( void *userData );
-
-/* Blocking prototypes */
-static signed long GetStreamReadAvailable( PaStream* s );
-static signed long GetStreamWriteAvailable( PaStream* s );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-
-
-static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation *hostApi, int device )
-{
-    return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device];
-}
-
-PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
-    PaError result = paNoError;
-    PaAlsaHostApiRepresentation *alsaHostApi = NULL;
-
-    PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory(
-                sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory );
-    PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
-    alsaHostApi->hostApiIndex = hostApiIndex;
-
-    *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi;
-    (*hostApi)->info.structVersion = 1;
-    (*hostApi)->info.type = paALSA;
-    (*hostApi)->info.name = "ALSA";
-
-    (*hostApi)->Terminate = Terminate;
-    (*hostApi)->OpenStream = OpenStream;
-    (*hostApi)->IsFormatSupported = IsFormatSupported;
-
-    PA_ENSURE( BuildDeviceList( alsaHostApi ) );
-
-    PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface,
-                                      CloseStream, StartStream,
-                                      StopStream, AbortStream,
-                                      IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, GetStreamCpuLoad,
-                                      PaUtil_DummyRead, PaUtil_DummyWrite,
-                                      PaUtil_DummyGetReadAvailable,
-                                      PaUtil_DummyGetWriteAvailable );
-
-    PaUtil_InitializeStreamInterface( &alsaHostApi->blockingStreamInterface,
-                                      CloseStream, StartStream,
-                                      StopStream, AbortStream,
-                                      IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
-                                      ReadStream, WriteStream,
-                                      GetStreamReadAvailable,
-                                      GetStreamWriteAvailable );
-
-    return result;
-
-error:
-    if( alsaHostApi )
-    {
-        if( alsaHostApi->allocations )
-        {
-            PaUtil_FreeAllAllocations( alsaHostApi->allocations );
-            PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
-        }
-
-        PaUtil_FreeMemory( alsaHostApi );
-    }
-
-    return result;
-}
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
-    PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
-
-    assert( hostApi );
-
-    if( alsaHostApi->allocations )
-    {
-        PaUtil_FreeAllAllocations( alsaHostApi->allocations );
-        PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
-    }
-
-    PaUtil_FreeMemory( alsaHostApi );
-    snd_config_update_free_global();
-}
-
-/*! Determine max channels and default latencies.
- *
- * This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for 
- * traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero,
- * and a suitable result returned. The device is closed before returning.
- */
-static PaError GropeDevice( snd_pcm_t *pcm, int *minChannels, int *maxChannels, double *defaultLowLatency,
-        double *defaultHighLatency, double *defaultSampleRate, int isPlug )
-{
-    PaError result = paNoError;
-    snd_pcm_hw_params_t *hwParams;
-    snd_pcm_uframes_t lowLatency = 512, highLatency = 2048;
-    unsigned int minChans, maxChans;
-    double defaultSr = *defaultSampleRate;
-
-    assert( pcm );
-
-    ENSURE_( snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError );
-
-    snd_pcm_hw_params_alloca( &hwParams );
-    snd_pcm_hw_params_any( pcm, hwParams );
-
-    if( defaultSr >= 0 )
-    {
-        /* Could be that the device opened in one mode supports samplerates that the other mode wont have,
-         * so try again .. */
-        if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 )
-        {
-            defaultSr = -1.;
-            PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ ));
-        }
-    }
-
-    if( defaultSr < 0. )           /* Default sample rate not set */
-    {
-        unsigned int sampleRate = 44100;        /* Will contain approximate rate returned by alsa-lib */
-        ENSURE_( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ), paUnanticipatedHostError );
-        ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError );
-    }
-
-    ENSURE_( snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError );
-    ENSURE_( snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError );
-    assert( maxChans <= INT_MAX );
-    assert( maxChans > 0 );    /* Weird linking issue could cause wrong version of ALSA symbols to be called,
-                                   resulting in zeroed values */
-
-    /* XXX: Limit to sensible number (ALSA plugins accept a crazy amount of channels)? */
-    if( isPlug && maxChans > 128 )
-    {
-        maxChans = 128;
-        PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans ));
-    }
-
-    /* TWEAKME:
-     *
-     * Giving values for default min and max latency is not
-     * straightforward.  Here are our objectives:
-     *
-     *         * for low latency, we want to give the lowest value
-     *         that will work reliably.  This varies based on the
-     *         sound card, kernel, CPU, etc.  I think it is better
-     *         to give sub-optimal latency than to give a number
-     *         too low and cause dropouts.  My conservative
-     *         estimate at this point is to base it on 4096-sample
-     *         latency at 44.1 kHz, which gives a latency of 23ms.
-     *         * for high latency we want to give a large enough
-     *         value that dropouts are basically impossible.  This
-     *         doesn't really require as much tweaking, since
-     *         providing too large a number will just cause us to
-     *         select the nearest setting that will work at stream
-     *         config time.
-     */
-    ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError );
-
-    /* Have to reset hwParams, to set new buffer size */
-    ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); 
-    ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError );
-
-    *minChannels = (int)minChans;
-    *maxChannels = (int)maxChans;
-    *defaultSampleRate = defaultSr;
-    *defaultLowLatency = (double) lowLatency / *defaultSampleRate;
-    *defaultHighLatency = (double) highLatency / *defaultSampleRate;
-
-end:
-    snd_pcm_close( pcm );
-    return result;
-
-error:
-    goto end;
-}
-
-/* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate
- * wether input/output is available) */
-static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo )
-{
-    deviceInfo->structVersion = -1;
-    deviceInfo->name = NULL;
-    deviceInfo->hostApi = -1;
-    deviceInfo->maxInputChannels = 0;
-    deviceInfo->maxOutputChannels = 0;
-    deviceInfo->defaultLowInputLatency = -1.;
-    deviceInfo->defaultLowOutputLatency = -1.;
-    deviceInfo->defaultHighInputLatency = -1.;
-    deviceInfo->defaultHighOutputLatency = -1.;
-    deviceInfo->defaultSampleRate = -1.;
-}
-
-/* Helper struct */
-typedef struct
-{
-    char *alsaName;
-    char *name;
-    int isPlug;
-    int hasPlayback;
-    int hasCapture;
-} DeviceNames;
-
-static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi,
-        char **dst,
-        const char *src)
-{
-    PaError result = paNoError;
-    int len = strlen( src ) + 1;
-
-    /* PA_DEBUG(("PaStrDup %s %d\n", src, len)); */
-
-    PA_UNLESS( *dst = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
-            paInsufficientMemory );
-    strncpy( *dst, src, len );
-
-error:
-    return result;
-}
-
-/* Disregard standard plugins
- * XXX: Might want to make the "default" plugin available, if we can make it work
- */
-static int IgnorePlugin( const char *pluginId )
-{
-#define numIgnored 10
-    static const char *ignoredPlugins[numIgnored] = {"hw", "plughw", "plug", "default", "dsnoop", "dmix", "tee",
-        "file", "null", "shm"};
-    int i;
-
-    for( i = 0; i < numIgnored; ++i )
-    {
-        if( !strcmp( pluginId, ignoredPlugins[i] ) )
-        {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */
-static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
-{
-    PaUtilHostApiRepresentation *commonApi = &alsaApi->commonHostApiRep;
-    PaAlsaDeviceInfo *deviceInfoArray;
-    int cardIdx = -1, devIdx = 0;
-    snd_ctl_card_info_t *cardInfo;
-    PaError result = paNoError;
-    size_t numDeviceNames = 0, maxDeviceNames = 1, i;
-    DeviceNames *deviceNames = NULL;
-    snd_config_t *topNode = NULL;
-    snd_pcm_info_t *pcmInfo;
-    int res;
-    int blocking = SND_PCM_NONBLOCK;
-    char alsaCardName[50];
-    if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) )
-        blocking = 0;
-
-    /* These two will be set to the first working input and output device, respectively */
-    commonApi->info.defaultInputDevice = paNoDevice;
-    commonApi->info.defaultOutputDevice = paNoDevice;
-
-    /* count the devices by enumerating all the card numbers */
-
-    /* snd_card_next() modifies the integer passed to it to be:
-     *      the index of the first card if the parameter is -1
-     *      the index of the next card if the parameter is the index of a card
-     *      -1 if there are no more cards
-     *
-     * The function itself returns 0 if it succeeded. */
-    cardIdx = -1;
-    snd_ctl_card_info_alloca( &cardInfo );
-    snd_pcm_info_alloca( &pcmInfo );
-    while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 )
-    {
-        char *cardName;
-        int devIdx = -1;
-        snd_ctl_t *ctl;
-        char buf[50];
-
-        snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx );
-
-        /* Acquire name of card */
-        if( snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 )
-            continue;   /* Unable to open card :( */
-        snd_ctl_card_info( ctl, cardInfo );
-
-        PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, snd_ctl_card_info_get_name( cardInfo )) );
-
-        while( snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 )
-        {
-            char *alsaDeviceName, *deviceName;
-            size_t len;
-            int hasPlayback = 0, hasCapture = 0;
-            snprintf( buf, sizeof (buf), "%s:%d,%d", "hw", cardIdx, devIdx );
-
-            /* Obtain info about this particular device */
-            snd_pcm_info_set_device( pcmInfo, devIdx );
-            snd_pcm_info_set_subdevice( pcmInfo, 0 );
-            snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE );
-            if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
-                hasCapture = 1;
-            
-            snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK );
-            if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
-                hasPlayback = 1;
-
-            if( !hasPlayback && !hasCapture )
-            {
-                continue;   /* Error */
-            }
-
-            /* The length of the string written by snprintf plus terminating 0 */
-            len = snprintf( NULL, 0, "%s: %s (%s)", cardName, snd_pcm_info_get_name( pcmInfo ), buf ) + 1;
-            PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
-                    paInsufficientMemory );
-            snprintf( deviceName, len, "%s: %s (%s)", cardName,
-                    snd_pcm_info_get_name( pcmInfo ), buf );
-
-            ++numDeviceNames;
-            if( !deviceNames || numDeviceNames > maxDeviceNames )
-            {
-                maxDeviceNames *= 2;
-                PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ),
-                        paInsufficientMemory );
-            }
-
-            PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) );
-
-            deviceNames[ numDeviceNames - 1 ].alsaName = alsaDeviceName;
-            deviceNames[ numDeviceNames - 1 ].name = deviceName;
-            deviceNames[ numDeviceNames - 1 ].isPlug = 0;
-            deviceNames[ numDeviceNames - 1 ].hasPlayback = hasPlayback;
-            deviceNames[ numDeviceNames - 1 ].hasCapture = hasCapture;
-        }
-        snd_ctl_close( ctl );
-    }
-
-    /* Iterate over plugin devices */
-    snd_config_update();
-    if( (res = snd_config_search( snd_config, "pcm", &topNode )) >= 0 )
-    {
-        snd_config_iterator_t i, next;
-
-        snd_config_for_each( i, next, topNode )
-        {
-            const char *tpStr = NULL, *idStr = NULL;
-            char *alsaDeviceName, *deviceName;
-            snd_config_t *n = snd_config_iterator_entry( i ), *tp = NULL;
-            if( snd_config_get_type( n ) != SND_CONFIG_TYPE_COMPOUND )
-                continue;
-
-            ENSURE_( snd_config_search( n, "type", &tp ), paUnanticipatedHostError );
-            ENSURE_( snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError );
-
-            ENSURE_( snd_config_get_id( n, &idStr ), paUnanticipatedHostError );
-            if( IgnorePlugin( idStr ) )
-            {
-                PA_DEBUG(( "%s: Ignoring ALSA plugin device %s of type %s\n", __FUNCTION__, idStr, tpStr ));
-                continue;
-            }
-
-            PA_DEBUG(( "%s: Found plugin %s of type %s\n", __FUNCTION__, idStr, tpStr ));
-
-            PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
-                                                            strlen(idStr) + 6 ), paInsufficientMemory );
-            strcpy( alsaDeviceName, idStr );
-            PA_UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
-                                                            strlen(idStr) + 1 ), paInsufficientMemory );
-            strcpy( deviceName, idStr );
-
-            ++numDeviceNames;
-            if( !deviceNames || numDeviceNames > maxDeviceNames )
-            {
-                maxDeviceNames *= 2;
-                PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ),
-                        paInsufficientMemory );
-            }
-
-            deviceNames[numDeviceNames - 1].alsaName = alsaDeviceName;
-            deviceNames[numDeviceNames - 1].name = deviceName;
-            deviceNames[numDeviceNames - 1].isPlug = 1;
-            deviceNames[numDeviceNames - 1].hasPlayback = 1;
-            deviceNames[numDeviceNames - 1].hasCapture = 1;
-        }
-    }
-    else
-        PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, snd_strerror( res ) ));
-
-    /* allocate deviceInfo memory based on the number of devices */
-    PA_UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
-            alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory );
-
-    /* allocate all device info structs in a contiguous block */
-    PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory(
-            alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory );
-
-    /* Loop over list of cards, filling in info, if a device is deemed unavailable (can't get name),
-     * it's ignored.
-     */
-    /* while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) */
-    for( i = 0, devIdx = 0; i < numDeviceNames; ++i )
-    {
-        snd_pcm_t *pcm;
-        PaAlsaDeviceInfo *deviceInfo = &deviceInfoArray[devIdx];
-        PaDeviceInfo *commonDeviceInfo = &deviceInfo->commonDeviceInfo;
-
-        /* Zero fields */
-        InitializeDeviceInfo( commonDeviceInfo );
-
-        /* to determine device capabilities, we must open the device and query the
-         * hardware parameter configuration space */
-
-        /* Query capture */
-        if( deviceNames[i].hasCapture &&
-                snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_CAPTURE, blocking ) >= 0 )
-        {
-            if( GropeDevice( pcm, &deviceInfo->minInputChannels, &commonDeviceInfo->maxInputChannels,
-                        &commonDeviceInfo->defaultLowInputLatency, &commonDeviceInfo->defaultHighInputLatency,
-                        &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError )
-                continue;   /* Error */
-        }
-
-        /* Query playback */
-        if( deviceNames[i].hasPlayback &&
-                snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_PLAYBACK, blocking ) >= 0 )
-        {
-            if( GropeDevice( pcm, &deviceInfo->minOutputChannels, &commonDeviceInfo->maxOutputChannels,
-                        &commonDeviceInfo->defaultLowOutputLatency, &commonDeviceInfo->defaultHighOutputLatency,
-                        &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError )
-                continue;   /* Error */
-        }
-
-        commonDeviceInfo->structVersion = 2;
-        commonDeviceInfo->hostApi = alsaApi->hostApiIndex;
-        commonDeviceInfo->name = deviceNames[i].name;
-        deviceInfo->alsaName = deviceNames[i].alsaName;
-        deviceInfo->isPlug = deviceNames[i].isPlug;
-
-        /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object.
-         * Should now be safe to add device info, unless the device supports neither capture nor playback
-         */
-        if( commonDeviceInfo->maxInputChannels > 0 || commonDeviceInfo->maxOutputChannels > 0 )
-        {
-            if( commonApi->info.defaultInputDevice == paNoDevice && commonDeviceInfo->maxInputChannels > 0 )
-                commonApi->info.defaultInputDevice = devIdx;
-            if(  commonApi->info.defaultOutputDevice == paNoDevice && commonDeviceInfo->maxOutputChannels > 0 )
-                commonApi->info.defaultOutputDevice = devIdx;
-
-            commonApi->deviceInfos[devIdx++] = (PaDeviceInfo *) deviceInfo;
-        }
-    }
-    free( deviceNames );
-
-    commonApi->info.deviceCount = devIdx;   /* Number of successfully queried devices */
-
-end:
-    return result;
-
-error:
-    goto end;   /* No particular action */
-}
-
-/* Check against known device capabilities */
-static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilHostApiRepresentation *hostApi, StreamDirection mode )
-{
-    PaError result = paNoError;
-    int maxChans;
-    const PaAlsaDeviceInfo *deviceInfo = NULL;
-    assert( parameters );
-
-    if( parameters->device != paUseHostApiSpecificDeviceSpecification )
-    {
-        assert( parameters->device < hostApi->info.deviceCount );
-        PA_UNLESS( parameters->hostApiSpecificStreamInfo == NULL, paBadIODeviceCombination );
-        deviceInfo = GetDeviceInfo( hostApi, parameters->device );
-    }
-    else
-    {
-        const PaAlsaStreamInfo *streamInfo = parameters->hostApiSpecificStreamInfo;
-
-        PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice );
-        PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1,
-                paIncompatibleHostApiSpecificStreamInfo );
-
-        return paNoError;   /* Skip further checking */
-    }
-
-    assert( deviceInfo );
-    assert( parameters->hostApiSpecificStreamInfo == NULL );
-    maxChans = (StreamDirection_In == mode ? deviceInfo->commonDeviceInfo.maxInputChannels :
-        deviceInfo->commonDeviceInfo.maxOutputChannels);
-    PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount );
-
-error:
-    return result;
-}
-
-/* Given an open stream, what sample formats are available? */
-
-static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm )
-{
-    PaSampleFormat available = 0;
-    snd_pcm_hw_params_t *hwParams;
-    snd_pcm_hw_params_alloca( &hwParams );
-
-    snd_pcm_hw_params_any( pcm, hwParams );
-
-    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0)
-        available |= paFloat32;
-
-    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)
-        available |= paInt32;
-
-    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >= 0)
-        available |= paInt24;
-
-    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)
-        available |= paInt16;
-
-    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0)
-        available |= paUInt8;
-
-    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0)
-        available |= paInt8;
-
-    return available;
-}
-
-static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat )
-{
-    switch( paFormat )
-    {
-        case paFloat32:
-            return SND_PCM_FORMAT_FLOAT;
-
-        case paInt16:
-            return SND_PCM_FORMAT_S16;
-
-        case paInt24:
-            return SND_PCM_FORMAT_S24;
-
-        case paInt32:
-            return SND_PCM_FORMAT_S32;
-
-        case paInt8:
-            return SND_PCM_FORMAT_S8;
-
-        case paUInt8:
-            return SND_PCM_FORMAT_U8;
-
-        default:
-            return SND_PCM_FORMAT_UNKNOWN;
-    }
-}
-
-/** Open an ALSA pcm handle.
- * 
- * The device to be open can be specified in a custom PaAlsaStreamInfo struct, or it will be a device number. In case of a
- * device number, it maybe specified through an env variable (PA_ALSA_PLUGHW) that we should open the corresponding plugin
- * device.
- */
-static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection
-        streamDir, snd_pcm_t **pcm )
-{
-    PaError result = paNoError;
-    int ret;
-    const char *deviceName = alloca( 50 );
-    const PaAlsaDeviceInfo *deviceInfo = NULL;
-    PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo;
-
-    if( !streamInfo )
-    {
-        int usePlug = 0;
-        deviceInfo = GetDeviceInfo( hostApi, params->device );
-        
-        /* If device name starts with hw: and PA_ALSA_PLUGHW is 1, we open the plughw device instead */
-        if( !strncmp( "hw:", deviceInfo->alsaName, 3 ) && getenv( "PA_ALSA_PLUGHW" ) )
-            usePlug = atoi( getenv( "PA_ALSA_PLUGHW" ) );
-        if( usePlug )
-            snprintf( (char *) deviceName, 50, "plug%s", deviceInfo->alsaName );
-        else
-            deviceName = deviceInfo->alsaName;
-    }
-    else
-        deviceName = streamInfo->deviceString;
-
-    if( (ret = snd_pcm_open( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
-                    SND_PCM_NONBLOCK )) < 0 )
-    {
-        *pcm = NULL;     /* Not to be closed */
-        ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable : paBadIODeviceCombination );
-    }
-    ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
-
-end:
-    return result;
-
-error:
-    goto end;
-}
-
-static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters,
-        double sampleRate, StreamDirection streamDir )
-{
-    PaError result = paNoError;
-    snd_pcm_t *pcm = NULL;
-    PaSampleFormat availableFormats;
-    /* We are able to adapt to a number of channels less than what the device supports */
-    unsigned int numHostChannels;
-    PaSampleFormat hostFormat;
-    snd_pcm_hw_params_t *hwParams;
-    snd_pcm_hw_params_alloca( &hwParams );
-    
-    if( !parameters->hostApiSpecificStreamInfo )
-    {
-        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device );
-        numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ?
-                devInfo->minInputChannels : devInfo->minOutputChannels );
-    }
-    else
-        numHostChannels = parameters->channelCount;
-
-    PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) );
-
-    snd_pcm_hw_params_any( pcm, hwParams );
-
-    if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 )
-    {
-        result = paInvalidSampleRate;
-        goto error;
-    }
-
-    if( snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 )
-    {
-        result = paInvalidChannelCount;
-        goto error;
-    }
-
-    /* See if we can find a best possible match */
-    availableFormats = GetAvailableFormats( pcm );
-    PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );
-    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError );
-
-    ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );
-
-end:
-    if( pcm )
-        snd_pcm_close( pcm );
-    return result;
-
-error:
-    goto end;
-}
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate )
-{
-    int inputChannelCount = 0, outputChannelCount = 0;
-    PaSampleFormat inputSampleFormat, outputSampleFormat;
-    PaError result = paFormatIsSupported;
-
-    if( inputParameters )
-    {
-        PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
-
-        inputChannelCount = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-    }
-
-    if( outputParameters )
-    {
-        PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
-
-        outputChannelCount = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-    }
-
-    if( inputChannelCount )
-    {
-        if( (result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ))
-                != paNoError )
-            goto error;
-    }
-    if ( outputChannelCount )
-    {
-        if( (result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ))
-                != paNoError )
-            goto error;
-    }
-
-    return paFormatIsSupported;
-
-error:
-    return result;
-}
-
-static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi,
-        const PaStreamParameters *params, StreamDirection streamDir, int callbackMode )
-{
-    PaError result = paNoError;
-    PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat;
-    assert( params->channelCount > 0 );
-
-    /* Make sure things have an initial value */
-    memset( self, 0, sizeof (PaAlsaStreamComponent) );
-
-    if( NULL == params->hostApiSpecificStreamInfo )
-    {
-        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->commonHostApiRep, params->device );
-        self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels
-                : devInfo->minOutputChannels );
-    }
-    else
-    {
-        /* We're blissfully unaware of the minimum channelCount */
-        self->numHostChannels = params->channelCount;
-    }
-
-    PA_ENSURE( AlsaOpen( &alsaApi->commonHostApiRep, params, streamDir, &self->pcm ) );
-    self->nfds = snd_pcm_poll_descriptors_count( self->pcm );
-    hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat );
-
-    self->hostSampleFormat = hostSampleFormat;
-    self->nativeFormat = Pa2AlsaFormat( hostSampleFormat );
-    self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved);
-    self->numUserChannels = params->channelCount;
-    self->streamDir = streamDir;
-
-    if( !callbackMode && !self->userInterleaved )
-    {
-        /* Pre-allocate non-interleaved user provided buffers */
-        PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ),
-                paInsufficientMemory );
-    }
-
-error:
-    return result;
-}
-
-static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
-{
-    snd_pcm_close( self->pcm );
-    if( self->userBuffers )
-        PaUtil_FreeMemory( self->userBuffers );
-}
-
-/** Configure the associated ALSA pcm.
- *
- */
-static PaError PaAlsaStreamComponent_Configure( PaAlsaStreamComponent *self, const PaStreamParameters *params, unsigned long
-        framesPerHostBuffer, int primeBuffers, int callbackMode, double *sampleRate, PaTime *returnedLatency )
-{
-    /*
-    int numPeriods;
-
-    if( getenv("PA_NUMPERIODS") != NULL )
-        numPeriods = atoi( getenv("PA_NUMPERIODS") );
-    else
-        numPeriods = ( (latency * sampleRate) / *framesPerBuffer ) + 1;
-
-    PA_DEBUG(( "latency: %f, rate: %f, framesPerBuffer: %d\n", latency, sampleRate, *framesPerBuffer ));
-    if( numPeriods <= 1 )
-        numPeriods = 2;
-    */
-
-    /* Configuration consists of setting all of ALSA's parameters.
-     * These parameters come in two flavors: hardware parameters
-     * and software paramters.  Hardware parameters will affect
-     * the way the device is initialized, software parameters
-     * affect the way ALSA interacts with me, the user-level client.
-     */
-
-    snd_pcm_hw_params_t *hwParams;
-    snd_pcm_sw_params_t *swParams;
-    PaError result = paNoError;
-    snd_pcm_access_t accessMode, alternateAccessMode;
-    unsigned int numPeriods, minPeriods = 2;
-    int dir = 0;
-    snd_pcm_t *pcm = self->pcm;
-    PaTime latency = params->suggestedLatency;
-    double sr = *sampleRate;
-    *returnedLatency = -1.;
-
-    snd_pcm_hw_params_alloca( &hwParams );
-    snd_pcm_sw_params_alloca( &swParams );
-
-    self->framesPerBuffer = framesPerHostBuffer;
-
-    /* ... fill up the configuration space with all possibile
-     * combinations of parameters this device will accept */
-    ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
-
-    ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
-    ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );
-
-    if( self->userInterleaved )
-    {
-        accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
-        alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
-    }
-    else
-    {
-        accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
-        alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
-    }
-
-    /* If requested access mode fails, try alternate mode */
-    if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
-    {
-        ENSURE_( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ), paUnanticipatedHostError );
-        /* Flip mode */
-        self->hostInterleaved = !self->userInterleaved;
-    }
-
-    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );
-
-    ENSURE_( SetApproximateSampleRate( pcm, hwParams, sr ), paInvalidSampleRate );
-    ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError );
-    /* reject if there's no sample rate within 1% of the one requested */
-    if( (fabs( *sampleRate - sr ) / *sampleRate) > 0.01 )
-    {
-        PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));                 
-        PA_ENSURE( paInvalidSampleRate );
-    }
-
-    ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount );
-
-    /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */
-    dir = 0;
-    ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError );
-    dir = 0;
-    ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &self->framesPerBuffer, &dir ), paUnanticipatedHostError );
-    
-    /* Find an acceptable number of periods */
-    numPeriods = (latency * sr) / self->framesPerBuffer + 1;
-    dir = 0;
-    ENSURE_( snd_pcm_hw_params_set_periods_near( pcm, hwParams, &numPeriods, &dir ), paUnanticipatedHostError );
-    /* Minimum of periods should already be 2 */
-    PA_UNLESS( numPeriods >= 2, paInternalError );
-
-    /* Set the parameters! */
-    ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );
-    ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError );
-
-    /* Latency in seconds, one period is not counted as latency */
-    latency = (numPeriods - 1) * self->framesPerBuffer / sr;
-
-    /* Now software parameters... */
-    ENSURE_( snd_pcm_sw_params_current( pcm, swParams ), paUnanticipatedHostError );
-
-    ENSURE_( snd_pcm_sw_params_set_start_threshold( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
-    ENSURE_( snd_pcm_sw_params_set_stop_threshold( pcm, swParams, self->bufferSize ), paUnanticipatedHostError );
-
-    /* Silence buffer in the case of underrun */
-    if( !primeBuffers ) /* XXX: Make sense? */
-    {
-        snd_pcm_uframes_t boundary;
-        ENSURE_( snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_sw_params_set_silence_threshold( pcm, swParams, 0 ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_sw_params_set_silence_size( pcm, swParams, boundary ), paUnanticipatedHostError );
-    }
-        
-    ENSURE_( snd_pcm_sw_params_set_avail_min( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
-    ENSURE_( snd_pcm_sw_params_set_xfer_align( pcm, swParams, 1 ), paUnanticipatedHostError );
-    ENSURE_( snd_pcm_sw_params_set_tstamp_mode( pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError );
-
-    /* Set the parameters! */
-    ENSURE_( snd_pcm_sw_params( pcm, swParams ), paUnanticipatedHostError );
-
-    *sampleRate = sr;
-    *returnedLatency = latency;
-
-end:
-    return result;
-
-error:
-    goto end;   /* No particular action */
-}
-
-static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams,
-        const PaStreamParameters *outParams, double sampleRate, unsigned long framesPerUserBuffer, PaStreamCallback callback,
-        PaStreamFlags streamFlags, void *userData )
-{
-    PaError result = paNoError;
-    assert( self );
-
-    memset( self, 0, sizeof (PaAlsaStream) );
-
-    if( NULL != callback )
-    {
-        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
-                                               &alsaApi->callbackStreamInterface,
-                                               callback, userData );
-        self->callbackMode = 1;
-    }
-    else
-    {
-        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
-                                               &alsaApi->blockingStreamInterface,
-                                               NULL, userData );
-    }
-
-    self->framesPerUserBuffer = framesPerUserBuffer;
-    self->neverDropInput = streamFlags & paNeverDropInput;
-    /* XXX: Ignore paPrimeOutputBuffersUsingStreamCallback untill buffer priming is fully supported in pa_process.c */
-    /*
-    if( outParams & streamFlags & paPrimeOutputBuffersUsingStreamCallback )
-        self->primeBuffers = 1;
-        */
-    memset( &self->capture, 0, sizeof (PaAlsaStreamComponent) );
-    memset( &self->playback, 0, sizeof (PaAlsaStreamComponent) );
-    if( inParams )
-        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback ) );
-    if( outParams )
-        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->playback, alsaApi, outParams, StreamDirection_Out, NULL != callback ) );
-
-    assert( self->capture.nfds || self->playback.nfds );
-
-    PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( (self->capture.nfds +
-                    self->playback.nfds) * sizeof (struct pollfd) ), paInsufficientMemory );
-
-    PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate );
-    InitializeThreading( &self->threading, &self->cpuLoadMeasurer );
-    ASSERT_CALL_( pthread_mutex_init( &self->stateMtx, NULL ), 0 );
-    ASSERT_CALL_( pthread_mutex_init( &self->startMtx, NULL ), 0 );
-    ASSERT_CALL_( pthread_cond_init( &self->startCond, NULL ), 0 );
-
-error:
-    return result;
-}
-
-/** Free resources associated with stream, and eventually stream itself.
- *
- * Frees allocated memory, and terminates individual StreamComponents.
- */
-static void PaAlsaStream_Terminate( PaAlsaStream *self )
-{
-    assert( self );
-
-    if( self->capture.pcm )
-    {
-        PaAlsaStreamComponent_Terminate( &self->capture );
-    }
-    if( self->playback.pcm )
-    {
-        PaAlsaStreamComponent_Terminate( &self->playback );
-    }
-
-    PaUtil_FreeMemory( self->pfds );
-    ASSERT_CALL_( pthread_mutex_destroy( &self->stateMtx ), 0 );
-    ASSERT_CALL_( pthread_mutex_destroy( &self->startMtx ), 0 );
-    ASSERT_CALL_( pthread_cond_destroy( &self->startCond ), 0 );
-
-    PaUtil_FreeMemory( self );
-}
-
-/** Calculate polling timeout
- *
- * @param frames Time to wait
- * @return Polling timeout in milliseconds
- */
-static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frames )
-{
-    assert( stream->streamRepresentation.streamInfo.sampleRate > 0.0 );
-    /* Period in msecs, rounded up */
-    return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate );
-}
-
-/** Set up ALSA stream parameters.
- *
- */
-static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters
-        *outParams, double sampleRate, unsigned long framesPerHostBuffer, double *inputLatency, double *outputLatency,
-        unsigned long *maxHostBufferSize )
-{
-    PaError result = paNoError;
-    double realSr = sampleRate;
-
-    if( self->capture.pcm )
-        PA_ENSURE( PaAlsaStreamComponent_Configure( &self->capture, inParams, framesPerHostBuffer, self->primeBuffers,
-                    self->callbackMode, &realSr, inputLatency ) );
-    if( self->playback.pcm )
-        PA_ENSURE( PaAlsaStreamComponent_Configure( &self->playback, outParams, framesPerHostBuffer, self->primeBuffers,
-                    self->callbackMode, &realSr, outputLatency ) );
-
-    /* Should be exact now */
-    self->streamRepresentation.streamInfo.sampleRate = realSr;
-
-    /* this will cause the two streams to automatically start/stop/prepare in sync.
-     * We only need to execute these operations on one of the pair.
-     * A: We don't want to do this on a blocking stream.
-     */
-    if( self->callbackMode && self->capture.pcm && self->playback.pcm )
-    {
-        int err = snd_pcm_link( self->capture.pcm, self->playback.pcm );
-        if( err >= 0 )
-            self->pcmsSynced = 1;
-        else
-            PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, snd_strerror( err ) ));
-    }
-
-    /* Frames per host buffer for the stream is set as a compromise between the two directions */
-    framesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX,
-            self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX );
-    self->pollTimeout = CalculatePollTimeout( self, framesPerHostBuffer );    /* Period in msecs, rounded up */
-
-    *maxHostBufferSize = PA_MAX( self->capture.pcm ? self->capture.bufferSize : 0,
-            self->playback.pcm ? self->playback.bufferSize : 0 );
-
-    /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */
-    self->threading.throttledSleepTime = (unsigned long) (framesPerHostBuffer / sampleRate / 4 * 1000);
-
-    if( self->callbackMode )
-    {
-        /* If the user expects a certain number of frames per callback we will either have to rely on block adaption
-         * (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number
-         * of host buffer frames with what the user specified */
-        if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )
-        {
-            /* self->alignFrames = 1; */
-
-            /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely
-             * on block adaption */
-        /*
-            if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm &&
-                        self->capture.framesPerBuffer != self->playback.framesPerBuffer) )
-                self->useBlockAdaption = 1;
-            else
-                self->alignFrames = 1;
-        */
-        }
-    }
-
-error:
-    return result;
-}
-
-/* We need to determine how many frames per host buffer to use.  Our
- * goals are to provide the best possible performance, but also to
- * most closely honor the requested latency settings.  Therefore this
- * decision is based on:
- *
- *   - the period sizes that playback and/or capture support.  The
- *     host buffer size has to be one of these.
- *   - the number of periods that playback and/or capture support.
- *
- * We want to make period_size*(num_periods-1) to be as close as possible
- * to latency*rate for both playback and capture.
- *
- * This is one of those blocks of code that will just take a lot of
- * refinement to be any good.
- *
- * In the full-duplex case it is possible that the routine was unable
- * to find a number of frames per buffer acceptable to both devices
- * TODO: Implement an algorithm to find the value closest to acceptance
- * by both devices, to minimize difference between period sizes?
- */
-static PaError DetermineFramesPerBuffer( const PaAlsaStream *stream, double sampleRate, const PaStreamParameters *inputParameters,
-        const PaStreamParameters *outputParameters, unsigned long *determinedFrames, const PaUtilHostApiRepresentation *hostApi )
-{
-    PaError result = paNoError;
-    unsigned long framesPerBuffer = 0;
-    int numHostInputChannels = 0, numHostOutputChannels = 0;
-
-    /* XXX: Clean this up */
-    if( stream->capture.pcm )
-    {
-        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, inputParameters->device );
-        numHostInputChannels = PA_MAX( inputParameters->channelCount, devInfo->minInputChannels );
-    }
-    if( stream->playback.pcm )
-    {
-        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, outputParameters->device );
-        numHostOutputChannels = PA_MAX( outputParameters->channelCount, devInfo->minOutputChannels );
-    }
-
-    if( stream->capture.pcm && stream->playback.pcm )
-    {
-        snd_pcm_uframes_t desiredLatency, e;
-        snd_pcm_uframes_t minPeriodSize, minPlayback, minCapture, maxPeriodSize, maxPlayback, maxCapture,
-                          optimalPeriodSize, periodSize;
-        int dir = 0;
-        unsigned int minPeriods = 2;
-
-        snd_pcm_t *pcm;
-        snd_pcm_hw_params_t *hwParamsPlayback, *hwParamsCapture;
-
-        snd_pcm_hw_params_alloca( &hwParamsPlayback );
-        snd_pcm_hw_params_alloca( &hwParamsCapture );
-
-        /* Come up with a common desired latency */
-        pcm = stream->playback.pcm;
-        snd_pcm_hw_params_any( pcm, hwParamsPlayback );
-        ENSURE_( SetApproximateSampleRate( pcm, hwParamsPlayback, sampleRate ), paInvalidSampleRate );
-        ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsPlayback, numHostOutputChannels ),
-                paBadIODeviceCombination );
-
-        ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsPlayback, &minPeriods, &dir ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );
-
-        pcm = stream->capture.pcm;
-        ENSURE_( snd_pcm_hw_params_any( pcm, hwParamsCapture ), paUnanticipatedHostError );
-        ENSURE_( SetApproximateSampleRate( pcm, hwParamsCapture, sampleRate ), paBadIODeviceCombination );
-        ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsCapture, numHostInputChannels ),
-                paBadIODeviceCombination );
-
-        ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsCapture, &minPeriods, &dir ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );
-
-        minPeriodSize = PA_MAX( minPlayback, minCapture );
-        maxPeriodSize = PA_MIN( maxPlayback, maxCapture );
-
-        desiredLatency = (snd_pcm_uframes_t) (PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )
-                * sampleRate);
-        /* Clamp desiredLatency */
-        {
-            snd_pcm_uframes_t tmp, maxBufferSize = ULONG_MAX;
-            ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSize ), paUnanticipatedHostError );
-            ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &tmp ), paUnanticipatedHostError );
-            maxBufferSize = PA_MIN( maxBufferSize, tmp );
-
-            desiredLatency = PA_MIN( desiredLatency, maxBufferSize );
-        }
-
-        /* Find the closest power of 2 */
-        e = ilogb( minPeriodSize );
-        if( minPeriodSize & (minPeriodSize - 1) )
-            e += 1;
-        periodSize = (snd_pcm_uframes_t) pow( 2, e );
-
-        while( periodSize <= maxPeriodSize )
-        {
-            if( snd_pcm_hw_params_test_period_size( stream->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&
-                    snd_pcm_hw_params_test_period_size( stream->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )
-                break;  /* Ok! */
-
-            periodSize *= 2;
-        }
-
-        /* 4 periods considered optimal */
-        optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
-        optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
-
-        /* Find the closest power of 2 */
-        e = ilogb( optimalPeriodSize );
-        if( optimalPeriodSize & (optimalPeriodSize - 1) )
-            e += 1;
-        optimalPeriodSize = (snd_pcm_uframes_t) pow( 2, e );
-
-        while( optimalPeriodSize >= periodSize )
-        {
-            pcm = stream->playback.pcm;
-            if( snd_pcm_hw_params_test_period_size( pcm, hwParamsPlayback, optimalPeriodSize, 0 ) < 0 )
-                continue;
-
-            pcm = stream->capture.pcm;
-            if( snd_pcm_hw_params_test_period_size( pcm, hwParamsCapture, optimalPeriodSize, 0 ) >= 0 )
-                break;
-
-            optimalPeriodSize /= 2;
-        }
-
-        if( optimalPeriodSize > periodSize )
-            periodSize = optimalPeriodSize;
-
-        if( periodSize <= maxPeriodSize )
-        {
-            /* Looks good */
-            framesPerBuffer = periodSize;
-        }
-        else
-        {
-            /* Unable to find a common period size, oh well */
-            optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
-            optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
-
-            /* ConfigureStream should find individual period sizes acceptable for each device */
-            framesPerBuffer = optimalPeriodSize;
-            /* PA_ENSURE( paBadIODeviceCombination ); */
-        }
-    }
-    else    /* half-duplex is a slightly simpler case */
-    {
-        unsigned long bufferSize, channels;
-        snd_pcm_t *pcm;
-        snd_pcm_hw_params_t *hwParams;
-
-        snd_pcm_hw_params_alloca( &hwParams );
-
-        if( stream->capture.pcm )
-        {
-            pcm = stream->capture.pcm;
-            bufferSize = inputParameters->suggestedLatency * sampleRate;
-            channels = numHostInputChannels;
-        }
-        else
-        {
-            pcm = stream->playback.pcm;
-            bufferSize = outputParameters->suggestedLatency * sampleRate;
-            channels = numHostOutputChannels;
-        }
-
-        ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
-        ENSURE_( SetApproximateSampleRate( pcm, hwParams, sampleRate ), paInvalidSampleRate );
-        ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, channels ), paBadIODeviceCombination );
-
-        ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
-
-        /* Using 5 as a base number of periods, we try to approximate the suggested latency (+1 period),
-           finding a combination of period/buffer size which best fits these constraints */
-        framesPerBuffer = bufferSize / 4;
-        bufferSize += framesPerBuffer;   /* One period doesn't count as latency */
-        ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &bufferSize ), paUnanticipatedHostError );
-        ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &framesPerBuffer, NULL ), paUnanticipatedHostError );
-    }
-
-    PA_UNLESS( framesPerBuffer != 0, paInternalError );
-    *determinedFrames = framesPerBuffer;
-
-error:
-    return result;
-}
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** s,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *callback,
-                           void *userData )
-{
-    PaError result = paNoError;
-    PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
-    PaAlsaStream *stream = NULL;
-    PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0;
-    PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;
-    int numInputChannels = 0, numOutputChannels = 0;
-    PaTime inputLatency, outputLatency;
-    unsigned long framesPerHostBuffer;
-    PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilBoundedHostBufferSize;
-    unsigned long maxHostBufferSize;    /* Upper bound of host buffer size */
-
-    if( (streamFlags & paPlatformSpecificFlags) != 0 )
-        return paInvalidFlag;
-
-    if( inputParameters )
-    {
-        PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
-
-        numInputChannels = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-    }
-    if( outputParameters )
-    {
-        PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
-
-        numOutputChannels = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-    }
-
-    /* XXX: Why do we support this anyway? */
-    if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL )
-    {
-        PA_DEBUG(( "%s: Getting framesPerBuffer from environment\n", __FUNCTION__ ));
-        framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") );
-    }
-    framesPerHostBuffer = framesPerBuffer;
-
-    PA_UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory );
-    PA_ENSURE( PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate,
-                framesPerBuffer, callback, streamFlags, userData ) );
-
-    /* If the number of frames per buffer is unspecified, we have to come up with
-     * one. This is both a blessing and a curse: a blessing because we can optimize
-     * the number to best meet the requirements, but a curse because that's really
-     * hard to do well. For this reason we also support an interface where the user
-     * specifies these by setting environment variables. */
-    if( framesPerBuffer == paFramesPerBufferUnspecified )
-    {
-        PA_ENSURE( DetermineFramesPerBuffer( stream, sampleRate, inputParameters, outputParameters, &framesPerHostBuffer,
-                    hostApi ) );
-    }
-
-    PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerHostBuffer,
-                &inputLatency, &outputLatency, &maxHostBufferSize ) );
-    hostInputSampleFormat = stream->capture.hostSampleFormat;
-    hostOutputSampleFormat = stream->playback.hostSampleFormat;
-
-    if( framesPerHostBuffer != framesPerBuffer )
-    {
-        PA_DEBUG(( "%s: Number of frames per user and host buffer differs\n", __FUNCTION__ ));
-    }
-
-    PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
-                    numInputChannels, inputSampleFormat, hostInputSampleFormat,
-                    numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
-                    sampleRate, streamFlags, framesPerBuffer, maxHostBufferSize,
-                    hostBufferSizeMode, callback, userData ) );
-
-    /* Ok, buffer processor is initialized, now we can deduce it's latency */
-    if( numInputChannels > 0 )
-        stream->streamRepresentation.streamInfo.inputLatency = inputLatency + PaUtil_GetBufferProcessorInputLatency(
-                &stream->bufferProcessor );
-    if( numOutputChannels > 0 )
-        stream->streamRepresentation.streamInfo.outputLatency = outputLatency + PaUtil_GetBufferProcessorOutputLatency(
-                &stream->bufferProcessor );
-
-    *s = (PaStream*)stream;
-
-    return result;
-
-error:
-    if( stream )
-        PaAlsaStream_Terminate( stream );
-
-    return result;
-}
-
-static PaError CloseStream( PaStream* s )
-{
-    PaError result = paNoError;
-    PaAlsaStream *stream = (PaAlsaStream*)s;
-
-    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
-    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-
-    PaAlsaStream_Terminate( stream );
-
-    return result;
-}
-
-static void SilenceBuffer( PaAlsaStream *stream )
-{
-    const snd_pcm_channel_area_t *areas;
-    snd_pcm_uframes_t frames = (snd_pcm_uframes_t)snd_pcm_avail_update( stream->playback.pcm ), offset;
-
-    snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames );
-    snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat );
-    snd_pcm_mmap_commit( stream->playback.pcm, offset, frames );
-}
-
-/** Start/prepare pcm(s) for streaming.
- *
- * Depending on wether the stream is in callback or blocking mode, we will respectively start or simply
- * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and
- * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will
- * be started automatically as the user writes to output. 
- *
- * The capture pcm, however, will simply be prepared and started.
- *
- * PaAlsaStream::startMtx makes sure access is synchronized (useful in callback mode)
- */
-static PaError AlsaStart( PaAlsaStream *stream, int priming )
-{
-    PaError result = paNoError;
-
-    if( stream->playback.pcm )
-    {
-        if( stream->callbackMode )
-        {
-            if( !priming )
-            {
-                /* Buffer isn't primed, so prepare and silence */
-                ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
-                SilenceBuffer( stream );
-            }
-            ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
-        }
-        else
-            ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
-    }
-    if( stream->capture.pcm && !stream->pcmsSynced )
-    {
-        ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
-        /* For a blocking stream we want to start capture as well, since nothing will happen otherwise */
-        ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
-    }
-
-end:
-    return result;
-error:
-    goto end;
-}
-
-/** Utility function for determining if pcms are in running state.
- *
- */
-static int IsRunning( PaAlsaStream *stream )
-{
-    int result = 0;
-
-    ASSERT_CALL_( pthread_mutex_lock( &stream->stateMtx ), 0 ); /* Synchronize access to pcm state */
-    if( stream->capture.pcm )
-    {
-        snd_pcm_state_t capture_state = snd_pcm_state( stream->capture.pcm );
-
-        if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN
-                || capture_state == SND_PCM_STATE_DRAINING )
-        {
-            result = 1;
-            goto end;
-        }
-    }
-
-    if( stream->playback.pcm )
-    {
-        snd_pcm_state_t playback_state = snd_pcm_state( stream->playback.pcm );
-
-        if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN
-                || playback_state == SND_PCM_STATE_DRAINING )
-        {
-            result = 1;
-            goto end;
-        }
-    }
-
-end:
-    ASSERT_CALL_( pthread_mutex_unlock( &stream->stateMtx ), 0 );
-
-    return result;
-}
-
-static PaError StartStream( PaStream *s )
-{
-    PaError result = paNoError;
-    PaAlsaStream *stream = (PaAlsaStream*)s;
-    int streamStarted = 0;  /* So we can know wether we need to take the stream down */
-
-    /* Ready the processor */
-    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
-
-    /* Set now, so we can test for activity further down */
-    stream->isActive = 1;
-
-    if( stream->callbackMode )
-    {
-        int res = 0;
-        PaTime pt = PaUtil_GetTime();
-        struct timespec ts;
-
-        PA_ENSURE( CreateCallbackThread( &stream->threading, &CallbackThreadFunc, stream ) );
-        streamStarted = 1;
-
-        /* Wait for stream to be started */
-        ts.tv_sec = (time_t) floor( pt + 1 );
-        ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000);
-
-        /* Since we'll be holding a lock on the startMtx (when not waiting on the condition), IsRunning won't be checking
-         * stream state at the same time as the callback thread affects it. We also check IsStreamActive, in the unlikely
-         * case the callback thread exits in the meantime (the stream will be considered inactive after the thread exits) */
-        ASSERT_CALL_( pthread_mutex_lock( &stream->startMtx ), 0 );
-
-        /* Due to possible spurious wakeups, we enclose in a loop */
-        while( !IsRunning( stream ) && IsStreamActive( s ) && !res )
-        {
-            res = pthread_cond_timedwait( &stream->startCond, &stream->startMtx, &ts );
-        }
-        ASSERT_CALL_( pthread_mutex_unlock( &stream->startMtx ), 0 );
-
-        PA_UNLESS( !res || res == ETIMEDOUT, paInternalError );
-        PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - pt ));
-
-        if( res == ETIMEDOUT )
-        {
-            PA_ENSURE( paTimedOut );
-        }
-    }
-    else
-    {
-        PA_ENSURE( AlsaStart( stream, 0 ) );
-        streamStarted = 1;
-    }
-
-end:
-    return result;
-error:
-    if( streamStarted )
-        AbortStream( stream );
-    stream->isActive = 0;
-    
-    goto end;
-}
-
-static PaError AlsaStop( PaAlsaStream *stream, int abort )
-{
-    PaError result = paNoError;
-
-    if( abort )
-    {
-        if( stream->playback.pcm )
-            ENSURE_( snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError );
-        if( stream->capture.pcm && !stream->pcmsSynced )
-            ENSURE_( snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError );
-
-        PA_DEBUG(( "Dropped frames\n" ));
-    }
-    else
-    {
-        if( stream->playback.pcm )
-            ENSURE_( snd_pcm_drain( stream->playback.pcm ), paUnanticipatedHostError );
-        if( stream->capture.pcm && !stream->pcmsSynced )
-            ENSURE_( snd_pcm_drain( stream->capture.pcm ), paUnanticipatedHostError );
-    }
-
-end:
-    return result;
-error:
-    goto end;
-}
-
-/** Stop or abort stream.
- *
- * If a stream is in callback mode we will have to inspect wether the background thread has
- * finished, or we will have to take it out. In either case we join the thread before
- * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish
- * buffers (drain)
- *
- * Stream will be considered inactive (!PaAlsaStream::isActive) after a call to this function
- */
-static PaError RealStop( PaAlsaStream *stream, int abort )
-{
-    PaError result = paNoError;
-
-    /* First deal with the callback thread, cancelling and/or joining
-     * it if necessary
-     */
-    if( stream->callbackMode )
-    {
-        PaError threadRes, watchdogRes;
-        stream->callbackAbort = abort;
-
-        if( !abort )
-        {
-            PA_DEBUG(( "Stopping callback\n" ));
-            stream->callbackStop = 1;
-        }
-        PA_ENSURE( KillCallbackThread( &stream->threading, !abort, &threadRes, &watchdogRes ) );
-        if( threadRes != paNoError )
-            PA_DEBUG(( "Callback thread returned: %d\n", threadRes ));
-        if( watchdogRes != paNoError )
-            PA_DEBUG(( "Watchdog thread returned: %d\n", watchdogRes ));
-
-        stream->callbackStop = 0;   /* The deed is done */
-        stream->callback_finished = 0;
-    }
-    else
-    {
-        PA_ENSURE( AlsaStop( stream, abort ) );
-    }
-
-    stream->isActive = 0;
-
-end:
-    return result;
-
-error:
-    goto end;
-}
-
-static PaError StopStream( PaStream *s )
-{
-    return RealStop( (PaAlsaStream *) s, 0 );
-}
-
-static PaError AbortStream( PaStream *s )
-{
-    return RealStop( (PaAlsaStream * ) s, 1 );
-}
-
-/** The stream is considered stopped before StartStream, or AFTER a call to Abort/StopStream (callback
- * returning !paContinue is not considered)
- *
- */
-static PaError IsStreamStopped( PaStream *s )
-{
-    PaAlsaStream *stream = (PaAlsaStream *)s;
-
-    /* callback_finished indicates we need to join callback thread (ie. in Abort/StopStream) */
-    return !IsStreamActive( s ) && !stream->callback_finished;
-}
-
-static PaError IsStreamActive( PaStream *s )
-{
-    PaAlsaStream *stream = (PaAlsaStream*)s;
-    return stream->isActive;
-}
-
-static PaTime GetStreamTime( PaStream *s )
-{
-    PaAlsaStream *stream = (PaAlsaStream*)s;
-
-    snd_timestamp_t timestamp;
-    snd_pcm_status_t *status;
-    snd_pcm_status_alloca( &status );
-
-    /* TODO: what if we have both?  does it really matter? */
-
-    /* TODO: if running in callback mode, this will mean
-     * libasound routines are being called from multiple threads.
-     * need to verify that libasound is thread-safe. */
-
-    if( stream->capture.pcm )
-    {
-        snd_pcm_status( stream->capture.pcm, status );
-    }
-    else if( stream->playback.pcm )
-    {
-        snd_pcm_status( stream->playback.pcm, status );
-    }
-
-    snd_pcm_status_get_tstamp( status, &timestamp );
-    return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1000000.0;
-}
-
-static double GetStreamCpuLoad( PaStream* s )
-{
-    PaAlsaStream *stream = (PaAlsaStream*)s;
-
-    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate )
-{
-    unsigned long approx = (unsigned long) sampleRate;
-    int dir = 0;
-    double fraction = sampleRate - approx;
-
-    assert( pcm && hwParams );
-
-    if( fraction > 0.0 )
-    {
-        if( fraction > 0.5 )
-        {
-            ++approx;
-            dir = -1;
-        }
-        else
-            dir = 1;
-    }
-
-    return snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir );
-}
-
-/* Return exact sample rate in param sampleRate */
-static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate )
-{
-    unsigned int num, den;
-    int err; 
-
-    assert( hwParams );
-
-    err = snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den );
-    *sampleRate = (double) num / den;
-
-    return err;
-}
-
-/* Utility functions for blocking/callback interfaces */
-
-/* Atomic restart of stream (we don't want the intermediate state visible) */
-static PaError AlsaRestart( PaAlsaStream *stream )
-{
-    PaError result = paNoError;
-
-    ASSERT_CALL_( pthread_mutex_lock( &stream->stateMtx ), 0 );
-    PA_ENSURE( AlsaStop( stream, 0 ) );
-    PA_ENSURE( AlsaStart( stream, 0 ) );
-
-    PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ ));
-
-error:
-    ASSERT_CALL_( pthread_mutex_unlock( &stream->stateMtx ), 0 );
-    return result;
-}
-
-/** Recover from xrun state.
- *
- */
-static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self )
-{
-    PaError result = paNoError;
-    snd_pcm_status_t *st;
-    PaTime now = PaUtil_GetTime();
-    snd_timestamp_t t;
-
-    snd_pcm_status_alloca( &st );
-
-    if( self->playback.pcm )
-    {
-        snd_pcm_status( self->playback.pcm, st );
-        if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
-        {
-            snd_pcm_status_get_trigger_tstamp( st, &t );
-            self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
-        }
-    }
-    if( self->capture.pcm )
-    {
-        snd_pcm_status( self->capture.pcm, st );
-        if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
-        {
-            snd_pcm_status_get_trigger_tstamp( st, &t );
-            self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
-        }
-    }
-
-    PA_ENSURE( AlsaRestart( self ) );
-
-end:
-    return result;
-error:
-    goto end;
-}
-
-/** Decide if we should continue polling for specified direction, eventually adjust the poll timeout.
- * 
- */
-static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamDir, int *pollTimeout, int *continuePoll )
-{
-    PaError result = paNoError;
-    snd_pcm_sframes_t delay, margin;
-    int err;
-    const PaAlsaStreamComponent *component = NULL, *otherComponent = NULL;
-
-    *continuePoll = 1;
-
-    if( StreamDirection_In == streamDir )
-    {
-        component = &stream->capture;
-        otherComponent = &stream->playback;
-    }
-    else
-    {
-        component = &stream->playback;
-        otherComponent = &stream->capture;
-    }
-
-    /* ALSA docs say that negative delay should indicate xrun, but in my experience snd_pcm_delay returns -EPIPE */
-    if( (err = snd_pcm_delay( otherComponent->pcm, &delay )) < 0 )
-    {
-        if( err == -EPIPE )
-        {
-            /* Xrun */
-            *continuePoll = 0;
-            goto error;
-        }
-
-        ENSURE_( err, paUnanticipatedHostError );
-    }
-
-    if( StreamDirection_Out == streamDir )
-    {
-        /* Number of eligible frames before capture overrun */
-        delay = otherComponent->bufferSize - delay;
-    }
-    margin = delay - otherComponent->framesPerBuffer / 2;
-
-    if( margin < 0 )
-    {
-        PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" ));
-        *continuePoll = 0;
-    }
-    else if( margin < otherComponent->framesPerBuffer )
-    {
-        *pollTimeout = CalculatePollTimeout( stream, margin );
-        PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n",
-                    __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback", *pollTimeout ));
-    }
-
-error:
-    return result;
-}
-
-/* Callback interface */
-
-static void OnExit( void *data )
-{
-    PaAlsaStream *stream = (PaAlsaStream *) data;
-
-    assert( data );
-
-    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
-
-    stream->callback_finished = 1;  /* Let the outside world know stream was stopped in callback */
-    AlsaStop( stream, stream->callbackAbort );
-    stream->callbackAbort = 0;      /* Clear state */
-    
-    PA_DEBUG(( "OnExit: Stoppage\n" ));
-
-    /* Eventually notify user all buffers have played */
-    if( stream->streamRepresentation.streamFinishedCallback )
-        stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
-    stream->isActive = 0;
-}
-
-static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *timeInfo )
-{
-    snd_pcm_status_t *capture_status, *playback_status;
-    snd_timestamp_t capture_timestamp, playback_timestamp;
-    PaTime capture_time = 0., playback_time = 0.;
-
-    snd_pcm_status_alloca( &capture_status );
-    snd_pcm_status_alloca( &playback_status );
-
-    if( stream->capture.pcm )
-    {
-        snd_pcm_sframes_t capture_delay;
-
-        snd_pcm_status( stream->capture.pcm, capture_status );
-        snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
-
-        capture_time = capture_timestamp.tv_sec +
-            ((PaTime)capture_timestamp.tv_usec / 1000000.0);
-        timeInfo->currentTime = capture_time;
-
-        capture_delay = snd_pcm_status_get_delay( capture_status );
-        timeInfo->inputBufferAdcTime = timeInfo->currentTime -
-            (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
-    }
-    if( stream->playback.pcm )
-    {
-        snd_pcm_sframes_t playback_delay;
-
-        snd_pcm_status( stream->playback.pcm, playback_status );
-        snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
-
-        playback_time = playback_timestamp.tv_sec +
-            ((PaTime)playback_timestamp.tv_usec / 1000000.0);
-
-        if( stream->capture.pcm ) /* Full duplex */
-        {
-            /* Hmm, we have both a playback and a capture timestamp.
-             * Hopefully they are the same... */
-            if( fabs( capture_time - playback_time ) > 0.01 )
-                PA_DEBUG(("Capture time and playback time differ by %f\n", fabs(capture_time-playback_time)));
-        }
-        else
-            timeInfo->currentTime = playback_time;
-
-        playback_delay = snd_pcm_status_get_delay( playback_status );
-        timeInfo->outputBufferDacTime = timeInfo->currentTime +
-            (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
-    }
-}
-
-/** Called after buffer processing is finished.
- *
- * A number of mmapped frames is committed, it is possible that an xrun has occurred in the meantime.
- *
- * @param numFrames The number of frames that has been processed
- * @param xrun Return whether an xrun has occurred
- */
-static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun )
-{
-    PaError result = paNoError;
-    int res;
-
-    /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed
-     * afterwards
-     */
-    if( !self->ready )
-        goto end;
-
-    res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
-    if( res == -EPIPE || res == -ESTRPIPE )
-    {
-        *xrun = 1;
-    }
-    else
-    {
-        ENSURE_( res, paUnanticipatedHostError );
-    }
-
-end:
-error:
-    return result;
-}
-
-/* Extract buffer from channel area */
-static unsigned char *ExtractAddress( const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset )
-{
-    return (unsigned char *) area->addr + (area->first + offset * area->step) / 8;
-}
-
-/** Do necessary adaption between user and host channels.
- *
-    @concern ChannelAdaption Adapting between user and host channels can involve silencing unused channels and
-    duplicating mono information if host outputs come in pairs.
- */
-static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp, int numFrames )
-{
-    PaError result = paNoError;
-    unsigned char *p;
-    int i;
-    int unusedChans = self->numHostChannels - self->numUserChannels;
-    unsigned char *src, *dst;
-    int convertMono = (self->numHostChannels % 2) == 0 && (self->numUserChannels % 2) != 0;
-
-    assert( StreamDirection_Out == self->streamDir );
-
-    if( self->hostInterleaved )
-    {
-        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
-        unsigned char *buffer = ExtractAddress( self->channelAreas, self->offset );
-
-        /* Start after the last user channel */
-        p = buffer + self->numUserChannels * swidth;
-
-        if( convertMono )
-        {
-            /* Convert the last user channel into stereo pair */
-            src = buffer + (self->numUserChannels - 1) * swidth;
-            for( i = 0; i < numFrames; ++i )
-            {
-                dst = src + swidth;
-                memcpy( dst, src, swidth );
-                src += self->numHostChannels * swidth;
-            }
-
-            /* Don't touch the channel we just wrote to */
-            p += swidth;
-            --unusedChans;
-        }
-
-        if( unusedChans > 0 )
-        {
-            /* Silence unused output channels */
-            for( i = 0; i < numFrames; ++i )
-            {
-                memset( p, 0, swidth * unusedChans );
-                p += self->numHostChannels * swidth;
-            }
-        }
-    }
-    else
-    {
-        /* We extract the last user channel */
-        if( convertMono )
-        {
-            ENSURE_( snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas +
-                    (self->numUserChannels - 1), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError );
-            --unusedChans;
-        }
-        if( unusedChans > 0 )
-        {
-            snd_pcm_areas_silence( self->channelAreas + (self->numHostChannels - unusedChans), self->offset, unusedChans, numFrames,
-                    self->nativeFormat );
-        }
-    }
-
-error:
-    return result;
-}
-
-static PaError PaAlsaStream_EndProcessing( PaAlsaStream *self, unsigned long numFrames, int *xrunOccurred )
-{
-    PaError result = paNoError;
-    int xrun = 0;
-
-    if( self->capture.pcm )
-    {
-        PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->capture, numFrames, &xrun ) );
-    }
-    if( self->playback.pcm )
-    {
-        if( self->playback.numHostChannels > self->playback.numUserChannels )
-            PA_ENSURE( PaAlsaStreamComponent_DoChannelAdaption( &self->playback, &self->bufferProcessor, numFrames ) );
-        PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->playback, numFrames, &xrun ) );
-    }
-
-error:
-    *xrunOccurred = xrun;
-    return result;
-}
-
-/** Update the number of available frames.
- *
- */
-static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *self, unsigned long *numFrames, int *xrunOccurred )
-{
-    PaError result = paNoError;
-    snd_pcm_sframes_t framesAvail = snd_pcm_avail_update( self->pcm );
-    *xrunOccurred = 0;
-
-    if( -EPIPE == framesAvail )
-    {
-        *xrunOccurred = 1;
-        framesAvail = 0;
-    }
-    else
-        ENSURE_( framesAvail, paUnanticipatedHostError );
-
-    *numFrames = framesAvail;
-
-error:
-    return result;
-}
-
-/** Fill in pollfd objects.
- */
-static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent *self, struct pollfd *pfds )
-{
-    PaError result = paNoError;
-    int ret = snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds );
-    assert( ret == self->nfds );
-
-    self->ready = 0;
-
-    return result;
-}
-
-/** Examine results from poll().
- *
- * @param pfds pollfds to inspect
- * @param shouldPoll Should we continue to poll
- * @param xrun Has an xrun occurred
- */
-static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent *self, struct pollfd *pfds, int *shouldPoll, int *xrun )
-{
-    PaError result = paNoError;
-    unsigned short revents;
-
-    ENSURE_( snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError );
-    if( revents != 0 )
-    {
-        if( revents & POLLERR )
-        {
-            *xrun = 1;
-        }
-        else
-            self->ready = 1;
-
-        *shouldPoll = 0;
-    }
-
-error:
-    return result;
-}
-
-/** Return the number of available frames for this stream.
- *
- * @concern FullDuplex The minimum available for the two directions is calculated, it might be desirable to ignore
- * one direction however (not marked ready from poll), so this is controlled by queryCapture and queryPlayback.
- *
- * @param queryCapture Check available for capture
- * @param queryPlayback Check available for playback
- * @param available The returned number of frames
- * @param xrunOccurred Return whether an xrun has occurred
- */
-static PaError PaAlsaStream_GetAvailableFrames( PaAlsaStream *self, int queryCapture, int queryPlayback, unsigned long
-        *available, int *xrunOccurred )
-{
-    PaError result = paNoError;
-    unsigned long captureFrames, playbackFrames;
-    *xrunOccurred = 0;
-
-    assert( queryCapture || queryPlayback );
-
-    if( queryCapture )
-    {
-        assert( self->capture.pcm );
-        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->capture, &captureFrames, xrunOccurred ) );
-        if( *xrunOccurred )
-            goto end;
-    }
-    if( queryPlayback )
-    {
-        assert( self->playback.pcm );
-        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->playback, &playbackFrames, xrunOccurred ) );
-        if( *xrunOccurred )
-            goto end;
-    }
-
-    if( queryCapture && queryPlayback )
-    {
-        *available = PA_MIN( captureFrames, playbackFrames );
-    }
-    else if( queryCapture )
-    {
-        *available = captureFrames;
-    }
-    else
-    {
-        *available = playbackFrames;
-    }
-
-end:
-error:
-    return result;
-}
-
-/** Wait for and report available buffer space from ALSA.
- *
- * Unless ALSA reports a minimum of frames available for I/O, we poll the ALSA filedescriptors for more.
- * Both of these operations can uncover xrun conditions.
- *
- * @concern Xruns Both polling and querying available frames can report an xrun condition.
- *
- * @param framesAvail Return the number of available frames
- * @param xrunOccurred Return whether an xrun has occurred
- */ 
-static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *framesAvail, int *xrunOccurred )
-{
-    PaError result = paNoError;
-    int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL;
-    int pollTimeout = self->pollTimeout;
-    int xrun = 0;
-
-    assert( self );
-    assert( framesAvail );
-
-    if( !self->callbackMode )
-    {
-        /* In blocking mode we will only wait if necessary */
-        PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, self->capture.pcm != NULL, self->playback.pcm != NULL,
-                    framesAvail, &xrun ) );
-        if( xrun )
-        {
-            goto end;
-        }
-
-        if( *framesAvail > 0 )
-        {
-            /* Mark pcms ready from poll */
-            if( self->capture.pcm )
-                self->capture.ready = 1;
-            if( self->playback.pcm )
-                self->playback.ready = 1;
-
-            goto end;
-        }
-    }
-
-    while( pollPlayback || pollCapture )
-    {
-        int totalFds = 0;
-        struct pollfd *capturePfds = NULL, *playbackPfds = NULL;
-
-        pthread_testcancel();
-
-        if( pollCapture )
-        {
-            capturePfds = self->pfds;
-            PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->capture, capturePfds ) );
-            totalFds += self->capture.nfds;
-        }
-        if( pollPlayback )
-        {
-            playbackPfds = self->pfds + (self->capture.pcm ? self->capture.nfds : 0);
-            PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) );
-            totalFds += self->playback.nfds;
-        }
-
-        if( poll( self->pfds, totalFds, pollTimeout ) < 0 )
-        {
-            /*  XXX: Depend on preprocessor condition? */
-            if( errno == EINTR ) {  /* gdb */
-                continue;
-            }
-
-            /* TODO: Add macro for checking system calls */
-            PA_ENSURE( paInternalError );
-        }
-
-        /* check the return status of our pfds */
-        if( pollCapture )
-        {
-            PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->capture, capturePfds, &pollCapture, &xrun ) );
-        }
-        if( pollPlayback )
-        {
-            PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->playback, playbackPfds, &pollPlayback, &xrun ) );
-        }
-        if( xrun )
-        {
-            break;
-        }
-
-        /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two.
-         * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will
-         * stop polling.
-         */
-        if( self->capture.pcm && self->playback.pcm )
-        {
-            if( pollCapture && !pollPlayback )
-            {
-                PA_ENSURE( ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture ) );
-            }
-            else if( pollPlayback && !pollCapture )
-            {
-                PA_ENSURE( ContinuePoll( self, StreamDirection_Out, &pollTimeout, &pollPlayback ) );
-            }
-        }
-    }
-
-    if( !xrun )
-    {
-        /* Get the number of available frames for the pcms that are marked ready.
-         * @concern FullDuplex If only one direction is marked ready (from poll), the number of frames available for
-         * the other direction is returned. This under the assumption that input is dropped earlier if paNeverDropInput
-         * is not specified.
-         */
-        int captureReady = self->capture.pcm ? self->capture.ready : 0,
-            playbackReady = self->playback.pcm ? self->playback.ready : 0;
-        PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, captureReady, playbackReady, framesAvail, &xrun ) );
-
-        if( self->capture.pcm && self->playback.pcm )
-        {
-            if( !self->playback.ready && !self->neverDropInput )
-            {
-                /* TODO: Drop input */
-            }
-        }
-    }
-
-end:
-error:
-    if( xrun )
-    {
-        /* Recover from the xrun state */
-        PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
-        *framesAvail = 0;
-    }
-    *xrunOccurred = xrun;
-
-    return result;
-}
-
-/** Register per-channel ALSA buffer information with buffer processor.
- *
- * Mmapped buffer space is acquired from ALSA, and registered with the buffer processor. Differences between the
- * number of host and user channels is taken into account.
- * 
- * @param numFrames On entrance the number of requested frames, on exit the number of contiguously accessible frames.
- */
-static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp,
-        unsigned long *numFrames, int *xrun )
-{
-    PaError result = paNoError;
-    const snd_pcm_channel_area_t *areas, *area;
-    void (*setChannel)(PaUtilBufferProcessor *, unsigned int, void *, unsigned int) =
-        StreamDirection_In == self->streamDir ? PaUtil_SetInputChannel : PaUtil_SetOutputChannel;
-    unsigned char *buffer, *p;
-    int i;
-    unsigned long framesAvail;
-
-    /* This _must_ be called before mmap_begin */
-    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( self, &framesAvail, xrun ) );
-    if( *xrun )
-    {
-        *numFrames = 0;
-        goto end;
-    }
-
-    ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );
-
-    if( self->hostInterleaved )
-    {
-        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
-
-        p = buffer = ExtractAddress( areas, self->offset );
-        for( i = 0; i < self->numUserChannels; ++i )
-        {
-            /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */
-            setChannel( bp, i, p, self->numHostChannels );
-            p += swidth;
-        }
-    }
-    else
-    {
-        for( i = 0; i < self->numUserChannels; ++i )
-        {
-            area = areas + i;
-            buffer = ExtractAddress( area, self->offset );
-            setChannel( bp, i, buffer, 1 );
-        }
-    }
-
-    /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */
-    self->channelAreas = (snd_pcm_channel_area_t *)areas;
-
-end:
-error:
-    return result;
-}
-
-/** Initiate buffer processing.
- *
- * ALSA buffers are registered with the PA buffer processor and the buffer size (in frames) set.
- *
- * @concern FullDuplex If both directions are being processed, the minimum amount of frames for the two directions is
- * calculated.
- *
- * @param numFrames On entrance the number of available frames, on exit the number of received frames
- * @param xrunOccurred Return whether an xrun has occurred
- */
-static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream *self, unsigned long *numFrames, int *xrunOccurred )
-{
-    PaError result = paNoError;
-    unsigned long captureFrames = ULONG_MAX, playbackFrames = ULONG_MAX, commonFrames = 0;
-    int xrun = 0;
-
-    /* Extract per-channel ALSA buffer pointers and register them with the buffer processor.
-     * It is possible that a direction is not marked ready however, because it is out of sync with the other.
-     */
-    if( self->capture.pcm && self->capture.ready )
-    {
-        captureFrames = *numFrames;
-        PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->capture, &self->bufferProcessor, &captureFrames, 
-                    &xrun ) );
-    }
-    if( self->playback.pcm && self->playback.ready )
-    {
-        playbackFrames = *numFrames;
-        PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->playback, &self->bufferProcessor, &playbackFrames, 
-                    &xrun ) );
-    }
-    if( xrun )
-    {
-        /* Nothing more to do */
-        assert( 0 == commonFrames );
-        goto end;
-    }
-
-    commonFrames = PA_MIN( captureFrames, playbackFrames );
-    assert( commonFrames <= *numFrames );
-
-    /* Inform PortAudio of the number of frames we got.
-     * @concern FullDuplex We might be experiencing underflow in either end; if its an input underflow, we go on
-     * with output. If its output underflow however, depending on the paNeverDropInput flag, we may want to simply
-     * discard the excess input or call the callback with paOutputOverflow flagged.
-     */
-    if( self->capture.pcm )
-    {
-        if( self->capture.ready )
-        {
-            PaUtil_SetInputFrameCount( &self->bufferProcessor, commonFrames );
-        }
-        else
-        {
-            /* We have input underflow */
-            PaUtil_SetNoInput( &self->bufferProcessor );
-        }
-    }
-    if( self->playback.pcm )
-    {
-        if( self->playback.ready )
-        {
-            PaUtil_SetOutputFrameCount( &self->bufferProcessor, commonFrames );
-        }
-        else
-        {
-            /* We have output underflow, but keeping input data (paNeverDropInput) */
-            /* assert( self->neverDropInput ); */
-            PaUtil_SetNoOutput( &self->bufferProcessor );
-        }
-    }
-    
-end:
-    *numFrames = commonFrames;
-error:
-    if( xrun )
-    {
-        PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
-        *numFrames = 0;
-    }
-    *xrunOccurred = xrun;
-
-    return result;
-}
-
-/** Callback thread's function.
- *
- * Roughly, the workflow can be described in the following way: The number of available frames that can be processed
- * directly is obtained from ALSA, we then request as much directly accessible memory as possible within this amount
- * from ALSA. The buffer memory is registered with the PA buffer processor and processing is carried out with
- * PaUtil_EndBufferProcessing. Finally, the number of processed frames is reported to ALSA. The processing can
- * happen in several iterations untill we have consumed the known number of available frames (or an xrun is detected).
- */
-static void *CallbackThreadFunc( void *userData )
-{
-    PaError result = paNoError, *pres = NULL;
-    PaAlsaStream *stream = (PaAlsaStream*) userData;
-    PaStreamCallbackTimeInfo timeInfo = {0, 0, 0};
-    snd_pcm_sframes_t startThreshold = 0;
-    int callbackResult = paContinue;
-    PaStreamCallbackFlags cbFlags = 0;  /* We might want to keep state across iterations */
-    int streamStarted = 0;
-
-    assert( stream );
-
-    callbackThread_ = pthread_self();
-    /* Execute OnExit when exiting */
-    pthread_cleanup_push( &OnExit, stream );
-
-    /* Not implemented */
-    assert( !stream->primeBuffers );
-
-    /* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the
-     * stream is started immediately. The latter involves signaling the waiting main thread.
-     */
-    if( stream->primeBuffers )
-    {
-        snd_pcm_sframes_t avail;
-        
-        if( stream->playback.pcm )
-            ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
-        if( stream->capture.pcm && !stream->pcmsSynced )
-            ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
-
-        /* We can't be certain that the whole ring buffer is available for priming, but there should be
-         * at least one period */
-        avail = snd_pcm_avail_update( stream->playback.pcm );
-        startThreshold = avail - (avail % stream->playback.framesPerBuffer);
-        assert( startThreshold >= stream->playback.framesPerBuffer );
-    }
-    else
-    {
-        ASSERT_CALL_( pthread_mutex_lock( &stream->startMtx ), 0 );
-        PA_ENSURE( AlsaStart( stream, 0 ) );    /* Buffer will be zeroed */
-        ASSERT_CALL_( pthread_cond_signal( &stream->startCond ), 0 );
-        ASSERT_CALL_( pthread_mutex_unlock( &stream->startMtx ), 0 );
-
-        streamStarted = 1;
-    }
-
-    while( 1 )
-    {
-        unsigned long framesAvail, framesGot;
-        int xrun = 0;
-
-        pthread_testcancel();
-
-        /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively
-         * stopped we signal this condition by modifying callbackResult (we'll want to flush buffered output).
-         */
-        if( stream->callbackStop && paContinue == callbackResult )
-        {
-            PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
-            callbackResult = paComplete;
-        }
-
-        if( paContinue != callbackResult )
-        {
-            stream->callbackAbort = (paAbort == callbackResult);
-            if( stream->callbackAbort ||
-                    /** @concern BlockAdaption Go on if adaption buffers are empty */
-                    PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) 
-                goto end;
-
-            PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ ));
-            /* There is still buffered output that needs to be processed */
-        }
-
-        /* Wait for data to become available, this comes down to polling the ALSA file descriptors untill we have
-         * a number of available frames.
-         */
-        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
-        if( xrun )
-        {
-            assert( 0 == framesAvail );
-            continue;
-
-            /* XXX: Report xruns to the user? A situation is conceivable where the callback is never invoked due
-             * to constant xruns, it might be desirable to notify the user of this.
-             */
-        }
-
-        /* Consume buffer space. Once we have a number of frames available for consumption we must retrieve the
-         * mmapped buffers from ALSA, this is contiguously accessible memory however, so we may receive smaller
-         * portions at a time than is available as a whole. Therefore we should be prepared to process several
-         * chunks successively. The buffers are passed to the PA buffer processor.
-         */
-        while( framesAvail > 0 )
-        {
-            xrun = 0;
-
-            pthread_testcancel();
-
-            /** @concern Xruns Under/overflows are to be reported to the callback */
-            if( stream->underrun > 0.0 )
-            {
-                cbFlags |= paOutputUnderflow;
-                stream->underrun = 0.0;
-            }
-            if( stream->overrun > 0.0 )
-            {
-                cbFlags |= paInputOverflow;
-                stream->overrun = 0.0;
-            }
-            if( stream->capture.pcm && stream->playback.pcm )
-            {
-                /** @concern FullDuplex It's possible that only one direction is being processed to avoid an
-                 * under- or overflow, this should be reported correspondingly */
-                if( !stream->capture.ready )
-                {
-                    cbFlags |= paInputUnderflow;
-                    PA_DEBUG(( "%s: Input underflow\n", __FUNCTION__ ));
-                }
-                else if( !stream->playback.ready )
-                {
-                    cbFlags |= paOutputOverflow;
-                    PA_DEBUG(( "%s: Output overflow\n", __FUNCTION__ ));
-                }
-            }
-
-            CallbackUpdate( &stream->threading );
-            CalculateTimeInfo( stream, &timeInfo );
-            PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags );
-            cbFlags = 0;
-
-            /* CPU load measurement should include processing activivity external to the stream callback */
-            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
-            framesGot = framesAvail;
-            PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
-            framesAvail -= framesGot;
-
-            if( framesGot > 0 )
-            {
-                assert( !xrun );
-
-                PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
-                PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
-            }
-            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot );
-
-            if( framesGot == 0 )
-            {
-                if( !xrun )
-                    PA_DEBUG(( "%s: Received less frames than reported from ALSA!\n", __FUNCTION__ ));
-
-                /* Go back to polling for more frames */
-                break;
-
-            }
-
-            if( paContinue != callbackResult )
-                break;
-        }
-    }
-
-    /* Match pthread_cleanup_push */
-    pthread_cleanup_pop( 1 );
-
-end:
-    pthread_exit( pres );
-
-error:
-    /* Pass on error code */
-    pres = malloc( sizeof (PaError) );
-    *pres = result;
-    
-    goto end;
-}
-
-/* Blocking interface */
-
-static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames )
-{
-    PaError result = paNoError;
-    PaAlsaStream *stream = (PaAlsaStream*)s;
-    unsigned long framesGot, framesAvail;
-    void *userBuffer;
-    snd_pcm_t *save = stream->playback.pcm;
-
-    assert( stream );
-
-    PA_UNLESS( stream->capture.pcm, paCanNotReadFromAnOutputOnlyStream );
-
-    /* Disregard playback */
-    stream->playback.pcm = NULL;
-
-    if( stream->overrun > 0. )
-    {
-        result = paInputOverflowed;
-        stream->overrun = 0.0;
-    }
-
-    if( stream->capture.userInterleaved )
-        userBuffer = buffer;
-    else
-    {
-        /* Copy channels into local array */
-        userBuffer = stream->capture.userBuffers;
-        memcpy( userBuffer, buffer, sizeof (void *) * stream->capture.numUserChannels );
-    }
-
-    /* Start stream if in prepared state */
-    if( snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED )
-    {
-        ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
-    }
-
-    while( frames > 0 )
-    {
-        int xrun = 0;
-        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
-        framesGot = PA_MIN( framesAvail, frames );
-
-        PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
-        if( framesGot > 0 )
-        {
-            framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot );
-            PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
-            frames -= framesGot;
-        }
-    }
-
-end:
-    stream->playback.pcm = save;
-    return result;
-error:
-    goto end;
-}
-
-static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames )
-{
-    PaError result = paNoError;
-    signed long err;
-    PaAlsaStream *stream = (PaAlsaStream*)s;
-    snd_pcm_uframes_t framesGot, framesAvail;
-    const void *userBuffer;
-    snd_pcm_t *save = stream->capture.pcm;
-    
-    assert( stream );
-
-    PA_UNLESS( stream->playback.pcm, paCanNotWriteToAnInputOnlyStream );
-
-    /* Disregard capture */
-    stream->capture.pcm = NULL;
-
-    if( stream->underrun > 0. )
-    {
-        result = paOutputUnderflowed;
-        stream->underrun = 0.0;
-    }
-
-    if( stream->playback.userInterleaved )
-        userBuffer = buffer;
-    else /* Copy channels into local array */
-    {
-        userBuffer = stream->playback.userBuffers;
-        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback.numUserChannels );
-    }
-
-    while( frames > 0 )
-    {
-        int xrun = 0;
-        snd_pcm_uframes_t hwAvail;
-
-        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
-        framesGot = PA_MIN( framesAvail, frames );
-
-        PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
-        if( framesGot > 0 )
-        {
-            framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot );
-            PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
-            frames -= framesGot;
-        }
-
-        /* Frames residing in buffer */
-        PA_ENSURE( err = GetStreamWriteAvailable( stream ) );
-        framesAvail = err;
-        hwAvail = stream->playback.bufferSize - framesAvail;
-
-        /* Start stream after one period of samples worth */
-        if( snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED &&
-                hwAvail >= stream->playback.framesPerBuffer )
-        {
-            ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
-        }
-    }
-
-end:
-    stream->capture.pcm = save;
-    return result;
-error:
-    goto end;
-}
-
-/* Return frames available for reading. In the event of an overflow, the capture pcm will be restarted */
-static signed long GetStreamReadAvailable( PaStream* s )
-{
-    PaError result = paNoError;
-    PaAlsaStream *stream = (PaAlsaStream*)s;
-    unsigned long avail;
-    int xrun;
-
-    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
-    if( xrun )
-    {
-        PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
-        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
-        if( xrun )
-            PA_ENSURE( paInputOverflowed );
-    }
-
-    return (signed long)avail;
-
-error:
-    return result;
-}
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
-    PaError result = paNoError;
-    PaAlsaStream *stream = (PaAlsaStream*)s;
-    unsigned long avail;
-    int xrun;
-
-    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->playback, &avail, &xrun ) );
-    if( xrun )
-    {
-        snd_pcm_sframes_t savail;
-
-        PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
-        savail = snd_pcm_avail_update( stream->playback.pcm );
-
-        /* savail should not contain -EPIPE now, since PaAlsaStream_HandleXrun will only prepare the pcm */
-        ENSURE_( savail, paUnanticipatedHostError );
-
-        avail = (unsigned long) savail;
-    }
-
-    return (signed long)avail;
-
-error:
-    return result;
-}
-
-/* Extensions */
-
-/* Initialize host api specific structure */
-void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info )
-{
-    info->size = sizeof (PaAlsaStreamInfo);
-    info->hostApiType = paALSA;
-    info->version = 1;
-    info->deviceString = NULL;
-}
-
-void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable )
-{
-    PaAlsaStream *stream = (PaAlsaStream *) s;
-    stream->threading.rtSched = enable;
-}
-
-void PaAlsa_EnableWatchdog( PaStream *s, int enable )
-{
-    PaAlsaStream *stream = (PaAlsaStream *) s;
-    stream->threading.useWatchdog = enable;
-}
+/*

+ * $Id: pa_linux_alsa.c,v 1.1.2.71 2005/04/15 18:20:18 aknudsen Exp $

+ * PortAudio Portable Real-Time Audio Library

+ * Latest Version at: http://www.portaudio.com

+ * ALSA implementation by Joshua Haberman and Arve Knudsen

+ *

+ * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>

+ * Copyright (c) 2005 Arve Knudsen <aknuds-1@broadpark.no>

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#define ALSA_PCM_NEW_HW_PARAMS_API

+#define ALSA_PCM_NEW_SW_PARAMS_API

+#include <alsa/asoundlib.h>

+#undef ALSA_PCM_NEW_HW_PARAMS_API

+#undef ALSA_PCM_NEW_SW_PARAMS_API

+

+#include <sys/poll.h>

+#include <string.h> /* strlen() */

+#include <limits.h>

+#include <math.h>

+#include <pthread.h>

+#include <signal.h>

+#include <time.h>

+#include <sys/mman.h>

+#include <signal.h> /* For sig_atomic_t */

+

+#include "portaudio.h"

+#include "pa_util.h"

+#include "pa_unix_util.h"

+#include "pa_allocation.h"

+#include "pa_hostapi.h"

+#include "pa_stream.h"

+#include "pa_cpuload.h"

+#include "pa_process.h"

+

+#include "pa_linux_alsa.h"

+

+/* Check return value of ALSA function, and map it to PaError */

+#define ENSURE_(expr, code) \

+    do { \

+        if( UNLIKELY( (aErr_ = (expr)) < 0 ) ) \

+        { \

+            /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \

+            if( (code) == paUnanticipatedHostError && pthread_self() != callbackThread_ ) \

+            { \

+                PaUtil_SetLastHostErrorInfo( paALSA, aErr_, snd_strerror( aErr_ ) ); \

+            } \

+            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \

+            result = (code); \

+            goto error; \

+        } \

+    } while( 0 );

+

+#define ASSERT_CALL_(expr, success) \

+    aErr_ = (expr); \

+    assert( aErr_ == success );

+

+static int aErr_;               /* Used with ENSURE_ */

+static pthread_t callbackThread_;

+

+typedef enum

+{

+    StreamDirection_In,

+    StreamDirection_Out

+} StreamDirection;

+

+/* Threading utility struct */

+typedef struct PaAlsaThreading

+{

+    pthread_t watchdogThread;

+    pthread_t callbackThread;

+    int watchdogRunning;

+    int rtSched;

+    int rtPrio;

+    int useWatchdog;

+    unsigned long throttledSleepTime;

+    volatile PaTime callbackTime;

+    volatile PaTime callbackCpuTime;

+    PaUtilCpuLoadMeasurer *cpuLoadMeasurer;

+} PaAlsaThreading;

+

+typedef struct

+{

+    PaSampleFormat hostSampleFormat;

+    unsigned long framesPerBuffer;

+    int numUserChannels, numHostChannels;

+    int userInterleaved, hostInterleaved;

+

+    snd_pcm_t *pcm;

+    snd_pcm_uframes_t bufferSize;

+    snd_pcm_format_t nativeFormat;

+    unsigned int nfds;

+    int ready;  /* Marked ready from poll */

+    void **userBuffers;

+    snd_pcm_uframes_t offset;

+    StreamDirection streamDir;

+

+    snd_pcm_channel_area_t *channelAreas;  /* Needed for channel adaption */

+} PaAlsaStreamComponent;

+

+/* Implementation specific stream structure */

+typedef struct PaAlsaStream

+{

+    PaUtilStreamRepresentation streamRepresentation;

+    PaUtilCpuLoadMeasurer cpuLoadMeasurer;

+    PaUtilBufferProcessor bufferProcessor;

+    PaAlsaThreading threading;

+

+    unsigned long framesPerUserBuffer;

+

+    int primeBuffers;

+    int callbackMode;              /* bool: are we running in callback mode? */

+    int pcmsSynced;	            /* Have we successfully synced pcms */

+

+    /* the callback thread uses these to poll the sound device(s), waiting

+     * for data to be ready/available */

+    struct pollfd *pfds;

+    int pollTimeout;

+

+    /* Used in communication between threads */

+    volatile sig_atomic_t callback_finished; /* bool: are we in the "callback finished" state? */

+    volatile sig_atomic_t callbackAbort;    /* Drop frames? */

+    volatile sig_atomic_t callbackStop;     /* Signal a stop */

+    volatile sig_atomic_t isActive;         /* Is stream in active state? (Between StartStream and StopStream || !paContinue) */

+    pthread_mutex_t stateMtx;               /* Used to synchronize access to stream state */

+    pthread_mutex_t startMtx;               /* Used to synchronize stream start in callback mode */

+    pthread_cond_t startCond;               /* Wait untill audio is started in callback thread */

+

+    int neverDropInput;

+

+    PaTime underrun;

+    PaTime overrun;

+

+    PaAlsaStreamComponent capture, playback;

+}

+PaAlsaStream;

+

+/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */

+

+typedef struct PaAlsaHostApiRepresentation

+{

+    PaUtilHostApiRepresentation commonHostApiRep;

+    PaUtilStreamInterface callbackStreamInterface;

+    PaUtilStreamInterface blockingStreamInterface;

+

+    PaUtilAllocationGroup *allocations;

+

+    PaHostApiIndex hostApiIndex;

+}

+PaAlsaHostApiRepresentation;

+

+typedef struct PaAlsaDeviceInfo

+{

+    PaDeviceInfo commonDeviceInfo;

+    char *alsaName;

+    int isPlug;

+    int minInputChannels;

+    int minOutputChannels;

+}

+PaAlsaDeviceInfo;

+

+/* Threading utilities */

+

+static void InitializeThreading( PaAlsaThreading *th, PaUtilCpuLoadMeasurer *clm )

+{

+    th->watchdogRunning = 0;

+    th->rtSched = 0;

+    th->callbackTime = 0;

+    th->callbackCpuTime = 0;

+    th->useWatchdog = 1;

+    th->throttledSleepTime = 0;

+    th->cpuLoadMeasurer = clm;

+

+    th->rtPrio = (sched_get_priority_max( SCHED_FIFO ) - sched_get_priority_min( SCHED_FIFO )) / 2

+            + sched_get_priority_min( SCHED_FIFO );

+}

+

+static PaError KillCallbackThread( PaAlsaThreading *th, int wait, PaError *exitResult, PaError *watchdogExitResult )

+{

+    PaError result = paNoError;

+    void *pret;

+

+    if( exitResult )

+        *exitResult = paNoError;

+    if( watchdogExitResult )

+        *watchdogExitResult = paNoError;

+

+    if( th->watchdogRunning )

+    {

+        pthread_cancel( th->watchdogThread );

+        ASSERT_CALL_( pthread_join( th->watchdogThread, &pret ), 0 );

+

+        if( pret && pret != PTHREAD_CANCELED )

+        {

+            if( watchdogExitResult )

+                *watchdogExitResult = *(PaError *) pret;

+            free( pret );

+        }

+    }

+

+    /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */

+    /* TODO: Make join time out */

+    if( !wait )

+        pthread_cancel( th->callbackThread );   /* XXX: Safe to call this if the thread has exited on its own? */

+    ASSERT_CALL_( pthread_join( th->callbackThread, &pret ), 0 );

+

+    if( pret && pret != PTHREAD_CANCELED )

+    {

+        if( exitResult )

+            *exitResult = *(PaError *) pret;

+        free( pret );

+    }

+

+    return result;

+}

+

+static void OnWatchdogExit( void *userData )

+{

+    PaAlsaThreading *th = (PaAlsaThreading *) userData;

+    struct sched_param spm = { 0 };

+    assert( th );

+

+    ASSERT_CALL_( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 );    /* Lower before exiting */

+    PA_DEBUG(( "Watchdog exiting\n" ));

+}

+

+static PaError BoostPriority( PaAlsaThreading *th )

+{

+    PaError result = paNoError;

+    struct sched_param spm = { 0 };

+    spm.sched_priority = th->rtPrio;

+

+    assert( th );

+

+    if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )

+    {

+        PA_UNLESS( errno == EPERM, paInternalError );  /* Lack permission to raise priority */

+        PA_DEBUG(( "Failed bumping priority\n" ));

+        result = 0;

+    }

+    else

+        result = 1; /* Success */

+error:

+    return result;

+}

+

+static void *WatchdogFunc( void *userData )

+{

+    PaError result = paNoError, *pres = NULL;

+    int err;

+    PaAlsaThreading *th = (PaAlsaThreading *) userData;

+    unsigned intervalMsec = 500;

+    const PaTime maxSeconds = 3.;   /* Max seconds between callbacks */

+    PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed;

+    double cpuLoad, avgCpuLoad = 0.;

+    int throttled = 0;

+

+    assert( th );

+

+    pthread_cleanup_push( &OnWatchdogExit, th );	/* Execute OnWatchdogExit when exiting */

+

+    /* Boost priority of callback thread */

+    PA_ENSURE( result = BoostPriority( th ) );

+    if( !result )

+    {

+        pthread_exit( NULL );   /* Boost failed, might as well exit */

+    }

+

+    cpuTimeThen = th->callbackCpuTime;

+    {

+        int policy;

+        struct sched_param spm = { 0 };

+        pthread_getschedparam( pthread_self(), &policy, &spm );

+        PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority ));

+    }

+

+    while( 1 )

+    {

+        double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff;

+        

+        /* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */

+        pthread_testcancel();

+        Pa_Sleep( intervalMsec );

+        pthread_testcancel();

+

+        if( PaUtil_GetTime() - th->callbackTime > maxSeconds )

+        {

+            PA_DEBUG(( "Watchdog: Terminating callback thread\n" ));

+            /* Tell thread to terminate */

+            err = pthread_kill( th->callbackThread, SIGKILL );

+            pthread_exit( NULL );

+        }

+

+        PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) ));

+

+        /* Check if we should throttle, or unthrottle :P */

+        cpuTimeNow = th->callbackCpuTime;

+        cpuTimeElapsed = cpuTimeNow - cpuTimeThen;

+        cpuTimeThen = cpuTimeNow;

+

+        timeNow = PaUtil_GetTime();

+        timeElapsed = timeNow - timeThen;

+        timeThen = timeNow;

+        cpuLoad = cpuTimeElapsed / timeElapsed;

+        avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1;

+        /*

+        if( throttled )

+            PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed ));

+            */

+        if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 )

+        {

+            static int policy;

+            static struct sched_param spm = { 0 };

+            static const struct sched_param defaultSpm = { 0 };

+            PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority ));

+

+            pthread_getschedparam( th->callbackThread, &policy, &spm );

+            if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) )

+            {

+                throttled = 1;

+            }

+            else

+                PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) ));

+

+            /* Give other processes a go, before raising priority again */

+            PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime ));

+            Pa_Sleep( th->throttledSleepTime );

+

+            /* Reset callback priority */

+            if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )

+            {

+                PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) ));

+            }

+

+            if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 )

+                intervalMsec = 50;

+            else

+                intervalMsec = 100;

+

+            /*

+            lowpassCoeff = .97;

+            lowpassCoeff1 = .99999 - lowpassCoeff;

+            */

+        }

+        else if( throttled && avgCpuLoad < .8 )

+        {

+            intervalMsec = 500;

+            throttled = 0;

+

+            /*

+            lowpassCoeff = .9;

+            lowpassCoeff1 = .99999 - lowpassCoeff;

+            */

+        }

+    }

+

+    pthread_cleanup_pop( 1 );   /* Execute cleanup on exit */

+

+error:

+    /* Shouldn't get here in the normal case */

+

+    /* Pass on error code */

+    pres = malloc( sizeof (PaError) );

+    *pres = result;

+    

+    pthread_exit( pres );

+}

+

+static PaError CreateCallbackThread( PaAlsaThreading *th, void *(*callbackThreadFunc)( void * ), PaStream *s )

+{

+    PaError result = paNoError;

+    pthread_attr_t attr;

+    int started = 0;

+

+#if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)

+    if( th->rtSched )

+    {

+        if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 )

+        {

+            int savedErrno = errno;             /* In case errno gets overwritten */

+            assert( savedErrno != EINVAL );     /* Most likely a programmer error */

+            PA_UNLESS( (savedErrno == EPERM), paInternalError );

+            PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ ));

+        }

+        else

+            PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ ));

+    }

+#endif

+

+    PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );

+    /* Priority relative to other processes */

+    PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );   

+

+    PA_UNLESS( !pthread_create( &th->callbackThread, &attr, callbackThreadFunc, s ), paInternalError );

+    started = 1;

+

+    if( th->rtSched )

+    {

+        if( th->useWatchdog )

+        {

+            int err;

+            struct sched_param wdSpm = { 0 };

+            /* Launch watchdog, watchdog sets callback thread priority */

+            int prio = PA_MIN( th->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) );

+            wdSpm.sched_priority = prio;

+

+            PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );

+            PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError );

+            PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );

+            PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError );

+            PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError );

+            if( (err = pthread_create( &th->watchdogThread, &attr, &WatchdogFunc, th )) )

+            {

+                PA_UNLESS( err == EPERM, paInternalError );

+                /* Permission error, go on without realtime privileges */

+                PA_DEBUG(( "Failed bumping priority\n" ));

+            }

+            else

+            {

+                int policy;

+                th->watchdogRunning = 1;

+                ASSERT_CALL_( pthread_getschedparam( th->watchdogThread, &policy, &wdSpm ), 0 );

+                /* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */

+                if( wdSpm.sched_priority != prio )

+                {

+                    PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority ));

+                    PA_ENSURE( paInternalError );

+                }

+            }

+        }

+        else

+            PA_ENSURE( BoostPriority( th ) );

+    }

+

+end:

+    return result;

+error:

+    if( started )

+        KillCallbackThread( th, 0, NULL, NULL );

+

+    goto end;

+}

+

+static void CallbackUpdate( PaAlsaThreading *th )

+{

+    th->callbackTime = PaUtil_GetTime();

+    th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer );

+}

+

+/* prototypes for functions declared in this file */

+

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate );

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** s,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *callback,

+                           void *userData );

+static PaError CloseStream( PaStream* stream );

+static PaError StartStream( PaStream *stream );

+static PaError StopStream( PaStream *stream );

+static PaError AbortStream( PaStream *stream );

+static PaError IsStreamStopped( PaStream *s );

+static PaError IsStreamActive( PaStream *stream );

+static PaTime GetStreamTime( PaStream *stream );

+static double GetStreamCpuLoad( PaStream* stream );

+static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );

+static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate );

+static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate );

+

+/* Callback prototypes */

+static void *CallbackThreadFunc( void *userData );

+

+/* Blocking prototypes */

+static signed long GetStreamReadAvailable( PaStream* s );

+static signed long GetStreamWriteAvailable( PaStream* s );

+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );

+static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );

+

+

+static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation *hostApi, int device )

+{

+    return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device];

+}

+

+PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )

+{

+    PaError result = paNoError;

+    PaAlsaHostApiRepresentation *alsaHostApi = NULL;

+

+    PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory(

+                sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory );

+    PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );

+    alsaHostApi->hostApiIndex = hostApiIndex;

+

+    *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi;

+    (*hostApi)->info.structVersion = 1;

+    (*hostApi)->info.type = paALSA;

+    (*hostApi)->info.name = "ALSA";

+

+    (*hostApi)->Terminate = Terminate;

+    (*hostApi)->OpenStream = OpenStream;

+    (*hostApi)->IsFormatSupported = IsFormatSupported;

+

+    PA_ENSURE( BuildDeviceList( alsaHostApi ) );

+

+    PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface,

+                                      CloseStream, StartStream,

+                                      StopStream, AbortStream,

+                                      IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, GetStreamCpuLoad,

+                                      PaUtil_DummyRead, PaUtil_DummyWrite,

+                                      PaUtil_DummyGetReadAvailable,

+                                      PaUtil_DummyGetWriteAvailable );

+

+    PaUtil_InitializeStreamInterface( &alsaHostApi->blockingStreamInterface,

+                                      CloseStream, StartStream,

+                                      StopStream, AbortStream,

+                                      IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, PaUtil_DummyGetCpuLoad,

+                                      ReadStream, WriteStream,

+                                      GetStreamReadAvailable,

+                                      GetStreamWriteAvailable );

+

+    return result;

+

+error:

+    if( alsaHostApi )

+    {

+        if( alsaHostApi->allocations )

+        {

+            PaUtil_FreeAllAllocations( alsaHostApi->allocations );

+            PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );

+        }

+

+        PaUtil_FreeMemory( alsaHostApi );

+    }

+

+    return result;

+}

+

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )

+{

+    PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;

+

+    assert( hostApi );

+

+    if( alsaHostApi->allocations )

+    {

+        PaUtil_FreeAllAllocations( alsaHostApi->allocations );

+        PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );

+    }

+

+    PaUtil_FreeMemory( alsaHostApi );

+    snd_config_update_free_global();

+}

+

+/*! Determine max channels and default latencies.

+ *

+ * This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for 

+ * traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero,

+ * and a suitable result returned. The device is closed before returning.

+ */

+static PaError GropeDevice( snd_pcm_t *pcm, int *minChannels, int *maxChannels, double *defaultLowLatency,

+        double *defaultHighLatency, double *defaultSampleRate, int isPlug )

+{

+    PaError result = paNoError;

+    snd_pcm_hw_params_t *hwParams;

+    snd_pcm_uframes_t lowLatency = 512, highLatency = 2048;

+    unsigned int minChans, maxChans;

+    double defaultSr = *defaultSampleRate;

+

+    assert( pcm );

+

+    ENSURE_( snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError );

+

+    snd_pcm_hw_params_alloca( &hwParams );

+    snd_pcm_hw_params_any( pcm, hwParams );

+

+    if( defaultSr >= 0 )

+    {

+        /* Could be that the device opened in one mode supports samplerates that the other mode wont have,

+         * so try again .. */

+        if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 )

+        {

+            defaultSr = -1.;

+            PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ ));

+        }

+    }

+

+    if( defaultSr < 0. )           /* Default sample rate not set */

+    {

+        unsigned int sampleRate = 44100;        /* Will contain approximate rate returned by alsa-lib */

+        ENSURE_( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ), paUnanticipatedHostError );

+        ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError );

+    }

+

+    ENSURE_( snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError );

+    ENSURE_( snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError );

+    assert( maxChans <= INT_MAX );

+    assert( maxChans > 0 );    /* Weird linking issue could cause wrong version of ALSA symbols to be called,

+                                   resulting in zeroed values */

+

+    /* XXX: Limit to sensible number (ALSA plugins accept a crazy amount of channels)? */

+    if( isPlug && maxChans > 128 )

+    {

+        maxChans = 128;

+        PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans ));

+    }

+

+    /* TWEAKME:

+     *

+     * Giving values for default min and max latency is not

+     * straightforward.  Here are our objectives:

+     *

+     *         * for low latency, we want to give the lowest value

+     *         that will work reliably.  This varies based on the

+     *         sound card, kernel, CPU, etc.  I think it is better

+     *         to give sub-optimal latency than to give a number

+     *         too low and cause dropouts.  My conservative

+     *         estimate at this point is to base it on 4096-sample

+     *         latency at 44.1 kHz, which gives a latency of 23ms.

+     *         * for high latency we want to give a large enough

+     *         value that dropouts are basically impossible.  This

+     *         doesn't really require as much tweaking, since

+     *         providing too large a number will just cause us to

+     *         select the nearest setting that will work at stream

+     *         config time.

+     */

+    ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError );

+

+    /* Have to reset hwParams, to set new buffer size */

+    ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError ); 

+    ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError );

+

+    *minChannels = (int)minChans;

+    *maxChannels = (int)maxChans;

+    *defaultSampleRate = defaultSr;

+    *defaultLowLatency = (double) lowLatency / *defaultSampleRate;

+    *defaultHighLatency = (double) highLatency / *defaultSampleRate;

+

+end:

+    snd_pcm_close( pcm );

+    return result;

+

+error:

+    goto end;

+}

+

+/* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate

+ * wether input/output is available) */

+static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo )

+{

+    deviceInfo->structVersion = -1;

+    deviceInfo->name = NULL;

+    deviceInfo->hostApi = -1;

+    deviceInfo->maxInputChannels = 0;

+    deviceInfo->maxOutputChannels = 0;

+    deviceInfo->defaultLowInputLatency = -1.;

+    deviceInfo->defaultLowOutputLatency = -1.;

+    deviceInfo->defaultHighInputLatency = -1.;

+    deviceInfo->defaultHighOutputLatency = -1.;

+    deviceInfo->defaultSampleRate = -1.;

+}

+

+/* Helper struct */

+typedef struct

+{

+    char *alsaName;

+    char *name;

+    int isPlug;

+    int hasPlayback;

+    int hasCapture;

+} DeviceNames;

+

+static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi,

+        char **dst,

+        const char *src)

+{

+    PaError result = paNoError;

+    int len = strlen( src ) + 1;

+

+    /* PA_DEBUG(("PaStrDup %s %d\n", src, len)); */

+

+    PA_UNLESS( *dst = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),

+            paInsufficientMemory );

+    strncpy( *dst, src, len );

+

+error:

+    return result;

+}

+

+/* Disregard standard plugins

+ * XXX: Might want to make the "default" plugin available, if we can make it work

+ */

+static int IgnorePlugin( const char *pluginId )

+{

+#define numIgnored 10

+    static const char *ignoredPlugins[numIgnored] = {"hw", "plughw", "plug", "default", "dsnoop", "dmix", "tee",

+        "file", "null", "shm"};

+    int i;

+

+    for( i = 0; i < numIgnored; ++i )

+    {

+        if( !strcmp( pluginId, ignoredPlugins[i] ) )

+        {

+            return 1;

+        }

+    }

+

+    return 0;

+}

+

+/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */

+static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )

+{

+    PaUtilHostApiRepresentation *commonApi = &alsaApi->commonHostApiRep;

+    PaAlsaDeviceInfo *deviceInfoArray;

+    int cardIdx = -1, devIdx = 0;

+    snd_ctl_card_info_t *cardInfo;

+    PaError result = paNoError;

+    size_t numDeviceNames = 0, maxDeviceNames = 1, i;

+    DeviceNames *deviceNames = NULL;

+    snd_config_t *topNode = NULL;

+    snd_pcm_info_t *pcmInfo;

+    int res;

+    int blocking = SND_PCM_NONBLOCK;

+    char alsaCardName[50];

+    if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) )

+        blocking = 0;

+

+    /* These two will be set to the first working input and output device, respectively */

+    commonApi->info.defaultInputDevice = paNoDevice;

+    commonApi->info.defaultOutputDevice = paNoDevice;

+

+    /* count the devices by enumerating all the card numbers */

+

+    /* snd_card_next() modifies the integer passed to it to be:

+     *      the index of the first card if the parameter is -1

+     *      the index of the next card if the parameter is the index of a card

+     *      -1 if there are no more cards

+     *

+     * The function itself returns 0 if it succeeded. */

+    cardIdx = -1;

+    snd_ctl_card_info_alloca( &cardInfo );

+    snd_pcm_info_alloca( &pcmInfo );

+    while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 )

+    {

+        char *cardName;

+        int devIdx = -1;

+        snd_ctl_t *ctl;

+        char buf[50];

+

+        snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx );

+

+        /* Acquire name of card */

+        if( snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 )

+            continue;   /* Unable to open card :( */

+        snd_ctl_card_info( ctl, cardInfo );

+

+        PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, snd_ctl_card_info_get_name( cardInfo )) );

+

+        while( snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 )

+        {

+            char *alsaDeviceName, *deviceName;

+            size_t len;

+            int hasPlayback = 0, hasCapture = 0;

+            snprintf( buf, sizeof (buf), "%s:%d,%d", "hw", cardIdx, devIdx );

+

+            /* Obtain info about this particular device */

+            snd_pcm_info_set_device( pcmInfo, devIdx );

+            snd_pcm_info_set_subdevice( pcmInfo, 0 );

+            snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE );

+            if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )

+                hasCapture = 1;

+            

+            snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK );

+            if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )

+                hasPlayback = 1;

+

+            if( !hasPlayback && !hasCapture )

+            {

+                continue;   /* Error */

+            }

+

+            /* The length of the string written by snprintf plus terminating 0 */

+            len = snprintf( NULL, 0, "%s: %s (%s)", cardName, snd_pcm_info_get_name( pcmInfo ), buf ) + 1;

+            PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),

+                    paInsufficientMemory );

+            snprintf( deviceName, len, "%s: %s (%s)", cardName,

+                    snd_pcm_info_get_name( pcmInfo ), buf );

+

+            ++numDeviceNames;

+            if( !deviceNames || numDeviceNames > maxDeviceNames )

+            {

+                maxDeviceNames *= 2;

+                PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ),

+                        paInsufficientMemory );

+            }

+

+            PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) );

+

+            deviceNames[ numDeviceNames - 1 ].alsaName = alsaDeviceName;

+            deviceNames[ numDeviceNames - 1 ].name = deviceName;

+            deviceNames[ numDeviceNames - 1 ].isPlug = 0;

+            deviceNames[ numDeviceNames - 1 ].hasPlayback = hasPlayback;

+            deviceNames[ numDeviceNames - 1 ].hasCapture = hasCapture;

+        }

+        snd_ctl_close( ctl );

+    }

+

+    /* Iterate over plugin devices */

+    snd_config_update();

+    if( (res = snd_config_search( snd_config, "pcm", &topNode )) >= 0 )

+    {

+        snd_config_iterator_t i, next;

+

+        snd_config_for_each( i, next, topNode )

+        {

+            const char *tpStr = NULL, *idStr = NULL;

+            char *alsaDeviceName, *deviceName;

+            snd_config_t *n = snd_config_iterator_entry( i ), *tp = NULL;

+            if( snd_config_get_type( n ) != SND_CONFIG_TYPE_COMPOUND )

+                continue;

+

+            ENSURE_( snd_config_search( n, "type", &tp ), paUnanticipatedHostError );

+            ENSURE_( snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError );

+

+            ENSURE_( snd_config_get_id( n, &idStr ), paUnanticipatedHostError );

+            if( IgnorePlugin( idStr ) )

+            {

+                PA_DEBUG(( "%s: Ignoring ALSA plugin device %s of type %s\n", __FUNCTION__, idStr, tpStr ));

+                continue;

+            }

+

+            PA_DEBUG(( "%s: Found plugin %s of type %s\n", __FUNCTION__, idStr, tpStr ));

+

+            PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,

+                                                            strlen(idStr) + 6 ), paInsufficientMemory );

+            strcpy( alsaDeviceName, idStr );

+            PA_UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,

+                                                            strlen(idStr) + 1 ), paInsufficientMemory );

+            strcpy( deviceName, idStr );

+

+            ++numDeviceNames;

+            if( !deviceNames || numDeviceNames > maxDeviceNames )

+            {

+                maxDeviceNames *= 2;

+                PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ),

+                        paInsufficientMemory );

+            }

+

+            deviceNames[numDeviceNames - 1].alsaName = alsaDeviceName;

+            deviceNames[numDeviceNames - 1].name = deviceName;

+            deviceNames[numDeviceNames - 1].isPlug = 1;

+            deviceNames[numDeviceNames - 1].hasPlayback = 1;

+            deviceNames[numDeviceNames - 1].hasCapture = 1;

+        }

+    }

+    else

+        PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, snd_strerror( res ) ));

+

+    /* allocate deviceInfo memory based on the number of devices */

+    PA_UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(

+            alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory );

+

+    /* allocate all device info structs in a contiguous block */

+    PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory(

+            alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory );

+

+    /* Loop over list of cards, filling in info, if a device is deemed unavailable (can't get name),

+     * it's ignored.

+     */

+    /* while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) */

+    for( i = 0, devIdx = 0; i < numDeviceNames; ++i )

+    {

+        snd_pcm_t *pcm;

+        PaAlsaDeviceInfo *deviceInfo = &deviceInfoArray[devIdx];

+        PaDeviceInfo *commonDeviceInfo = &deviceInfo->commonDeviceInfo;

+

+        /* Zero fields */

+        InitializeDeviceInfo( commonDeviceInfo );

+

+        /* to determine device capabilities, we must open the device and query the

+         * hardware parameter configuration space */

+

+        /* Query capture */

+        if( deviceNames[i].hasCapture &&

+                snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_CAPTURE, blocking ) >= 0 )

+        {

+            if( GropeDevice( pcm, &deviceInfo->minInputChannels, &commonDeviceInfo->maxInputChannels,

+                        &commonDeviceInfo->defaultLowInputLatency, &commonDeviceInfo->defaultHighInputLatency,

+                        &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError )

+                continue;   /* Error */

+        }

+

+        /* Query playback */

+        if( deviceNames[i].hasPlayback &&

+                snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_PLAYBACK, blocking ) >= 0 )

+        {

+            if( GropeDevice( pcm, &deviceInfo->minOutputChannels, &commonDeviceInfo->maxOutputChannels,

+                        &commonDeviceInfo->defaultLowOutputLatency, &commonDeviceInfo->defaultHighOutputLatency,

+                        &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError )

+                continue;   /* Error */

+        }

+

+        commonDeviceInfo->structVersion = 2;

+        commonDeviceInfo->hostApi = alsaApi->hostApiIndex;

+        commonDeviceInfo->name = deviceNames[i].name;

+        deviceInfo->alsaName = deviceNames[i].alsaName;

+        deviceInfo->isPlug = deviceNames[i].isPlug;

+

+        /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object.

+         * Should now be safe to add device info, unless the device supports neither capture nor playback

+         */

+        if( commonDeviceInfo->maxInputChannels > 0 || commonDeviceInfo->maxOutputChannels > 0 )

+        {

+            if( commonApi->info.defaultInputDevice == paNoDevice && commonDeviceInfo->maxInputChannels > 0 )

+                commonApi->info.defaultInputDevice = devIdx;

+            if(  commonApi->info.defaultOutputDevice == paNoDevice && commonDeviceInfo->maxOutputChannels > 0 )

+                commonApi->info.defaultOutputDevice = devIdx;

+

+            commonApi->deviceInfos[devIdx++] = (PaDeviceInfo *) deviceInfo;

+        }

+    }

+    free( deviceNames );

+

+    commonApi->info.deviceCount = devIdx;   /* Number of successfully queried devices */

+

+end:

+    return result;

+

+error:

+    goto end;   /* No particular action */

+}

+

+/* Check against known device capabilities */

+static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilHostApiRepresentation *hostApi, StreamDirection mode )

+{

+    PaError result = paNoError;

+    int maxChans;

+    const PaAlsaDeviceInfo *deviceInfo = NULL;

+    assert( parameters );

+

+    if( parameters->device != paUseHostApiSpecificDeviceSpecification )

+    {

+        assert( parameters->device < hostApi->info.deviceCount );

+        PA_UNLESS( parameters->hostApiSpecificStreamInfo == NULL, paBadIODeviceCombination );

+        deviceInfo = GetDeviceInfo( hostApi, parameters->device );

+    }

+    else

+    {

+        const PaAlsaStreamInfo *streamInfo = parameters->hostApiSpecificStreamInfo;

+

+        PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice );

+        PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1,

+                paIncompatibleHostApiSpecificStreamInfo );

+

+        return paNoError;   /* Skip further checking */

+    }

+

+    assert( deviceInfo );

+    assert( parameters->hostApiSpecificStreamInfo == NULL );

+    maxChans = (StreamDirection_In == mode ? deviceInfo->commonDeviceInfo.maxInputChannels :

+        deviceInfo->commonDeviceInfo.maxOutputChannels);

+    PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount );

+

+error:

+    return result;

+}

+

+/* Given an open stream, what sample formats are available? */

+

+static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm )

+{

+    PaSampleFormat available = 0;

+    snd_pcm_hw_params_t *hwParams;

+    snd_pcm_hw_params_alloca( &hwParams );

+

+    snd_pcm_hw_params_any( pcm, hwParams );

+

+    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0)

+        available |= paFloat32;

+

+    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)

+        available |= paInt32;

+

+    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >= 0)

+        available |= paInt24;

+

+    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)

+        available |= paInt16;

+

+    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0)

+        available |= paUInt8;

+

+    if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0)

+        available |= paInt8;

+

+    return available;

+}

+

+static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat )

+{

+    switch( paFormat )

+    {

+        case paFloat32:

+            return SND_PCM_FORMAT_FLOAT;

+

+        case paInt16:

+            return SND_PCM_FORMAT_S16;

+

+        case paInt24:

+            return SND_PCM_FORMAT_S24;

+

+        case paInt32:

+            return SND_PCM_FORMAT_S32;

+

+        case paInt8:

+            return SND_PCM_FORMAT_S8;

+

+        case paUInt8:

+            return SND_PCM_FORMAT_U8;

+

+        default:

+            return SND_PCM_FORMAT_UNKNOWN;

+    }

+}

+

+/** Open an ALSA pcm handle.

+ * 

+ * The device to be open can be specified in a custom PaAlsaStreamInfo struct, or it will be a device number. In case of a

+ * device number, it maybe specified through an env variable (PA_ALSA_PLUGHW) that we should open the corresponding plugin

+ * device.

+ */

+static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection

+        streamDir, snd_pcm_t **pcm )

+{

+    PaError result = paNoError;

+    int ret;

+    const char *deviceName = alloca( 50 );

+    const PaAlsaDeviceInfo *deviceInfo = NULL;

+    PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo;

+

+    if( !streamInfo )

+    {

+        int usePlug = 0;

+        deviceInfo = GetDeviceInfo( hostApi, params->device );

+        

+        /* If device name starts with hw: and PA_ALSA_PLUGHW is 1, we open the plughw device instead */

+        if( !strncmp( "hw:", deviceInfo->alsaName, 3 ) && getenv( "PA_ALSA_PLUGHW" ) )

+            usePlug = atoi( getenv( "PA_ALSA_PLUGHW" ) );

+        if( usePlug )

+            snprintf( (char *) deviceName, 50, "plug%s", deviceInfo->alsaName );

+        else

+            deviceName = deviceInfo->alsaName;

+    }

+    else

+        deviceName = streamInfo->deviceString;

+

+    if( (ret = snd_pcm_open( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,

+                    SND_PCM_NONBLOCK )) < 0 )

+    {

+        *pcm = NULL;     /* Not to be closed */

+        ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable : paBadIODeviceCombination );

+    }

+    ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );

+

+end:

+    return result;

+

+error:

+    goto end;

+}

+

+static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters,

+        double sampleRate, StreamDirection streamDir )

+{

+    PaError result = paNoError;

+    snd_pcm_t *pcm = NULL;

+    PaSampleFormat availableFormats;

+    /* We are able to adapt to a number of channels less than what the device supports */

+    unsigned int numHostChannels;

+    PaSampleFormat hostFormat;

+    snd_pcm_hw_params_t *hwParams;

+    snd_pcm_hw_params_alloca( &hwParams );

+    

+    if( !parameters->hostApiSpecificStreamInfo )

+    {

+        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device );

+        numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ?

+                devInfo->minInputChannels : devInfo->minOutputChannels );

+    }

+    else

+        numHostChannels = parameters->channelCount;

+

+    PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) );

+

+    snd_pcm_hw_params_any( pcm, hwParams );

+

+    if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 )

+    {

+        result = paInvalidSampleRate;

+        goto error;

+    }

+

+    if( snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 )

+    {

+        result = paInvalidChannelCount;

+        goto error;

+    }

+

+    /* See if we can find a best possible match */

+    availableFormats = GetAvailableFormats( pcm );

+    PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );

+    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError );

+

+    ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );

+

+end:

+    if( pcm )

+        snd_pcm_close( pcm );

+    return result;

+

+error:

+    goto end;

+}

+

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate )

+{

+    int inputChannelCount = 0, outputChannelCount = 0;

+    PaSampleFormat inputSampleFormat, outputSampleFormat;

+    PaError result = paFormatIsSupported;

+

+    if( inputParameters )

+    {

+        PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );

+

+        inputChannelCount = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+    }

+

+    if( outputParameters )

+    {

+        PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );

+

+        outputChannelCount = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+    }

+

+    if( inputChannelCount )

+    {

+        if( (result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ))

+                != paNoError )

+            goto error;

+    }

+    if ( outputChannelCount )

+    {

+        if( (result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ))

+                != paNoError )

+            goto error;

+    }

+

+    return paFormatIsSupported;

+

+error:

+    return result;

+}

+

+static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi,

+        const PaStreamParameters *params, StreamDirection streamDir, int callbackMode )

+{

+    PaError result = paNoError;

+    PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat;

+    assert( params->channelCount > 0 );

+

+    /* Make sure things have an initial value */

+    memset( self, 0, sizeof (PaAlsaStreamComponent) );

+

+    if( NULL == params->hostApiSpecificStreamInfo )

+    {

+        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->commonHostApiRep, params->device );

+        self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels

+                : devInfo->minOutputChannels );

+    }

+    else

+    {

+        /* We're blissfully unaware of the minimum channelCount */

+        self->numHostChannels = params->channelCount;

+    }

+

+    PA_ENSURE( AlsaOpen( &alsaApi->commonHostApiRep, params, streamDir, &self->pcm ) );

+    self->nfds = snd_pcm_poll_descriptors_count( self->pcm );

+    hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat );

+

+    self->hostSampleFormat = hostSampleFormat;

+    self->nativeFormat = Pa2AlsaFormat( hostSampleFormat );

+    self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved);

+    self->numUserChannels = params->channelCount;

+    self->streamDir = streamDir;

+

+    if( !callbackMode && !self->userInterleaved )

+    {

+        /* Pre-allocate non-interleaved user provided buffers */

+        PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ),

+                paInsufficientMemory );

+    }

+

+error:

+    return result;

+}

+

+static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )

+{

+    snd_pcm_close( self->pcm );

+    if( self->userBuffers )

+        PaUtil_FreeMemory( self->userBuffers );

+}

+

+/** Configure the associated ALSA pcm.

+ *

+ */

+static PaError PaAlsaStreamComponent_Configure( PaAlsaStreamComponent *self, const PaStreamParameters *params, unsigned long

+        framesPerHostBuffer, int primeBuffers, int callbackMode, double *sampleRate, PaTime *returnedLatency )

+{

+    /*

+    int numPeriods;

+

+    if( getenv("PA_NUMPERIODS") != NULL )

+        numPeriods = atoi( getenv("PA_NUMPERIODS") );

+    else

+        numPeriods = ( (latency * sampleRate) / *framesPerBuffer ) + 1;

+

+    PA_DEBUG(( "latency: %f, rate: %f, framesPerBuffer: %d\n", latency, sampleRate, *framesPerBuffer ));

+    if( numPeriods <= 1 )

+        numPeriods = 2;

+    */

+

+    /* Configuration consists of setting all of ALSA's parameters.

+     * These parameters come in two flavors: hardware parameters

+     * and software paramters.  Hardware parameters will affect

+     * the way the device is initialized, software parameters

+     * affect the way ALSA interacts with me, the user-level client.

+     */

+

+    snd_pcm_hw_params_t *hwParams;

+    snd_pcm_sw_params_t *swParams;

+    PaError result = paNoError;

+    snd_pcm_access_t accessMode, alternateAccessMode;

+    unsigned int numPeriods, minPeriods = 2;

+    int dir = 0;

+    snd_pcm_t *pcm = self->pcm;

+    PaTime latency = params->suggestedLatency;

+    double sr = *sampleRate;

+    *returnedLatency = -1.;

+

+    snd_pcm_hw_params_alloca( &hwParams );

+    snd_pcm_sw_params_alloca( &swParams );

+

+    self->framesPerBuffer = framesPerHostBuffer;

+

+    /* ... fill up the configuration space with all possibile

+     * combinations of parameters this device will accept */

+    ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );

+

+    ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );

+    ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );

+

+    if( self->userInterleaved )

+    {

+        accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;

+        alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;

+    }

+    else

+    {

+        accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;

+        alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;

+    }

+

+    /* If requested access mode fails, try alternate mode */

+    if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )

+    {

+        ENSURE_( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ), paUnanticipatedHostError );

+        /* Flip mode */

+        self->hostInterleaved = !self->userInterleaved;

+    }

+

+    ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );

+

+    ENSURE_( SetApproximateSampleRate( pcm, hwParams, sr ), paInvalidSampleRate );

+    ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError );

+    /* reject if there's no sample rate within 1% of the one requested */

+    if( (fabs( *sampleRate - sr ) / *sampleRate) > 0.01 )

+    {

+        PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));                 

+        PA_ENSURE( paInvalidSampleRate );

+    }

+

+    ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount );

+

+    /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */

+    dir = 0;

+    ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError );

+    dir = 0;

+    ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &self->framesPerBuffer, &dir ), paUnanticipatedHostError );

+    

+    /* Find an acceptable number of periods */

+    numPeriods = (latency * sr) / self->framesPerBuffer + 1;

+    dir = 0;

+    ENSURE_( snd_pcm_hw_params_set_periods_near( pcm, hwParams, &numPeriods, &dir ), paUnanticipatedHostError );

+    /* Minimum of periods should already be 2 */

+    PA_UNLESS( numPeriods >= 2, paInternalError );

+

+    /* Set the parameters! */

+    ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );

+    ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError );

+

+    /* Latency in seconds, one period is not counted as latency */

+    latency = (numPeriods - 1) * self->framesPerBuffer / sr;

+

+    /* Now software parameters... */

+    ENSURE_( snd_pcm_sw_params_current( pcm, swParams ), paUnanticipatedHostError );

+

+    ENSURE_( snd_pcm_sw_params_set_start_threshold( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );

+    ENSURE_( snd_pcm_sw_params_set_stop_threshold( pcm, swParams, self->bufferSize ), paUnanticipatedHostError );

+

+    /* Silence buffer in the case of underrun */

+    if( !primeBuffers ) /* XXX: Make sense? */

+    {

+        snd_pcm_uframes_t boundary;

+        ENSURE_( snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_sw_params_set_silence_threshold( pcm, swParams, 0 ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_sw_params_set_silence_size( pcm, swParams, boundary ), paUnanticipatedHostError );

+    }

+        

+    ENSURE_( snd_pcm_sw_params_set_avail_min( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );

+    ENSURE_( snd_pcm_sw_params_set_xfer_align( pcm, swParams, 1 ), paUnanticipatedHostError );

+    ENSURE_( snd_pcm_sw_params_set_tstamp_mode( pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError );

+

+    /* Set the parameters! */

+    ENSURE_( snd_pcm_sw_params( pcm, swParams ), paUnanticipatedHostError );

+

+    *sampleRate = sr;

+    *returnedLatency = latency;

+

+end:

+    return result;

+

+error:

+    goto end;   /* No particular action */

+}

+

+static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams,

+        const PaStreamParameters *outParams, double sampleRate, unsigned long framesPerUserBuffer, PaStreamCallback callback,

+        PaStreamFlags streamFlags, void *userData )

+{

+    PaError result = paNoError;

+    assert( self );

+

+    memset( self, 0, sizeof (PaAlsaStream) );

+

+    if( NULL != callback )

+    {

+        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,

+                                               &alsaApi->callbackStreamInterface,

+                                               callback, userData );

+        self->callbackMode = 1;

+    }

+    else

+    {

+        PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,

+                                               &alsaApi->blockingStreamInterface,

+                                               NULL, userData );

+    }

+

+    self->framesPerUserBuffer = framesPerUserBuffer;

+    self->neverDropInput = streamFlags & paNeverDropInput;

+    /* XXX: Ignore paPrimeOutputBuffersUsingStreamCallback untill buffer priming is fully supported in pa_process.c */

+    /*

+    if( outParams & streamFlags & paPrimeOutputBuffersUsingStreamCallback )

+        self->primeBuffers = 1;

+        */

+    memset( &self->capture, 0, sizeof (PaAlsaStreamComponent) );

+    memset( &self->playback, 0, sizeof (PaAlsaStreamComponent) );

+    if( inParams )

+        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback ) );

+    if( outParams )

+        PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->playback, alsaApi, outParams, StreamDirection_Out, NULL != callback ) );

+

+    assert( self->capture.nfds || self->playback.nfds );

+

+    PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( (self->capture.nfds +

+                    self->playback.nfds) * sizeof (struct pollfd) ), paInsufficientMemory );

+

+    PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate );

+    InitializeThreading( &self->threading, &self->cpuLoadMeasurer );

+    ASSERT_CALL_( pthread_mutex_init( &self->stateMtx, NULL ), 0 );

+    ASSERT_CALL_( pthread_mutex_init( &self->startMtx, NULL ), 0 );

+    ASSERT_CALL_( pthread_cond_init( &self->startCond, NULL ), 0 );

+

+error:

+    return result;

+}

+

+/** Free resources associated with stream, and eventually stream itself.

+ *

+ * Frees allocated memory, and terminates individual StreamComponents.

+ */

+static void PaAlsaStream_Terminate( PaAlsaStream *self )

+{

+    assert( self );

+

+    if( self->capture.pcm )

+    {

+        PaAlsaStreamComponent_Terminate( &self->capture );

+    }

+    if( self->playback.pcm )

+    {

+        PaAlsaStreamComponent_Terminate( &self->playback );

+    }

+

+    PaUtil_FreeMemory( self->pfds );

+    ASSERT_CALL_( pthread_mutex_destroy( &self->stateMtx ), 0 );

+    ASSERT_CALL_( pthread_mutex_destroy( &self->startMtx ), 0 );

+    ASSERT_CALL_( pthread_cond_destroy( &self->startCond ), 0 );

+

+    PaUtil_FreeMemory( self );

+}

+

+/** Calculate polling timeout

+ *

+ * @param frames Time to wait

+ * @return Polling timeout in milliseconds

+ */

+static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frames )

+{

+    assert( stream->streamRepresentation.streamInfo.sampleRate > 0.0 );

+    /* Period in msecs, rounded up */

+    return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate );

+}

+

+/** Set up ALSA stream parameters.

+ *

+ */

+static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters

+        *outParams, double sampleRate, unsigned long framesPerHostBuffer, double *inputLatency, double *outputLatency,

+        unsigned long *maxHostBufferSize )

+{

+    PaError result = paNoError;

+    double realSr = sampleRate;

+

+    if( self->capture.pcm )

+        PA_ENSURE( PaAlsaStreamComponent_Configure( &self->capture, inParams, framesPerHostBuffer, self->primeBuffers,

+                    self->callbackMode, &realSr, inputLatency ) );

+    if( self->playback.pcm )

+        PA_ENSURE( PaAlsaStreamComponent_Configure( &self->playback, outParams, framesPerHostBuffer, self->primeBuffers,

+                    self->callbackMode, &realSr, outputLatency ) );

+

+    /* Should be exact now */

+    self->streamRepresentation.streamInfo.sampleRate = realSr;

+

+    /* this will cause the two streams to automatically start/stop/prepare in sync.

+     * We only need to execute these operations on one of the pair.

+     * A: We don't want to do this on a blocking stream.

+     */

+    if( self->callbackMode && self->capture.pcm && self->playback.pcm )

+    {

+        int err = snd_pcm_link( self->capture.pcm, self->playback.pcm );

+        if( err >= 0 )

+            self->pcmsSynced = 1;

+        else

+            PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, snd_strerror( err ) ));

+    }

+

+    /* Frames per host buffer for the stream is set as a compromise between the two directions */

+    framesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX,

+            self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX );

+    self->pollTimeout = CalculatePollTimeout( self, framesPerHostBuffer );    /* Period in msecs, rounded up */

+

+    *maxHostBufferSize = PA_MAX( self->capture.pcm ? self->capture.bufferSize : 0,

+            self->playback.pcm ? self->playback.bufferSize : 0 );

+

+    /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */

+    self->threading.throttledSleepTime = (unsigned long) (framesPerHostBuffer / sampleRate / 4 * 1000);

+

+    if( self->callbackMode )

+    {

+        /* If the user expects a certain number of frames per callback we will either have to rely on block adaption

+         * (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number

+         * of host buffer frames with what the user specified */

+        if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )

+        {

+            /* self->alignFrames = 1; */

+

+            /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely

+             * on block adaption */

+        /*

+            if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm &&

+                        self->capture.framesPerBuffer != self->playback.framesPerBuffer) )

+                self->useBlockAdaption = 1;

+            else

+                self->alignFrames = 1;

+        */

+        }

+    }

+

+error:

+    return result;

+}

+

+/* We need to determine how many frames per host buffer to use.  Our

+ * goals are to provide the best possible performance, but also to

+ * most closely honor the requested latency settings.  Therefore this

+ * decision is based on:

+ *

+ *   - the period sizes that playback and/or capture support.  The

+ *     host buffer size has to be one of these.

+ *   - the number of periods that playback and/or capture support.

+ *

+ * We want to make period_size*(num_periods-1) to be as close as possible

+ * to latency*rate for both playback and capture.

+ *

+ * This is one of those blocks of code that will just take a lot of

+ * refinement to be any good.

+ *

+ * In the full-duplex case it is possible that the routine was unable

+ * to find a number of frames per buffer acceptable to both devices

+ * TODO: Implement an algorithm to find the value closest to acceptance

+ * by both devices, to minimize difference between period sizes?

+ */

+static PaError DetermineFramesPerBuffer( const PaAlsaStream *stream, double sampleRate, const PaStreamParameters *inputParameters,

+        const PaStreamParameters *outputParameters, unsigned long *determinedFrames, const PaUtilHostApiRepresentation *hostApi )

+{

+    PaError result = paNoError;

+    unsigned long framesPerBuffer = 0;

+    int numHostInputChannels = 0, numHostOutputChannels = 0;

+

+    /* XXX: Clean this up */

+    if( stream->capture.pcm )

+    {

+        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, inputParameters->device );

+        numHostInputChannels = PA_MAX( inputParameters->channelCount, devInfo->minInputChannels );

+    }

+    if( stream->playback.pcm )

+    {

+        const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, outputParameters->device );

+        numHostOutputChannels = PA_MAX( outputParameters->channelCount, devInfo->minOutputChannels );

+    }

+

+    if( stream->capture.pcm && stream->playback.pcm )

+    {

+        snd_pcm_uframes_t desiredLatency, e;

+        snd_pcm_uframes_t minPeriodSize, minPlayback, minCapture, maxPeriodSize, maxPlayback, maxCapture,

+                          optimalPeriodSize, periodSize;

+        int dir = 0;

+        unsigned int minPeriods = 2;

+

+        snd_pcm_t *pcm;

+        snd_pcm_hw_params_t *hwParamsPlayback, *hwParamsCapture;

+

+        snd_pcm_hw_params_alloca( &hwParamsPlayback );

+        snd_pcm_hw_params_alloca( &hwParamsCapture );

+

+        /* Come up with a common desired latency */

+        pcm = stream->playback.pcm;

+        snd_pcm_hw_params_any( pcm, hwParamsPlayback );

+        ENSURE_( SetApproximateSampleRate( pcm, hwParamsPlayback, sampleRate ), paInvalidSampleRate );

+        ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsPlayback, numHostOutputChannels ),

+                paBadIODeviceCombination );

+

+        ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsPlayback, &minPeriods, &dir ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );

+

+        pcm = stream->capture.pcm;

+        ENSURE_( snd_pcm_hw_params_any( pcm, hwParamsCapture ), paUnanticipatedHostError );

+        ENSURE_( SetApproximateSampleRate( pcm, hwParamsCapture, sampleRate ), paBadIODeviceCombination );

+        ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsCapture, numHostInputChannels ),

+                paBadIODeviceCombination );

+

+        ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsCapture, &minPeriods, &dir ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );

+

+        minPeriodSize = PA_MAX( minPlayback, minCapture );

+        maxPeriodSize = PA_MIN( maxPlayback, maxCapture );

+

+        desiredLatency = (snd_pcm_uframes_t) (PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )

+                * sampleRate);

+        /* Clamp desiredLatency */

+        {

+            snd_pcm_uframes_t tmp, maxBufferSize = ULONG_MAX;

+            ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSize ), paUnanticipatedHostError );

+            ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &tmp ), paUnanticipatedHostError );

+            maxBufferSize = PA_MIN( maxBufferSize, tmp );

+

+            desiredLatency = PA_MIN( desiredLatency, maxBufferSize );

+        }

+

+        /* Find the closest power of 2 */

+        e = ilogb( minPeriodSize );

+        if( minPeriodSize & (minPeriodSize - 1) )

+            e += 1;

+        periodSize = (snd_pcm_uframes_t) pow( 2, e );

+

+        while( periodSize <= maxPeriodSize )

+        {

+            if( snd_pcm_hw_params_test_period_size( stream->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&

+                    snd_pcm_hw_params_test_period_size( stream->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )

+                break;  /* Ok! */

+

+            periodSize *= 2;

+        }

+

+        /* 4 periods considered optimal */

+        optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );

+        optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );

+

+        /* Find the closest power of 2 */

+        e = ilogb( optimalPeriodSize );

+        if( optimalPeriodSize & (optimalPeriodSize - 1) )

+            e += 1;

+        optimalPeriodSize = (snd_pcm_uframes_t) pow( 2, e );

+

+        while( optimalPeriodSize >= periodSize )

+        {

+            pcm = stream->playback.pcm;

+            if( snd_pcm_hw_params_test_period_size( pcm, hwParamsPlayback, optimalPeriodSize, 0 ) < 0 )

+                continue;

+

+            pcm = stream->capture.pcm;

+            if( snd_pcm_hw_params_test_period_size( pcm, hwParamsCapture, optimalPeriodSize, 0 ) >= 0 )

+                break;

+

+            optimalPeriodSize /= 2;

+        }

+

+        if( optimalPeriodSize > periodSize )

+            periodSize = optimalPeriodSize;

+

+        if( periodSize <= maxPeriodSize )

+        {

+            /* Looks good */

+            framesPerBuffer = periodSize;

+        }

+        else

+        {

+            /* Unable to find a common period size, oh well */

+            optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );

+            optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );

+

+            /* ConfigureStream should find individual period sizes acceptable for each device */

+            framesPerBuffer = optimalPeriodSize;

+            /* PA_ENSURE( paBadIODeviceCombination ); */

+        }

+    }

+    else    /* half-duplex is a slightly simpler case */

+    {

+        unsigned long bufferSize, channels;

+        snd_pcm_t *pcm;

+        snd_pcm_hw_params_t *hwParams;

+

+        snd_pcm_hw_params_alloca( &hwParams );

+

+        if( stream->capture.pcm )

+        {

+            pcm = stream->capture.pcm;

+            bufferSize = inputParameters->suggestedLatency * sampleRate;

+            channels = numHostInputChannels;

+        }

+        else

+        {

+            pcm = stream->playback.pcm;

+            bufferSize = outputParameters->suggestedLatency * sampleRate;

+            channels = numHostOutputChannels;

+        }

+

+        ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );

+        ENSURE_( SetApproximateSampleRate( pcm, hwParams, sampleRate ), paInvalidSampleRate );

+        ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, channels ), paBadIODeviceCombination );

+

+        ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );

+

+        /* Using 5 as a base number of periods, we try to approximate the suggested latency (+1 period),

+           finding a combination of period/buffer size which best fits these constraints */

+        framesPerBuffer = bufferSize / 4;

+        bufferSize += framesPerBuffer;   /* One period doesn't count as latency */

+        ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &bufferSize ), paUnanticipatedHostError );

+        ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &framesPerBuffer, NULL ), paUnanticipatedHostError );

+    }

+

+    PA_UNLESS( framesPerBuffer != 0, paInternalError );

+    *determinedFrames = framesPerBuffer;

+

+error:

+    return result;

+}

+

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** s,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *callback,

+                           void *userData )

+{

+    PaError result = paNoError;

+    PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;

+    PaAlsaStream *stream = NULL;

+    PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0;

+    PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;

+    int numInputChannels = 0, numOutputChannels = 0;

+    PaTime inputLatency, outputLatency;

+    unsigned long framesPerHostBuffer;

+    PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilBoundedHostBufferSize;

+    unsigned long maxHostBufferSize;    /* Upper bound of host buffer size */

+

+    if( (streamFlags & paPlatformSpecificFlags) != 0 )

+        return paInvalidFlag;

+

+    if( inputParameters )

+    {

+        PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );

+

+        numInputChannels = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+    }

+    if( outputParameters )

+    {

+        PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );

+

+        numOutputChannels = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+    }

+

+    /* XXX: Why do we support this anyway? */

+    if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL )

+    {

+        PA_DEBUG(( "%s: Getting framesPerBuffer from environment\n", __FUNCTION__ ));

+        framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") );

+    }

+    framesPerHostBuffer = framesPerBuffer;

+

+    PA_UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory );

+    PA_ENSURE( PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate,

+                framesPerBuffer, callback, streamFlags, userData ) );

+

+    /* If the number of frames per buffer is unspecified, we have to come up with

+     * one. This is both a blessing and a curse: a blessing because we can optimize

+     * the number to best meet the requirements, but a curse because that's really

+     * hard to do well. For this reason we also support an interface where the user

+     * specifies these by setting environment variables. */

+    if( framesPerBuffer == paFramesPerBufferUnspecified )

+    {

+        PA_ENSURE( DetermineFramesPerBuffer( stream, sampleRate, inputParameters, outputParameters, &framesPerHostBuffer,

+                    hostApi ) );

+    }

+

+    PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerHostBuffer,

+                &inputLatency, &outputLatency, &maxHostBufferSize ) );

+    hostInputSampleFormat = stream->capture.hostSampleFormat;

+    hostOutputSampleFormat = stream->playback.hostSampleFormat;

+

+    if( framesPerHostBuffer != framesPerBuffer )

+    {

+        PA_DEBUG(( "%s: Number of frames per user and host buffer differs\n", __FUNCTION__ ));

+    }

+

+    PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,

+                    numInputChannels, inputSampleFormat, hostInputSampleFormat,

+                    numOutputChannels, outputSampleFormat, hostOutputSampleFormat,

+                    sampleRate, streamFlags, framesPerBuffer, maxHostBufferSize,

+                    hostBufferSizeMode, callback, userData ) );

+

+    /* Ok, buffer processor is initialized, now we can deduce it's latency */

+    if( numInputChannels > 0 )

+        stream->streamRepresentation.streamInfo.inputLatency = inputLatency + PaUtil_GetBufferProcessorInputLatency(

+                &stream->bufferProcessor );

+    if( numOutputChannels > 0 )

+        stream->streamRepresentation.streamInfo.outputLatency = outputLatency + PaUtil_GetBufferProcessorOutputLatency(

+                &stream->bufferProcessor );

+

+    *s = (PaStream*)stream;

+

+    return result;

+

+error:

+    if( stream )

+        PaAlsaStream_Terminate( stream );

+

+    return result;

+}

+

+static PaError CloseStream( PaStream* s )

+{

+    PaError result = paNoError;

+    PaAlsaStream *stream = (PaAlsaStream*)s;

+

+    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );

+    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );

+

+    PaAlsaStream_Terminate( stream );

+

+    return result;

+}

+

+static void SilenceBuffer( PaAlsaStream *stream )

+{

+    const snd_pcm_channel_area_t *areas;

+    snd_pcm_uframes_t frames = (snd_pcm_uframes_t)snd_pcm_avail_update( stream->playback.pcm ), offset;

+

+    snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames );

+    snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat );

+    snd_pcm_mmap_commit( stream->playback.pcm, offset, frames );

+}

+

+/** Start/prepare pcm(s) for streaming.

+ *

+ * Depending on wether the stream is in callback or blocking mode, we will respectively start or simply

+ * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and

+ * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will

+ * be started automatically as the user writes to output. 

+ *

+ * The capture pcm, however, will simply be prepared and started.

+ *

+ * PaAlsaStream::startMtx makes sure access is synchronized (useful in callback mode)

+ */

+static PaError AlsaStart( PaAlsaStream *stream, int priming )

+{

+    PaError result = paNoError;

+

+    if( stream->playback.pcm )

+    {

+        if( stream->callbackMode )

+        {

+            if( !priming )

+            {

+                /* Buffer isn't primed, so prepare and silence */

+                ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );

+                SilenceBuffer( stream );

+            }

+            ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );

+        }

+        else

+            ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );

+    }

+    if( stream->capture.pcm && !stream->pcmsSynced )

+    {

+        ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );

+        /* For a blocking stream we want to start capture as well, since nothing will happen otherwise */

+        ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );

+    }

+

+end:

+    return result;

+error:

+    goto end;

+}

+

+/** Utility function for determining if pcms are in running state.

+ *

+ */

+static int IsRunning( PaAlsaStream *stream )

+{

+    int result = 0;

+

+    ASSERT_CALL_( pthread_mutex_lock( &stream->stateMtx ), 0 ); /* Synchronize access to pcm state */

+    if( stream->capture.pcm )

+    {

+        snd_pcm_state_t capture_state = snd_pcm_state( stream->capture.pcm );

+

+        if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN

+                || capture_state == SND_PCM_STATE_DRAINING )

+        {

+            result = 1;

+            goto end;

+        }

+    }

+

+    if( stream->playback.pcm )

+    {

+        snd_pcm_state_t playback_state = snd_pcm_state( stream->playback.pcm );

+

+        if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN

+                || playback_state == SND_PCM_STATE_DRAINING )

+        {

+            result = 1;

+            goto end;

+        }

+    }

+

+end:

+    ASSERT_CALL_( pthread_mutex_unlock( &stream->stateMtx ), 0 );

+

+    return result;

+}

+

+static PaError StartStream( PaStream *s )

+{

+    PaError result = paNoError;

+    PaAlsaStream *stream = (PaAlsaStream*)s;

+    int streamStarted = 0;  /* So we can know wether we need to take the stream down */

+

+    /* Ready the processor */

+    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );

+

+    /* Set now, so we can test for activity further down */

+    stream->isActive = 1;

+

+    if( stream->callbackMode )

+    {

+        int res = 0;

+        PaTime pt = PaUtil_GetTime();

+        struct timespec ts;

+

+        PA_ENSURE( CreateCallbackThread( &stream->threading, &CallbackThreadFunc, stream ) );

+        streamStarted = 1;

+

+        /* Wait for stream to be started */

+        ts.tv_sec = (time_t) floor( pt + 1 );

+        ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000);

+

+        /* Since we'll be holding a lock on the startMtx (when not waiting on the condition), IsRunning won't be checking

+         * stream state at the same time as the callback thread affects it. We also check IsStreamActive, in the unlikely

+         * case the callback thread exits in the meantime (the stream will be considered inactive after the thread exits) */

+        ASSERT_CALL_( pthread_mutex_lock( &stream->startMtx ), 0 );

+

+        /* Due to possible spurious wakeups, we enclose in a loop */

+        while( !IsRunning( stream ) && IsStreamActive( s ) && !res )

+        {

+            res = pthread_cond_timedwait( &stream->startCond, &stream->startMtx, &ts );

+        }

+        ASSERT_CALL_( pthread_mutex_unlock( &stream->startMtx ), 0 );

+

+        PA_UNLESS( !res || res == ETIMEDOUT, paInternalError );

+        PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - pt ));

+

+        if( res == ETIMEDOUT )

+        {

+            PA_ENSURE( paTimedOut );

+        }

+    }

+    else

+    {

+        PA_ENSURE( AlsaStart( stream, 0 ) );

+        streamStarted = 1;

+    }

+

+end:

+    return result;

+error:

+    if( streamStarted )

+        AbortStream( stream );

+    stream->isActive = 0;

+    

+    goto end;

+}

+

+static PaError AlsaStop( PaAlsaStream *stream, int abort )

+{

+    PaError result = paNoError;

+

+    if( abort )

+    {

+        if( stream->playback.pcm )

+            ENSURE_( snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError );

+        if( stream->capture.pcm && !stream->pcmsSynced )

+            ENSURE_( snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError );

+

+        PA_DEBUG(( "Dropped frames\n" ));

+    }

+    else

+    {

+        if( stream->playback.pcm )

+            ENSURE_( snd_pcm_drain( stream->playback.pcm ), paUnanticipatedHostError );

+        if( stream->capture.pcm && !stream->pcmsSynced )

+            ENSURE_( snd_pcm_drain( stream->capture.pcm ), paUnanticipatedHostError );

+    }

+

+end:

+    return result;

+error:

+    goto end;

+}

+

+/** Stop or abort stream.

+ *

+ * If a stream is in callback mode we will have to inspect wether the background thread has

+ * finished, or we will have to take it out. In either case we join the thread before

+ * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish

+ * buffers (drain)

+ *

+ * Stream will be considered inactive (!PaAlsaStream::isActive) after a call to this function

+ */

+static PaError RealStop( PaAlsaStream *stream, int abort )

+{

+    PaError result = paNoError;

+

+    /* First deal with the callback thread, cancelling and/or joining

+     * it if necessary

+     */

+    if( stream->callbackMode )

+    {

+        PaError threadRes, watchdogRes;

+        stream->callbackAbort = abort;

+

+        if( !abort )

+        {

+            PA_DEBUG(( "Stopping callback\n" ));

+            stream->callbackStop = 1;

+        }

+        PA_ENSURE( KillCallbackThread( &stream->threading, !abort, &threadRes, &watchdogRes ) );

+        if( threadRes != paNoError )

+            PA_DEBUG(( "Callback thread returned: %d\n", threadRes ));

+        if( watchdogRes != paNoError )

+            PA_DEBUG(( "Watchdog thread returned: %d\n", watchdogRes ));

+

+        stream->callbackStop = 0;   /* The deed is done */

+        stream->callback_finished = 0;

+    }

+    else

+    {

+        PA_ENSURE( AlsaStop( stream, abort ) );

+    }

+

+    stream->isActive = 0;

+

+end:

+    return result;

+

+error:

+    goto end;

+}

+

+static PaError StopStream( PaStream *s )

+{

+    return RealStop( (PaAlsaStream *) s, 0 );

+}

+

+static PaError AbortStream( PaStream *s )

+{

+    return RealStop( (PaAlsaStream * ) s, 1 );

+}

+

+/** The stream is considered stopped before StartStream, or AFTER a call to Abort/StopStream (callback

+ * returning !paContinue is not considered)

+ *

+ */

+static PaError IsStreamStopped( PaStream *s )

+{

+    PaAlsaStream *stream = (PaAlsaStream *)s;

+

+    /* callback_finished indicates we need to join callback thread (ie. in Abort/StopStream) */

+    return !IsStreamActive( s ) && !stream->callback_finished;

+}

+

+static PaError IsStreamActive( PaStream *s )

+{

+    PaAlsaStream *stream = (PaAlsaStream*)s;

+    return stream->isActive;

+}

+

+static PaTime GetStreamTime( PaStream *s )

+{

+    PaAlsaStream *stream = (PaAlsaStream*)s;

+

+    snd_timestamp_t timestamp;

+    snd_pcm_status_t *status;

+    snd_pcm_status_alloca( &status );

+

+    /* TODO: what if we have both?  does it really matter? */

+

+    /* TODO: if running in callback mode, this will mean

+     * libasound routines are being called from multiple threads.

+     * need to verify that libasound is thread-safe. */

+

+    if( stream->capture.pcm )

+    {

+        snd_pcm_status( stream->capture.pcm, status );

+    }

+    else if( stream->playback.pcm )

+    {

+        snd_pcm_status( stream->playback.pcm, status );

+    }

+

+    snd_pcm_status_get_tstamp( status, &timestamp );

+    return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1000000.0;

+}

+

+static double GetStreamCpuLoad( PaStream* s )

+{

+    PaAlsaStream *stream = (PaAlsaStream*)s;

+

+    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );

+}

+

+static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate )

+{

+    unsigned long approx = (unsigned long) sampleRate;

+    int dir = 0;

+    double fraction = sampleRate - approx;

+

+    assert( pcm && hwParams );

+

+    if( fraction > 0.0 )

+    {

+        if( fraction > 0.5 )

+        {

+            ++approx;

+            dir = -1;

+        }

+        else

+            dir = 1;

+    }

+

+    return snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir );

+}

+

+/* Return exact sample rate in param sampleRate */

+static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate )

+{

+    unsigned int num, den;

+    int err; 

+

+    assert( hwParams );

+

+    err = snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den );

+    *sampleRate = (double) num / den;

+

+    return err;

+}

+

+/* Utility functions for blocking/callback interfaces */

+

+/* Atomic restart of stream (we don't want the intermediate state visible) */

+static PaError AlsaRestart( PaAlsaStream *stream )

+{

+    PaError result = paNoError;

+

+    ASSERT_CALL_( pthread_mutex_lock( &stream->stateMtx ), 0 );

+    PA_ENSURE( AlsaStop( stream, 0 ) );

+    PA_ENSURE( AlsaStart( stream, 0 ) );

+

+    PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ ));

+

+error:

+    ASSERT_CALL_( pthread_mutex_unlock( &stream->stateMtx ), 0 );

+    return result;

+}

+

+/** Recover from xrun state.

+ *

+ */

+static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self )

+{

+    PaError result = paNoError;

+    snd_pcm_status_t *st;

+    PaTime now = PaUtil_GetTime();

+    snd_timestamp_t t;

+

+    snd_pcm_status_alloca( &st );

+

+    if( self->playback.pcm )

+    {

+        snd_pcm_status( self->playback.pcm, st );

+        if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )

+        {

+            snd_pcm_status_get_trigger_tstamp( st, &t );

+            self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);

+        }

+    }

+    if( self->capture.pcm )

+    {

+        snd_pcm_status( self->capture.pcm, st );

+        if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )

+        {

+            snd_pcm_status_get_trigger_tstamp( st, &t );

+            self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);

+        }

+    }

+

+    PA_ENSURE( AlsaRestart( self ) );

+

+end:

+    return result;

+error:

+    goto end;

+}

+

+/** Decide if we should continue polling for specified direction, eventually adjust the poll timeout.

+ * 

+ */

+static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamDir, int *pollTimeout, int *continuePoll )

+{

+    PaError result = paNoError;

+    snd_pcm_sframes_t delay, margin;

+    int err;

+    const PaAlsaStreamComponent *component = NULL, *otherComponent = NULL;

+

+    *continuePoll = 1;

+

+    if( StreamDirection_In == streamDir )

+    {

+        component = &stream->capture;

+        otherComponent = &stream->playback;

+    }

+    else

+    {

+        component = &stream->playback;

+        otherComponent = &stream->capture;

+    }

+

+    /* ALSA docs say that negative delay should indicate xrun, but in my experience snd_pcm_delay returns -EPIPE */

+    if( (err = snd_pcm_delay( otherComponent->pcm, &delay )) < 0 )

+    {

+        if( err == -EPIPE )

+        {

+            /* Xrun */

+            *continuePoll = 0;

+            goto error;

+        }

+

+        ENSURE_( err, paUnanticipatedHostError );

+    }

+

+    if( StreamDirection_Out == streamDir )

+    {

+        /* Number of eligible frames before capture overrun */

+        delay = otherComponent->bufferSize - delay;

+    }

+    margin = delay - otherComponent->framesPerBuffer / 2;

+

+    if( margin < 0 )

+    {

+        PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" ));

+        *continuePoll = 0;

+    }

+    else if( margin < otherComponent->framesPerBuffer )

+    {

+        *pollTimeout = CalculatePollTimeout( stream, margin );

+        PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n",

+                    __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback", *pollTimeout ));

+    }

+

+error:

+    return result;

+}

+

+/* Callback interface */

+

+static void OnExit( void *data )

+{

+    PaAlsaStream *stream = (PaAlsaStream *) data;

+

+    assert( data );

+

+    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );

+

+    stream->callback_finished = 1;  /* Let the outside world know stream was stopped in callback */

+    AlsaStop( stream, stream->callbackAbort );

+    stream->callbackAbort = 0;      /* Clear state */

+    

+    PA_DEBUG(( "OnExit: Stoppage\n" ));

+

+    /* Eventually notify user all buffers have played */

+    if( stream->streamRepresentation.streamFinishedCallback )

+        stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );

+    stream->isActive = 0;

+}

+

+static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *timeInfo )

+{

+    snd_pcm_status_t *capture_status, *playback_status;

+    snd_timestamp_t capture_timestamp, playback_timestamp;

+    PaTime capture_time = 0., playback_time = 0.;

+

+    snd_pcm_status_alloca( &capture_status );

+    snd_pcm_status_alloca( &playback_status );

+

+    if( stream->capture.pcm )

+    {

+        snd_pcm_sframes_t capture_delay;

+

+        snd_pcm_status( stream->capture.pcm, capture_status );

+        snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );

+

+        capture_time = capture_timestamp.tv_sec +

+            ((PaTime)capture_timestamp.tv_usec / 1000000.0);

+        timeInfo->currentTime = capture_time;

+

+        capture_delay = snd_pcm_status_get_delay( capture_status );

+        timeInfo->inputBufferAdcTime = timeInfo->currentTime -

+            (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;

+    }

+    if( stream->playback.pcm )

+    {

+        snd_pcm_sframes_t playback_delay;

+

+        snd_pcm_status( stream->playback.pcm, playback_status );

+        snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );

+

+        playback_time = playback_timestamp.tv_sec +

+            ((PaTime)playback_timestamp.tv_usec / 1000000.0);

+

+        if( stream->capture.pcm ) /* Full duplex */

+        {

+            /* Hmm, we have both a playback and a capture timestamp.

+             * Hopefully they are the same... */

+            if( fabs( capture_time - playback_time ) > 0.01 )

+                PA_DEBUG(("Capture time and playback time differ by %f\n", fabs(capture_time-playback_time)));

+        }

+        else

+            timeInfo->currentTime = playback_time;

+

+        playback_delay = snd_pcm_status_get_delay( playback_status );

+        timeInfo->outputBufferDacTime = timeInfo->currentTime +

+            (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;

+    }

+}

+

+/** Called after buffer processing is finished.

+ *

+ * A number of mmapped frames is committed, it is possible that an xrun has occurred in the meantime.

+ *

+ * @param numFrames The number of frames that has been processed

+ * @param xrun Return whether an xrun has occurred

+ */

+static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun )

+{

+    PaError result = paNoError;

+    int res;

+

+    /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed

+     * afterwards

+     */

+    if( !self->ready )

+        goto end;

+

+    res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );

+    if( res == -EPIPE || res == -ESTRPIPE )

+    {

+        *xrun = 1;

+    }

+    else

+    {

+        ENSURE_( res, paUnanticipatedHostError );

+    }

+

+end:

+error:

+    return result;

+}

+

+/* Extract buffer from channel area */

+static unsigned char *ExtractAddress( const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset )

+{

+    return (unsigned char *) area->addr + (area->first + offset * area->step) / 8;

+}

+

+/** Do necessary adaption between user and host channels.

+ *

+    @concern ChannelAdaption Adapting between user and host channels can involve silencing unused channels and

+    duplicating mono information if host outputs come in pairs.

+ */

+static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp, int numFrames )

+{

+    PaError result = paNoError;

+    unsigned char *p;

+    int i;

+    int unusedChans = self->numHostChannels - self->numUserChannels;

+    unsigned char *src, *dst;

+    int convertMono = (self->numHostChannels % 2) == 0 && (self->numUserChannels % 2) != 0;

+

+    assert( StreamDirection_Out == self->streamDir );

+

+    if( self->hostInterleaved )

+    {

+        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );

+        unsigned char *buffer = ExtractAddress( self->channelAreas, self->offset );

+

+        /* Start after the last user channel */

+        p = buffer + self->numUserChannels * swidth;

+

+        if( convertMono )

+        {

+            /* Convert the last user channel into stereo pair */

+            src = buffer + (self->numUserChannels - 1) * swidth;

+            for( i = 0; i < numFrames; ++i )

+            {

+                dst = src + swidth;

+                memcpy( dst, src, swidth );

+                src += self->numHostChannels * swidth;

+            }

+

+            /* Don't touch the channel we just wrote to */

+            p += swidth;

+            --unusedChans;

+        }

+

+        if( unusedChans > 0 )

+        {

+            /* Silence unused output channels */

+            for( i = 0; i < numFrames; ++i )

+            {

+                memset( p, 0, swidth * unusedChans );

+                p += self->numHostChannels * swidth;

+            }

+        }

+    }

+    else

+    {

+        /* We extract the last user channel */

+        if( convertMono )

+        {

+            ENSURE_( snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas +

+                    (self->numUserChannels - 1), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError );

+            --unusedChans;

+        }

+        if( unusedChans > 0 )

+        {

+            snd_pcm_areas_silence( self->channelAreas + (self->numHostChannels - unusedChans), self->offset, unusedChans, numFrames,

+                    self->nativeFormat );

+        }

+    }

+

+error:

+    return result;

+}

+

+static PaError PaAlsaStream_EndProcessing( PaAlsaStream *self, unsigned long numFrames, int *xrunOccurred )

+{

+    PaError result = paNoError;

+    int xrun = 0;

+

+    if( self->capture.pcm )

+    {

+        PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->capture, numFrames, &xrun ) );

+    }

+    if( self->playback.pcm )

+    {

+        if( self->playback.numHostChannels > self->playback.numUserChannels )

+            PA_ENSURE( PaAlsaStreamComponent_DoChannelAdaption( &self->playback, &self->bufferProcessor, numFrames ) );

+        PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->playback, numFrames, &xrun ) );

+    }

+

+error:

+    *xrunOccurred = xrun;

+    return result;

+}

+

+/** Update the number of available frames.

+ *

+ */

+static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *self, unsigned long *numFrames, int *xrunOccurred )

+{

+    PaError result = paNoError;

+    snd_pcm_sframes_t framesAvail = snd_pcm_avail_update( self->pcm );

+    *xrunOccurred = 0;

+

+    if( -EPIPE == framesAvail )

+    {

+        *xrunOccurred = 1;

+        framesAvail = 0;

+    }

+    else

+        ENSURE_( framesAvail, paUnanticipatedHostError );

+

+    *numFrames = framesAvail;

+

+error:

+    return result;

+}

+

+/** Fill in pollfd objects.

+ */

+static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent *self, struct pollfd *pfds )

+{

+    PaError result = paNoError;

+    int ret = snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds );

+    assert( ret == self->nfds );

+

+    self->ready = 0;

+

+    return result;

+}

+

+/** Examine results from poll().

+ *

+ * @param pfds pollfds to inspect

+ * @param shouldPoll Should we continue to poll

+ * @param xrun Has an xrun occurred

+ */

+static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent *self, struct pollfd *pfds, int *shouldPoll, int *xrun )

+{

+    PaError result = paNoError;

+    unsigned short revents;

+

+    ENSURE_( snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError );

+    if( revents != 0 )

+    {

+        if( revents & POLLERR )

+        {

+            *xrun = 1;

+        }

+        else

+            self->ready = 1;

+

+        *shouldPoll = 0;

+    }

+

+error:

+    return result;

+}

+

+/** Return the number of available frames for this stream.

+ *

+ * @concern FullDuplex The minimum available for the two directions is calculated, it might be desirable to ignore

+ * one direction however (not marked ready from poll), so this is controlled by queryCapture and queryPlayback.

+ *

+ * @param queryCapture Check available for capture

+ * @param queryPlayback Check available for playback

+ * @param available The returned number of frames

+ * @param xrunOccurred Return whether an xrun has occurred

+ */

+static PaError PaAlsaStream_GetAvailableFrames( PaAlsaStream *self, int queryCapture, int queryPlayback, unsigned long

+        *available, int *xrunOccurred )

+{

+    PaError result = paNoError;

+    unsigned long captureFrames, playbackFrames;

+    *xrunOccurred = 0;

+

+    assert( queryCapture || queryPlayback );

+

+    if( queryCapture )

+    {

+        assert( self->capture.pcm );

+        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->capture, &captureFrames, xrunOccurred ) );

+        if( *xrunOccurred )

+            goto end;

+    }

+    if( queryPlayback )

+    {

+        assert( self->playback.pcm );

+        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->playback, &playbackFrames, xrunOccurred ) );

+        if( *xrunOccurred )

+            goto end;

+    }

+

+    if( queryCapture && queryPlayback )

+    {

+        *available = PA_MIN( captureFrames, playbackFrames );

+    }

+    else if( queryCapture )

+    {

+        *available = captureFrames;

+    }

+    else

+    {

+        *available = playbackFrames;

+    }

+

+end:

+error:

+    return result;

+}

+

+/** Wait for and report available buffer space from ALSA.

+ *

+ * Unless ALSA reports a minimum of frames available for I/O, we poll the ALSA filedescriptors for more.

+ * Both of these operations can uncover xrun conditions.

+ *

+ * @concern Xruns Both polling and querying available frames can report an xrun condition.

+ *

+ * @param framesAvail Return the number of available frames

+ * @param xrunOccurred Return whether an xrun has occurred

+ */ 

+static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *framesAvail, int *xrunOccurred )

+{

+    PaError result = paNoError;

+    int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL;

+    int pollTimeout = self->pollTimeout;

+    int xrun = 0;

+

+    assert( self );

+    assert( framesAvail );

+

+    if( !self->callbackMode )

+    {

+        /* In blocking mode we will only wait if necessary */

+        PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, self->capture.pcm != NULL, self->playback.pcm != NULL,

+                    framesAvail, &xrun ) );

+        if( xrun )

+        {

+            goto end;

+        }

+

+        if( *framesAvail > 0 )

+        {

+            /* Mark pcms ready from poll */

+            if( self->capture.pcm )

+                self->capture.ready = 1;

+            if( self->playback.pcm )

+                self->playback.ready = 1;

+

+            goto end;

+        }

+    }

+

+    while( pollPlayback || pollCapture )

+    {

+        int totalFds = 0;

+        struct pollfd *capturePfds = NULL, *playbackPfds = NULL;

+

+        pthread_testcancel();

+

+        if( pollCapture )

+        {

+            capturePfds = self->pfds;

+            PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->capture, capturePfds ) );

+            totalFds += self->capture.nfds;

+        }

+        if( pollPlayback )

+        {

+            playbackPfds = self->pfds + (self->capture.pcm ? self->capture.nfds : 0);

+            PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) );

+            totalFds += self->playback.nfds;

+        }

+

+        if( poll( self->pfds, totalFds, pollTimeout ) < 0 )

+        {

+            /*  XXX: Depend on preprocessor condition? */

+            if( errno == EINTR ) {  /* gdb */

+                continue;

+            }

+

+            /* TODO: Add macro for checking system calls */

+            PA_ENSURE( paInternalError );

+        }

+

+        /* check the return status of our pfds */

+        if( pollCapture )

+        {

+            PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->capture, capturePfds, &pollCapture, &xrun ) );

+        }

+        if( pollPlayback )

+        {

+            PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->playback, playbackPfds, &pollPlayback, &xrun ) );

+        }

+        if( xrun )

+        {

+            break;

+        }

+

+        /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two.

+         * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will

+         * stop polling.

+         */

+        if( self->capture.pcm && self->playback.pcm )

+        {

+            if( pollCapture && !pollPlayback )

+            {

+                PA_ENSURE( ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture ) );

+            }

+            else if( pollPlayback && !pollCapture )

+            {

+                PA_ENSURE( ContinuePoll( self, StreamDirection_Out, &pollTimeout, &pollPlayback ) );

+            }

+        }

+    }

+

+    if( !xrun )

+    {

+        /* Get the number of available frames for the pcms that are marked ready.

+         * @concern FullDuplex If only one direction is marked ready (from poll), the number of frames available for

+         * the other direction is returned. This under the assumption that input is dropped earlier if paNeverDropInput

+         * is not specified.

+         */

+        int captureReady = self->capture.pcm ? self->capture.ready : 0,

+            playbackReady = self->playback.pcm ? self->playback.ready : 0;

+        PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, captureReady, playbackReady, framesAvail, &xrun ) );

+

+        if( self->capture.pcm && self->playback.pcm )

+        {

+            if( !self->playback.ready && !self->neverDropInput )

+            {

+                /* TODO: Drop input */

+            }

+        }

+    }

+

+end:

+error:

+    if( xrun )

+    {

+        /* Recover from the xrun state */

+        PA_ENSURE( PaAlsaStream_HandleXrun( self ) );

+        *framesAvail = 0;

+    }

+    *xrunOccurred = xrun;

+

+    return result;

+}

+

+/** Register per-channel ALSA buffer information with buffer processor.

+ *

+ * Mmapped buffer space is acquired from ALSA, and registered with the buffer processor. Differences between the

+ * number of host and user channels is taken into account.

+ * 

+ * @param numFrames On entrance the number of requested frames, on exit the number of contiguously accessible frames.

+ */

+static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp,

+        unsigned long *numFrames, int *xrun )

+{

+    PaError result = paNoError;

+    const snd_pcm_channel_area_t *areas, *area;

+    void (*setChannel)(PaUtilBufferProcessor *, unsigned int, void *, unsigned int) =

+        StreamDirection_In == self->streamDir ? PaUtil_SetInputChannel : PaUtil_SetOutputChannel;

+    unsigned char *buffer, *p;

+    int i;

+    unsigned long framesAvail;

+

+    /* This _must_ be called before mmap_begin */

+    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( self, &framesAvail, xrun ) );

+    if( *xrun )

+    {

+        *numFrames = 0;

+        goto end;

+    }

+

+    ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );

+

+    if( self->hostInterleaved )

+    {

+        int swidth = snd_pcm_format_size( self->nativeFormat, 1 );

+

+        p = buffer = ExtractAddress( areas, self->offset );

+        for( i = 0; i < self->numUserChannels; ++i )

+        {

+            /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */

+            setChannel( bp, i, p, self->numHostChannels );

+            p += swidth;

+        }

+    }

+    else

+    {

+        for( i = 0; i < self->numUserChannels; ++i )

+        {

+            area = areas + i;

+            buffer = ExtractAddress( area, self->offset );

+            setChannel( bp, i, buffer, 1 );

+        }

+    }

+

+    /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */

+    self->channelAreas = (snd_pcm_channel_area_t *)areas;

+

+end:

+error:

+    return result;

+}

+

+/** Initiate buffer processing.

+ *

+ * ALSA buffers are registered with the PA buffer processor and the buffer size (in frames) set.

+ *

+ * @concern FullDuplex If both directions are being processed, the minimum amount of frames for the two directions is

+ * calculated.

+ *

+ * @param numFrames On entrance the number of available frames, on exit the number of received frames

+ * @param xrunOccurred Return whether an xrun has occurred

+ */

+static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream *self, unsigned long *numFrames, int *xrunOccurred )

+{

+    PaError result = paNoError;

+    unsigned long captureFrames = ULONG_MAX, playbackFrames = ULONG_MAX, commonFrames = 0;

+    int xrun = 0;

+

+    /* Extract per-channel ALSA buffer pointers and register them with the buffer processor.

+     * It is possible that a direction is not marked ready however, because it is out of sync with the other.

+     */

+    if( self->capture.pcm && self->capture.ready )

+    {

+        captureFrames = *numFrames;

+        PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->capture, &self->bufferProcessor, &captureFrames, 

+                    &xrun ) );

+    }

+    if( self->playback.pcm && self->playback.ready )

+    {

+        playbackFrames = *numFrames;

+        PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->playback, &self->bufferProcessor, &playbackFrames, 

+                    &xrun ) );

+    }

+    if( xrun )

+    {

+        /* Nothing more to do */

+        assert( 0 == commonFrames );

+        goto end;

+    }

+

+    commonFrames = PA_MIN( captureFrames, playbackFrames );

+    assert( commonFrames <= *numFrames );

+

+    /* Inform PortAudio of the number of frames we got.

+     * @concern FullDuplex We might be experiencing underflow in either end; if its an input underflow, we go on

+     * with output. If its output underflow however, depending on the paNeverDropInput flag, we may want to simply

+     * discard the excess input or call the callback with paOutputOverflow flagged.

+     */

+    if( self->capture.pcm )

+    {

+        if( self->capture.ready )

+        {

+            PaUtil_SetInputFrameCount( &self->bufferProcessor, commonFrames );

+        }

+        else

+        {

+            /* We have input underflow */

+            PaUtil_SetNoInput( &self->bufferProcessor );

+        }

+    }

+    if( self->playback.pcm )

+    {

+        if( self->playback.ready )

+        {

+            PaUtil_SetOutputFrameCount( &self->bufferProcessor, commonFrames );

+        }

+        else

+        {

+            /* We have output underflow, but keeping input data (paNeverDropInput) */

+            /* assert( self->neverDropInput ); */

+            PaUtil_SetNoOutput( &self->bufferProcessor );

+        }

+    }

+    

+end:

+    *numFrames = commonFrames;

+error:

+    if( xrun )

+    {

+        PA_ENSURE( PaAlsaStream_HandleXrun( self ) );

+        *numFrames = 0;

+    }

+    *xrunOccurred = xrun;

+

+    return result;

+}

+

+/** Callback thread's function.

+ *

+ * Roughly, the workflow can be described in the following way: The number of available frames that can be processed

+ * directly is obtained from ALSA, we then request as much directly accessible memory as possible within this amount

+ * from ALSA. The buffer memory is registered with the PA buffer processor and processing is carried out with

+ * PaUtil_EndBufferProcessing. Finally, the number of processed frames is reported to ALSA. The processing can

+ * happen in several iterations untill we have consumed the known number of available frames (or an xrun is detected).

+ */

+static void *CallbackThreadFunc( void *userData )

+{

+    PaError result = paNoError, *pres = NULL;

+    PaAlsaStream *stream = (PaAlsaStream*) userData;

+    PaStreamCallbackTimeInfo timeInfo = {0, 0, 0};

+    snd_pcm_sframes_t startThreshold = 0;

+    int callbackResult = paContinue;

+    PaStreamCallbackFlags cbFlags = 0;  /* We might want to keep state across iterations */

+    int streamStarted = 0;

+

+    assert( stream );

+

+    callbackThread_ = pthread_self();

+    /* Execute OnExit when exiting */

+    pthread_cleanup_push( &OnExit, stream );

+

+    /* Not implemented */

+    assert( !stream->primeBuffers );

+

+    /* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the

+     * stream is started immediately. The latter involves signaling the waiting main thread.

+     */

+    if( stream->primeBuffers )

+    {

+        snd_pcm_sframes_t avail;

+        

+        if( stream->playback.pcm )

+            ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );

+        if( stream->capture.pcm && !stream->pcmsSynced )

+            ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );

+

+        /* We can't be certain that the whole ring buffer is available for priming, but there should be

+         * at least one period */

+        avail = snd_pcm_avail_update( stream->playback.pcm );

+        startThreshold = avail - (avail % stream->playback.framesPerBuffer);

+        assert( startThreshold >= stream->playback.framesPerBuffer );

+    }

+    else

+    {

+        ASSERT_CALL_( pthread_mutex_lock( &stream->startMtx ), 0 );

+        PA_ENSURE( AlsaStart( stream, 0 ) );    /* Buffer will be zeroed */

+        ASSERT_CALL_( pthread_cond_signal( &stream->startCond ), 0 );

+        ASSERT_CALL_( pthread_mutex_unlock( &stream->startMtx ), 0 );

+

+        streamStarted = 1;

+    }

+

+    while( 1 )

+    {

+        unsigned long framesAvail, framesGot;

+        int xrun = 0;

+

+        pthread_testcancel();

+

+        /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively

+         * stopped we signal this condition by modifying callbackResult (we'll want to flush buffered output).

+         */

+        if( stream->callbackStop && paContinue == callbackResult )

+        {

+            PA_DEBUG(( "Setting callbackResult to paComplete\n" ));

+            callbackResult = paComplete;

+        }

+

+        if( paContinue != callbackResult )

+        {

+            stream->callbackAbort = (paAbort == callbackResult);

+            if( stream->callbackAbort ||

+                    /** @concern BlockAdaption Go on if adaption buffers are empty */

+                    PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) 

+                goto end;

+

+            PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ ));

+            /* There is still buffered output that needs to be processed */

+        }

+

+        /* Wait for data to become available, this comes down to polling the ALSA file descriptors untill we have

+         * a number of available frames.

+         */

+        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );

+        if( xrun )

+        {

+            assert( 0 == framesAvail );

+            continue;

+

+            /* XXX: Report xruns to the user? A situation is conceivable where the callback is never invoked due

+             * to constant xruns, it might be desirable to notify the user of this.

+             */

+        }

+

+        /* Consume buffer space. Once we have a number of frames available for consumption we must retrieve the

+         * mmapped buffers from ALSA, this is contiguously accessible memory however, so we may receive smaller

+         * portions at a time than is available as a whole. Therefore we should be prepared to process several

+         * chunks successively. The buffers are passed to the PA buffer processor.

+         */

+        while( framesAvail > 0 )

+        {

+            xrun = 0;

+

+            pthread_testcancel();

+

+            /** @concern Xruns Under/overflows are to be reported to the callback */

+            if( stream->underrun > 0.0 )

+            {

+                cbFlags |= paOutputUnderflow;

+                stream->underrun = 0.0;

+            }

+            if( stream->overrun > 0.0 )

+            {

+                cbFlags |= paInputOverflow;

+                stream->overrun = 0.0;

+            }

+            if( stream->capture.pcm && stream->playback.pcm )

+            {

+                /** @concern FullDuplex It's possible that only one direction is being processed to avoid an

+                 * under- or overflow, this should be reported correspondingly */

+                if( !stream->capture.ready )

+                {

+                    cbFlags |= paInputUnderflow;

+                    PA_DEBUG(( "%s: Input underflow\n", __FUNCTION__ ));

+                }

+                else if( !stream->playback.ready )

+                {

+                    cbFlags |= paOutputOverflow;

+                    PA_DEBUG(( "%s: Output overflow\n", __FUNCTION__ ));

+                }

+            }

+

+            CallbackUpdate( &stream->threading );

+            CalculateTimeInfo( stream, &timeInfo );

+            PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags );

+            cbFlags = 0;

+

+            /* CPU load measurement should include processing activivity external to the stream callback */

+            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

+

+            framesGot = framesAvail;

+            PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );

+            framesAvail -= framesGot;

+

+            if( framesGot > 0 )

+            {

+                assert( !xrun );

+

+                PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );

+                PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );

+            }

+            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot );

+

+            if( framesGot == 0 )

+            {

+                if( !xrun )

+                    PA_DEBUG(( "%s: Received less frames than reported from ALSA!\n", __FUNCTION__ ));

+

+                /* Go back to polling for more frames */

+                break;

+

+            }

+

+            if( paContinue != callbackResult )

+                break;

+        }

+    }

+

+    /* Match pthread_cleanup_push */

+    pthread_cleanup_pop( 1 );

+

+end:

+    pthread_exit( pres );

+

+error:

+    /* Pass on error code */

+    pres = malloc( sizeof (PaError) );

+    *pres = result;

+    

+    goto end;

+}

+

+/* Blocking interface */

+

+static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames )

+{

+    PaError result = paNoError;

+    PaAlsaStream *stream = (PaAlsaStream*)s;

+    unsigned long framesGot, framesAvail;

+    void *userBuffer;

+    snd_pcm_t *save = stream->playback.pcm;

+

+    assert( stream );

+

+    PA_UNLESS( stream->capture.pcm, paCanNotReadFromAnOutputOnlyStream );

+

+    /* Disregard playback */

+    stream->playback.pcm = NULL;

+

+    if( stream->overrun > 0. )

+    {

+        result = paInputOverflowed;

+        stream->overrun = 0.0;

+    }

+

+    if( stream->capture.userInterleaved )

+        userBuffer = buffer;

+    else

+    {

+        /* Copy channels into local array */

+        userBuffer = stream->capture.userBuffers;

+        memcpy( userBuffer, buffer, sizeof (void *) * stream->capture.numUserChannels );

+    }

+

+    /* Start stream if in prepared state */

+    if( snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED )

+    {

+        ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );

+    }

+

+    while( frames > 0 )

+    {

+        int xrun = 0;

+        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );

+        framesGot = PA_MIN( framesAvail, frames );

+

+        PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );

+        if( framesGot > 0 )

+        {

+            framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot );

+            PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );

+            frames -= framesGot;

+        }

+    }

+

+end:

+    stream->playback.pcm = save;

+    return result;

+error:

+    goto end;

+}

+

+static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames )

+{

+    PaError result = paNoError;

+    signed long err;

+    PaAlsaStream *stream = (PaAlsaStream*)s;

+    snd_pcm_uframes_t framesGot, framesAvail;

+    const void *userBuffer;

+    snd_pcm_t *save = stream->capture.pcm;

+    

+    assert( stream );

+

+    PA_UNLESS( stream->playback.pcm, paCanNotWriteToAnInputOnlyStream );

+

+    /* Disregard capture */

+    stream->capture.pcm = NULL;

+

+    if( stream->underrun > 0. )

+    {

+        result = paOutputUnderflowed;

+        stream->underrun = 0.0;

+    }

+

+    if( stream->playback.userInterleaved )

+        userBuffer = buffer;

+    else /* Copy channels into local array */

+    {

+        userBuffer = stream->playback.userBuffers;

+        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback.numUserChannels );

+    }

+

+    while( frames > 0 )

+    {

+        int xrun = 0;

+        snd_pcm_uframes_t hwAvail;

+

+        PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );

+        framesGot = PA_MIN( framesAvail, frames );

+

+        PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );

+        if( framesGot > 0 )

+        {

+            framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot );

+            PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );

+            frames -= framesGot;

+        }

+

+        /* Frames residing in buffer */

+        PA_ENSURE( err = GetStreamWriteAvailable( stream ) );

+        framesAvail = err;

+        hwAvail = stream->playback.bufferSize - framesAvail;

+

+        /* Start stream after one period of samples worth */

+        if( snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED &&

+                hwAvail >= stream->playback.framesPerBuffer )

+        {

+            ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );

+        }

+    }

+

+end:

+    stream->capture.pcm = save;

+    return result;

+error:

+    goto end;

+}

+

+/* Return frames available for reading. In the event of an overflow, the capture pcm will be restarted */

+static signed long GetStreamReadAvailable( PaStream* s )

+{

+    PaError result = paNoError;

+    PaAlsaStream *stream = (PaAlsaStream*)s;

+    unsigned long avail;

+    int xrun;

+

+    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );

+    if( xrun )

+    {

+        PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );

+        PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );

+        if( xrun )

+            PA_ENSURE( paInputOverflowed );

+    }

+

+    return (signed long)avail;

+

+error:

+    return result;

+}

+

+static signed long GetStreamWriteAvailable( PaStream* s )

+{

+    PaError result = paNoError;

+    PaAlsaStream *stream = (PaAlsaStream*)s;

+    unsigned long avail;

+    int xrun;

+

+    PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->playback, &avail, &xrun ) );

+    if( xrun )

+    {

+        snd_pcm_sframes_t savail;

+

+        PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );

+        savail = snd_pcm_avail_update( stream->playback.pcm );

+

+        /* savail should not contain -EPIPE now, since PaAlsaStream_HandleXrun will only prepare the pcm */

+        ENSURE_( savail, paUnanticipatedHostError );

+

+        avail = (unsigned long) savail;

+    }

+

+    return (signed long)avail;

+

+error:

+    return result;

+}

+

+/* Extensions */

+

+/* Initialize host api specific structure */

+void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info )

+{

+    info->size = sizeof (PaAlsaStreamInfo);

+    info->hostApiType = paALSA;

+    info->version = 1;

+    info->deviceString = NULL;

+}

+

+void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable )

+{

+    PaAlsaStream *stream = (PaAlsaStream *) s;

+    stream->threading.rtSched = enable;

+}

+

+void PaAlsa_EnableWatchdog( PaStream *s, int enable )

+{

+    PaAlsaStream *stream = (PaAlsaStream *) s;

+    stream->threading.useWatchdog = enable;

+}

diff --git a/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.h b/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.h
index e6f44b1..a8d811b 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.h
@@ -1,64 +1,85 @@
-#ifndef PA_LINUX_ALSA_H
-#define PA_LINUX_ALSA_H
-
-/*
- * $Id: pa_linux_alsa.h,v 1.1.2.12 2004/09/25 14:15:25 aknudsen Exp $
- * PortAudio Portable Real-Time Audio Library
- * ALSA-specific extensions
- *
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-/** @file
- * ALSA-specific PortAudio API extension header file.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct PaAlsaStreamInfo
-{
-    unsigned long size;
-    PaHostApiTypeId hostApiType;
-    unsigned long version;
-
-    const char *deviceString;
-}
-PaAlsaStreamInfo;
-
-void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info );
-
-void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable );
-
-void PaAlsa_EnableWatchdog( PaStream *s, int enable );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_LINUX_ALSA_H

+#define PA_LINUX_ALSA_H

+

+/*

+ * $Id: pa_linux_alsa.h,v 1.1.2.12 2004/09/25 14:15:25 aknudsen Exp $

+ * PortAudio Portable Real-Time Audio Library

+ * ALSA-specific extensions

+ *

+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ *

+ */

+

+/** @file

+ * ALSA-specific PortAudio API extension header file.

+ */

+

+#ifdef __cplusplus

+extern "C" {

+#endif

+

+typedef struct PaAlsaStreamInfo

+{

+    unsigned long size;

+    PaHostApiTypeId hostApiType;

+    unsigned long version;

+

+    const char *deviceString;

+}

+PaAlsaStreamInfo;

+

+void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info );

+

+void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable );

+

+void PaAlsa_EnableWatchdog( PaStream *s, int enable );

+

+#ifdef __cplusplus

+}

+#endif

+

+#endif

diff --git a/pjmedia/src/pjmedia/portaudio/pa_process.c b/pjmedia/src/pjmedia/portaudio/pa_process.c
index cf711d4..041593b 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_process.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_process.c
@@ -1,1756 +1,1777 @@
-/*
- * $Id: pa_process.c,v 1.1.2.48 2004/12/13 09:48:43 rossbencina Exp $
- * Portable Audio I/O Library
- * streamCallback <-> host buffer processing adapter
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Buffer Processor implementation.
-    
- The code in this file is not optimised yet - although it's not clear that
- it needs to be. there may appear to be redundancies
- that could be factored into common functions, but the redundanceis are left
- intentionally as each appearance may have different optimisation possibilities.
-
- The optimisations which are planned involve only converting data in-place
- where possible, rather than copying to the temp buffer(s).
-
- Note that in the extreme case of being able to convert in-place, and there
- being no conversion necessary there should be some code which short-circuits
- the operation.
-
-    @todo Consider cache tilings for intereave<->deinterleave.
-
-    @todo implement timeInfo->currentTime int PaUtil_BeginBufferProcessing()
-
-    @todo specify and implement some kind of logical policy for handling the
-        underflow and overflow stream flags when the underflow/overflow overlaps
-        multiple user buffers/callbacks.
-
-	@todo provide support for priming the buffers with data from the callback.
-        The client interface is now implemented through PaUtil_SetNoInput()
-        which sets bp->hostInputChannels[0][0].data to zero. However this is
-        currently only implemented in NonAdaptingProcess(). It shouldn't be
-        needed for AdaptingInputOnlyProcess() (no priming should ever be
-        requested for AdaptingInputOnlyProcess()).
-        Not sure if additional work should be required to make it work with
-        AdaptingOutputOnlyProcess, but it definitely is required for
-        AdaptingProcess.
-
-    @todo implement PaUtil_SetNoOutput for AdaptingProcess
-
-    @todo don't allocate temp buffers for blocking streams unless they are
-        needed. At the moment they are needed, but perhaps for host APIs
-        where the implementation passes a buffer to the host they could be
-        used.
-*/
-
-
-#include <assert.h>
-#include <string.h> /* memset() */
-
-#include "pa_process.h"
-#include "pa_util.h"
-
-
-#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_    1024
-
-#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) )
-
-
-/* greatest common divisor - PGCD in French */
-static unsigned long GCD( unsigned long a, unsigned long b )
-{
-    return (b==0) ? a : GCD( b, a%b);
-}
-
-/* least common multiple - PPCM in French */
-static unsigned long LCM( unsigned long a, unsigned long b )
-{
-    return (a*b) / GCD(a,b);
-}
-
-#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b))
-
-static unsigned long CalculateFrameShift( unsigned long M, unsigned long N )
-{
-    unsigned long result = 0;
-    unsigned long i;
-    unsigned long lcm;
-
-    assert( M > 0 );
-    assert( N > 0 );
-
-    lcm = LCM( M, N );
-    for( i = M; i < lcm; i += M )
-        result = PA_MAX_( result, i % N );
-
-    return result;
-}
-
-
-PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
-        int inputChannelCount, PaSampleFormat userInputSampleFormat,
-        PaSampleFormat hostInputSampleFormat,
-        int outputChannelCount, PaSampleFormat userOutputSampleFormat,
-        PaSampleFormat hostOutputSampleFormat,
-        double sampleRate,
-        PaStreamFlags streamFlags,
-        unsigned long framesPerUserBuffer,
-        unsigned long framesPerHostBuffer,
-        PaUtilHostBufferSizeMode hostBufferSizeMode,
-        PaStreamCallback *streamCallback, void *userData )
-{
-    PaError result = paNoError;
-    PaError bytesPerSample;
-    unsigned long tempInputBufferSize, tempOutputBufferSize;
-
-    /* initialize buffer ptrs to zero so they can be freed if necessary in error */
-    bp->tempInputBuffer = 0;
-    bp->tempInputBufferPtrs = 0;
-    bp->tempOutputBuffer = 0;
-    bp->tempOutputBufferPtrs = 0;
-
-    bp->framesPerUserBuffer = framesPerUserBuffer;
-    bp->framesPerHostBuffer = framesPerHostBuffer;
-
-    bp->inputChannelCount = inputChannelCount;
-    bp->outputChannelCount = outputChannelCount;
-
-    bp->hostBufferSizeMode = hostBufferSizeMode;
-
-    bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0;
-    bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0;
-
-    if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */
-    {
-        bp->useNonAdaptingProcess = 1;
-        bp->initialFramesInTempInputBuffer = 0;
-        bp->initialFramesInTempOutputBuffer = 0;
-
-        if( hostBufferSizeMode == paUtilFixedHostBufferSize
-                || hostBufferSizeMode == paUtilBoundedHostBufferSize )
-        {
-            bp->framesPerTempBuffer = framesPerHostBuffer;
-        }
-        else /* unknown host buffer size */
-        {
-             bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_;
-        }
-    }
-    else
-    {
-        bp->framesPerTempBuffer = framesPerUserBuffer;
-
-        if( hostBufferSizeMode == paUtilFixedHostBufferSize
-                && framesPerHostBuffer % framesPerUserBuffer == 0 )
-        {
-            bp->useNonAdaptingProcess = 1;
-            bp->initialFramesInTempInputBuffer = 0;
-            bp->initialFramesInTempOutputBuffer = 0;
-        }
-        else
-        {
-            bp->useNonAdaptingProcess = 0;
-
-            if( inputChannelCount > 0 && outputChannelCount > 0 )
-            {
-                /* full duplex */
-                if( hostBufferSizeMode == paUtilFixedHostBufferSize )
-                {
-                    unsigned long frameShift =
-                        CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer );
-
-                    if( framesPerUserBuffer > framesPerHostBuffer )
-                    {
-                        bp->initialFramesInTempInputBuffer = frameShift;
-                        bp->initialFramesInTempOutputBuffer = 0;
-                    }
-                    else
-                    {
-                        bp->initialFramesInTempInputBuffer = 0;
-                        bp->initialFramesInTempOutputBuffer = frameShift;
-                    }
-                }
-                else /* variable host buffer size, add framesPerUserBuffer latency */
-                {
-                    bp->initialFramesInTempInputBuffer = 0;
-                    bp->initialFramesInTempOutputBuffer = framesPerUserBuffer;
-                }
-            }
-            else
-            {
-                /* half duplex */
-                bp->initialFramesInTempInputBuffer = 0;
-                bp->initialFramesInTempOutputBuffer = 0;
-            }
-        }
-    }
-
-
-    bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
-    bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
-
-    
-    if( inputChannelCount > 0 )
-    {
-        bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat );
-        if( bytesPerSample > 0 )
-        {
-            bp->bytesPerHostInputSample = bytesPerSample;
-        }
-        else
-        {
-            result = bytesPerSample;
-            goto error;
-        }
-
-        bytesPerSample = Pa_GetSampleSize( userInputSampleFormat );
-        if( bytesPerSample > 0 )
-        {
-            bp->bytesPerUserInputSample = bytesPerSample;
-        }
-        else
-        {
-            result = bytesPerSample;
-            goto error;
-        }
-
-        bp->inputConverter =
-            PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, streamFlags );
-
-        bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat );
-            
-        bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
-
-
-        tempInputBufferSize =
-            bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
-         
-        bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );
-        if( bp->tempInputBuffer == 0 )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-        
-        if( bp->framesInTempInputBuffer > 0 )
-            memset( bp->tempInputBuffer, 0, tempInputBufferSize );
-
-        if( userInputSampleFormat & paNonInterleaved )
-        {
-            bp->tempInputBufferPtrs =
-                (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );
-            if( bp->tempInputBufferPtrs == 0 )
-            {
-                result = paInsufficientMemory;
-                goto error;
-            }
-        }
-
-        bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)
-                PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);
-        if( bp->hostInputChannels[0] == 0 )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];
-    }
-
-    if( outputChannelCount > 0 )
-    {
-        bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );
-        if( bytesPerSample > 0 )
-        {
-            bp->bytesPerHostOutputSample = bytesPerSample;
-        }
-        else
-        {
-            result = bytesPerSample;
-            goto error;
-        }
-
-        bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );
-        if( bytesPerSample > 0 )
-        {
-            bp->bytesPerUserOutputSample = bytesPerSample;
-        }
-        else
-        {
-            result = bytesPerSample;
-            goto error;
-        }
-
-        bp->outputConverter =
-            PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );
-
-        bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat );
-
-        bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
-
-        tempOutputBufferSize =
-                bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
-
-        bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );
-        if( bp->tempOutputBuffer == 0 )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        if( bp->framesInTempOutputBuffer > 0 )
-            memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
-        
-        if( userOutputSampleFormat & paNonInterleaved )
-        {
-            bp->tempOutputBufferPtrs =
-                (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );
-            if( bp->tempOutputBufferPtrs == 0 )
-            {
-                result = paInsufficientMemory;
-                goto error;
-            }
-        }
-
-        bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)
-                PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );
-        if( bp->hostOutputChannels[0] == 0 )
-        {                                                                     
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];
-    }
-
-    PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );
-
-    bp->samplePeriod = 1. / sampleRate;
-
-    bp->streamCallback = streamCallback;
-    bp->userData = userData;
-
-    return result;
-
-error:
-    if( bp->tempInputBuffer )
-        PaUtil_FreeMemory( bp->tempInputBuffer );
-
-    if( bp->tempInputBufferPtrs )
-        PaUtil_FreeMemory( bp->tempInputBufferPtrs );
-
-    if( bp->hostInputChannels[0] )
-        PaUtil_FreeMemory( bp->hostInputChannels[0] );
-
-    if( bp->tempOutputBuffer )
-        PaUtil_FreeMemory( bp->tempOutputBuffer );
-
-    if( bp->tempOutputBufferPtrs )
-        PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
-
-    if( bp->hostOutputChannels[0] )
-        PaUtil_FreeMemory( bp->hostOutputChannels[0] );
-
-    return result;
-}
-
-
-void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )
-{
-    if( bp->tempInputBuffer )
-        PaUtil_FreeMemory( bp->tempInputBuffer );
-
-    if( bp->tempInputBufferPtrs )
-        PaUtil_FreeMemory( bp->tempInputBufferPtrs );
-
-    if( bp->hostInputChannels[0] )
-        PaUtil_FreeMemory( bp->hostInputChannels[0] );
-        
-    if( bp->tempOutputBuffer )
-        PaUtil_FreeMemory( bp->tempOutputBuffer );
-
-    if( bp->tempOutputBufferPtrs )
-        PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
-
-    if( bp->hostOutputChannels[0] )
-        PaUtil_FreeMemory( bp->hostOutputChannels[0] );
-}
-
-
-void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp )
-{
-    unsigned long tempInputBufferSize, tempOutputBufferSize;
-
-    bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
-    bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
-
-    if( bp->framesInTempInputBuffer > 0 )
-    {
-        tempInputBufferSize =
-            bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount;
-        memset( bp->tempInputBuffer, 0, tempInputBufferSize );
-    }
-
-    if( bp->framesInTempOutputBuffer > 0 )
-    {      
-        tempOutputBufferSize =
-            bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount;
-        memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
-    }
-}
-
-
-unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bp )
-{
-    return bp->initialFramesInTempInputBuffer;
-}
-
-
-unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bp )
-{
-    return bp->initialFramesInTempOutputBuffer;
-}
-
-
-void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,
-        unsigned long frameCount )
-{
-    if( frameCount == 0 )
-        bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;
-    else
-        bp->hostInputFrameCount[0] = frameCount;
-}
-        
-
-void PaUtil_SetNoInput( PaUtilBufferProcessor* bp )
-{
-    assert( bp->inputChannelCount > 0 );
-
-    bp->hostInputChannels[0][0].data = 0;
-}
-
-
-void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,
-        unsigned int channel, void *data, unsigned int stride )
-{
-    assert( channel < bp->inputChannelCount );
-    
-    bp->hostInputChannels[0][channel].data = data;
-    bp->hostInputChannels[0][channel].stride = stride;
-}
-
-
-void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
-        unsigned int firstChannel, void *data, unsigned int channelCount )
-{
-    unsigned int i;
-    unsigned int channel = firstChannel;
-    unsigned char *p = (unsigned char*)data;
-
-    if( channelCount == 0 )
-        channelCount = bp->inputChannelCount;
-
-    assert( firstChannel < bp->inputChannelCount );
-    assert( firstChannel + channelCount <= bp->inputChannelCount );
-
-    for( i=0; i< channelCount; ++i )
-    {
-        bp->hostInputChannels[0][channel+i].data = p;
-        p += bp->bytesPerHostInputSample;
-        bp->hostInputChannels[0][channel+i].stride = channelCount;
-    }
-}
-
-
-void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
-        unsigned int channel, void *data )
-{
-    assert( channel < bp->inputChannelCount );
-    
-    bp->hostInputChannels[0][channel].data = data;
-    bp->hostInputChannels[0][channel].stride = 1;
-}
-
-
-void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,
-        unsigned long frameCount )
-{
-    bp->hostInputFrameCount[1] = frameCount;
-}
-
-
-void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,
-        unsigned int channel, void *data, unsigned int stride )
-{
-    assert( channel < bp->inputChannelCount );
-
-    bp->hostInputChannels[1][channel].data = data;
-    bp->hostInputChannels[1][channel].stride = stride;
-}
-
-
-void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
-        unsigned int firstChannel, void *data, unsigned int channelCount )
-{
-    unsigned int i;
-    unsigned int channel = firstChannel;
-    unsigned char *p = (unsigned char*)data;
-
-    if( channelCount == 0 )
-        channelCount = bp->inputChannelCount;
-
-    assert( firstChannel < bp->inputChannelCount );
-    assert( firstChannel + channelCount <= bp->inputChannelCount );
-    
-    for( i=0; i< channelCount; ++i )
-    {
-        bp->hostInputChannels[1][channel+i].data = p;
-        p += bp->bytesPerHostInputSample;
-        bp->hostInputChannels[1][channel+i].stride = channelCount;
-    }
-}
-
-        
-void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
-        unsigned int channel, void *data )
-{
-    assert( channel < bp->inputChannelCount );
-    
-    bp->hostInputChannels[1][channel].data = data;
-    bp->hostInputChannels[1][channel].stride = 1;
-}
-
-
-void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,
-        unsigned long frameCount )
-{
-    if( frameCount == 0 )
-        bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;
-    else
-        bp->hostOutputFrameCount[0] = frameCount;
-}
-
-
-void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp )
-{
-    assert( bp->outputChannelCount > 0 );
-
-    bp->hostOutputChannels[0][0].data = 0;
-}
-
-
-void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
-        unsigned int channel, void *data, unsigned int stride )
-{
-    assert( channel < bp->outputChannelCount );
-    
-    bp->hostOutputChannels[0][channel].data = data;
-    bp->hostOutputChannels[0][channel].stride = stride;
-}
-
-
-void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
-        unsigned int firstChannel, void *data, unsigned int channelCount )
-{
-    unsigned int i;
-    unsigned int channel = firstChannel;
-    unsigned char *p = (unsigned char*)data;
-
-    if( channelCount == 0 )
-        channelCount = bp->outputChannelCount;
-
-    assert( firstChannel < bp->outputChannelCount );
-    assert( firstChannel + channelCount <= bp->outputChannelCount );
-    
-    for( i=0; i< channelCount; ++i )
-    {
-        bp->hostOutputChannels[0][channel+i].data = p;
-        p += bp->bytesPerHostOutputSample;
-        bp->hostOutputChannels[0][channel+i].stride = channelCount;
-    }
-}
-
-
-void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
-        unsigned int channel, void *data )
-{
-    assert( channel < bp->outputChannelCount );
-
-    bp->hostOutputChannels[0][channel].data = data;
-    bp->hostOutputChannels[0][channel].stride = 1;
-}
-
-
-void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,
-        unsigned long frameCount )
-{
-    bp->hostOutputFrameCount[1] = frameCount;
-}
-
-
-void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
-        unsigned int channel, void *data, unsigned int stride )
-{
-    assert( channel < bp->outputChannelCount );
-
-    bp->hostOutputChannels[1][channel].data = data;
-    bp->hostOutputChannels[1][channel].stride = stride;
-}
-
-
-void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
-        unsigned int firstChannel, void *data, unsigned int channelCount )
-{
-    unsigned int i;
-    unsigned int channel = firstChannel;
-    unsigned char *p = (unsigned char*)data;
-
-    if( channelCount == 0 )
-        channelCount = bp->outputChannelCount;
-
-    assert( firstChannel < bp->outputChannelCount );
-    assert( firstChannel + channelCount <= bp->outputChannelCount );
-    
-    for( i=0; i< channelCount; ++i )
-    {
-        bp->hostOutputChannels[1][channel+i].data = p;
-        p += bp->bytesPerHostOutputSample;
-        bp->hostOutputChannels[1][channel+i].stride = channelCount;
-    }
-}
-
-        
-void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
-        unsigned int channel, void *data )
-{
-    assert( channel < bp->outputChannelCount );
-    
-    bp->hostOutputChannels[1][channel].data = data;
-    bp->hostOutputChannels[1][channel].stride = 1;
-}
-
-
-void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp,
-        PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags )
-{
-    bp->timeInfo = timeInfo;
-
-    /* the first streamCallback will be called to process samples which are
-        currently in the input buffer before the ones starting at the timeInfo time */
-        
-    bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;
-    
-    bp->timeInfo->currentTime = 0; /** FIXME: @todo time info currentTime not implemented */
-
-    /* the first streamCallback will be called to generate samples which will be
-        outputted after the frames currently in the output buffer have been
-        outputted. */
-    bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;
-
-    bp->callbackStatusFlags = callbackStatusFlags;
-
-    bp->hostInputFrameCount[1] = 0;
-    bp->hostOutputFrameCount[1] = 0;
-}
-
-
-/*
-    NonAdaptingProcess() is a simple buffer copying adaptor that can handle
-    both full and half duplex copies. It processes framesToProcess frames,
-    broken into blocks bp->framesPerTempBuffer long.
-    This routine can be used when the streamCallback doesn't care what length
-    the buffers are, or when framesToProcess is an integer multiple of
-    bp->framesPerTempBuffer, in which case streamCallback will always be called
-    with bp->framesPerTempBuffer samples.
-*/
-static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
-        int *streamCallbackResult,
-        PaUtilChannelDescriptor *hostInputChannels,
-        PaUtilChannelDescriptor *hostOutputChannels,
-        unsigned long framesToProcess )
-{
-    void *userInput, *userOutput;
-    unsigned char *srcBytePtr, *destBytePtr;
-    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
-    unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
-    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
-    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
-    unsigned int i;
-    unsigned long frameCount;
-    unsigned long framesToGo = framesToProcess;
-    unsigned long framesProcessed = 0;
-
-
-    if( *streamCallbackResult == paContinue )
-    {
-        do
-        {
-            frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo );
-
-            /* configure user input buffer and convert input data (host -> user) */
-            if( bp->inputChannelCount == 0 )
-            {
-                /* no input */
-                userInput = 0;
-            }
-            else /* there are input channels */
-            {
-                /*
-                    could use more elaborate logic here and sometimes process
-                    buffers in-place.
-                */
-            
-                destBytePtr = (unsigned char *)bp->tempInputBuffer;
-
-                if( bp->userInputIsInterleaved )
-                {
-                    destSampleStrideSamples = bp->inputChannelCount;
-                    destChannelStrideBytes = bp->bytesPerUserInputSample;
-                    userInput = bp->tempInputBuffer;
-                }
-                else /* user input is not interleaved */
-                {
-                    destSampleStrideSamples = 1;
-                    destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;
-
-                    /* setup non-interleaved ptrs */
-                    for( i=0; i<bp->inputChannelCount; ++i )
-                    {
-                        bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
-                            i * bp->bytesPerUserInputSample * frameCount;
-                    }
-                
-                    userInput = bp->tempInputBufferPtrs;
-                }
-
-                if( !bp->hostInputChannels[0][0].data )
-                {
-                    /* no input was supplied (see PaUtil_SetNoInput), so
-                        zero the input buffer */
-
-                    for( i=0; i<bp->inputChannelCount; ++i )
-                    {
-                        bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount );
-                        destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
-                    }
-                }
-                else
-                {
-                    for( i=0; i<bp->inputChannelCount; ++i )
-                    {
-                        bp->inputConverter( destBytePtr, destSampleStrideSamples,
-                                                hostInputChannels[i].data,
-                                                hostInputChannels[i].stride,
-                                                frameCount, &bp->ditherGenerator );
-
-                        destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
-
-                        /* advance src ptr for next iteration */
-                        hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
-                                frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
-                    }
-                }
-            }
-
-            /* configure user output buffer */
-            if( bp->outputChannelCount == 0 )
-            {
-                /* no output */
-                userOutput = 0;
-            }
-            else /* there are output channels */
-            {
-                if( bp->userOutputIsInterleaved )
-                {
-                    userOutput = bp->tempOutputBuffer;
-                }
-                else /* user output is not interleaved */
-                {
-                    for( i = 0; i < bp->outputChannelCount; ++i )
-                    {
-                        bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
-                            i * bp->bytesPerUserOutputSample * frameCount;
-                    }
-
-                    userOutput = bp->tempOutputBufferPtrs;
-                }
-            }
-        
-            *streamCallbackResult = bp->streamCallback( userInput, userOutput,
-                    frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData );
-
-            if( *streamCallbackResult == paAbort )
-            {
-                /* callback returned paAbort, don't advance framesProcessed
-                        and framesToGo, they will be handled below */
-            }
-            else
-            {
-                bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
-                bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;
-
-                /* convert output data (user -> host) */
-                
-                if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
-                {
-                    /*
-                        could use more elaborate logic here and sometimes process
-                        buffers in-place.
-                    */
-            
-                    srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
-
-                    if( bp->userOutputIsInterleaved )
-                    {
-                        srcSampleStrideSamples = bp->outputChannelCount;
-                        srcChannelStrideBytes = bp->bytesPerUserOutputSample;
-                    }
-                    else /* user output is not interleaved */
-                    {
-                        srcSampleStrideSamples = 1;
-                        srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;
-                    }
-
-                    for( i=0; i<bp->outputChannelCount; ++i )
-                    {
-                        bp->outputConverter(    hostOutputChannels[i].data,
-                                                hostOutputChannels[i].stride,
-                                                srcBytePtr, srcSampleStrideSamples,
-                                                frameCount, &bp->ditherGenerator );
-
-                        srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
-
-                        /* advance dest ptr for next iteration */
-                        hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
-                                frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
-                    }
-                }
-             
-                framesProcessed += frameCount;
-
-                framesToGo -= frameCount;
-            }
-        }
-        while( framesToGo > 0  && *streamCallbackResult == paContinue );
-    }
-
-    if( framesToGo > 0 )
-    {
-        /* zero any remaining frames output. There will only be remaining frames
-            if the callback has returned paComplete or paAbort */
-
-        frameCount = framesToGo;
-
-        if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
-        {
-            for( i=0; i<bp->outputChannelCount; ++i )
-            {
-                bp->outputZeroer(   hostOutputChannels[i].data,
-                                    hostOutputChannels[i].stride,
-                                    frameCount );
-
-                /* advance dest ptr for next iteration */
-                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
-                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
-            }
-        }
-
-        framesProcessed += frameCount;
-    }
-
-    return framesProcessed;
-}
-
-
-/*
-    AdaptingInputOnlyProcess() is a half duplex input buffer processor. It
-    converts data from the input buffers into the temporary input buffer,
-    when the temporary input buffer is full, it calls the streamCallback.
-*/
-static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
-        int *streamCallbackResult,
-        PaUtilChannelDescriptor *hostInputChannels,
-        unsigned long framesToProcess )
-{
-    void *userInput, *userOutput;
-    unsigned char *destBytePtr;
-    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
-    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
-    unsigned int i;
-    unsigned long frameCount;
-    unsigned long framesToGo = framesToProcess;
-    unsigned long framesProcessed = 0;
-    
-    userOutput = 0;
-
-    do
-    {
-        frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )
-                ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )
-                : framesToGo;
-
-        /* convert frameCount samples into temp buffer */
-
-        if( bp->userInputIsInterleaved )
-        {
-            destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
-                    bp->bytesPerUserInputSample * bp->inputChannelCount *
-                    bp->framesInTempInputBuffer;
-                      
-            destSampleStrideSamples = bp->inputChannelCount;
-            destChannelStrideBytes = bp->bytesPerUserInputSample;
-
-            userInput = bp->tempInputBuffer;
-        }
-        else /* user input is not interleaved */
-        {
-            destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
-                    bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
-
-            destSampleStrideSamples = 1;
-            destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
-
-            /* setup non-interleaved ptrs */
-            for( i=0; i<bp->inputChannelCount; ++i )
-            {
-                bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
-                    i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;
-            }
-                    
-            userInput = bp->tempInputBufferPtrs;
-        }
-
-        for( i=0; i<bp->inputChannelCount; ++i )
-        {
-            bp->inputConverter( destBytePtr, destSampleStrideSamples,
-                                    hostInputChannels[i].data,
-                                    hostInputChannels[i].stride,
-                                    frameCount, &bp->ditherGenerator );
-
-            destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
-
-            /* advance src ptr for next iteration */
-            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
-                    frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
-        }
-
-        bp->framesInTempInputBuffer += frameCount;
-
-        if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )
-        {
-            /**
-            @todo (non-critical optimisation)
-            The conditional below implements the continue/complete/abort mechanism
-            simply by continuing on iterating through the input buffer, but not
-            passing the data to the callback. With care, the outer loop could be
-            terminated earlier, thus some unneeded conversion cycles would be
-            saved.
-            */
-            if( *streamCallbackResult == paContinue )
-            {
-                bp->timeInfo->outputBufferDacTime = 0;
-
-                *streamCallbackResult = bp->streamCallback( userInput, userOutput,
-                        bp->framesPerUserBuffer, bp->timeInfo,
-                        bp->callbackStatusFlags, bp->userData );
-
-                bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
-            }
-            
-            bp->framesInTempInputBuffer = 0;
-        }
-
-        framesProcessed += frameCount;
-
-        framesToGo -= frameCount;
-    }while( framesToGo > 0 );
-
-    return framesProcessed;
-}
-
-
-/*
-    AdaptingOutputOnlyProcess() is a half duplex output buffer processor.
-    It converts data from the temporary output buffer, to the output buffers,
-    when the temporary output buffer is empty, it calls the streamCallback.
-*/
-static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
-        int *streamCallbackResult,
-        PaUtilChannelDescriptor *hostOutputChannels,
-        unsigned long framesToProcess )
-{
-    void *userInput, *userOutput;
-    unsigned char *srcBytePtr;
-    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
-    unsigned int srcChannelStrideBytes;  /* stride from one channel to the next, in bytes */
-    unsigned int i;
-    unsigned long frameCount;
-    unsigned long framesToGo = framesToProcess;
-    unsigned long framesProcessed = 0;
-
-    do
-    {
-        if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue )
-        {
-            userInput = 0;
-
-            /* setup userOutput */
-            if( bp->userOutputIsInterleaved )
-            {
-                userOutput = bp->tempOutputBuffer;
-            }
-            else /* user output is not interleaved */
-            {
-                for( i = 0; i < bp->outputChannelCount; ++i )
-                {
-                    bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
-                            i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
-                }
-
-                userOutput = bp->tempOutputBufferPtrs;
-            }
-
-            bp->timeInfo->inputBufferAdcTime = 0;
-            
-            *streamCallbackResult = bp->streamCallback( userInput, userOutput,
-                    bp->framesPerUserBuffer, bp->timeInfo,
-                    bp->callbackStatusFlags, bp->userData );
-
-            if( *streamCallbackResult == paAbort )
-            {
-                /* if the callback returned paAbort, we disregard its output */
-            }
-            else
-            {
-                bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
-
-                bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
-            }
-        }
-
-        if( bp->framesInTempOutputBuffer > 0 )
-        {
-            /* convert frameCount frames from user buffer to host buffer */
-
-            frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo );
-
-            if( bp->userOutputIsInterleaved )
-            {
-                srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
-                        bp->bytesPerUserOutputSample * bp->outputChannelCount *
-                        (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
-
-                srcSampleStrideSamples = bp->outputChannelCount;
-                srcChannelStrideBytes = bp->bytesPerUserOutputSample;
-            }
-            else /* user output is not interleaved */
-            {
-                srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
-                        bp->bytesPerUserOutputSample *
-                        (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
-                            
-                srcSampleStrideSamples = 1;
-                srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
-            }
-
-            for( i=0; i<bp->outputChannelCount; ++i )
-            {
-                bp->outputConverter(    hostOutputChannels[i].data,
-                                        hostOutputChannels[i].stride,
-                                        srcBytePtr, srcSampleStrideSamples,
-                                        frameCount, &bp->ditherGenerator );
-
-                srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
-
-                /* advance dest ptr for next iteration */
-                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
-                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
-            }
-
-            bp->framesInTempOutputBuffer -= frameCount;
-        }
-        else
-        {
-            /* no more user data is available because the callback has returned
-                paComplete or paAbort. Fill the remainder of the host buffer
-                with zeros.
-            */
-
-            frameCount = framesToGo;
-
-            for( i=0; i<bp->outputChannelCount; ++i )
-            {
-                bp->outputZeroer(   hostOutputChannels[i].data,
-                                    hostOutputChannels[i].stride,
-                                    frameCount );
-
-                /* advance dest ptr for next iteration */
-                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
-                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
-            }
-        }
-        
-        framesProcessed += frameCount;
-        
-        framesToGo -= frameCount;
-
-    }while( framesToGo > 0 );
-
-    return framesProcessed;
-}
-
-/* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from
-	tempOutputBuffer to hostOutputChannels. This includes data conversion
-	and interleaving. 
-*/
-static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp)
-{
-    unsigned long maxFramesToCopy;
-    PaUtilChannelDescriptor *hostOutputChannels;
-    unsigned int frameCount;
-    unsigned char *srcBytePtr;
-    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
-    unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
-    unsigned int i;
-
-     /* copy frames from user to host output buffers */
-     while( bp->framesInTempOutputBuffer > 0 &&
-             ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )
-     {
-         maxFramesToCopy = bp->framesInTempOutputBuffer;
-
-         /* select the output buffer set (1st or 2nd) */
-         if( bp->hostOutputFrameCount[0] > 0 )
-         {
-             hostOutputChannels = bp->hostOutputChannels[0];
-             frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy );
-         }
-         else
-         {
-             hostOutputChannels = bp->hostOutputChannels[1];
-             frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy );
-         }
-
-         if( bp->userOutputIsInterleaved )
-         {
-             srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
-                     bp->bytesPerUserOutputSample * bp->outputChannelCount *
-                     (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
-                         
-             srcSampleStrideSamples = bp->outputChannelCount;
-             srcChannelStrideBytes = bp->bytesPerUserOutputSample;
-         }
-         else /* user output is not interleaved */
-         {
-             srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
-                     bp->bytesPerUserOutputSample *
-                     (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
-
-             srcSampleStrideSamples = 1;
-             srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
-         }
-
-         for( i=0; i<bp->outputChannelCount; ++i )
-         {
-             bp->outputConverter(    hostOutputChannels[i].data,
-                                     hostOutputChannels[i].stride,
-                                     srcBytePtr, srcSampleStrideSamples,
-                                     frameCount, &bp->ditherGenerator );
-
-             srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
-
-             /* advance dest ptr for next iteration */
-             hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
-                     frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
-         }
-
-         if( bp->hostOutputFrameCount[0] > 0 )
-             bp->hostOutputFrameCount[0] -= frameCount;
-         else
-             bp->hostOutputFrameCount[1] -= frameCount;
-
-         bp->framesInTempOutputBuffer -= frameCount;
-     }
-}
-
-/*
-    AdaptingProcess is a full duplex adapting buffer processor. It converts
-    data from the temporary output buffer into the host output buffers, then
-    from the host input buffers into the temporary input buffers. Calling the
-    streamCallback when necessary.
-    When processPartialUserBuffers is 0, all available input data will be
-    consumed and all available output space will be filled. When
-    processPartialUserBuffers is non-zero, as many full user buffers
-    as possible will be processed, but partial buffers will not be consumed.
-*/
-static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
-        int *streamCallbackResult, int processPartialUserBuffers )
-{
-    void *userInput, *userOutput;
-    unsigned long framesProcessed = 0;
-    unsigned long framesAvailable;
-    unsigned long endProcessingMinFrameCount;
-    unsigned long maxFramesToCopy;
-    PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;
-    unsigned int frameCount;
-    unsigned char *destBytePtr;
-    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
-    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
-    unsigned int i, j;
- 
-
-    framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */
-
-    if( processPartialUserBuffers )
-        endProcessingMinFrameCount = 0;
-    else
-        endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);
-
-    /* Fill host output with remaining frames in user output (tempOutputBuffer) */
-    CopyTempOutputBuffersToHostOutputBuffers( bp );		  	
-
-    while( framesAvailable > endProcessingMinFrameCount ) 
-    {
-
-        if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue )
-        {
-            /* the callback will not be called any more, so zero what remains
-                of the host output buffers */
-
-            for( i=0; i<2; ++i )
-            {
-                frameCount = bp->hostOutputFrameCount[i];
-                if( frameCount > 0 )
-                {
-                    hostOutputChannels = bp->hostOutputChannels[i];
-                    
-                    for( j=0; j<bp->outputChannelCount; ++j )
-                    {
-                        bp->outputZeroer(   hostOutputChannels[j].data,
-                                            hostOutputChannels[j].stride,
-                                            frameCount );
-
-                        /* advance dest ptr for next iteration  */
-                        hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) +
-                                frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample;
-                    }
-                    bp->hostOutputFrameCount[i] = 0;
-                }
-            }
-        }          
-
-
-        /* copy frames from host to user input buffers */
-        while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&
-                ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )
-        {
-            maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;
-
-            /* select the input buffer set (1st or 2nd) */
-            if( bp->hostInputFrameCount[0] > 0 )
-            {
-                hostInputChannels = bp->hostInputChannels[0];
-                frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy );
-            }
-            else
-            {
-                hostInputChannels = bp->hostInputChannels[1];
-                frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy );
-            }
-
-            /* configure conversion destination pointers */
-            if( bp->userInputIsInterleaved )
-            {
-                destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
-                        bp->bytesPerUserInputSample * bp->inputChannelCount *
-                        bp->framesInTempInputBuffer;
-
-                destSampleStrideSamples = bp->inputChannelCount;
-                destChannelStrideBytes = bp->bytesPerUserInputSample;
-            }
-            else /* user input is not interleaved */
-            {
-                destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
-                        bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
-
-                destSampleStrideSamples = 1;
-                destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
-            }
-
-            for( i=0; i<bp->inputChannelCount; ++i )
-            {
-                bp->inputConverter( destBytePtr, destSampleStrideSamples,
-                                        hostInputChannels[i].data,
-                                        hostInputChannels[i].stride,
-                                        frameCount, &bp->ditherGenerator );
-
-                destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */
-
-                /* advance src ptr for next iteration */
-                hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
-                        frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
-            }
-
-            if( bp->hostInputFrameCount[0] > 0 )
-                bp->hostInputFrameCount[0] -= frameCount;
-            else
-                bp->hostInputFrameCount[1] -= frameCount;
-                
-            bp->framesInTempInputBuffer += frameCount;
-
-            /* update framesAvailable and framesProcessed based on input consumed
-                unless something is very wrong this will also correspond to the
-                amount of output generated */
-            framesAvailable -= frameCount;
-            framesProcessed += frameCount;
-        }
-
-        /* call streamCallback */
-        if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&
-            bp->framesInTempOutputBuffer == 0 )
-        {
-            if( *streamCallbackResult == paContinue )
-            {
-                /* setup userInput */
-                if( bp->userInputIsInterleaved )
-                {
-                    userInput = bp->tempInputBuffer;
-                }
-                else /* user input is not interleaved */
-                {
-                    for( i = 0; i < bp->inputChannelCount; ++i )
-                    {
-                        bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
-                                i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
-                    }
-
-                    userInput = bp->tempInputBufferPtrs;
-                }
-
-                /* setup userOutput */
-                if( bp->userOutputIsInterleaved )
-                {
-                    userOutput = bp->tempOutputBuffer;
-                }
-                else /* user output is not interleaved */
-                {
-                    for( i = 0; i < bp->outputChannelCount; ++i )
-                    {
-                        bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
-                                i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
-                    }
-
-                    userOutput = bp->tempOutputBufferPtrs;
-                }
-
-                /* call streamCallback */
-
-                *streamCallbackResult = bp->streamCallback( userInput, userOutput,
-                        bp->framesPerUserBuffer, bp->timeInfo,
-                        bp->callbackStatusFlags, bp->userData );
-
-                bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
-                bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
-
-                bp->framesInTempInputBuffer = 0;
-
-                if( *streamCallbackResult == paAbort )
-                    bp->framesInTempOutputBuffer = 0;
-                else
-                    bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
-            }
-            else
-            {
-                /* paComplete or paAbort has already been called. */
-
-                bp->framesInTempInputBuffer = 0;
-            }
-        }
-
-        /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels) 
-           Means to process the user output provided by the callback. Has to be called after
-            each callback. */
-        CopyTempOutputBuffersToHostOutputBuffers( bp );		  	
-
-    }
-    
-    return framesProcessed;
-}
-
-
-unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )
-{
-    unsigned long framesToProcess, framesToGo;
-    unsigned long framesProcessed = 0;
-    
-    if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0
-            && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */
-            && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ )
-    {
-        assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==
-                (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );
-    }
-
-    assert( *streamCallbackResult == paContinue
-            || *streamCallbackResult == paComplete
-            || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */
-
-    if( bp->useNonAdaptingProcess )
-    {
-        if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
-        {
-            /* full duplex non-adapting process, splice buffers if they are
-                different lengths */
-
-            framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */
-
-            do{
-                unsigned long noInputInputFrameCount;
-                unsigned long *hostInputFrameCount;
-                PaUtilChannelDescriptor *hostInputChannels;
-                unsigned long noOutputOutputFrameCount;
-                unsigned long *hostOutputFrameCount;
-                PaUtilChannelDescriptor *hostOutputChannels;
-                unsigned long framesProcessedThisIteration;
-
-                if( !bp->hostInputChannels[0][0].data )
-                {
-                    /* no input was supplied (see PaUtil_SetNoInput)
-                        NonAdaptingProcess knows how to deal with this
-                    */
-                    noInputInputFrameCount = framesToGo;
-                    hostInputFrameCount = &noInputInputFrameCount;
-                    hostInputChannels = 0;
-                }
-                else if( bp->hostInputFrameCount[0] != 0 )
-                {
-                    hostInputFrameCount = &bp->hostInputFrameCount[0];
-                    hostInputChannels = bp->hostInputChannels[0];
-                }
-                else
-                {
-                    hostInputFrameCount = &bp->hostInputFrameCount[1];
-                    hostInputChannels = bp->hostInputChannels[1];
-                }
-
-                if( !bp->hostOutputChannels[0][0].data )
-                {
-                    /* no output was supplied (see PaUtil_SetNoOutput)
-                        NonAdaptingProcess knows how to deal with this
-                    */
-                    noOutputOutputFrameCount = framesToGo;
-                    hostOutputFrameCount = &noOutputOutputFrameCount;
-                    hostOutputChannels = 0;
-                }
-                if( bp->hostOutputFrameCount[0] != 0 )
-                {
-                    hostOutputFrameCount = &bp->hostOutputFrameCount[0];
-                    hostOutputChannels = bp->hostOutputChannels[0];
-                }
-                else
-                {
-                    hostOutputFrameCount = &bp->hostOutputFrameCount[1];
-                    hostOutputChannels = bp->hostOutputChannels[1];
-                }
-
-                framesToProcess = PA_MIN_( *hostInputFrameCount,
-                                       *hostOutputFrameCount );
-
-                assert( framesToProcess != 0 );
-                
-                framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,
-                        hostInputChannels, hostOutputChannels,
-                        framesToProcess );                                       
-
-                *hostInputFrameCount -= framesProcessedThisIteration;
-                *hostOutputFrameCount -= framesProcessedThisIteration;
-
-                framesProcessed += framesProcessedThisIteration;
-                framesToGo -= framesProcessedThisIteration;
-                
-            }while( framesToGo > 0 );
-        }
-        else
-        {
-            /* half duplex non-adapting process, just process 1st and 2nd buffer */
-            /* process first buffer */
-
-            framesToProcess = (bp->inputChannelCount != 0)
-                            ? bp->hostInputFrameCount[0]
-                            : bp->hostOutputFrameCount[0];
-
-            framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,
-                        bp->hostInputChannels[0], bp->hostOutputChannels[0],
-                        framesToProcess );
-
-            /* process second buffer if provided */
-    
-            framesToProcess = (bp->inputChannelCount != 0)
-                            ? bp->hostInputFrameCount[1]
-                            : bp->hostOutputFrameCount[1];
-            if( framesToProcess > 0 )
-            {
-                framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,
-                    bp->hostInputChannels[1], bp->hostOutputChannels[1],
-                    framesToProcess );
-            }
-        }
-    }
-    else /* block adaption necessary*/
-    {
-
-        if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
-        {
-            /* full duplex */
-            
-            if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed  )
-            {
-                framesProcessed = AdaptingProcess( bp, streamCallbackResult,
-                        0 /* dont process partial user buffers */ );
-            }
-            else
-            {
-                framesProcessed = AdaptingProcess( bp, streamCallbackResult,
-                        1 /* process partial user buffers */ );
-            }
-        }
-        else if( bp->inputChannelCount != 0 )
-        {
-            /* input only */
-            framesToProcess = bp->hostInputFrameCount[0];
-
-            framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,
-                        bp->hostInputChannels[0], framesToProcess );
-
-            framesToProcess = bp->hostInputFrameCount[1];
-            if( framesToProcess > 0 )
-            {
-                framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,
-                        bp->hostInputChannels[1], framesToProcess );
-            }
-        }
-        else
-        {
-            /* output only */
-            framesToProcess = bp->hostOutputFrameCount[0];
-
-            framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,
-                        bp->hostOutputChannels[0], framesToProcess );
-
-            framesToProcess = bp->hostOutputFrameCount[1];
-            if( framesToProcess > 0 )
-            {
-                framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,
-                        bp->hostOutputChannels[1], framesToProcess );
-            }
-        }
-    }
-
-    return framesProcessed;
-}
-
-
-int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp )
-{
-    return (bp->framesInTempOutputBuffer) ? 0 : 1;
-} 
-
-
-unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp,
-        void **buffer, unsigned long frameCount )
-{
-    PaUtilChannelDescriptor *hostInputChannels;
-    unsigned int framesToCopy;
-    unsigned char *destBytePtr;
-    void **nonInterleavedDestPtrs;
-    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
-    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
-    unsigned int i;
-
-    hostInputChannels = bp->hostInputChannels[0];
-    framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount );
-
-    if( bp->userInputIsInterleaved )
-    {
-        destBytePtr = (unsigned char*)*buffer;
-        
-        destSampleStrideSamples = bp->inputChannelCount;
-        destChannelStrideBytes = bp->bytesPerUserInputSample;
-
-        for( i=0; i<bp->inputChannelCount; ++i )
-        {
-            bp->inputConverter( destBytePtr, destSampleStrideSamples,
-                                hostInputChannels[i].data,
-                                hostInputChannels[i].stride,
-                                framesToCopy, &bp->ditherGenerator );
-
-            destBytePtr += destChannelStrideBytes;  /* skip to next source channel */
-
-            /* advance dest ptr for next iteration */
-            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
-                    framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
-        }
-
-        /* advance callers dest pointer (buffer) */
-        *buffer = ((unsigned char *)*buffer) +
-                framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample;
-    }
-    else
-    {
-        /* user input is not interleaved */
-        
-        nonInterleavedDestPtrs = (void**)*buffer;
-
-        destSampleStrideSamples = 1;
-        
-        for( i=0; i<bp->inputChannelCount; ++i )
-        {
-            destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i];
-
-            bp->inputConverter( destBytePtr, destSampleStrideSamples,
-                                hostInputChannels[i].data,
-                                hostInputChannels[i].stride,
-                                framesToCopy, &bp->ditherGenerator );
-
-            /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */
-            destBytePtr += bp->bytesPerUserInputSample * framesToCopy;
-            nonInterleavedDestPtrs[i] = destBytePtr;
-            
-            /* advance dest ptr for next iteration */
-            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
-                    framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
-        }
-    }
-
-    bp->hostInputFrameCount[0] -= framesToCopy;
-    
-    return framesToCopy;
-}
-
-unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp,
-        const void ** buffer, unsigned long frameCount )
-{
-    PaUtilChannelDescriptor *hostOutputChannels;
-    unsigned int framesToCopy;
-    unsigned char *srcBytePtr;
-    void **nonInterleavedSrcPtrs;
-    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
-    unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
-    unsigned int i;
-
-    hostOutputChannels = bp->hostOutputChannels[0];
-    framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
-
-    if( bp->userOutputIsInterleaved )
-    {
-        srcBytePtr = (unsigned char*)*buffer;
-        
-        srcSampleStrideSamples = bp->outputChannelCount;
-        srcChannelStrideBytes = bp->bytesPerUserOutputSample;
-
-        for( i=0; i<bp->outputChannelCount; ++i )
-        {
-            bp->outputConverter(    hostOutputChannels[i].data,
-                                    hostOutputChannels[i].stride,
-                                    srcBytePtr, srcSampleStrideSamples,
-                                    framesToCopy, &bp->ditherGenerator );
-
-            srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */
-
-            /* advance dest ptr for next iteration */
-            hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
-                    framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
-        }
-
-        /* advance callers source pointer (buffer) */
-        *buffer = ((unsigned char *)*buffer) +
-                framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample;
-
-    }
-    else
-    {
-        /* user output is not interleaved */
-        
-        nonInterleavedSrcPtrs = (void**)*buffer;
-
-        srcSampleStrideSamples = 1;
-        
-        for( i=0; i<bp->outputChannelCount; ++i )
-        {
-            srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i];
-            
-            bp->outputConverter(    hostOutputChannels[i].data,
-                                    hostOutputChannels[i].stride,
-                                    srcBytePtr, srcSampleStrideSamples,
-                                    framesToCopy, &bp->ditherGenerator );
-
-
-            /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */
-            srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy;
-            nonInterleavedSrcPtrs[i] = srcBytePtr;
-            
-            /* advance dest ptr for next iteration */
-            hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
-                    framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
-        }
-    }
-
-    bp->hostOutputFrameCount[0] += framesToCopy;
-    
-    return framesToCopy;
-}
-
-
-unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount )
-{
-    PaUtilChannelDescriptor *hostOutputChannels;
-    unsigned int framesToZero;
-    unsigned int i;
-
-    hostOutputChannels = bp->hostOutputChannels[0];
-    framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
-
-    for( i=0; i<bp->outputChannelCount; ++i )
-    {
-        bp->outputZeroer(   hostOutputChannels[i].data,
-                            hostOutputChannels[i].stride,
-                            framesToZero );
-
-
-        /* advance dest ptr for next iteration */
-        hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
-                framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
-    }
-
-    bp->hostOutputFrameCount[0] += framesToZero;
-    
-    return framesToZero;
-}
+/*

+ * $Id: pa_process.c,v 1.1.2.48 2004/12/13 09:48:43 rossbencina Exp $

+ * Portable Audio I/O Library

+ * streamCallback <-> host buffer processing adapter

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+ @brief Buffer Processor implementation.

+    

+ The code in this file is not optimised yet - although it's not clear that

+ it needs to be. there may appear to be redundancies

+ that could be factored into common functions, but the redundanceis are left

+ intentionally as each appearance may have different optimisation possibilities.

+

+ The optimisations which are planned involve only converting data in-place

+ where possible, rather than copying to the temp buffer(s).

+

+ Note that in the extreme case of being able to convert in-place, and there

+ being no conversion necessary there should be some code which short-circuits

+ the operation.

+

+    @todo Consider cache tilings for intereave<->deinterleave.

+

+    @todo implement timeInfo->currentTime int PaUtil_BeginBufferProcessing()

+

+    @todo specify and implement some kind of logical policy for handling the

+        underflow and overflow stream flags when the underflow/overflow overlaps

+        multiple user buffers/callbacks.

+

+	@todo provide support for priming the buffers with data from the callback.

+        The client interface is now implemented through PaUtil_SetNoInput()

+        which sets bp->hostInputChannels[0][0].data to zero. However this is

+        currently only implemented in NonAdaptingProcess(). It shouldn't be

+        needed for AdaptingInputOnlyProcess() (no priming should ever be

+        requested for AdaptingInputOnlyProcess()).

+        Not sure if additional work should be required to make it work with

+        AdaptingOutputOnlyProcess, but it definitely is required for

+        AdaptingProcess.

+

+    @todo implement PaUtil_SetNoOutput for AdaptingProcess

+

+    @todo don't allocate temp buffers for blocking streams unless they are

+        needed. At the moment they are needed, but perhaps for host APIs

+        where the implementation passes a buffer to the host they could be

+        used.

+*/

+

+

+#include <assert.h>

+#include <string.h> /* memset() */

+

+#include "pa_process.h"

+#include "pa_util.h"

+

+

+#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_    1024

+

+#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) )

+

+

+/* greatest common divisor - PGCD in French */

+static unsigned long GCD( unsigned long a, unsigned long b )

+{

+    return (b==0) ? a : GCD( b, a%b);

+}

+

+/* least common multiple - PPCM in French */

+static unsigned long LCM( unsigned long a, unsigned long b )

+{

+    return (a*b) / GCD(a,b);

+}

+

+#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b))

+

+static unsigned long CalculateFrameShift( unsigned long M, unsigned long N )

+{

+    unsigned long result = 0;

+    unsigned long i;

+    unsigned long lcm;

+

+    assert( M > 0 );

+    assert( N > 0 );

+

+    lcm = LCM( M, N );

+    for( i = M; i < lcm; i += M )

+        result = PA_MAX_( result, i % N );

+

+    return result;

+}

+

+

+PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,

+        int inputChannelCount, PaSampleFormat userInputSampleFormat,

+        PaSampleFormat hostInputSampleFormat,

+        int outputChannelCount, PaSampleFormat userOutputSampleFormat,

+        PaSampleFormat hostOutputSampleFormat,

+        double sampleRate,

+        PaStreamFlags streamFlags,

+        unsigned long framesPerUserBuffer,

+        unsigned long framesPerHostBuffer,

+        PaUtilHostBufferSizeMode hostBufferSizeMode,

+        PaStreamCallback *streamCallback, void *userData )

+{

+    PaError result = paNoError;

+    PaError bytesPerSample;

+    unsigned long tempInputBufferSize, tempOutputBufferSize;

+

+    /* initialize buffer ptrs to zero so they can be freed if necessary in error */

+    bp->tempInputBuffer = 0;

+    bp->tempInputBufferPtrs = 0;

+    bp->tempOutputBuffer = 0;

+    bp->tempOutputBufferPtrs = 0;

+

+    bp->framesPerUserBuffer = framesPerUserBuffer;

+    bp->framesPerHostBuffer = framesPerHostBuffer;

+

+    bp->inputChannelCount = inputChannelCount;

+    bp->outputChannelCount = outputChannelCount;

+

+    bp->hostBufferSizeMode = hostBufferSizeMode;

+

+    bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0;

+    bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0;

+

+    if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */

+    {

+        bp->useNonAdaptingProcess = 1;

+        bp->initialFramesInTempInputBuffer = 0;

+        bp->initialFramesInTempOutputBuffer = 0;

+

+        if( hostBufferSizeMode == paUtilFixedHostBufferSize

+                || hostBufferSizeMode == paUtilBoundedHostBufferSize )

+        {

+            bp->framesPerTempBuffer = framesPerHostBuffer;

+        }

+        else /* unknown host buffer size */

+        {

+             bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_;

+        }

+    }

+    else

+    {

+        bp->framesPerTempBuffer = framesPerUserBuffer;

+

+        if( hostBufferSizeMode == paUtilFixedHostBufferSize

+                && framesPerHostBuffer % framesPerUserBuffer == 0 )

+        {

+            bp->useNonAdaptingProcess = 1;

+            bp->initialFramesInTempInputBuffer = 0;

+            bp->initialFramesInTempOutputBuffer = 0;

+        }

+        else

+        {

+            bp->useNonAdaptingProcess = 0;

+

+            if( inputChannelCount > 0 && outputChannelCount > 0 )

+            {

+                /* full duplex */

+                if( hostBufferSizeMode == paUtilFixedHostBufferSize )

+                {

+                    unsigned long frameShift =

+                        CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer );

+

+                    if( framesPerUserBuffer > framesPerHostBuffer )

+                    {

+                        bp->initialFramesInTempInputBuffer = frameShift;

+                        bp->initialFramesInTempOutputBuffer = 0;

+                    }

+                    else

+                    {

+                        bp->initialFramesInTempInputBuffer = 0;

+                        bp->initialFramesInTempOutputBuffer = frameShift;

+                    }

+                }

+                else /* variable host buffer size, add framesPerUserBuffer latency */

+                {

+                    bp->initialFramesInTempInputBuffer = 0;

+                    bp->initialFramesInTempOutputBuffer = framesPerUserBuffer;

+                }

+            }

+            else

+            {

+                /* half duplex */

+                bp->initialFramesInTempInputBuffer = 0;

+                bp->initialFramesInTempOutputBuffer = 0;

+            }

+        }

+    }

+

+

+    bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;

+    bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;

+

+    

+    if( inputChannelCount > 0 )

+    {

+        bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat );

+        if( bytesPerSample > 0 )

+        {

+            bp->bytesPerHostInputSample = bytesPerSample;

+        }

+        else

+        {

+            result = bytesPerSample;

+            goto error;

+        }

+

+        bytesPerSample = Pa_GetSampleSize( userInputSampleFormat );

+        if( bytesPerSample > 0 )

+        {

+            bp->bytesPerUserInputSample = bytesPerSample;

+        }

+        else

+        {

+            result = bytesPerSample;

+            goto error;

+        }

+

+        bp->inputConverter =

+            PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, streamFlags );

+

+        bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat );

+            

+        bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;

+

+

+        tempInputBufferSize =

+            bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;

+         

+        bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );

+        if( bp->tempInputBuffer == 0 )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+        

+        if( bp->framesInTempInputBuffer > 0 )

+            memset( bp->tempInputBuffer, 0, tempInputBufferSize );

+

+        if( userInputSampleFormat & paNonInterleaved )

+        {

+            bp->tempInputBufferPtrs =

+                (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );

+            if( bp->tempInputBufferPtrs == 0 )

+            {

+                result = paInsufficientMemory;

+                goto error;

+            }

+        }

+

+        bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)

+                PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);

+        if( bp->hostInputChannels[0] == 0 )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];

+    }

+

+    if( outputChannelCount > 0 )

+    {

+        bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );

+        if( bytesPerSample > 0 )

+        {

+            bp->bytesPerHostOutputSample = bytesPerSample;

+        }

+        else

+        {

+            result = bytesPerSample;

+            goto error;

+        }

+

+        bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );

+        if( bytesPerSample > 0 )

+        {

+            bp->bytesPerUserOutputSample = bytesPerSample;

+        }

+        else

+        {

+            result = bytesPerSample;

+            goto error;

+        }

+

+        bp->outputConverter =

+            PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );

+

+        bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat );

+

+        bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;

+

+        tempOutputBufferSize =

+                bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;

+

+        bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );

+        if( bp->tempOutputBuffer == 0 )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        if( bp->framesInTempOutputBuffer > 0 )

+            memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );

+        

+        if( userOutputSampleFormat & paNonInterleaved )

+        {

+            bp->tempOutputBufferPtrs =

+                (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );

+            if( bp->tempOutputBufferPtrs == 0 )

+            {

+                result = paInsufficientMemory;

+                goto error;

+            }

+        }

+

+        bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)

+                PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );

+        if( bp->hostOutputChannels[0] == 0 )

+        {                                                                     

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];

+    }

+

+    PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );

+

+    bp->samplePeriod = 1. / sampleRate;

+

+    bp->streamCallback = streamCallback;

+    bp->userData = userData;

+

+    return result;

+

+error:

+    if( bp->tempInputBuffer )

+        PaUtil_FreeMemory( bp->tempInputBuffer );

+

+    if( bp->tempInputBufferPtrs )

+        PaUtil_FreeMemory( bp->tempInputBufferPtrs );

+

+    if( bp->hostInputChannels[0] )

+        PaUtil_FreeMemory( bp->hostInputChannels[0] );

+

+    if( bp->tempOutputBuffer )

+        PaUtil_FreeMemory( bp->tempOutputBuffer );

+

+    if( bp->tempOutputBufferPtrs )

+        PaUtil_FreeMemory( bp->tempOutputBufferPtrs );

+

+    if( bp->hostOutputChannels[0] )

+        PaUtil_FreeMemory( bp->hostOutputChannels[0] );

+

+    return result;

+}

+

+

+void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )

+{

+    if( bp->tempInputBuffer )

+        PaUtil_FreeMemory( bp->tempInputBuffer );

+

+    if( bp->tempInputBufferPtrs )

+        PaUtil_FreeMemory( bp->tempInputBufferPtrs );

+

+    if( bp->hostInputChannels[0] )

+        PaUtil_FreeMemory( bp->hostInputChannels[0] );

+        

+    if( bp->tempOutputBuffer )

+        PaUtil_FreeMemory( bp->tempOutputBuffer );

+

+    if( bp->tempOutputBufferPtrs )

+        PaUtil_FreeMemory( bp->tempOutputBufferPtrs );

+

+    if( bp->hostOutputChannels[0] )

+        PaUtil_FreeMemory( bp->hostOutputChannels[0] );

+}

+

+

+void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp )

+{

+    unsigned long tempInputBufferSize, tempOutputBufferSize;

+

+    bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;

+    bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;

+

+    if( bp->framesInTempInputBuffer > 0 )

+    {

+        tempInputBufferSize =

+            bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount;

+        memset( bp->tempInputBuffer, 0, tempInputBufferSize );

+    }

+

+    if( bp->framesInTempOutputBuffer > 0 )

+    {      

+        tempOutputBufferSize =

+            bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount;

+        memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );

+    }

+}

+

+

+unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bp )

+{

+    return bp->initialFramesInTempInputBuffer;

+}

+

+

+unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bp )

+{

+    return bp->initialFramesInTempOutputBuffer;

+}

+

+

+void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,

+        unsigned long frameCount )

+{

+    if( frameCount == 0 )

+        bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;

+    else

+        bp->hostInputFrameCount[0] = frameCount;

+}

+        

+

+void PaUtil_SetNoInput( PaUtilBufferProcessor* bp )

+{

+    assert( bp->inputChannelCount > 0 );

+

+    bp->hostInputChannels[0][0].data = 0;

+}

+

+

+void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,

+        unsigned int channel, void *data, unsigned int stride )

+{

+    assert( channel < bp->inputChannelCount );

+    

+    bp->hostInputChannels[0][channel].data = data;

+    bp->hostInputChannels[0][channel].stride = stride;

+}

+

+

+void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,

+        unsigned int firstChannel, void *data, unsigned int channelCount )

+{

+    unsigned int i;

+    unsigned int channel = firstChannel;

+    unsigned char *p = (unsigned char*)data;

+

+    if( channelCount == 0 )

+        channelCount = bp->inputChannelCount;

+

+    assert( firstChannel < bp->inputChannelCount );

+    assert( firstChannel + channelCount <= bp->inputChannelCount );

+

+    for( i=0; i< channelCount; ++i )

+    {

+        bp->hostInputChannels[0][channel+i].data = p;

+        p += bp->bytesPerHostInputSample;

+        bp->hostInputChannels[0][channel+i].stride = channelCount;

+    }

+}

+

+

+void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,

+        unsigned int channel, void *data )

+{

+    assert( channel < bp->inputChannelCount );

+    

+    bp->hostInputChannels[0][channel].data = data;

+    bp->hostInputChannels[0][channel].stride = 1;

+}

+

+

+void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,

+        unsigned long frameCount )

+{

+    bp->hostInputFrameCount[1] = frameCount;

+}

+

+

+void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,

+        unsigned int channel, void *data, unsigned int stride )

+{

+    assert( channel < bp->inputChannelCount );

+

+    bp->hostInputChannels[1][channel].data = data;

+    bp->hostInputChannels[1][channel].stride = stride;

+}

+

+

+void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,

+        unsigned int firstChannel, void *data, unsigned int channelCount )

+{

+    unsigned int i;

+    unsigned int channel = firstChannel;

+    unsigned char *p = (unsigned char*)data;

+

+    if( channelCount == 0 )

+        channelCount = bp->inputChannelCount;

+

+    assert( firstChannel < bp->inputChannelCount );

+    assert( firstChannel + channelCount <= bp->inputChannelCount );

+    

+    for( i=0; i< channelCount; ++i )

+    {

+        bp->hostInputChannels[1][channel+i].data = p;

+        p += bp->bytesPerHostInputSample;

+        bp->hostInputChannels[1][channel+i].stride = channelCount;

+    }

+}

+

+        

+void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,

+        unsigned int channel, void *data )

+{

+    assert( channel < bp->inputChannelCount );

+    

+    bp->hostInputChannels[1][channel].data = data;

+    bp->hostInputChannels[1][channel].stride = 1;

+}

+

+

+void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,

+        unsigned long frameCount )

+{

+    if( frameCount == 0 )

+        bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;

+    else

+        bp->hostOutputFrameCount[0] = frameCount;

+}

+

+

+void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp )

+{

+    assert( bp->outputChannelCount > 0 );

+

+    bp->hostOutputChannels[0][0].data = 0;

+}

+

+

+void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,

+        unsigned int channel, void *data, unsigned int stride )

+{

+    assert( channel < bp->outputChannelCount );

+    

+    bp->hostOutputChannels[0][channel].data = data;

+    bp->hostOutputChannels[0][channel].stride = stride;

+}

+

+

+void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,

+        unsigned int firstChannel, void *data, unsigned int channelCount )

+{

+    unsigned int i;

+    unsigned int channel = firstChannel;

+    unsigned char *p = (unsigned char*)data;

+

+    if( channelCount == 0 )

+        channelCount = bp->outputChannelCount;

+

+    assert( firstChannel < bp->outputChannelCount );

+    assert( firstChannel + channelCount <= bp->outputChannelCount );

+    

+    for( i=0; i< channelCount; ++i )

+    {

+        bp->hostOutputChannels[0][channel+i].data = p;

+        p += bp->bytesPerHostOutputSample;

+        bp->hostOutputChannels[0][channel+i].stride = channelCount;

+    }

+}

+

+

+void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,

+        unsigned int channel, void *data )

+{

+    assert( channel < bp->outputChannelCount );

+

+    bp->hostOutputChannels[0][channel].data = data;

+    bp->hostOutputChannels[0][channel].stride = 1;

+}

+

+

+void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,

+        unsigned long frameCount )

+{

+    bp->hostOutputFrameCount[1] = frameCount;

+}

+

+

+void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,

+        unsigned int channel, void *data, unsigned int stride )

+{

+    assert( channel < bp->outputChannelCount );

+

+    bp->hostOutputChannels[1][channel].data = data;

+    bp->hostOutputChannels[1][channel].stride = stride;

+}

+

+

+void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,

+        unsigned int firstChannel, void *data, unsigned int channelCount )

+{

+    unsigned int i;

+    unsigned int channel = firstChannel;

+    unsigned char *p = (unsigned char*)data;

+

+    if( channelCount == 0 )

+        channelCount = bp->outputChannelCount;

+

+    assert( firstChannel < bp->outputChannelCount );

+    assert( firstChannel + channelCount <= bp->outputChannelCount );

+    

+    for( i=0; i< channelCount; ++i )

+    {

+        bp->hostOutputChannels[1][channel+i].data = p;

+        p += bp->bytesPerHostOutputSample;

+        bp->hostOutputChannels[1][channel+i].stride = channelCount;

+    }

+}

+

+        

+void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,

+        unsigned int channel, void *data )

+{

+    assert( channel < bp->outputChannelCount );

+    

+    bp->hostOutputChannels[1][channel].data = data;

+    bp->hostOutputChannels[1][channel].stride = 1;

+}

+

+

+void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp,

+        PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags )

+{

+    bp->timeInfo = timeInfo;

+

+    /* the first streamCallback will be called to process samples which are

+        currently in the input buffer before the ones starting at the timeInfo time */

+        

+    bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;

+    

+    bp->timeInfo->currentTime = 0; /** FIXME: @todo time info currentTime not implemented */

+

+    /* the first streamCallback will be called to generate samples which will be

+        outputted after the frames currently in the output buffer have been

+        outputted. */

+    bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;

+

+    bp->callbackStatusFlags = callbackStatusFlags;

+

+    bp->hostInputFrameCount[1] = 0;

+    bp->hostOutputFrameCount[1] = 0;

+}

+

+

+/*

+    NonAdaptingProcess() is a simple buffer copying adaptor that can handle

+    both full and half duplex copies. It processes framesToProcess frames,

+    broken into blocks bp->framesPerTempBuffer long.

+    This routine can be used when the streamCallback doesn't care what length

+    the buffers are, or when framesToProcess is an integer multiple of

+    bp->framesPerTempBuffer, in which case streamCallback will always be called

+    with bp->framesPerTempBuffer samples.

+*/

+static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,

+        int *streamCallbackResult,

+        PaUtilChannelDescriptor *hostInputChannels,

+        PaUtilChannelDescriptor *hostOutputChannels,

+        unsigned long framesToProcess )

+{

+    void *userInput, *userOutput;

+    unsigned char *srcBytePtr, *destBytePtr;

+    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */

+    unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */

+    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */

+    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */

+    unsigned int i;

+    unsigned long frameCount;

+    unsigned long framesToGo = framesToProcess;

+    unsigned long framesProcessed = 0;

+

+

+    if( *streamCallbackResult == paContinue )

+    {

+        do

+        {

+            frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo );

+

+            /* configure user input buffer and convert input data (host -> user) */

+            if( bp->inputChannelCount == 0 )

+            {

+                /* no input */

+                userInput = 0;

+            }

+            else /* there are input channels */

+            {

+                /*

+                    could use more elaborate logic here and sometimes process

+                    buffers in-place.

+                */

+            

+                destBytePtr = (unsigned char *)bp->tempInputBuffer;

+

+                if( bp->userInputIsInterleaved )

+                {

+                    destSampleStrideSamples = bp->inputChannelCount;

+                    destChannelStrideBytes = bp->bytesPerUserInputSample;

+                    userInput = bp->tempInputBuffer;

+                }

+                else /* user input is not interleaved */

+                {

+                    destSampleStrideSamples = 1;

+                    destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;

+

+                    /* setup non-interleaved ptrs */

+                    for( i=0; i<bp->inputChannelCount; ++i )

+                    {

+                        bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +

+                            i * bp->bytesPerUserInputSample * frameCount;

+                    }

+                

+                    userInput = bp->tempInputBufferPtrs;

+                }

+

+                if( !bp->hostInputChannels[0][0].data )

+                {

+                    /* no input was supplied (see PaUtil_SetNoInput), so

+                        zero the input buffer */

+

+                    for( i=0; i<bp->inputChannelCount; ++i )

+                    {

+                        bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount );

+                        destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */

+                    }

+                }

+                else

+                {

+                    for( i=0; i<bp->inputChannelCount; ++i )

+                    {

+                        bp->inputConverter( destBytePtr, destSampleStrideSamples,

+                                                hostInputChannels[i].data,

+                                                hostInputChannels[i].stride,

+                                                frameCount, &bp->ditherGenerator );

+

+                        destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */

+

+                        /* advance src ptr for next iteration */

+                        hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +

+                                frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;

+                    }

+                }

+            }

+

+            /* configure user output buffer */

+            if( bp->outputChannelCount == 0 )

+            {

+                /* no output */

+                userOutput = 0;

+            }

+            else /* there are output channels */

+            {

+                if( bp->userOutputIsInterleaved )

+                {

+                    userOutput = bp->tempOutputBuffer;

+                }

+                else /* user output is not interleaved */

+                {

+                    for( i = 0; i < bp->outputChannelCount; ++i )

+                    {

+                        bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +

+                            i * bp->bytesPerUserOutputSample * frameCount;

+                    }

+

+                    userOutput = bp->tempOutputBufferPtrs;

+                }

+            }

+        

+            *streamCallbackResult = bp->streamCallback( userInput, userOutput,

+                    frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData );

+

+            if( *streamCallbackResult == paAbort )

+            {

+                /* callback returned paAbort, don't advance framesProcessed

+                        and framesToGo, they will be handled below */

+            }

+            else

+            {

+                bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;

+                bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;

+

+                /* convert output data (user -> host) */

+                

+                if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )

+                {

+                    /*

+                        could use more elaborate logic here and sometimes process

+                        buffers in-place.

+                    */

+            

+                    srcBytePtr = (unsigned char *)bp->tempOutputBuffer;

+

+                    if( bp->userOutputIsInterleaved )

+                    {

+                        srcSampleStrideSamples = bp->outputChannelCount;

+                        srcChannelStrideBytes = bp->bytesPerUserOutputSample;

+                    }

+                    else /* user output is not interleaved */

+                    {

+                        srcSampleStrideSamples = 1;

+                        srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;

+                    }

+

+                    for( i=0; i<bp->outputChannelCount; ++i )

+                    {

+                        bp->outputConverter(    hostOutputChannels[i].data,

+                                                hostOutputChannels[i].stride,

+                                                srcBytePtr, srcSampleStrideSamples,

+                                                frameCount, &bp->ditherGenerator );

+

+                        srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */

+

+                        /* advance dest ptr for next iteration */

+                        hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +

+                                frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;

+                    }

+                }

+             

+                framesProcessed += frameCount;

+

+                framesToGo -= frameCount;

+            }

+        }

+        while( framesToGo > 0  && *streamCallbackResult == paContinue );

+    }

+

+    if( framesToGo > 0 )

+    {

+        /* zero any remaining frames output. There will only be remaining frames

+            if the callback has returned paComplete or paAbort */

+

+        frameCount = framesToGo;

+

+        if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )

+        {

+            for( i=0; i<bp->outputChannelCount; ++i )

+            {

+                bp->outputZeroer(   hostOutputChannels[i].data,

+                                    hostOutputChannels[i].stride,

+                                    frameCount );

+

+                /* advance dest ptr for next iteration */

+                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +

+                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;

+            }

+        }

+

+        framesProcessed += frameCount;

+    }

+

+    return framesProcessed;

+}

+

+

+/*

+    AdaptingInputOnlyProcess() is a half duplex input buffer processor. It

+    converts data from the input buffers into the temporary input buffer,

+    when the temporary input buffer is full, it calls the streamCallback.

+*/

+static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,

+        int *streamCallbackResult,

+        PaUtilChannelDescriptor *hostInputChannels,

+        unsigned long framesToProcess )

+{

+    void *userInput, *userOutput;

+    unsigned char *destBytePtr;

+    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */

+    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */

+    unsigned int i;

+    unsigned long frameCount;

+    unsigned long framesToGo = framesToProcess;

+    unsigned long framesProcessed = 0;

+    

+    userOutput = 0;

+

+    do

+    {

+        frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )

+                ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )

+                : framesToGo;

+

+        /* convert frameCount samples into temp buffer */

+

+        if( bp->userInputIsInterleaved )

+        {

+            destBytePtr = ((unsigned char*)bp->tempInputBuffer) +

+                    bp->bytesPerUserInputSample * bp->inputChannelCount *

+                    bp->framesInTempInputBuffer;

+                      

+            destSampleStrideSamples = bp->inputChannelCount;

+            destChannelStrideBytes = bp->bytesPerUserInputSample;

+

+            userInput = bp->tempInputBuffer;

+        }

+        else /* user input is not interleaved */

+        {

+            destBytePtr = ((unsigned char*)bp->tempInputBuffer) +

+                    bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;

+

+            destSampleStrideSamples = 1;

+            destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;

+

+            /* setup non-interleaved ptrs */

+            for( i=0; i<bp->inputChannelCount; ++i )

+            {

+                bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +

+                    i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;

+            }

+                    

+            userInput = bp->tempInputBufferPtrs;

+        }

+

+        for( i=0; i<bp->inputChannelCount; ++i )

+        {

+            bp->inputConverter( destBytePtr, destSampleStrideSamples,

+                                    hostInputChannels[i].data,

+                                    hostInputChannels[i].stride,

+                                    frameCount, &bp->ditherGenerator );

+

+            destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */

+

+            /* advance src ptr for next iteration */

+            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +

+                    frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;

+        }

+

+        bp->framesInTempInputBuffer += frameCount;

+

+        if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )

+        {

+            /**

+            @todo (non-critical optimisation)

+            The conditional below implements the continue/complete/abort mechanism

+            simply by continuing on iterating through the input buffer, but not

+            passing the data to the callback. With care, the outer loop could be

+            terminated earlier, thus some unneeded conversion cycles would be

+            saved.

+            */

+            if( *streamCallbackResult == paContinue )

+            {

+                bp->timeInfo->outputBufferDacTime = 0;

+

+                *streamCallbackResult = bp->streamCallback( userInput, userOutput,

+                        bp->framesPerUserBuffer, bp->timeInfo,

+                        bp->callbackStatusFlags, bp->userData );

+

+                bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;

+            }

+            

+            bp->framesInTempInputBuffer = 0;

+        }

+

+        framesProcessed += frameCount;

+

+        framesToGo -= frameCount;

+    }while( framesToGo > 0 );

+

+    return framesProcessed;

+}

+

+

+/*

+    AdaptingOutputOnlyProcess() is a half duplex output buffer processor.

+    It converts data from the temporary output buffer, to the output buffers,

+    when the temporary output buffer is empty, it calls the streamCallback.

+*/

+static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,

+        int *streamCallbackResult,

+        PaUtilChannelDescriptor *hostOutputChannels,

+        unsigned long framesToProcess )

+{

+    void *userInput, *userOutput;

+    unsigned char *srcBytePtr;

+    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */

+    unsigned int srcChannelStrideBytes;  /* stride from one channel to the next, in bytes */

+    unsigned int i;

+    unsigned long frameCount;

+    unsigned long framesToGo = framesToProcess;

+    unsigned long framesProcessed = 0;

+

+    do

+    {

+        if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue )

+        {

+            userInput = 0;

+

+            /* setup userOutput */

+            if( bp->userOutputIsInterleaved )

+            {

+                userOutput = bp->tempOutputBuffer;

+            }

+            else /* user output is not interleaved */

+            {

+                for( i = 0; i < bp->outputChannelCount; ++i )

+                {

+                    bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +

+                            i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;

+                }

+

+                userOutput = bp->tempOutputBufferPtrs;

+            }

+

+            bp->timeInfo->inputBufferAdcTime = 0;

+            

+            *streamCallbackResult = bp->streamCallback( userInput, userOutput,

+                    bp->framesPerUserBuffer, bp->timeInfo,

+                    bp->callbackStatusFlags, bp->userData );

+

+            if( *streamCallbackResult == paAbort )

+            {

+                /* if the callback returned paAbort, we disregard its output */

+            }

+            else

+            {

+                bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;

+

+                bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;

+            }

+        }

+

+        if( bp->framesInTempOutputBuffer > 0 )

+        {

+            /* convert frameCount frames from user buffer to host buffer */

+

+            frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo );

+

+            if( bp->userOutputIsInterleaved )

+            {

+                srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +

+                        bp->bytesPerUserOutputSample * bp->outputChannelCount *

+                        (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);

+

+                srcSampleStrideSamples = bp->outputChannelCount;

+                srcChannelStrideBytes = bp->bytesPerUserOutputSample;

+            }

+            else /* user output is not interleaved */

+            {

+                srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +

+                        bp->bytesPerUserOutputSample *

+                        (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);

+                            

+                srcSampleStrideSamples = 1;

+                srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;

+            }

+

+            for( i=0; i<bp->outputChannelCount; ++i )

+            {

+                bp->outputConverter(    hostOutputChannels[i].data,

+                                        hostOutputChannels[i].stride,

+                                        srcBytePtr, srcSampleStrideSamples,

+                                        frameCount, &bp->ditherGenerator );

+

+                srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */

+

+                /* advance dest ptr for next iteration */

+                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +

+                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;

+            }

+

+            bp->framesInTempOutputBuffer -= frameCount;

+        }

+        else

+        {

+            /* no more user data is available because the callback has returned

+                paComplete or paAbort. Fill the remainder of the host buffer

+                with zeros.

+            */

+

+            frameCount = framesToGo;

+

+            for( i=0; i<bp->outputChannelCount; ++i )

+            {

+                bp->outputZeroer(   hostOutputChannels[i].data,

+                                    hostOutputChannels[i].stride,

+                                    frameCount );

+

+                /* advance dest ptr for next iteration */

+                hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +

+                        frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;

+            }

+        }

+        

+        framesProcessed += frameCount;

+        

+        framesToGo -= frameCount;

+

+    }while( framesToGo > 0 );

+

+    return framesProcessed;

+}

+

+/* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from

+	tempOutputBuffer to hostOutputChannels. This includes data conversion

+	and interleaving. 

+*/

+static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp)

+{

+    unsigned long maxFramesToCopy;

+    PaUtilChannelDescriptor *hostOutputChannels;

+    unsigned int frameCount;

+    unsigned char *srcBytePtr;

+    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */

+    unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */

+    unsigned int i;

+

+     /* copy frames from user to host output buffers */

+     while( bp->framesInTempOutputBuffer > 0 &&

+             ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )

+     {

+         maxFramesToCopy = bp->framesInTempOutputBuffer;

+

+         /* select the output buffer set (1st or 2nd) */

+         if( bp->hostOutputFrameCount[0] > 0 )

+         {

+             hostOutputChannels = bp->hostOutputChannels[0];

+             frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy );

+         }

+         else

+         {

+             hostOutputChannels = bp->hostOutputChannels[1];

+             frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy );

+         }

+

+         if( bp->userOutputIsInterleaved )

+         {

+             srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +

+                     bp->bytesPerUserOutputSample * bp->outputChannelCount *

+                     (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);

+                         

+             srcSampleStrideSamples = bp->outputChannelCount;

+             srcChannelStrideBytes = bp->bytesPerUserOutputSample;

+         }

+         else /* user output is not interleaved */

+         {

+             srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +

+                     bp->bytesPerUserOutputSample *

+                     (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);

+

+             srcSampleStrideSamples = 1;

+             srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;

+         }

+

+         for( i=0; i<bp->outputChannelCount; ++i )

+         {

+             bp->outputConverter(    hostOutputChannels[i].data,

+                                     hostOutputChannels[i].stride,

+                                     srcBytePtr, srcSampleStrideSamples,

+                                     frameCount, &bp->ditherGenerator );

+

+             srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */

+

+             /* advance dest ptr for next iteration */

+             hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +

+                     frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;

+         }

+

+         if( bp->hostOutputFrameCount[0] > 0 )

+             bp->hostOutputFrameCount[0] -= frameCount;

+         else

+             bp->hostOutputFrameCount[1] -= frameCount;

+

+         bp->framesInTempOutputBuffer -= frameCount;

+     }

+}

+

+/*

+    AdaptingProcess is a full duplex adapting buffer processor. It converts

+    data from the temporary output buffer into the host output buffers, then

+    from the host input buffers into the temporary input buffers. Calling the

+    streamCallback when necessary.

+    When processPartialUserBuffers is 0, all available input data will be

+    consumed and all available output space will be filled. When

+    processPartialUserBuffers is non-zero, as many full user buffers

+    as possible will be processed, but partial buffers will not be consumed.

+*/

+static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,

+        int *streamCallbackResult, int processPartialUserBuffers )

+{

+    void *userInput, *userOutput;

+    unsigned long framesProcessed = 0;

+    unsigned long framesAvailable;

+    unsigned long endProcessingMinFrameCount;

+    unsigned long maxFramesToCopy;

+    PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;

+    unsigned int frameCount;

+    unsigned char *destBytePtr;

+    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */

+    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */

+    unsigned int i, j;

+ 

+

+    framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */

+

+    if( processPartialUserBuffers )

+        endProcessingMinFrameCount = 0;

+    else

+        endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);

+

+    /* Fill host output with remaining frames in user output (tempOutputBuffer) */

+    CopyTempOutputBuffersToHostOutputBuffers( bp );		  	

+

+    while( framesAvailable > endProcessingMinFrameCount ) 

+    {

+

+        if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue )

+        {

+            /* the callback will not be called any more, so zero what remains

+                of the host output buffers */

+

+            for( i=0; i<2; ++i )

+            {

+                frameCount = bp->hostOutputFrameCount[i];

+                if( frameCount > 0 )

+                {

+                    hostOutputChannels = bp->hostOutputChannels[i];

+                    

+                    for( j=0; j<bp->outputChannelCount; ++j )

+                    {

+                        bp->outputZeroer(   hostOutputChannels[j].data,

+                                            hostOutputChannels[j].stride,

+                                            frameCount );

+

+                        /* advance dest ptr for next iteration  */

+                        hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) +

+                                frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample;

+                    }

+                    bp->hostOutputFrameCount[i] = 0;

+                }

+            }

+        }          

+

+

+        /* copy frames from host to user input buffers */

+        while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&

+                ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )

+        {

+            maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;

+

+            /* select the input buffer set (1st or 2nd) */

+            if( bp->hostInputFrameCount[0] > 0 )

+            {

+                hostInputChannels = bp->hostInputChannels[0];

+                frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy );

+            }

+            else

+            {

+                hostInputChannels = bp->hostInputChannels[1];

+                frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy );

+            }

+

+            /* configure conversion destination pointers */

+            if( bp->userInputIsInterleaved )

+            {

+                destBytePtr = ((unsigned char*)bp->tempInputBuffer) +

+                        bp->bytesPerUserInputSample * bp->inputChannelCount *

+                        bp->framesInTempInputBuffer;

+

+                destSampleStrideSamples = bp->inputChannelCount;

+                destChannelStrideBytes = bp->bytesPerUserInputSample;

+            }

+            else /* user input is not interleaved */

+            {

+                destBytePtr = ((unsigned char*)bp->tempInputBuffer) +

+                        bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;

+

+                destSampleStrideSamples = 1;

+                destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;

+            }

+

+            for( i=0; i<bp->inputChannelCount; ++i )

+            {

+                bp->inputConverter( destBytePtr, destSampleStrideSamples,

+                                        hostInputChannels[i].data,

+                                        hostInputChannels[i].stride,

+                                        frameCount, &bp->ditherGenerator );

+

+                destBytePtr += destChannelStrideBytes;  /* skip to next destination channel */

+

+                /* advance src ptr for next iteration */

+                hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +

+                        frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;

+            }

+

+            if( bp->hostInputFrameCount[0] > 0 )

+                bp->hostInputFrameCount[0] -= frameCount;

+            else

+                bp->hostInputFrameCount[1] -= frameCount;

+                

+            bp->framesInTempInputBuffer += frameCount;

+

+            /* update framesAvailable and framesProcessed based on input consumed

+                unless something is very wrong this will also correspond to the

+                amount of output generated */

+            framesAvailable -= frameCount;

+            framesProcessed += frameCount;

+        }

+

+        /* call streamCallback */

+        if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&

+            bp->framesInTempOutputBuffer == 0 )

+        {

+            if( *streamCallbackResult == paContinue )

+            {

+                /* setup userInput */

+                if( bp->userInputIsInterleaved )

+                {

+                    userInput = bp->tempInputBuffer;

+                }

+                else /* user input is not interleaved */

+                {

+                    for( i = 0; i < bp->inputChannelCount; ++i )

+                    {

+                        bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +

+                                i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;

+                    }

+

+                    userInput = bp->tempInputBufferPtrs;

+                }

+

+                /* setup userOutput */

+                if( bp->userOutputIsInterleaved )

+                {

+                    userOutput = bp->tempOutputBuffer;

+                }

+                else /* user output is not interleaved */

+                {

+                    for( i = 0; i < bp->outputChannelCount; ++i )

+                    {

+                        bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +

+                                i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;

+                    }

+

+                    userOutput = bp->tempOutputBufferPtrs;

+                }

+

+                /* call streamCallback */

+

+                *streamCallbackResult = bp->streamCallback( userInput, userOutput,

+                        bp->framesPerUserBuffer, bp->timeInfo,

+                        bp->callbackStatusFlags, bp->userData );

+

+                bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;

+                bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;

+

+                bp->framesInTempInputBuffer = 0;

+

+                if( *streamCallbackResult == paAbort )

+                    bp->framesInTempOutputBuffer = 0;

+                else

+                    bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;

+            }

+            else

+            {

+                /* paComplete or paAbort has already been called. */

+

+                bp->framesInTempInputBuffer = 0;

+            }

+        }

+

+        /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels) 

+           Means to process the user output provided by the callback. Has to be called after

+            each callback. */

+        CopyTempOutputBuffersToHostOutputBuffers( bp );		  	

+

+    }

+    

+    return framesProcessed;

+}

+

+

+unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )

+{

+    unsigned long framesToProcess, framesToGo;

+    unsigned long framesProcessed = 0;

+    

+    if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0

+            && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */

+            && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ )

+    {

+        assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==

+                (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );

+    }

+

+    assert( *streamCallbackResult == paContinue

+            || *streamCallbackResult == paComplete

+            || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */

+

+    if( bp->useNonAdaptingProcess )

+    {

+        if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )

+        {

+            /* full duplex non-adapting process, splice buffers if they are

+                different lengths */

+

+            framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */

+

+            do{

+                unsigned long noInputInputFrameCount;

+                unsigned long *hostInputFrameCount;

+                PaUtilChannelDescriptor *hostInputChannels;

+                unsigned long noOutputOutputFrameCount;

+                unsigned long *hostOutputFrameCount;

+                PaUtilChannelDescriptor *hostOutputChannels;

+                unsigned long framesProcessedThisIteration;

+

+                if( !bp->hostInputChannels[0][0].data )

+                {

+                    /* no input was supplied (see PaUtil_SetNoInput)

+                        NonAdaptingProcess knows how to deal with this

+                    */

+                    noInputInputFrameCount = framesToGo;

+                    hostInputFrameCount = &noInputInputFrameCount;

+                    hostInputChannels = 0;

+                }

+                else if( bp->hostInputFrameCount[0] != 0 )

+                {

+                    hostInputFrameCount = &bp->hostInputFrameCount[0];

+                    hostInputChannels = bp->hostInputChannels[0];

+                }

+                else

+                {

+                    hostInputFrameCount = &bp->hostInputFrameCount[1];

+                    hostInputChannels = bp->hostInputChannels[1];

+                }

+

+                if( !bp->hostOutputChannels[0][0].data )

+                {

+                    /* no output was supplied (see PaUtil_SetNoOutput)

+                        NonAdaptingProcess knows how to deal with this

+                    */

+                    noOutputOutputFrameCount = framesToGo;

+                    hostOutputFrameCount = &noOutputOutputFrameCount;

+                    hostOutputChannels = 0;

+                }

+                if( bp->hostOutputFrameCount[0] != 0 )

+                {

+                    hostOutputFrameCount = &bp->hostOutputFrameCount[0];

+                    hostOutputChannels = bp->hostOutputChannels[0];

+                }

+                else

+                {

+                    hostOutputFrameCount = &bp->hostOutputFrameCount[1];

+                    hostOutputChannels = bp->hostOutputChannels[1];

+                }

+

+                framesToProcess = PA_MIN_( *hostInputFrameCount,

+                                       *hostOutputFrameCount );

+

+                assert( framesToProcess != 0 );

+                

+                framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,

+                        hostInputChannels, hostOutputChannels,

+                        framesToProcess );                                       

+

+                *hostInputFrameCount -= framesProcessedThisIteration;

+                *hostOutputFrameCount -= framesProcessedThisIteration;

+

+                framesProcessed += framesProcessedThisIteration;

+                framesToGo -= framesProcessedThisIteration;

+                

+            }while( framesToGo > 0 );

+        }

+        else

+        {

+            /* half duplex non-adapting process, just process 1st and 2nd buffer */

+            /* process first buffer */

+

+            framesToProcess = (bp->inputChannelCount != 0)

+                            ? bp->hostInputFrameCount[0]

+                            : bp->hostOutputFrameCount[0];

+

+            framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,

+                        bp->hostInputChannels[0], bp->hostOutputChannels[0],

+                        framesToProcess );

+

+            /* process second buffer if provided */

+    

+            framesToProcess = (bp->inputChannelCount != 0)

+                            ? bp->hostInputFrameCount[1]

+                            : bp->hostOutputFrameCount[1];

+            if( framesToProcess > 0 )

+            {

+                framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,

+                    bp->hostInputChannels[1], bp->hostOutputChannels[1],

+                    framesToProcess );

+            }

+        }

+    }

+    else /* block adaption necessary*/

+    {

+

+        if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )

+        {

+            /* full duplex */

+            

+            if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed  )

+            {

+                framesProcessed = AdaptingProcess( bp, streamCallbackResult,

+                        0 /* dont process partial user buffers */ );

+            }

+            else

+            {

+                framesProcessed = AdaptingProcess( bp, streamCallbackResult,

+                        1 /* process partial user buffers */ );

+            }

+        }

+        else if( bp->inputChannelCount != 0 )

+        {

+            /* input only */

+            framesToProcess = bp->hostInputFrameCount[0];

+

+            framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,

+                        bp->hostInputChannels[0], framesToProcess );

+

+            framesToProcess = bp->hostInputFrameCount[1];

+            if( framesToProcess > 0 )

+            {

+                framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,

+                        bp->hostInputChannels[1], framesToProcess );

+            }

+        }

+        else

+        {

+            /* output only */

+            framesToProcess = bp->hostOutputFrameCount[0];

+

+            framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,

+                        bp->hostOutputChannels[0], framesToProcess );

+

+            framesToProcess = bp->hostOutputFrameCount[1];

+            if( framesToProcess > 0 )

+            {

+                framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,

+                        bp->hostOutputChannels[1], framesToProcess );

+            }

+        }

+    }

+

+    return framesProcessed;

+}

+

+

+int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp )

+{

+    return (bp->framesInTempOutputBuffer) ? 0 : 1;

+} 

+

+

+unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp,

+        void **buffer, unsigned long frameCount )

+{

+    PaUtilChannelDescriptor *hostInputChannels;

+    unsigned int framesToCopy;

+    unsigned char *destBytePtr;

+    void **nonInterleavedDestPtrs;

+    unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */

+    unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */

+    unsigned int i;

+

+    hostInputChannels = bp->hostInputChannels[0];

+    framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount );

+

+    if( bp->userInputIsInterleaved )

+    {

+        destBytePtr = (unsigned char*)*buffer;

+        

+        destSampleStrideSamples = bp->inputChannelCount;

+        destChannelStrideBytes = bp->bytesPerUserInputSample;

+

+        for( i=0; i<bp->inputChannelCount; ++i )

+        {

+            bp->inputConverter( destBytePtr, destSampleStrideSamples,

+                                hostInputChannels[i].data,

+                                hostInputChannels[i].stride,

+                                framesToCopy, &bp->ditherGenerator );

+

+            destBytePtr += destChannelStrideBytes;  /* skip to next source channel */

+

+            /* advance dest ptr for next iteration */

+            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +

+                    framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;

+        }

+

+        /* advance callers dest pointer (buffer) */

+        *buffer = ((unsigned char *)*buffer) +

+                framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample;

+    }

+    else

+    {

+        /* user input is not interleaved */

+        

+        nonInterleavedDestPtrs = (void**)*buffer;

+

+        destSampleStrideSamples = 1;

+        

+        for( i=0; i<bp->inputChannelCount; ++i )

+        {

+            destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i];

+

+            bp->inputConverter( destBytePtr, destSampleStrideSamples,

+                                hostInputChannels[i].data,

+                                hostInputChannels[i].stride,

+                                framesToCopy, &bp->ditherGenerator );

+

+            /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */

+            destBytePtr += bp->bytesPerUserInputSample * framesToCopy;

+            nonInterleavedDestPtrs[i] = destBytePtr;

+            

+            /* advance dest ptr for next iteration */

+            hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +

+                    framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;

+        }

+    }

+

+    bp->hostInputFrameCount[0] -= framesToCopy;

+    

+    return framesToCopy;

+}

+

+unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp,

+        const void ** buffer, unsigned long frameCount )

+{

+    PaUtilChannelDescriptor *hostOutputChannels;

+    unsigned int framesToCopy;

+    unsigned char *srcBytePtr;

+    void **nonInterleavedSrcPtrs;

+    unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */

+    unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */

+    unsigned int i;

+

+    hostOutputChannels = bp->hostOutputChannels[0];

+    framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );

+

+    if( bp->userOutputIsInterleaved )

+    {

+        srcBytePtr = (unsigned char*)*buffer;

+        

+        srcSampleStrideSamples = bp->outputChannelCount;

+        srcChannelStrideBytes = bp->bytesPerUserOutputSample;

+

+        for( i=0; i<bp->outputChannelCount; ++i )

+        {

+            bp->outputConverter(    hostOutputChannels[i].data,

+                                    hostOutputChannels[i].stride,

+                                    srcBytePtr, srcSampleStrideSamples,

+                                    framesToCopy, &bp->ditherGenerator );

+

+            srcBytePtr += srcChannelStrideBytes;  /* skip to next source channel */

+

+            /* advance dest ptr for next iteration */

+            hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +

+                    framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;

+        }

+

+        /* advance callers source pointer (buffer) */

+        *buffer = ((unsigned char *)*buffer) +

+                framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample;

+

+    }

+    else

+    {

+        /* user output is not interleaved */

+        

+        nonInterleavedSrcPtrs = (void**)*buffer;

+

+        srcSampleStrideSamples = 1;

+        

+        for( i=0; i<bp->outputChannelCount; ++i )

+        {

+            srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i];

+            

+            bp->outputConverter(    hostOutputChannels[i].data,

+                                    hostOutputChannels[i].stride,

+                                    srcBytePtr, srcSampleStrideSamples,

+                                    framesToCopy, &bp->ditherGenerator );

+

+

+            /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */

+            srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy;

+            nonInterleavedSrcPtrs[i] = srcBytePtr;

+            

+            /* advance dest ptr for next iteration */

+            hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +

+                    framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;

+        }

+    }

+

+    bp->hostOutputFrameCount[0] += framesToCopy;

+    

+    return framesToCopy;

+}

+

+

+unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount )

+{

+    PaUtilChannelDescriptor *hostOutputChannels;

+    unsigned int framesToZero;

+    unsigned int i;

+

+    hostOutputChannels = bp->hostOutputChannels[0];

+    framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );

+

+    for( i=0; i<bp->outputChannelCount; ++i )

+    {

+        bp->outputZeroer(   hostOutputChannels[i].data,

+                            hostOutputChannels[i].stride,

+                            framesToZero );

+

+

+        /* advance dest ptr for next iteration */

+        hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +

+                framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;

+    }

+

+    bp->hostOutputFrameCount[0] += framesToZero;

+    

+    return framesToZero;

+}

diff --git a/pjmedia/src/pjmedia/portaudio/pa_process.h b/pjmedia/src/pjmedia/portaudio/pa_process.h
index c52e9ea..21ebece 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_process.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_process.h
@@ -1,741 +1,762 @@
-#ifndef PA_PROCESS_H
-#define PA_PROCESS_H
-/*
- * $Id: pa_process.h,v 1.1.2.30 2004/12/13 09:48:44 rossbencina Exp $
- * Portable Audio I/O Library callback buffer processing adapters
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- 
-/** @file
- @brief Buffer Processor prototypes. A Buffer Processor performs buffer length
- adaption, coordinates sample format conversion, and interleaves/deinterleaves
- channels.
-
- <h3>Overview</h3>
-
- The "Buffer Processor" (PaUtilBufferProcessor) manages conversion of audio
- data from host buffers to user buffers and back again. Where required, the
- buffer processor takes care of converting between host and user sample formats,
- interleaving and deinterleaving multichannel buffers, and adapting between host
- and user buffers with different lengths. The buffer processor may be used with
- full and half duplex streams, for both callback streams and blocking read/write
- streams.
-
- One of the important capabilities provided by the buffer processor is
- the ability to adapt between user and host buffer sizes of different lengths
- with minimum latency. Although this task is relatively easy to perform when
- the host buffer size is an integer multiple of the user buffer size, the
- problem is more complicated when this is not the case - especially for
- full-duplex callback streams. Where necessary the adaption is implemented by
- internally buffering some input and/or output data. The buffer adation
- algorithm used by the buffer processor was originally implemented by
- Stephan Letz for the ASIO version of PortAudio, and is described in his
- Callback_adaption_.pdf which is included in the distribution.
-
- The buffer processor performs sample conversion using the functions provided
- by pa_converters.c.
-
- The following sections provide an overview of how to use the buffer processor.
- Interested readers are advised to consult the host API implementations for
- examples of buffer processor usage.
- 
-
- <h4>Initialization, resetting and termination</h4>
-
- When a stream is opened, the buffer processor should be initialized using
- PaUtil_InitializeBufferProcessor. This function initializes internal state
- and allocates temporary buffers as neccesary according to the supplied
- configuration parameters. Some of the parameters correspond to those requested
- by the user in their call to Pa_OpenStream(), others reflect the requirements
- of the host API implementation - they indicate host buffer sizes, formats,
- and the type of buffering which the Host API uses. The buffer processor should
- be initialized for callback streams and blocking read/write streams.
-
- Call PaUtil_ResetBufferProcessor to clear any sample data which is present
- in the buffer processor before starting to use it (for example when
- Pa_StartStream is called).
-
- When the buffer processor is no longer used call
- PaUtil_TerminateBufferProcessor.
-
- 
- <h4>Using the buffer processor for a callback stream</h4>
-
- The buffer processor's role in a callback stream is to take host input buffers
- process them with the stream callback, and fill host output buffers. For a
- full duplex stream, the buffer processor handles input and output simultaneously
- due to the requirements of the minimum-latency buffer adation algorithm.
-
- When a host buffer becomes available, the implementation should call
- the buffer processor to process the buffer. The buffer processor calls the
- stream callback to consume and/or produce audio data as necessary. The buffer
- processor will convert sample formats, interleave/deinterleave channels,
- and slice or chunk the data to the appropriate buffer lengths according to
- the requirements of the stream callback and the host API.
-
- To process a host buffer (or a pair of host buffers for a full-duplex stream)
- use the following calling sequence:
-
- -# Call PaUtil_BeginBufferProcessing
- -# For a stream which takes input:
-    - Call PaUtil_SetInputFrameCount with the number of frames in the host input
-        buffer.
-    - Call one of the following functions one or more times to tell the
-        buffer processor about the host input buffer(s): PaUtil_SetInputChannel,
-        PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel.
-        Which function you call will depend on whether the host buffer(s) are
-        interleaved or not.
-    - If the available host data is split accross two buffers (for example a
-        data range at the end of a circular buffer and another range at the
-        beginning of the circular buffer), also call
-        PaUtil_Set2ndInputFrameCount, PaUtil_Set2ndInputChannel,
-        PaUtil_Set2ndInterleavedInputChannels,
-        PaUtil_Set2ndNonInterleavedInputChannel as necessary to tell the buffer
-        processor about the second buffer.
- -# For a stream which generates output:
-    - Call PaUtil_SetOutputFrameCount with the number of frames in the host
-        output buffer.
-    - Call one of the following functions one or more times to tell the
-        buffer processor about the host output buffer(s): PaUtil_SetOutputChannel,
-        PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel.
-        Which function you call will depend on whether the host buffer(s) are
-        interleaved or not.
-    - If the available host output buffer space is split accross two buffers
-        (for example a data range at the end of a circular buffer and another
-        range at the beginning of the circular buffer), call
-        PaUtil_Set2ndOutputFrameCount, PaUtil_Set2ndOutputChannel,
-        PaUtil_Set2ndInterleavedOutputChannels,
-        PaUtil_Set2ndNonInterleavedOutputChannel as necessary to tell the buffer
-        processor about the second buffer.
- -# Call PaUtil_EndBufferProcessing, this function performs the actual data
-    conversion and processing.
-
-
- <h4>Using the buffer processor for a blocking read/write stream</h4>
-
- Blocking read/write streams use the buffer processor to convert and copy user
- output data to a host buffer, and to convert and copy host input data to
- the user's buffer. The buffer processor does not perform any buffer adaption.
- When using the buffer processor in a blocking read/write stream the input and
- output conversion are performed separately by the PaUtil_CopyInput and
- PaUtil_CopyOutput functions.
-
- To copy data from a host input buffer to the buffer(s) which the user supplies
- to Pa_ReadStream, use the following calling sequence.
-
- - Repeat the following three steps until the user buffer(s) have been filled
-    with samples from the host input buffers:
-     -# Call PaUtil_SetInputFrameCount with the number of frames in the host
-        input buffer.
-     -# Call one of the following functions one or more times to tell the
-        buffer processor about the host input buffer(s): PaUtil_SetInputChannel,
-        PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel.
-        Which function you call will depend on whether the host buffer(s) are
-        interleaved or not.
-     -# Call PaUtil_CopyInput with the user buffer pointer (or a copy of the
-        array of buffer pointers for a non-interleaved stream) passed to
-        Pa_ReadStream, along with the number of frames in the user buffer(s).
-        Be careful to pass a <i>copy</i> of the user buffer pointers to
-        PaUtil_CopyInput because PaUtil_CopyInput advances the pointers to
-        the start of the next region to copy.
- - PaUtil_CopyInput will not copy more data than is available in the
-    host buffer(s), so the above steps need to be repeated until the user
-    buffer(s) are full.
-
- 
- To copy data to the host output buffer from the user buffers(s) supplied
- to Pa_WriteStream use the following calling sequence.
-
- - Repeat the following three steps until all frames from the user buffer(s)
-    have been copied to the host API:
-     -# Call PaUtil_SetOutputFrameCount with the number of frames in the host
-        output buffer.
-     -# Call one of the following functions one or more times to tell the
-        buffer processor about the host output buffer(s): PaUtil_SetOutputChannel,
-        PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel.
-        Which function you call will depend on whether the host buffer(s) are
-        interleaved or not.
-     -# Call PaUtil_CopyOutput with the user buffer pointer (or a copy of the
-        array of buffer pointers for a non-interleaved stream) passed to
-        Pa_WriteStream, along with the number of frames in the user buffer(s).
-        Be careful to pass a <i>copy</i> of the user buffer pointers to 
-        PaUtil_CopyOutput because PaUtil_CopyOutput advances the pointers to
-        the start of the next region to copy.
- - PaUtil_CopyOutput will not copy more data than fits in the host buffer(s),
-    so the above steps need to be repeated until all user data is copied.
-*/
-
-
-#include "portaudio.h"
-#include "pa_converters.h"
-#include "pa_dither.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/** @brief Mode flag passed to PaUtil_InitializeBufferProcessor indicating the type
- of buffering that the host API uses.
-
- The mode used depends on whether the host API or the implementation manages
- the buffers, and how these buffers are used (scatter gather, circular buffer).
-*/
-typedef enum {
-/** The host buffer size is a fixed known size. */
-    paUtilFixedHostBufferSize,
-
-/** The host buffer size may vary, but has a known maximum size. */
-    paUtilBoundedHostBufferSize,
-
-/** Nothing is known about the host buffer size. */
-    paUtilUnknownHostBufferSize,
-
-/** The host buffer size varies, and the client does not require the buffer
- processor to consume all of the input and fill all of the output buffer. This
- is useful when the implementation has access to the host API's circular buffer
- and only needs to consume/fill some of it, not necessarily all of it, with each
- call to the buffer processor. This is the only mode where
- PaUtil_EndBufferProcessing() may not consume the whole buffer.
-*/
-    paUtilVariableHostBufferSizePartialUsageAllowed
-}PaUtilHostBufferSizeMode;
-
-
-/** @brief An auxilliary data structure used internally by the buffer processor
- to represent host input and output buffers. */
-typedef struct PaUtilChannelDescriptor{
-    void *data;
-    unsigned int stride;  /**< stride in samples, not bytes */
-}PaUtilChannelDescriptor;
-
-
-/** @brief The main buffer processor data structure.
-
- Allocate one of these, initialize it with PaUtil_InitializeBufferProcessor
- and terminate it with PaUtil_TerminateBufferProcessor.
-*/
-typedef struct {
-    unsigned long framesPerUserBuffer;
-    unsigned long framesPerHostBuffer;
-
-    PaUtilHostBufferSizeMode hostBufferSizeMode;
-    int useNonAdaptingProcess;
-    unsigned long framesPerTempBuffer;
-
-    unsigned int inputChannelCount;
-    unsigned int bytesPerHostInputSample;
-    unsigned int bytesPerUserInputSample;
-    int userInputIsInterleaved;
-    PaUtilConverter *inputConverter;
-    PaUtilZeroer *inputZeroer;
-    
-    unsigned int outputChannelCount;
-    unsigned int bytesPerHostOutputSample;
-    unsigned int bytesPerUserOutputSample;
-    int userOutputIsInterleaved;
-    PaUtilConverter *outputConverter;
-    PaUtilZeroer *outputZeroer;
-
-    unsigned long initialFramesInTempInputBuffer;
-    unsigned long initialFramesInTempOutputBuffer;
-
-    void *tempInputBuffer;          /**< used for slips, block adaption, and conversion. */
-    void **tempInputBufferPtrs;     /**< storage for non-interleaved buffer pointers, NULL for interleaved user input */
-    unsigned long framesInTempInputBuffer; /**< frames remaining in input buffer from previous adaption iteration */
-
-    void *tempOutputBuffer;         /**< used for slips, block adaption, and conversion. */
-    void **tempOutputBufferPtrs;    /**< storage for non-interleaved buffer pointers, NULL for interleaved user output */
-    unsigned long framesInTempOutputBuffer; /**< frames remaining in input buffer from previous adaption iteration */
-
-    PaStreamCallbackTimeInfo *timeInfo;
-
-    PaStreamCallbackFlags callbackStatusFlags;
-
-    unsigned long hostInputFrameCount[2];
-    PaUtilChannelDescriptor *hostInputChannels[2]; /**< pointers to arrays of channel descriptors.
-                                                        pointers are NULL for half-duplex output processing.
-                                                        hostInputChannels[i].data is NULL when the caller
-                                                        calls PaUtil_SetNoInput()
-                                                        */
-    unsigned long hostOutputFrameCount[2];
-    PaUtilChannelDescriptor *hostOutputChannels[2]; /**< pointers to arrays of channel descriptors.
-                                                         pointers are NULL for half-duplex input processing.
-                                                         hostOutputChannels[i].data is NULL when the caller
-                                                         calls PaUtil_SetNoOutput()
-                                                         */
-
-    PaUtilTriangularDitherGenerator ditherGenerator;
-
-    double samplePeriod;
-
-    PaStreamCallback *streamCallback;
-    void *userData;
-} PaUtilBufferProcessor;
-
-
-/** @name Initialization, termination, resetting and info */
-/*@{*/
-
-/** Initialize a buffer processor's representation stored in a
- PaUtilBufferProcessor structure. Be sure to call
- PaUtil_TerminateBufferProcessor after finishing with a buffer processor.
-
- @param bufferProcessor The buffer processor structure to initialize.
-
- @param inputChannelCount The number of input channels as passed to
- Pa_OpenStream or 0 for an output-only stream.
-
- @param userInputSampleFormat Format of user input samples, as passed to
- Pa_OpenStream. This parameter is ignored for ouput-only streams.
- 
- @param hostInputSampleFormat Format of host input samples. This parameter is
- ignored for output-only streams. See note about host buffer interleave below.
-
- @param outputChannelCount The number of output channels as passed to
- Pa_OpenStream or 0 for an input-only stream.
-
- @param userOutputSampleFormat Format of user output samples, as passed to
- Pa_OpenStream. This parameter is ignored for input-only streams.
- 
- @param hostOutputSampleFormat Format of host output samples. This parameter is
- ignored for input-only streams. See note about host buffer interleave below.
-
- @param sampleRate Sample rate of the stream. The more accurate this is the
- better - it is used for updating time stamps when adapting buffers.
- 
- @param streamFlags Stream flags as passed to Pa_OpenStream, this parameter is
- used for selecting special sample conversion options such as clipping and
- dithering.
- 
- @param framesPerUserBuffer Number of frames per user buffer, as requested
- by the framesPerBuffer parameter to Pa_OpenStream. This parameter may be
- zero to indicate that the user will accept any (and varying) buffer sizes.
-
- @param framesPerHostBuffer Specifies the number of frames per host buffer
- for the fixed buffer size mode, and the maximum number of frames
- per host buffer for the bounded host buffer size mode. It is ignored for
- the other modes.
-
- @param hostBufferSizeMode A mode flag indicating the size variability of
- host buffers that will be passed to the buffer processor. See
- PaUtilHostBufferSizeMode for further details.
- 
- @param streamCallback The user stream callback passed to Pa_OpenStream.
-
- @param userData The user data field passed to Pa_OpenStream.
-    
- @note The interleave flag is ignored for host buffer formats. Host
- interleave is determined by the use of different SetInput and SetOutput
- functions.
-
- @return An error code indicating whether the initialization was successful.
- If the error code is not PaNoError, the buffer processor was not initialized
- and should not be used.
- 
- @see Pa_OpenStream, PaUtilHostBufferSizeMode, PaUtil_TerminateBufferProcessor
-*/
-PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bufferProcessor,
-            int inputChannelCount, PaSampleFormat userInputSampleFormat,
-            PaSampleFormat hostInputSampleFormat,
-            int outputChannelCount, PaSampleFormat userOutputSampleFormat,
-            PaSampleFormat hostOutputSampleFormat,
-            double sampleRate,
-            PaStreamFlags streamFlags,
-            unsigned long framesPerUserBuffer, /* 0 indicates don't care */
-            unsigned long framesPerHostBuffer,
-            PaUtilHostBufferSizeMode hostBufferSizeMode,
-            PaStreamCallback *streamCallback, void *userData );
-
-
-/** Terminate a buffer processor's representation. Deallocates any temporary
- buffers allocated by PaUtil_InitializeBufferProcessor.
- 
- @param bufferProcessor The buffer processor structure to terminate.
-
- @see PaUtil_InitializeBufferProcessor.
-*/
-void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bufferProcessor );
-
-
-/** Clear any internally buffered data. If you call
- PaUtil_InitializeBufferProcessor in your OpenStream routine, make sure you
- call PaUtil_ResetBufferProcessor in your StartStream call.
-
- @param bufferProcessor The buffer processor to reset.
-*/
-void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bufferProcessor );
-
-
-/** Retrieve the input latency of a buffer processor.
-
- @param bufferProcessor The buffer processor examine.
-
- @return The input latency introduced by the buffer processor, in frames.
-
- @see PaUtil_GetBufferProcessorOutputLatency
-*/
-unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bufferProcessor );
-
-/** Retrieve the output latency of a buffer processor.
-
- @param bufferProcessor The buffer processor examine.
-
- @return The output latency introduced by the buffer processor, in frames.
-
- @see PaUtil_GetBufferProcessorInputLatency
-*/
-unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bufferProcessor );
-
-/*@}*/
-
-
-/** @name Host buffer pointer configuration
-
- Functions to set host input and output buffers, used by both callback streams
- and blocking read/write streams.
-*/
-/*@{*/ 
-
-
-/** Set the number of frames in the input host buffer(s) specified by the
- PaUtil_Set*InputChannel functions.
-
- @param bufferProcessor The buffer processor.
-
- @param frameCount The number of host input frames. A 0 frameCount indicates to
- use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor.
-
- @see PaUtil_SetNoInput, PaUtil_SetInputChannel,
- PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel
-*/
-void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
-        unsigned long frameCount );
-
-        
-/** Indicate that no input is avalable. This function should be used when
- priming the output of a full-duplex stream opened with the
- paPrimeOutputBuffersUsingStreamCallback flag. Note that it is not necessary
- to call this or any othe PaUtil_Set*Input* functions for ouput-only streams.
-
- @param bufferProcessor The buffer processor.
-*/
-void PaUtil_SetNoInput( PaUtilBufferProcessor* bufferProcessor );
-
-
-/** Provide the buffer processor with a pointer to a host input channel.
-
- @param bufferProcessor The buffer processor.
- @param channel The channel number.
- @param data The buffer.
- @param stride The stride from one sample to the next, in samples. For
- interleaved host buffers, the stride will usually be the same as the number of
- channels in the buffer.
-*/
-void PaUtil_SetInputChannel( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int channel, void *data, unsigned int stride );
-
-
-/** Provide the buffer processor with a pointer to an number of interleaved
- host input channels.
-
- @param bufferProcessor The buffer processor.
- @param firstChannel The first channel number.
- @param data The buffer.
- @param channelCount The number of interleaved channels in the buffer. If
- channelCount is zero, the number of channels specified to
- PaUtil_InitializeBufferProcessor will be used.
-*/
-void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int firstChannel, void *data, unsigned int channelCount );
-
-
-/** Provide the buffer processor with a pointer to one non-interleaved host
- output channel.
-
- @param bufferProcessor The buffer processor.
- @param channel The channel number.
- @param data The buffer.
-*/
-void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int channel, void *data );
-
-
-/** Use for the second buffer half when the input buffer is split in two halves.
- @see PaUtil_SetInputFrameCount
-*/
-void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
-        unsigned long frameCount );
-
-/** Use for the second buffer half when the input buffer is split in two halves.
- @see PaUtil_SetInputChannel
-*/
-void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int channel, void *data, unsigned int stride );
-
-/** Use for the second buffer half when the input buffer is split in two halves.
- @see PaUtil_SetInterleavedInputChannels
-*/
-void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int firstChannel, void *data, unsigned int channelCount );
-
-/** Use for the second buffer half when the input buffer is split in two halves.
- @see PaUtil_SetNonInterleavedInputChannel
-*/
-void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int channel, void *data );
-
-        
-/** Set the number of frames in the output host buffer(s) specified by the
- PaUtil_Set*OutputChannel functions.
-
- @param bufferProcessor The buffer processor.
-
- @param frameCount The number of host output frames. A 0 frameCount indicates to
- use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor.
-
- @see PaUtil_SetOutputChannel, PaUtil_SetInterleavedOutputChannels,
- PaUtil_SetNonInterleavedOutputChannel
-*/
-void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
-        unsigned long frameCount );
-
-
-/** Indicate that the output will be discarded. This function should be used
- when implementing the paNeverDropInput mode for full duplex streams.
-
- @param bufferProcessor The buffer processor.
-*/
-void PaUtil_SetNoOutput( PaUtilBufferProcessor* bufferProcessor );
-
-
-/** Provide the buffer processor with a pointer to a host output channel.
-
- @param bufferProcessor The buffer processor.
- @param channel The channel number.
- @param data The buffer.
- @param stride The stride from one sample to the next, in samples. For
- interleaved host buffers, the stride will usually be the same as the number of
- channels in the buffer.
-*/
-void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int channel, void *data, unsigned int stride );
-
-
-/** Provide the buffer processor with a pointer to a number of interleaved
- host output channels.
-
- @param bufferProcessor The buffer processor.
- @param firstChannel The first channel number.
- @param data The buffer.
- @param channelCount The number of interleaved channels in the buffer. If
- channelCount is zero, the number of channels specified to
- PaUtil_InitializeBufferProcessor will be used.
-*/
-void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int firstChannel, void *data, unsigned int channelCount );
-
-        
-/** Provide the buffer processor with a pointer to one non-interleaved host
- output channel.
-
- @param bufferProcessor The buffer processor.
- @param channel The channel number.
- @param data The buffer.
-*/
-void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int channel, void *data );
-
-
-/** Use for the second buffer half when the output buffer is split in two halves.
- @see PaUtil_SetOutputFrameCount
-*/
-void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
-        unsigned long frameCount );
-
-/** Use for the second buffer half when the output buffer is split in two halves.
- @see PaUtil_SetOutputChannel
-*/
-void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int channel, void *data, unsigned int stride );
-
-/** Use for the second buffer half when the output buffer is split in two halves.
- @see PaUtil_SetInterleavedOutputChannels
-*/
-void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int firstChannel, void *data, unsigned int channelCount );
-
-/** Use for the second buffer half when the output buffer is split in two halves.
- @see PaUtil_SetNonInterleavedOutputChannel
-*/
-void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
-        unsigned int channel, void *data );
-
-/*@}*/
-
-
-/** @name Buffer processing functions for callback streams
-*/
-/*@{*/
-
-/** Commence processing a host buffer (or a pair of host buffers in the
- full-duplex case) for a callback stream.
-
- @param bufferProcessor The buffer processor.
-
- @param timeInfo Timing information for the first sample of the host
- buffer(s). This information may be adjusted when buffer adaption is being
- performed.
-
- @param callbackStatusFlags Flags indicating whether underruns and overruns
- have occurred since the last time the buffer processor was called.
-*/
-void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bufferProcessor,
-        PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags );
-
-        
-/** Finish processing a host buffer (or a pair of host buffers in the
- full-duplex case) for a callback stream.
-
- @param bufferProcessor The buffer processor.
- 
- @param callbackResult On input, indicates a previous callback result, and on
- exit, the result of the user stream callback, if it is called.
- On entry callbackResult should contain one of { paContinue, paComplete, or
- paAbort}. If paComplete is passed, the stream callback will not be called
- but any audio that was generated by previous stream callbacks will be copied
- to the output buffer(s). You can check whether the buffer processor's internal
- buffer is empty by calling PaUtil_IsBufferProcessorOutputEmpty.
-
- If the stream callback is called its result is stored in *callbackResult. If
- the stream callback returns paComplete or paAbort, all output buffers will be
- full of valid data - some of which may be zeros to acount for data that
- wasn't generated by the terminating callback.
-
- @return The number of frames processed. This usually corresponds to the
- number of frames specified by the PaUtil_Set*FrameCount functions, exept in
- the paUtilVariableHostBufferSizePartialUsageAllowed buffer size mode when a
- smaller value may be returned.
-*/
-unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bufferProcessor,
-        int *callbackResult );
-
-
-/** Determine whether any callback generated output remains in the bufffer
- processor's internal buffers. This method may be used to determine when to
- continue calling PaUtil_EndBufferProcessing() after the callback has returned
- a callbackResult of paComplete.
-
- @param bufferProcessor The buffer processor.
- 
- @return Returns non-zero when callback generated output remains in the internal
- buffer and zero (0) when there internal buffer contains no callback generated
- data.
-*/
-int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bufferProcessor );
-
-/*@}*/
-
-
-/** @name Buffer processing functions for blocking read/write streams
-*/
-/*@{*/
-
-/** Copy samples from host input channels set up by the PaUtil_Set*InputChannels
- functions to a user supplied buffer. This function is intended for use with
- blocking read/write streams. Copies the minimum of the number of
- user frames (specified by the frameCount parameter) and the number of available
- host frames (specified in a previous call to SetInputFrameCount()).
-
- @param bufferProcessor The buffer processor.
-
- @param buffer A pointer to the user buffer pointer, or a pointer to a pointer
- to an array of user buffer pointers for a non-interleaved stream. It is
- important that this parameter points to a copy of the user buffer pointers,
- not to the actual user buffer pointers, because this function updates the
- pointers before returning.
-
- @param frameCount The number of frames of data in the buffer(s) pointed to by
- the buffer parameter.
-
- @return The number of frames copied. The buffer pointer(s) pointed to by the
- buffer parameter are advanced to point to the frame(s) following the last one
- filled.
-*/
-unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bufferProcessor,
-        void **buffer, unsigned long frameCount );
-
-
-/* Copy samples from a user supplied buffer to host output channels set up by
- the PaUtil_Set*OutputChannels functions. This function is intended for use with
- blocking read/write streams. Copies the minimum of the number of
- user frames (specified by the frameCount parameter) and the number of
- host frames (specified in a previous call to SetOutputFrameCount()).
-
- @param bufferProcessor The buffer processor.
-
- @param buffer A pointer to the user buffer pointer, or a pointer to a pointer
- to an array of user buffer pointers for a non-interleaved stream. It is
- important that this parameter points to a copy of the user buffer pointers,
- not to the actual user buffer pointers, because this function updates the
- pointers before returning.
-
- @param frameCount The number of frames of data in the buffer(s) pointed to by
- the buffer parameter.
-
- @return The number of frames copied. The buffer pointer(s) pointed to by the
- buffer parameter are advanced to point to the frame(s) following the last one
- copied.
-*/
-unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bufferProcessor,
-        const void ** buffer, unsigned long frameCount );
-
-
-/* Zero samples in host output channels set up by the PaUtil_Set*OutputChannels
- functions. This function is useful for flushing streams.
- Zeros the minimum of frameCount and the number of host frames specified in a
- previous call to SetOutputFrameCount().
-
- @param bufferProcessor The buffer processor.
-
- @param frameCount The maximum number of frames to zero.
- 
- @return The number of frames zeroed.
-*/
-unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bufferProcessor,
-        unsigned long frameCount );
-
-
-/*@}*/
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_PROCESS_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_PROCESS_H

+#define PA_PROCESS_H

+/*

+ * $Id: pa_process.h,v 1.1.2.30 2004/12/13 09:48:44 rossbencina Exp $

+ * Portable Audio I/O Library callback buffer processing adapters

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+ 

+/** @file

+ @brief Buffer Processor prototypes. A Buffer Processor performs buffer length

+ adaption, coordinates sample format conversion, and interleaves/deinterleaves

+ channels.

+

+ <h3>Overview</h3>

+

+ The "Buffer Processor" (PaUtilBufferProcessor) manages conversion of audio

+ data from host buffers to user buffers and back again. Where required, the

+ buffer processor takes care of converting between host and user sample formats,

+ interleaving and deinterleaving multichannel buffers, and adapting between host

+ and user buffers with different lengths. The buffer processor may be used with

+ full and half duplex streams, for both callback streams and blocking read/write

+ streams.

+

+ One of the important capabilities provided by the buffer processor is

+ the ability to adapt between user and host buffer sizes of different lengths

+ with minimum latency. Although this task is relatively easy to perform when

+ the host buffer size is an integer multiple of the user buffer size, the

+ problem is more complicated when this is not the case - especially for

+ full-duplex callback streams. Where necessary the adaption is implemented by

+ internally buffering some input and/or output data. The buffer adation

+ algorithm used by the buffer processor was originally implemented by

+ Stephan Letz for the ASIO version of PortAudio, and is described in his

+ Callback_adaption_.pdf which is included in the distribution.

+

+ The buffer processor performs sample conversion using the functions provided

+ by pa_converters.c.

+

+ The following sections provide an overview of how to use the buffer processor.

+ Interested readers are advised to consult the host API implementations for

+ examples of buffer processor usage.

+ 

+

+ <h4>Initialization, resetting and termination</h4>

+

+ When a stream is opened, the buffer processor should be initialized using

+ PaUtil_InitializeBufferProcessor. This function initializes internal state

+ and allocates temporary buffers as neccesary according to the supplied

+ configuration parameters. Some of the parameters correspond to those requested

+ by the user in their call to Pa_OpenStream(), others reflect the requirements

+ of the host API implementation - they indicate host buffer sizes, formats,

+ and the type of buffering which the Host API uses. The buffer processor should

+ be initialized for callback streams and blocking read/write streams.

+

+ Call PaUtil_ResetBufferProcessor to clear any sample data which is present

+ in the buffer processor before starting to use it (for example when

+ Pa_StartStream is called).

+

+ When the buffer processor is no longer used call

+ PaUtil_TerminateBufferProcessor.

+

+ 

+ <h4>Using the buffer processor for a callback stream</h4>

+

+ The buffer processor's role in a callback stream is to take host input buffers

+ process them with the stream callback, and fill host output buffers. For a

+ full duplex stream, the buffer processor handles input and output simultaneously

+ due to the requirements of the minimum-latency buffer adation algorithm.

+

+ When a host buffer becomes available, the implementation should call

+ the buffer processor to process the buffer. The buffer processor calls the

+ stream callback to consume and/or produce audio data as necessary. The buffer

+ processor will convert sample formats, interleave/deinterleave channels,

+ and slice or chunk the data to the appropriate buffer lengths according to

+ the requirements of the stream callback and the host API.

+

+ To process a host buffer (or a pair of host buffers for a full-duplex stream)

+ use the following calling sequence:

+

+ -# Call PaUtil_BeginBufferProcessing

+ -# For a stream which takes input:

+    - Call PaUtil_SetInputFrameCount with the number of frames in the host input

+        buffer.

+    - Call one of the following functions one or more times to tell the

+        buffer processor about the host input buffer(s): PaUtil_SetInputChannel,

+        PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel.

+        Which function you call will depend on whether the host buffer(s) are

+        interleaved or not.

+    - If the available host data is split accross two buffers (for example a

+        data range at the end of a circular buffer and another range at the

+        beginning of the circular buffer), also call

+        PaUtil_Set2ndInputFrameCount, PaUtil_Set2ndInputChannel,

+        PaUtil_Set2ndInterleavedInputChannels,

+        PaUtil_Set2ndNonInterleavedInputChannel as necessary to tell the buffer

+        processor about the second buffer.

+ -# For a stream which generates output:

+    - Call PaUtil_SetOutputFrameCount with the number of frames in the host

+        output buffer.

+    - Call one of the following functions one or more times to tell the

+        buffer processor about the host output buffer(s): PaUtil_SetOutputChannel,

+        PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel.

+        Which function you call will depend on whether the host buffer(s) are

+        interleaved or not.

+    - If the available host output buffer space is split accross two buffers

+        (for example a data range at the end of a circular buffer and another

+        range at the beginning of the circular buffer), call

+        PaUtil_Set2ndOutputFrameCount, PaUtil_Set2ndOutputChannel,

+        PaUtil_Set2ndInterleavedOutputChannels,

+        PaUtil_Set2ndNonInterleavedOutputChannel as necessary to tell the buffer

+        processor about the second buffer.

+ -# Call PaUtil_EndBufferProcessing, this function performs the actual data

+    conversion and processing.

+

+

+ <h4>Using the buffer processor for a blocking read/write stream</h4>

+

+ Blocking read/write streams use the buffer processor to convert and copy user

+ output data to a host buffer, and to convert and copy host input data to

+ the user's buffer. The buffer processor does not perform any buffer adaption.

+ When using the buffer processor in a blocking read/write stream the input and

+ output conversion are performed separately by the PaUtil_CopyInput and

+ PaUtil_CopyOutput functions.

+

+ To copy data from a host input buffer to the buffer(s) which the user supplies

+ to Pa_ReadStream, use the following calling sequence.

+

+ - Repeat the following three steps until the user buffer(s) have been filled

+    with samples from the host input buffers:

+     -# Call PaUtil_SetInputFrameCount with the number of frames in the host

+        input buffer.

+     -# Call one of the following functions one or more times to tell the

+        buffer processor about the host input buffer(s): PaUtil_SetInputChannel,

+        PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel.

+        Which function you call will depend on whether the host buffer(s) are

+        interleaved or not.

+     -# Call PaUtil_CopyInput with the user buffer pointer (or a copy of the

+        array of buffer pointers for a non-interleaved stream) passed to

+        Pa_ReadStream, along with the number of frames in the user buffer(s).

+        Be careful to pass a <i>copy</i> of the user buffer pointers to

+        PaUtil_CopyInput because PaUtil_CopyInput advances the pointers to

+        the start of the next region to copy.

+ - PaUtil_CopyInput will not copy more data than is available in the

+    host buffer(s), so the above steps need to be repeated until the user

+    buffer(s) are full.

+

+ 

+ To copy data to the host output buffer from the user buffers(s) supplied

+ to Pa_WriteStream use the following calling sequence.

+

+ - Repeat the following three steps until all frames from the user buffer(s)

+    have been copied to the host API:

+     -# Call PaUtil_SetOutputFrameCount with the number of frames in the host

+        output buffer.

+     -# Call one of the following functions one or more times to tell the

+        buffer processor about the host output buffer(s): PaUtil_SetOutputChannel,

+        PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel.

+        Which function you call will depend on whether the host buffer(s) are

+        interleaved or not.

+     -# Call PaUtil_CopyOutput with the user buffer pointer (or a copy of the

+        array of buffer pointers for a non-interleaved stream) passed to

+        Pa_WriteStream, along with the number of frames in the user buffer(s).

+        Be careful to pass a <i>copy</i> of the user buffer pointers to 

+        PaUtil_CopyOutput because PaUtil_CopyOutput advances the pointers to

+        the start of the next region to copy.

+ - PaUtil_CopyOutput will not copy more data than fits in the host buffer(s),

+    so the above steps need to be repeated until all user data is copied.

+*/

+

+

+#include "portaudio.h"

+#include "pa_converters.h"

+#include "pa_dither.h"

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+/** @brief Mode flag passed to PaUtil_InitializeBufferProcessor indicating the type

+ of buffering that the host API uses.

+

+ The mode used depends on whether the host API or the implementation manages

+ the buffers, and how these buffers are used (scatter gather, circular buffer).

+*/

+typedef enum {

+/** The host buffer size is a fixed known size. */

+    paUtilFixedHostBufferSize,

+

+/** The host buffer size may vary, but has a known maximum size. */

+    paUtilBoundedHostBufferSize,

+

+/** Nothing is known about the host buffer size. */

+    paUtilUnknownHostBufferSize,

+

+/** The host buffer size varies, and the client does not require the buffer

+ processor to consume all of the input and fill all of the output buffer. This

+ is useful when the implementation has access to the host API's circular buffer

+ and only needs to consume/fill some of it, not necessarily all of it, with each

+ call to the buffer processor. This is the only mode where

+ PaUtil_EndBufferProcessing() may not consume the whole buffer.

+*/

+    paUtilVariableHostBufferSizePartialUsageAllowed

+}PaUtilHostBufferSizeMode;

+

+

+/** @brief An auxilliary data structure used internally by the buffer processor

+ to represent host input and output buffers. */

+typedef struct PaUtilChannelDescriptor{

+    void *data;

+    unsigned int stride;  /**< stride in samples, not bytes */

+}PaUtilChannelDescriptor;

+

+

+/** @brief The main buffer processor data structure.

+

+ Allocate one of these, initialize it with PaUtil_InitializeBufferProcessor

+ and terminate it with PaUtil_TerminateBufferProcessor.

+*/

+typedef struct {

+    unsigned long framesPerUserBuffer;

+    unsigned long framesPerHostBuffer;

+

+    PaUtilHostBufferSizeMode hostBufferSizeMode;

+    int useNonAdaptingProcess;

+    unsigned long framesPerTempBuffer;

+

+    unsigned int inputChannelCount;

+    unsigned int bytesPerHostInputSample;

+    unsigned int bytesPerUserInputSample;

+    int userInputIsInterleaved;

+    PaUtilConverter *inputConverter;

+    PaUtilZeroer *inputZeroer;

+    

+    unsigned int outputChannelCount;

+    unsigned int bytesPerHostOutputSample;

+    unsigned int bytesPerUserOutputSample;

+    int userOutputIsInterleaved;

+    PaUtilConverter *outputConverter;

+    PaUtilZeroer *outputZeroer;

+

+    unsigned long initialFramesInTempInputBuffer;

+    unsigned long initialFramesInTempOutputBuffer;

+

+    void *tempInputBuffer;          /**< used for slips, block adaption, and conversion. */

+    void **tempInputBufferPtrs;     /**< storage for non-interleaved buffer pointers, NULL for interleaved user input */

+    unsigned long framesInTempInputBuffer; /**< frames remaining in input buffer from previous adaption iteration */

+

+    void *tempOutputBuffer;         /**< used for slips, block adaption, and conversion. */

+    void **tempOutputBufferPtrs;    /**< storage for non-interleaved buffer pointers, NULL for interleaved user output */

+    unsigned long framesInTempOutputBuffer; /**< frames remaining in input buffer from previous adaption iteration */

+

+    PaStreamCallbackTimeInfo *timeInfo;

+

+    PaStreamCallbackFlags callbackStatusFlags;

+

+    unsigned long hostInputFrameCount[2];

+    PaUtilChannelDescriptor *hostInputChannels[2]; /**< pointers to arrays of channel descriptors.

+                                                        pointers are NULL for half-duplex output processing.

+                                                        hostInputChannels[i].data is NULL when the caller

+                                                        calls PaUtil_SetNoInput()

+                                                        */

+    unsigned long hostOutputFrameCount[2];

+    PaUtilChannelDescriptor *hostOutputChannels[2]; /**< pointers to arrays of channel descriptors.

+                                                         pointers are NULL for half-duplex input processing.

+                                                         hostOutputChannels[i].data is NULL when the caller

+                                                         calls PaUtil_SetNoOutput()

+                                                         */

+

+    PaUtilTriangularDitherGenerator ditherGenerator;

+

+    double samplePeriod;

+

+    PaStreamCallback *streamCallback;

+    void *userData;

+} PaUtilBufferProcessor;

+

+

+/** @name Initialization, termination, resetting and info */

+/*@{*/

+

+/** Initialize a buffer processor's representation stored in a

+ PaUtilBufferProcessor structure. Be sure to call

+ PaUtil_TerminateBufferProcessor after finishing with a buffer processor.

+

+ @param bufferProcessor The buffer processor structure to initialize.

+

+ @param inputChannelCount The number of input channels as passed to

+ Pa_OpenStream or 0 for an output-only stream.

+

+ @param userInputSampleFormat Format of user input samples, as passed to

+ Pa_OpenStream. This parameter is ignored for ouput-only streams.

+ 

+ @param hostInputSampleFormat Format of host input samples. This parameter is

+ ignored for output-only streams. See note about host buffer interleave below.

+

+ @param outputChannelCount The number of output channels as passed to

+ Pa_OpenStream or 0 for an input-only stream.

+

+ @param userOutputSampleFormat Format of user output samples, as passed to

+ Pa_OpenStream. This parameter is ignored for input-only streams.

+ 

+ @param hostOutputSampleFormat Format of host output samples. This parameter is

+ ignored for input-only streams. See note about host buffer interleave below.

+

+ @param sampleRate Sample rate of the stream. The more accurate this is the

+ better - it is used for updating time stamps when adapting buffers.

+ 

+ @param streamFlags Stream flags as passed to Pa_OpenStream, this parameter is

+ used for selecting special sample conversion options such as clipping and

+ dithering.

+ 

+ @param framesPerUserBuffer Number of frames per user buffer, as requested

+ by the framesPerBuffer parameter to Pa_OpenStream. This parameter may be

+ zero to indicate that the user will accept any (and varying) buffer sizes.

+

+ @param framesPerHostBuffer Specifies the number of frames per host buffer

+ for the fixed buffer size mode, and the maximum number of frames

+ per host buffer for the bounded host buffer size mode. It is ignored for

+ the other modes.

+

+ @param hostBufferSizeMode A mode flag indicating the size variability of

+ host buffers that will be passed to the buffer processor. See

+ PaUtilHostBufferSizeMode for further details.

+ 

+ @param streamCallback The user stream callback passed to Pa_OpenStream.

+

+ @param userData The user data field passed to Pa_OpenStream.

+    

+ @note The interleave flag is ignored for host buffer formats. Host

+ interleave is determined by the use of different SetInput and SetOutput

+ functions.

+

+ @return An error code indicating whether the initialization was successful.

+ If the error code is not PaNoError, the buffer processor was not initialized

+ and should not be used.

+ 

+ @see Pa_OpenStream, PaUtilHostBufferSizeMode, PaUtil_TerminateBufferProcessor

+*/

+PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bufferProcessor,

+            int inputChannelCount, PaSampleFormat userInputSampleFormat,

+            PaSampleFormat hostInputSampleFormat,

+            int outputChannelCount, PaSampleFormat userOutputSampleFormat,

+            PaSampleFormat hostOutputSampleFormat,

+            double sampleRate,

+            PaStreamFlags streamFlags,

+            unsigned long framesPerUserBuffer, /* 0 indicates don't care */

+            unsigned long framesPerHostBuffer,

+            PaUtilHostBufferSizeMode hostBufferSizeMode,

+            PaStreamCallback *streamCallback, void *userData );

+

+

+/** Terminate a buffer processor's representation. Deallocates any temporary

+ buffers allocated by PaUtil_InitializeBufferProcessor.

+ 

+ @param bufferProcessor The buffer processor structure to terminate.

+

+ @see PaUtil_InitializeBufferProcessor.

+*/

+void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bufferProcessor );

+

+

+/** Clear any internally buffered data. If you call

+ PaUtil_InitializeBufferProcessor in your OpenStream routine, make sure you

+ call PaUtil_ResetBufferProcessor in your StartStream call.

+

+ @param bufferProcessor The buffer processor to reset.

+*/

+void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bufferProcessor );

+

+

+/** Retrieve the input latency of a buffer processor.

+

+ @param bufferProcessor The buffer processor examine.

+

+ @return The input latency introduced by the buffer processor, in frames.

+

+ @see PaUtil_GetBufferProcessorOutputLatency

+*/

+unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bufferProcessor );

+

+/** Retrieve the output latency of a buffer processor.

+

+ @param bufferProcessor The buffer processor examine.

+

+ @return The output latency introduced by the buffer processor, in frames.

+

+ @see PaUtil_GetBufferProcessorInputLatency

+*/

+unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bufferProcessor );

+

+/*@}*/

+

+

+/** @name Host buffer pointer configuration

+

+ Functions to set host input and output buffers, used by both callback streams

+ and blocking read/write streams.

+*/

+/*@{*/ 

+

+

+/** Set the number of frames in the input host buffer(s) specified by the

+ PaUtil_Set*InputChannel functions.

+

+ @param bufferProcessor The buffer processor.

+

+ @param frameCount The number of host input frames. A 0 frameCount indicates to

+ use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor.

+

+ @see PaUtil_SetNoInput, PaUtil_SetInputChannel,

+ PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel

+*/

+void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bufferProcessor,

+        unsigned long frameCount );

+

+        

+/** Indicate that no input is avalable. This function should be used when

+ priming the output of a full-duplex stream opened with the

+ paPrimeOutputBuffersUsingStreamCallback flag. Note that it is not necessary

+ to call this or any othe PaUtil_Set*Input* functions for ouput-only streams.

+

+ @param bufferProcessor The buffer processor.

+*/

+void PaUtil_SetNoInput( PaUtilBufferProcessor* bufferProcessor );

+

+

+/** Provide the buffer processor with a pointer to a host input channel.

+

+ @param bufferProcessor The buffer processor.

+ @param channel The channel number.

+ @param data The buffer.

+ @param stride The stride from one sample to the next, in samples. For

+ interleaved host buffers, the stride will usually be the same as the number of

+ channels in the buffer.

+*/

+void PaUtil_SetInputChannel( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int channel, void *data, unsigned int stride );

+

+

+/** Provide the buffer processor with a pointer to an number of interleaved

+ host input channels.

+

+ @param bufferProcessor The buffer processor.

+ @param firstChannel The first channel number.

+ @param data The buffer.

+ @param channelCount The number of interleaved channels in the buffer. If

+ channelCount is zero, the number of channels specified to

+ PaUtil_InitializeBufferProcessor will be used.

+*/

+void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int firstChannel, void *data, unsigned int channelCount );

+

+

+/** Provide the buffer processor with a pointer to one non-interleaved host

+ output channel.

+

+ @param bufferProcessor The buffer processor.

+ @param channel The channel number.

+ @param data The buffer.

+*/

+void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int channel, void *data );

+

+

+/** Use for the second buffer half when the input buffer is split in two halves.

+ @see PaUtil_SetInputFrameCount

+*/

+void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bufferProcessor,

+        unsigned long frameCount );

+

+/** Use for the second buffer half when the input buffer is split in two halves.

+ @see PaUtil_SetInputChannel

+*/

+void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int channel, void *data, unsigned int stride );

+

+/** Use for the second buffer half when the input buffer is split in two halves.

+ @see PaUtil_SetInterleavedInputChannels

+*/

+void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int firstChannel, void *data, unsigned int channelCount );

+

+/** Use for the second buffer half when the input buffer is split in two halves.

+ @see PaUtil_SetNonInterleavedInputChannel

+*/

+void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int channel, void *data );

+

+        

+/** Set the number of frames in the output host buffer(s) specified by the

+ PaUtil_Set*OutputChannel functions.

+

+ @param bufferProcessor The buffer processor.

+

+ @param frameCount The number of host output frames. A 0 frameCount indicates to

+ use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor.

+

+ @see PaUtil_SetOutputChannel, PaUtil_SetInterleavedOutputChannels,

+ PaUtil_SetNonInterleavedOutputChannel

+*/

+void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,

+        unsigned long frameCount );

+

+

+/** Indicate that the output will be discarded. This function should be used

+ when implementing the paNeverDropInput mode for full duplex streams.

+

+ @param bufferProcessor The buffer processor.

+*/

+void PaUtil_SetNoOutput( PaUtilBufferProcessor* bufferProcessor );

+

+

+/** Provide the buffer processor with a pointer to a host output channel.

+

+ @param bufferProcessor The buffer processor.

+ @param channel The channel number.

+ @param data The buffer.

+ @param stride The stride from one sample to the next, in samples. For

+ interleaved host buffers, the stride will usually be the same as the number of

+ channels in the buffer.

+*/

+void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int channel, void *data, unsigned int stride );

+

+

+/** Provide the buffer processor with a pointer to a number of interleaved

+ host output channels.

+

+ @param bufferProcessor The buffer processor.

+ @param firstChannel The first channel number.

+ @param data The buffer.

+ @param channelCount The number of interleaved channels in the buffer. If

+ channelCount is zero, the number of channels specified to

+ PaUtil_InitializeBufferProcessor will be used.

+*/

+void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int firstChannel, void *data, unsigned int channelCount );

+

+        

+/** Provide the buffer processor with a pointer to one non-interleaved host

+ output channel.

+

+ @param bufferProcessor The buffer processor.

+ @param channel The channel number.

+ @param data The buffer.

+*/

+void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int channel, void *data );

+

+

+/** Use for the second buffer half when the output buffer is split in two halves.

+ @see PaUtil_SetOutputFrameCount

+*/

+void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,

+        unsigned long frameCount );

+

+/** Use for the second buffer half when the output buffer is split in two halves.

+ @see PaUtil_SetOutputChannel

+*/

+void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int channel, void *data, unsigned int stride );

+

+/** Use for the second buffer half when the output buffer is split in two halves.

+ @see PaUtil_SetInterleavedOutputChannels

+*/

+void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int firstChannel, void *data, unsigned int channelCount );

+

+/** Use for the second buffer half when the output buffer is split in two halves.

+ @see PaUtil_SetNonInterleavedOutputChannel

+*/

+void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,

+        unsigned int channel, void *data );

+

+/*@}*/

+

+

+/** @name Buffer processing functions for callback streams

+*/

+/*@{*/

+

+/** Commence processing a host buffer (or a pair of host buffers in the

+ full-duplex case) for a callback stream.

+

+ @param bufferProcessor The buffer processor.

+

+ @param timeInfo Timing information for the first sample of the host

+ buffer(s). This information may be adjusted when buffer adaption is being

+ performed.

+

+ @param callbackStatusFlags Flags indicating whether underruns and overruns

+ have occurred since the last time the buffer processor was called.

+*/

+void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bufferProcessor,

+        PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags );

+

+        

+/** Finish processing a host buffer (or a pair of host buffers in the

+ full-duplex case) for a callback stream.

+

+ @param bufferProcessor The buffer processor.

+ 

+ @param callbackResult On input, indicates a previous callback result, and on

+ exit, the result of the user stream callback, if it is called.

+ On entry callbackResult should contain one of { paContinue, paComplete, or

+ paAbort}. If paComplete is passed, the stream callback will not be called

+ but any audio that was generated by previous stream callbacks will be copied

+ to the output buffer(s). You can check whether the buffer processor's internal

+ buffer is empty by calling PaUtil_IsBufferProcessorOutputEmpty.

+

+ If the stream callback is called its result is stored in *callbackResult. If

+ the stream callback returns paComplete or paAbort, all output buffers will be

+ full of valid data - some of which may be zeros to acount for data that

+ wasn't generated by the terminating callback.

+

+ @return The number of frames processed. This usually corresponds to the

+ number of frames specified by the PaUtil_Set*FrameCount functions, exept in

+ the paUtilVariableHostBufferSizePartialUsageAllowed buffer size mode when a

+ smaller value may be returned.

+*/

+unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bufferProcessor,

+        int *callbackResult );

+

+

+/** Determine whether any callback generated output remains in the bufffer

+ processor's internal buffers. This method may be used to determine when to

+ continue calling PaUtil_EndBufferProcessing() after the callback has returned

+ a callbackResult of paComplete.

+

+ @param bufferProcessor The buffer processor.

+ 

+ @return Returns non-zero when callback generated output remains in the internal

+ buffer and zero (0) when there internal buffer contains no callback generated

+ data.

+*/

+int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bufferProcessor );

+

+/*@}*/

+

+

+/** @name Buffer processing functions for blocking read/write streams

+*/

+/*@{*/

+

+/** Copy samples from host input channels set up by the PaUtil_Set*InputChannels

+ functions to a user supplied buffer. This function is intended for use with

+ blocking read/write streams. Copies the minimum of the number of

+ user frames (specified by the frameCount parameter) and the number of available

+ host frames (specified in a previous call to SetInputFrameCount()).

+

+ @param bufferProcessor The buffer processor.

+

+ @param buffer A pointer to the user buffer pointer, or a pointer to a pointer

+ to an array of user buffer pointers for a non-interleaved stream. It is

+ important that this parameter points to a copy of the user buffer pointers,

+ not to the actual user buffer pointers, because this function updates the

+ pointers before returning.

+

+ @param frameCount The number of frames of data in the buffer(s) pointed to by

+ the buffer parameter.

+

+ @return The number of frames copied. The buffer pointer(s) pointed to by the

+ buffer parameter are advanced to point to the frame(s) following the last one

+ filled.

+*/

+unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bufferProcessor,

+        void **buffer, unsigned long frameCount );

+

+

+/* Copy samples from a user supplied buffer to host output channels set up by

+ the PaUtil_Set*OutputChannels functions. This function is intended for use with

+ blocking read/write streams. Copies the minimum of the number of

+ user frames (specified by the frameCount parameter) and the number of

+ host frames (specified in a previous call to SetOutputFrameCount()).

+

+ @param bufferProcessor The buffer processor.

+

+ @param buffer A pointer to the user buffer pointer, or a pointer to a pointer

+ to an array of user buffer pointers for a non-interleaved stream. It is

+ important that this parameter points to a copy of the user buffer pointers,

+ not to the actual user buffer pointers, because this function updates the

+ pointers before returning.

+

+ @param frameCount The number of frames of data in the buffer(s) pointed to by

+ the buffer parameter.

+

+ @return The number of frames copied. The buffer pointer(s) pointed to by the

+ buffer parameter are advanced to point to the frame(s) following the last one

+ copied.

+*/

+unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bufferProcessor,

+        const void ** buffer, unsigned long frameCount );

+

+

+/* Zero samples in host output channels set up by the PaUtil_Set*OutputChannels

+ functions. This function is useful for flushing streams.

+ Zeros the minimum of frameCount and the number of host frames specified in a

+ previous call to SetOutputFrameCount().

+

+ @param bufferProcessor The buffer processor.

+

+ @param frameCount The maximum number of frames to zero.

+ 

+ @return The number of frames zeroed.

+*/

+unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bufferProcessor,

+        unsigned long frameCount );

+

+

+/*@}*/

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PA_PROCESS_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_skeleton.c b/pjmedia/src/pjmedia/portaudio/pa_skeleton.c
index ebc1f50..5df50c9 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_skeleton.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_skeleton.c
@@ -1,807 +1,828 @@
-/*
- * $Id: pa_skeleton.c,v 1.1.2.39 2003/11/26 14:56:09 rossbencina Exp $
- * Portable Audio I/O Library skeleton implementation
- * demonstrates how to use the common functions to implement support
- * for a host API
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Skeleton implementation of support for a host API.
-
- @note This file is provided as a starting point for implementing support for
- a new host API. IMPLEMENT ME comments are used to indicate functionality
- which much be customised for each implementation.
-*/
-
-
-#include <string.h> /* strlen() */
-
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
-
-/* prototypes for functions declared in this file */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** s,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *streamCallback,
-                           void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-
-
-/* IMPLEMENT ME: a macro like the following one should be used for reporting
- host errors */
-#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
-    PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
-
-/* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct
-{
-    PaUtilHostApiRepresentation inheritedHostApiRep;
-    PaUtilStreamInterface callbackStreamInterface;
-    PaUtilStreamInterface blockingStreamInterface;
-
-    PaUtilAllocationGroup *allocations;
-
-    /* implementation specific data goes here */
-}
-PaSkeletonHostApiRepresentation;  /* IMPLEMENT ME: rename this */
-
-
-PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
-    PaError result = paNoError;
-    int i, deviceCount;
-    PaSkeletonHostApiRepresentation *skeletonHostApi;
-    PaDeviceInfo *deviceInfoArray;
-
-    skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );
-    if( !skeletonHostApi )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
-    if( !skeletonHostApi->allocations )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    *hostApi = &skeletonHostApi->inheritedHostApiRep;
-    (*hostApi)->info.structVersion = 1;
-    (*hostApi)->info.type = paInDevelopment;            /* IMPLEMENT ME: change to correct type id */
-    (*hostApi)->info.name = "skeleton implementation";  /* IMPLEMENT ME: change to correct name */
-
-    (*hostApi)->info.defaultInputDevice = paNoDevice;  /* IMPLEMENT ME */
-    (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
-
-    (*hostApi)->info.deviceCount = 0;  
-
-    deviceCount = 0; /* IMPLEMENT ME */
-    
-    if( deviceCount > 0 )
-    {
-        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
-                skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
-        if( !(*hostApi)->deviceInfos )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        /* allocate all device info structs in a contiguous block */
-        deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
-                skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
-        if( !deviceInfoArray )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        for( i=0; i < deviceCount; ++i )
-        {
-            PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
-            deviceInfo->structVersion = 2;
-            deviceInfo->hostApi = hostApiIndex;
-            deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg:
-                deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 );
-                if( !deviceName )
-                {
-                    result = paInsufficientMemory;
-                    goto error;
-                }
-                strcpy( deviceName, srcName );
-                deviceInfo->name = deviceName;
-            */
-
-            deviceInfo->maxInputChannels = 0;  /* IMPLEMENT ME */
-            deviceInfo->maxOutputChannels = 0;  /* IMPLEMENT ME */
-            
-            deviceInfo->defaultLowInputLatency = 0.;  /* IMPLEMENT ME */
-            deviceInfo->defaultLowOutputLatency = 0.;  /* IMPLEMENT ME */
-            deviceInfo->defaultHighInputLatency = 0.;  /* IMPLEMENT ME */
-            deviceInfo->defaultHighOutputLatency = 0.;  /* IMPLEMENT ME */  
-
-            deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */
-            
-            (*hostApi)->deviceInfos[i] = deviceInfo;
-            ++(*hostApi)->info.deviceCount;
-        }
-    }
-
-    (*hostApi)->Terminate = Terminate;
-    (*hostApi)->OpenStream = OpenStream;
-    (*hostApi)->IsFormatSupported = IsFormatSupported;
-
-    PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, GetStreamCpuLoad,
-                                      PaUtil_DummyRead, PaUtil_DummyWrite,
-                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
-    PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
-                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
-    return result;
-
-error:
-    if( skeletonHostApi )
-    {
-        if( skeletonHostApi->allocations )
-        {
-            PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
-            PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
-        }
-                
-        PaUtil_FreeMemory( skeletonHostApi );
-    }
-    return result;
-}
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
-    PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
-
-    /*
-        IMPLEMENT ME:
-            - clean up any resources not handled by the allocation group
-    */
-
-    if( skeletonHostApi->allocations )
-    {
-        PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
-        PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
-    }
-
-    PaUtil_FreeMemory( skeletonHostApi );
-}
-
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate )
-{
-    int inputChannelCount, outputChannelCount;
-    PaSampleFormat inputSampleFormat, outputSampleFormat;
-    
-    if( inputParameters )
-    {
-        inputChannelCount = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-
-        /* all standard sample formats are supported by the buffer adapter,
-            this implementation doesn't support any custom sample formats */
-        if( inputSampleFormat & paCustomFormat )
-            return paSampleFormatNotSupported;
-            
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-
-        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that input device can support inputChannelCount */
-        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
-            return paInvalidChannelCount;
-
-        /* validate inputStreamInfo */
-        if( inputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-    }
-    else
-    {
-        inputChannelCount = 0;
-    }
-
-    if( outputParameters )
-    {
-        outputChannelCount = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-
-        /* all standard sample formats are supported by the buffer adapter,
-            this implementation doesn't support any custom sample formats */
-        if( outputSampleFormat & paCustomFormat )
-            return paSampleFormatNotSupported;
-            
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-
-        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that output device can support outputChannelCount */
-        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
-            return paInvalidChannelCount;
-
-        /* validate outputStreamInfo */
-        if( outputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-    }
-    else
-    {
-        outputChannelCount = 0;
-    }
-    
-    /*
-        IMPLEMENT ME:
-
-            - if a full duplex stream is requested, check that the combination
-                of input and output parameters is supported if necessary
-
-            - check that the device supports sampleRate
-
-        Because the buffer adapter handles conversion between all standard
-        sample formats, the following checks are only required if paCustomFormat
-        is implemented, or under some other unusual conditions.
-
-            - check that input device can support inputSampleFormat, or that
-                we have the capability to convert from inputSampleFormat to
-                a native format
-
-            - check that output device can support outputSampleFormat, or that
-                we have the capability to convert from outputSampleFormat to
-                a native format
-    */
-
-
-    /* suppress unused variable warnings */
-    (void) sampleRate;
-
-    return paFormatIsSupported;
-}
-
-/* PaSkeletonStream - a stream data structure specifically for this implementation */
-
-typedef struct PaSkeletonStream
-{ /* IMPLEMENT ME: rename this */
-    PaUtilStreamRepresentation streamRepresentation;
-    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
-    PaUtilBufferProcessor bufferProcessor;
-
-    /* IMPLEMENT ME:
-            - implementation specific data goes here
-    */
-    unsigned long framesPerHostCallback; /* just an example */
-}
-PaSkeletonStream;
-
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** s,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *streamCallback,
-                           void *userData )
-{
-    PaError result = paNoError;
-    PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
-    PaSkeletonStream *stream = 0;
-    unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */
-    int inputChannelCount, outputChannelCount;
-    PaSampleFormat inputSampleFormat, outputSampleFormat;
-    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
-
-
-    if( inputParameters )
-    {
-        inputChannelCount = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-
-        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that input device can support inputChannelCount */
-        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
-            return paInvalidChannelCount;
-
-        /* validate inputStreamInfo */
-        if( inputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-
-        /* IMPLEMENT ME - establish which  host formats are available */
-        hostInputSampleFormat =
-            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
-    }
-    else
-    {
-        inputChannelCount = 0;
-        inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
-    }
-
-    if( outputParameters )
-    {
-        outputChannelCount = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-        
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-
-        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that output device can support inputChannelCount */
-        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
-            return paInvalidChannelCount;
-
-        /* validate outputStreamInfo */
-        if( outputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-
-        /* IMPLEMENT ME - establish which  host formats are available */
-        hostOutputSampleFormat =
-            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
-    }
-    else
-    {
-        outputChannelCount = 0;
-        outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
-    }
-
-    /*
-        IMPLEMENT ME:
-
-        ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
-
-            - check that input device can support inputSampleFormat, or that
-                we have the capability to convert from outputSampleFormat to
-                a native format
-
-            - check that output device can support outputSampleFormat, or that
-                we have the capability to convert from outputSampleFormat to
-                a native format
-
-            - if a full duplex stream is requested, check that the combination
-                of input and output parameters is supported
-
-            - check that the device supports sampleRate
-
-            - alter sampleRate to a close allowable rate if possible / necessary
-
-            - validate suggestedInputLatency and suggestedOutputLatency parameters,
-                use default values where necessary
-    */
-
-
-
-
-    /* validate platform specific flags */
-    if( (streamFlags & paPlatformSpecificFlags) != 0 )
-        return paInvalidFlag; /* unexpected platform specific flag */
-
-
-    stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );
-    if( !stream )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    if( streamCallback )
-    {
-        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
-                                               &skeletonHostApi->callbackStreamInterface, streamCallback, userData );
-    }
-    else
-    {
-        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
-                                               &skeletonHostApi->blockingStreamInterface, streamCallback, userData );
-    }
-
-    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
-
-    /* we assume a fixed host buffer size in this example, but the buffer processor
-        can also support bounded and unknown host buffer sizes by passing 
-        paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
-        paUtilFixedHostBufferSize below. */
-        
-    result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
-              inputChannelCount, inputSampleFormat, hostInputSampleFormat,
-              outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
-              sampleRate, streamFlags, framesPerBuffer,
-              framesPerHostBuffer, paUtilFixedHostBufferSize,
-              streamCallback, userData );
-    if( result != paNoError )
-        goto error;
-
-
-    /*
-        IMPLEMENT ME: initialise the following fields with estimated or actual
-        values.
-    */
-    stream->streamRepresentation.streamInfo.inputLatency =
-            PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);
-    stream->streamRepresentation.streamInfo.outputLatency =
-            PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);
-    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
-    
-    /*
-        IMPLEMENT ME:
-            - additional stream setup + opening
-    */
-
-    stream->framesPerHostCallback = framesPerHostBuffer;
-
-    *s = (PaStream*)stream;
-
-    return result;
-
-error:
-    if( stream )
-        PaUtil_FreeMemory( stream );
-
-    return result;
-}
-
-/*
-    ExampleHostProcessingLoop() illustrates the kind of processing which may
-    occur in a host implementation.
- 
-*/
-static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
-{
-    PaSkeletonStream *stream = (PaSkeletonStream*)userData;
-    PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
-    int callbackResult;
-    unsigned long framesProcessed;
-    
-    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-    
-    /*
-        IMPLEMENT ME:
-            - generate timing information
-            - handle buffer slips
-    */
-
-    /*
-        If you need to byte swap or shift inputBuffer to convert it into a
-        portaudio format, do it here.
-    */
-
-
-
-    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );
-
-    /*
-        depending on whether the host buffers are interleaved, non-interleaved
-        or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
-        PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
-    */
-    
-    PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
-    PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
-            0, /* first channel of inputBuffer is channel 0 */
-            inputBuffer,
-            0 ); /* 0 - use inputChannelCount passed to init buffer processor */
-
-    PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
-    PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
-            0, /* first channel of outputBuffer is channel 0 */
-            outputBuffer,
-            0 ); /* 0 - use outputChannelCount passed to init buffer processor */
-
-    /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
-        in general you would pass paContinue for normal operation, and
-        paComplete to drain the buffer processor's internal output buffer.
-        You can check whether the buffer processor's output buffer is empty
-        using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
-    */
-    callbackResult = paContinue;
-    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
-
-    
-    /*
-        If you need to byte swap or shift outputBuffer to convert it to
-        host format, do it here.
-    */
-
-    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
-
-
-    if( callbackResult == paContinue )
-    {
-        /* nothing special to do */
-    }
-    else if( callbackResult == paAbort )
-    {
-        /* IMPLEMENT ME - finish playback immediately  */
-
-        /* once finished, call the finished callback */
-        if( stream->streamRepresentation.streamFinishedCallback != 0 )
-            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
-    }
-    else
-    {
-        /* User callback has asked us to stop with paComplete or other non-zero value */
-
-        /* IMPLEMENT ME - finish playback once currently queued audio has completed  */
-
-        /* once finished, call the finished callback */
-        if( stream->streamRepresentation.streamFinishedCallback != 0 )
-            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
-    }
-}
-
-
-/*
-    When CloseStream() is called, the multi-api layer ensures that
-    the stream has already been stopped or aborted.
-*/
-static PaError CloseStream( PaStream* s )
-{
-    PaError result = paNoError;
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /*
-        IMPLEMENT ME:
-            - additional stream closing + cleanup
-    */
-
-    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
-    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-    PaUtil_FreeMemory( stream );
-
-    return result;
-}
-
-
-static PaError StartStream( PaStream *s )
-{
-    PaError result = paNoError;
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
-
-    /* IMPLEMENT ME, see portaudio.h for required behavior */
-
-    /* suppress unused function warning. the code in ExampleHostProcessingLoop or
-       something similar should be implemented to feed samples to and from the
-       host after StartStream() is called.
-    */
-    (void) ExampleHostProcessingLoop;
-
-    return result;
-}
-
-
-static PaError StopStream( PaStream *s )
-{
-    PaError result = paNoError;
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) stream;
-
-    /* IMPLEMENT ME, see portaudio.h for required behavior */
-
-    return result;
-}
-
-
-static PaError AbortStream( PaStream *s )
-{
-    PaError result = paNoError;
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) stream;
-    
-    /* IMPLEMENT ME, see portaudio.h for required behavior */
-
-    return result;
-}
-
-
-static PaError IsStreamStopped( PaStream *s )
-{
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) stream;
-    
-    /* IMPLEMENT ME, see portaudio.h for required behavior */
-
-    return 0;
-}
-
-
-static PaError IsStreamActive( PaStream *s )
-{
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) stream;
-    
-    /* IMPLEMENT ME, see portaudio.h for required behavior */
-
-    return 0;
-}
-
-
-static PaTime GetStreamTime( PaStream *s )
-{
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) stream;
-    
-    /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
-    return 0;
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-/*
-    As separate stream interfaces are used for blocking and callback
-    streams, the following functions can be guaranteed to only be called
-    for blocking streams.
-*/
-
-static PaError ReadStream( PaStream* s,
-                           void *buffer,
-                           unsigned long frames )
-{
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) buffer;
-    (void) frames;
-    (void) stream;
-    
-    /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
-    return paNoError;
-}
-
-
-static PaError WriteStream( PaStream* s,
-                            const void *buffer,
-                            unsigned long frames )
-{
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) buffer;
-    (void) frames;
-    (void) stream;
-    
-    /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
-    return paNoError;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) stream;
-    
-    /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
-    return 0;
-}
-
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
-    PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) stream;
-    
-    /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
-    return 0;
-}
-
-
-
-
+/*

+ * $Id: pa_skeleton.c,v 1.1.2.39 2003/11/26 14:56:09 rossbencina Exp $

+ * Portable Audio I/O Library skeleton implementation

+ * demonstrates how to use the common functions to implement support

+ * for a host API

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+ @brief Skeleton implementation of support for a host API.

+

+ @note This file is provided as a starting point for implementing support for

+ a new host API. IMPLEMENT ME comments are used to indicate functionality

+ which much be customised for each implementation.

+*/

+

+

+#include <string.h> /* strlen() */

+

+#include "pa_util.h"

+#include "pa_allocation.h"

+#include "pa_hostapi.h"

+#include "pa_stream.h"

+#include "pa_cpuload.h"

+#include "pa_process.h"

+

+

+/* prototypes for functions declared in this file */

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+

+

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate );

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** s,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *streamCallback,

+                           void *userData );

+static PaError CloseStream( PaStream* stream );

+static PaError StartStream( PaStream *stream );

+static PaError StopStream( PaStream *stream );

+static PaError AbortStream( PaStream *stream );

+static PaError IsStreamStopped( PaStream *s );

+static PaError IsStreamActive( PaStream *stream );

+static PaTime GetStreamTime( PaStream *stream );

+static double GetStreamCpuLoad( PaStream* stream );

+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );

+static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );

+static signed long GetStreamReadAvailable( PaStream* stream );

+static signed long GetStreamWriteAvailable( PaStream* stream );

+

+

+/* IMPLEMENT ME: a macro like the following one should be used for reporting

+ host errors */

+#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \

+    PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )

+

+/* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */

+

+typedef struct

+{

+    PaUtilHostApiRepresentation inheritedHostApiRep;

+    PaUtilStreamInterface callbackStreamInterface;

+    PaUtilStreamInterface blockingStreamInterface;

+

+    PaUtilAllocationGroup *allocations;

+

+    /* implementation specific data goes here */

+}

+PaSkeletonHostApiRepresentation;  /* IMPLEMENT ME: rename this */

+

+

+PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )

+{

+    PaError result = paNoError;

+    int i, deviceCount;

+    PaSkeletonHostApiRepresentation *skeletonHostApi;

+    PaDeviceInfo *deviceInfoArray;

+

+    skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );

+    if( !skeletonHostApi )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();

+    if( !skeletonHostApi->allocations )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    *hostApi = &skeletonHostApi->inheritedHostApiRep;

+    (*hostApi)->info.structVersion = 1;

+    (*hostApi)->info.type = paInDevelopment;            /* IMPLEMENT ME: change to correct type id */

+    (*hostApi)->info.name = "skeleton implementation";  /* IMPLEMENT ME: change to correct name */

+

+    (*hostApi)->info.defaultInputDevice = paNoDevice;  /* IMPLEMENT ME */

+    (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */

+

+    (*hostApi)->info.deviceCount = 0;  

+

+    deviceCount = 0; /* IMPLEMENT ME */

+    

+    if( deviceCount > 0 )

+    {

+        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(

+                skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );

+        if( !(*hostApi)->deviceInfos )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        /* allocate all device info structs in a contiguous block */

+        deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(

+                skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );

+        if( !deviceInfoArray )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        for( i=0; i < deviceCount; ++i )

+        {

+            PaDeviceInfo *deviceInfo = &deviceInfoArray[i];

+            deviceInfo->structVersion = 2;

+            deviceInfo->hostApi = hostApiIndex;

+            deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg:

+                deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 );

+                if( !deviceName )

+                {

+                    result = paInsufficientMemory;

+                    goto error;

+                }

+                strcpy( deviceName, srcName );

+                deviceInfo->name = deviceName;

+            */

+

+            deviceInfo->maxInputChannels = 0;  /* IMPLEMENT ME */

+            deviceInfo->maxOutputChannels = 0;  /* IMPLEMENT ME */

+            

+            deviceInfo->defaultLowInputLatency = 0.;  /* IMPLEMENT ME */

+            deviceInfo->defaultLowOutputLatency = 0.;  /* IMPLEMENT ME */

+            deviceInfo->defaultHighInputLatency = 0.;  /* IMPLEMENT ME */

+            deviceInfo->defaultHighOutputLatency = 0.;  /* IMPLEMENT ME */  

+

+            deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */

+            

+            (*hostApi)->deviceInfos[i] = deviceInfo;

+            ++(*hostApi)->info.deviceCount;

+        }

+    }

+

+    (*hostApi)->Terminate = Terminate;

+    (*hostApi)->OpenStream = OpenStream;

+    (*hostApi)->IsFormatSupported = IsFormatSupported;

+

+    PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,

+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, GetStreamCpuLoad,

+                                      PaUtil_DummyRead, PaUtil_DummyWrite,

+                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );

+

+    PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,

+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, PaUtil_DummyGetCpuLoad,

+                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );

+

+    return result;

+

+error:

+    if( skeletonHostApi )

+    {

+        if( skeletonHostApi->allocations )

+        {

+            PaUtil_FreeAllAllocations( skeletonHostApi->allocations );

+            PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );

+        }

+                

+        PaUtil_FreeMemory( skeletonHostApi );

+    }

+    return result;

+}

+

+

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )

+{

+    PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;

+

+    /*

+        IMPLEMENT ME:

+            - clean up any resources not handled by the allocation group

+    */

+

+    if( skeletonHostApi->allocations )

+    {

+        PaUtil_FreeAllAllocations( skeletonHostApi->allocations );

+        PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );

+    }

+

+    PaUtil_FreeMemory( skeletonHostApi );

+}

+

+

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate )

+{

+    int inputChannelCount, outputChannelCount;

+    PaSampleFormat inputSampleFormat, outputSampleFormat;

+    

+    if( inputParameters )

+    {

+        inputChannelCount = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+

+        /* all standard sample formats are supported by the buffer adapter,

+            this implementation doesn't support any custom sample formats */

+        if( inputSampleFormat & paCustomFormat )

+            return paSampleFormatNotSupported;

+            

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+

+        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that input device can support inputChannelCount */

+        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )

+            return paInvalidChannelCount;

+

+        /* validate inputStreamInfo */

+        if( inputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */

+    }

+    else

+    {

+        inputChannelCount = 0;

+    }

+

+    if( outputParameters )

+    {

+        outputChannelCount = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+

+        /* all standard sample formats are supported by the buffer adapter,

+            this implementation doesn't support any custom sample formats */

+        if( outputSampleFormat & paCustomFormat )

+            return paSampleFormatNotSupported;

+            

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+

+        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that output device can support outputChannelCount */

+        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )

+            return paInvalidChannelCount;

+

+        /* validate outputStreamInfo */

+        if( outputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */

+    }

+    else

+    {

+        outputChannelCount = 0;

+    }

+    

+    /*

+        IMPLEMENT ME:

+

+            - if a full duplex stream is requested, check that the combination

+                of input and output parameters is supported if necessary

+

+            - check that the device supports sampleRate

+

+        Because the buffer adapter handles conversion between all standard

+        sample formats, the following checks are only required if paCustomFormat

+        is implemented, or under some other unusual conditions.

+

+            - check that input device can support inputSampleFormat, or that

+                we have the capability to convert from inputSampleFormat to

+                a native format

+

+            - check that output device can support outputSampleFormat, or that

+                we have the capability to convert from outputSampleFormat to

+                a native format

+    */

+

+

+    /* suppress unused variable warnings */

+    (void) sampleRate;

+

+    return paFormatIsSupported;

+}

+

+/* PaSkeletonStream - a stream data structure specifically for this implementation */

+

+typedef struct PaSkeletonStream

+{ /* IMPLEMENT ME: rename this */

+    PaUtilStreamRepresentation streamRepresentation;

+    PaUtilCpuLoadMeasurer cpuLoadMeasurer;

+    PaUtilBufferProcessor bufferProcessor;

+

+    /* IMPLEMENT ME:

+            - implementation specific data goes here

+    */

+    unsigned long framesPerHostCallback; /* just an example */

+}

+PaSkeletonStream;

+

+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */

+

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** s,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *streamCallback,

+                           void *userData )

+{

+    PaError result = paNoError;

+    PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;

+    PaSkeletonStream *stream = 0;

+    unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */

+    int inputChannelCount, outputChannelCount;

+    PaSampleFormat inputSampleFormat, outputSampleFormat;

+    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;

+

+

+    if( inputParameters )

+    {

+        inputChannelCount = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+

+        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that input device can support inputChannelCount */

+        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )

+            return paInvalidChannelCount;

+

+        /* validate inputStreamInfo */

+        if( inputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */

+

+        /* IMPLEMENT ME - establish which  host formats are available */

+        hostInputSampleFormat =

+            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );

+    }

+    else

+    {

+        inputChannelCount = 0;

+        inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */

+    }

+

+    if( outputParameters )

+    {

+        outputChannelCount = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+        

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+

+        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that output device can support inputChannelCount */

+        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )

+            return paInvalidChannelCount;

+

+        /* validate outputStreamInfo */

+        if( outputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */

+

+        /* IMPLEMENT ME - establish which  host formats are available */

+        hostOutputSampleFormat =

+            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );

+    }

+    else

+    {

+        outputChannelCount = 0;

+        outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */

+    }

+

+    /*

+        IMPLEMENT ME:

+

+        ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )

+

+            - check that input device can support inputSampleFormat, or that

+                we have the capability to convert from outputSampleFormat to

+                a native format

+

+            - check that output device can support outputSampleFormat, or that

+                we have the capability to convert from outputSampleFormat to

+                a native format

+

+            - if a full duplex stream is requested, check that the combination

+                of input and output parameters is supported

+

+            - check that the device supports sampleRate

+

+            - alter sampleRate to a close allowable rate if possible / necessary

+

+            - validate suggestedInputLatency and suggestedOutputLatency parameters,

+                use default values where necessary

+    */

+

+

+

+

+    /* validate platform specific flags */

+    if( (streamFlags & paPlatformSpecificFlags) != 0 )

+        return paInvalidFlag; /* unexpected platform specific flag */

+

+

+    stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );

+    if( !stream )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    if( streamCallback )

+    {

+        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,

+                                               &skeletonHostApi->callbackStreamInterface, streamCallback, userData );

+    }

+    else

+    {

+        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,

+                                               &skeletonHostApi->blockingStreamInterface, streamCallback, userData );

+    }

+

+    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );

+

+

+    /* we assume a fixed host buffer size in this example, but the buffer processor

+        can also support bounded and unknown host buffer sizes by passing 

+        paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of

+        paUtilFixedHostBufferSize below. */

+        

+    result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,

+              inputChannelCount, inputSampleFormat, hostInputSampleFormat,

+              outputChannelCount, outputSampleFormat, hostOutputSampleFormat,

+              sampleRate, streamFlags, framesPerBuffer,

+              framesPerHostBuffer, paUtilFixedHostBufferSize,

+              streamCallback, userData );

+    if( result != paNoError )

+        goto error;

+

+

+    /*

+        IMPLEMENT ME: initialise the following fields with estimated or actual

+        values.

+    */

+    stream->streamRepresentation.streamInfo.inputLatency =

+            PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);

+    stream->streamRepresentation.streamInfo.outputLatency =

+            PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);

+    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;

+

+    

+    /*

+        IMPLEMENT ME:

+            - additional stream setup + opening

+    */

+

+    stream->framesPerHostCallback = framesPerHostBuffer;

+

+    *s = (PaStream*)stream;

+

+    return result;

+

+error:

+    if( stream )

+        PaUtil_FreeMemory( stream );

+

+    return result;

+}

+

+/*

+    ExampleHostProcessingLoop() illustrates the kind of processing which may

+    occur in a host implementation.

+ 

+*/

+static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )

+{

+    PaSkeletonStream *stream = (PaSkeletonStream*)userData;

+    PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */

+    int callbackResult;

+    unsigned long framesProcessed;

+    

+    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

+    

+    /*

+        IMPLEMENT ME:

+            - generate timing information

+            - handle buffer slips

+    */

+

+    /*

+        If you need to byte swap or shift inputBuffer to convert it into a

+        portaudio format, do it here.

+    */

+

+

+

+    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );

+

+    /*

+        depending on whether the host buffers are interleaved, non-interleaved

+        or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),

+        PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.

+    */

+    

+    PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );

+    PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,

+            0, /* first channel of inputBuffer is channel 0 */

+            inputBuffer,

+            0 ); /* 0 - use inputChannelCount passed to init buffer processor */

+

+    PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );

+    PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,

+            0, /* first channel of outputBuffer is channel 0 */

+            outputBuffer,

+            0 ); /* 0 - use outputChannelCount passed to init buffer processor */

+

+    /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()

+        in general you would pass paContinue for normal operation, and

+        paComplete to drain the buffer processor's internal output buffer.

+        You can check whether the buffer processor's output buffer is empty

+        using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )

+    */

+    callbackResult = paContinue;

+    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );

+

+    

+    /*

+        If you need to byte swap or shift outputBuffer to convert it to

+        host format, do it here.

+    */

+

+    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );

+

+

+    if( callbackResult == paContinue )

+    {

+        /* nothing special to do */

+    }

+    else if( callbackResult == paAbort )

+    {

+        /* IMPLEMENT ME - finish playback immediately  */

+

+        /* once finished, call the finished callback */

+        if( stream->streamRepresentation.streamFinishedCallback != 0 )

+            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );

+    }

+    else

+    {

+        /* User callback has asked us to stop with paComplete or other non-zero value */

+

+        /* IMPLEMENT ME - finish playback once currently queued audio has completed  */

+

+        /* once finished, call the finished callback */

+        if( stream->streamRepresentation.streamFinishedCallback != 0 )

+            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );

+    }

+}

+

+

+/*

+    When CloseStream() is called, the multi-api layer ensures that

+    the stream has already been stopped or aborted.

+*/

+static PaError CloseStream( PaStream* s )

+{

+    PaError result = paNoError;

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /*

+        IMPLEMENT ME:

+            - additional stream closing + cleanup

+    */

+

+    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );

+    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );

+    PaUtil_FreeMemory( stream );

+

+    return result;

+}

+

+

+static PaError StartStream( PaStream *s )

+{

+    PaError result = paNoError;

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );

+

+    /* IMPLEMENT ME, see portaudio.h for required behavior */

+

+    /* suppress unused function warning. the code in ExampleHostProcessingLoop or

+       something similar should be implemented to feed samples to and from the

+       host after StartStream() is called.

+    */

+    (void) ExampleHostProcessingLoop;

+

+    return result;

+}

+

+

+static PaError StopStream( PaStream *s )

+{

+    PaError result = paNoError;

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) stream;

+

+    /* IMPLEMENT ME, see portaudio.h for required behavior */

+

+    return result;

+}

+

+

+static PaError AbortStream( PaStream *s )

+{

+    PaError result = paNoError;

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) stream;

+    

+    /* IMPLEMENT ME, see portaudio.h for required behavior */

+

+    return result;

+}

+

+

+static PaError IsStreamStopped( PaStream *s )

+{

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) stream;

+    

+    /* IMPLEMENT ME, see portaudio.h for required behavior */

+

+    return 0;

+}

+

+

+static PaError IsStreamActive( PaStream *s )

+{

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) stream;

+    

+    /* IMPLEMENT ME, see portaudio.h for required behavior */

+

+    return 0;

+}

+

+

+static PaTime GetStreamTime( PaStream *s )

+{

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) stream;

+    

+    /* IMPLEMENT ME, see portaudio.h for required behavior*/

+

+    return 0;

+}

+

+

+static double GetStreamCpuLoad( PaStream* s )

+{

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );

+}

+

+

+/*

+    As separate stream interfaces are used for blocking and callback

+    streams, the following functions can be guaranteed to only be called

+    for blocking streams.

+*/

+

+static PaError ReadStream( PaStream* s,

+                           void *buffer,

+                           unsigned long frames )

+{

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) buffer;

+    (void) frames;

+    (void) stream;

+    

+    /* IMPLEMENT ME, see portaudio.h for required behavior*/

+

+    return paNoError;

+}

+

+

+static PaError WriteStream( PaStream* s,

+                            const void *buffer,

+                            unsigned long frames )

+{

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) buffer;

+    (void) frames;

+    (void) stream;

+    

+    /* IMPLEMENT ME, see portaudio.h for required behavior*/

+

+    return paNoError;

+}

+

+

+static signed long GetStreamReadAvailable( PaStream* s )

+{

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) stream;

+    

+    /* IMPLEMENT ME, see portaudio.h for required behavior*/

+

+    return 0;

+}

+

+

+static signed long GetStreamWriteAvailable( PaStream* s )

+{

+    PaSkeletonStream *stream = (PaSkeletonStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) stream;

+    

+    /* IMPLEMENT ME, see portaudio.h for required behavior*/

+

+    return 0;

+}

+

+

+

+

diff --git a/pjmedia/src/pjmedia/portaudio/pa_stream.c b/pjmedia/src/pjmedia/portaudio/pa_stream.c
index 044dde2..0df0d06 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_stream.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_stream.c
@@ -1,141 +1,162 @@
-/*
- * $Id: pa_stream.c,v 1.1.2.12 2003/09/20 21:31:00 rossbencina Exp $
- * Portable Audio I/O Library
- * 
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 2002 Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Interface used by pa_front to virtualize functions which operate on
- streams.
-*/
-
-
-#include "pa_stream.h"
-
-
-void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,
-                                       PaError (*Close)( PaStream* ),
-                                       PaError (*Start)( PaStream* ),
-                                       PaError (*Stop)( PaStream* ),
-                                       PaError (*Abort)( PaStream* ),
-                                       PaError (*IsStopped)( PaStream* ),
-                                       PaError (*IsActive)( PaStream* ),
-                                       PaTime (*GetTime)( PaStream* ),
-                                       double (*GetCpuLoad)( PaStream* ),
-                                       PaError (*Read)( PaStream*, void *, unsigned long ),
-                                       PaError (*Write)( PaStream*, const void *, unsigned long ),
-                                       signed long (*GetReadAvailable)( PaStream* ),
-                                       signed long (*GetWriteAvailable)( PaStream* )  )
-{
-    streamInterface->Close = Close;
-    streamInterface->Start = Start;
-    streamInterface->Stop = Stop;
-    streamInterface->Abort = Abort;
-    streamInterface->IsStopped = IsStopped;
-    streamInterface->IsActive = IsActive;
-    streamInterface->GetTime = GetTime;
-    streamInterface->GetCpuLoad = GetCpuLoad;
-    streamInterface->Read = Read;
-    streamInterface->Write = Write;
-    streamInterface->GetReadAvailable = GetReadAvailable;
-    streamInterface->GetWriteAvailable = GetWriteAvailable;
-}
-
-
-void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation,
-        PaUtilStreamInterface *streamInterface,
-        PaStreamCallback *streamCallback,
-        void *userData )
-{
-    streamRepresentation->magic = PA_STREAM_MAGIC;
-    streamRepresentation->nextOpenStream = 0;
-    streamRepresentation->streamInterface = streamInterface;
-    streamRepresentation->streamCallback = streamCallback;
-    streamRepresentation->streamFinishedCallback = 0;
-
-    streamRepresentation->userData = userData;
-
-    streamRepresentation->streamInfo.inputLatency = 0.;
-    streamRepresentation->streamInfo.outputLatency = 0.;
-    streamRepresentation->streamInfo.sampleRate = 0.;
-}
-
-
-void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation )
-{
-    streamRepresentation->magic = 0;
-}
-
-
-PaError PaUtil_DummyRead( PaStream* stream,
-                               void *buffer,
-                               unsigned long frames )
-{
-    (void)stream; /* unused parameter */
-    (void)buffer; /* unused parameter */
-    (void)frames; /* unused parameter */
-
-    return paCanNotReadFromACallbackStream;
-}
-
-
-PaError PaUtil_DummyWrite( PaStream* stream,
-                               const void *buffer,
-                               unsigned long frames )
-{
-    (void)stream; /* unused parameter */
-    (void)buffer; /* unused parameter */
-    (void)frames; /* unused parameter */
-
-    return paCanNotWriteToACallbackStream;
-}
-
-
-signed long PaUtil_DummyGetReadAvailable( PaStream* stream )
-{
-    (void)stream; /* unused parameter */
-
-    return paCanNotReadFromACallbackStream;
-}
-
-
-signed long PaUtil_DummyGetWriteAvailable( PaStream* stream )
-{
-    (void)stream; /* unused parameter */
-
-    return paCanNotWriteToACallbackStream;
-}
-
-
-double PaUtil_DummyGetCpuLoad( PaStream* stream )
-{
-    (void)stream; /* unused parameter */
-
-    return 0.0;
-}
+/*

+ * $Id: pa_stream.c,v 1.1.2.12 2003/09/20 21:31:00 rossbencina Exp $

+ * Portable Audio I/O Library

+ * 

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 2002 Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+ @brief Interface used by pa_front to virtualize functions which operate on

+ streams.

+*/

+

+

+#include "pa_stream.h"

+

+

+void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,

+                                       PaError (*Close)( PaStream* ),

+                                       PaError (*Start)( PaStream* ),

+                                       PaError (*Stop)( PaStream* ),

+                                       PaError (*Abort)( PaStream* ),

+                                       PaError (*IsStopped)( PaStream* ),

+                                       PaError (*IsActive)( PaStream* ),

+                                       PaTime (*GetTime)( PaStream* ),

+                                       double (*GetCpuLoad)( PaStream* ),

+                                       PaError (*Read)( PaStream*, void *, unsigned long ),

+                                       PaError (*Write)( PaStream*, const void *, unsigned long ),

+                                       signed long (*GetReadAvailable)( PaStream* ),

+                                       signed long (*GetWriteAvailable)( PaStream* )  )

+{

+    streamInterface->Close = Close;

+    streamInterface->Start = Start;

+    streamInterface->Stop = Stop;

+    streamInterface->Abort = Abort;

+    streamInterface->IsStopped = IsStopped;

+    streamInterface->IsActive = IsActive;

+    streamInterface->GetTime = GetTime;

+    streamInterface->GetCpuLoad = GetCpuLoad;

+    streamInterface->Read = Read;

+    streamInterface->Write = Write;

+    streamInterface->GetReadAvailable = GetReadAvailable;

+    streamInterface->GetWriteAvailable = GetWriteAvailable;

+}

+

+

+void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation,

+        PaUtilStreamInterface *streamInterface,

+        PaStreamCallback *streamCallback,

+        void *userData )

+{

+    streamRepresentation->magic = PA_STREAM_MAGIC;

+    streamRepresentation->nextOpenStream = 0;

+    streamRepresentation->streamInterface = streamInterface;

+    streamRepresentation->streamCallback = streamCallback;

+    streamRepresentation->streamFinishedCallback = 0;

+

+    streamRepresentation->userData = userData;

+

+    streamRepresentation->streamInfo.inputLatency = 0.;

+    streamRepresentation->streamInfo.outputLatency = 0.;

+    streamRepresentation->streamInfo.sampleRate = 0.;

+}

+

+

+void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation )

+{

+    streamRepresentation->magic = 0;

+}

+

+

+PaError PaUtil_DummyRead( PaStream* stream,

+                               void *buffer,

+                               unsigned long frames )

+{

+    (void)stream; /* unused parameter */

+    (void)buffer; /* unused parameter */

+    (void)frames; /* unused parameter */

+

+    return paCanNotReadFromACallbackStream;

+}

+

+

+PaError PaUtil_DummyWrite( PaStream* stream,

+                               const void *buffer,

+                               unsigned long frames )

+{

+    (void)stream; /* unused parameter */

+    (void)buffer; /* unused parameter */

+    (void)frames; /* unused parameter */

+

+    return paCanNotWriteToACallbackStream;

+}

+

+

+signed long PaUtil_DummyGetReadAvailable( PaStream* stream )

+{

+    (void)stream; /* unused parameter */

+

+    return paCanNotReadFromACallbackStream;

+}

+

+

+signed long PaUtil_DummyGetWriteAvailable( PaStream* stream )

+{

+    (void)stream; /* unused parameter */

+

+    return paCanNotWriteToACallbackStream;

+}

+

+

+double PaUtil_DummyGetCpuLoad( PaStream* stream )

+{

+    (void)stream; /* unused parameter */

+

+    return 0.0;

+}

diff --git a/pjmedia/src/pjmedia/portaudio/pa_stream.h b/pjmedia/src/pjmedia/portaudio/pa_stream.h
index 8b86943..9e93429 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_stream.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_stream.h
@@ -1,196 +1,217 @@
-#ifndef PA_STREAM_H
-#define PA_STREAM_H
-/*
- * $Id: pa_stream.h,v 1.1.2.13 2003/11/01 06:37:28 rossbencina Exp $
- * Portable Audio I/O Library
- * stream interface
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Interface used by pa_front to virtualize functions which operate on
- streams.
-*/
-
-
-#include "portaudio.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-#define PA_STREAM_MAGIC (0x18273645)
-
-
-/** A structure representing an (abstract) interface to a host API. Contains
- pointers to functions which implement the interface.
-
- All PaStreamInterface functions are guaranteed to be called with a non-null,
- valid stream parameter.
-*/
-typedef struct {
-    PaError (*Close)( PaStream* stream );
-    PaError (*Start)( PaStream *stream );
-    PaError (*Stop)( PaStream *stream );
-    PaError (*Abort)( PaStream *stream );
-    PaError (*IsStopped)( PaStream *stream );
-    PaError (*IsActive)( PaStream *stream );
-    PaTime (*GetTime)( PaStream *stream );
-    double (*GetCpuLoad)( PaStream* stream );
-    PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames );
-    PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames );
-    signed long (*GetReadAvailable)( PaStream* stream );
-    signed long (*GetWriteAvailable)( PaStream* stream );
-} PaUtilStreamInterface;
-
-
-/** Initialize the fields of a PaUtilStreamInterface structure.
-*/
-void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,
-    PaError (*Close)( PaStream* ),
-    PaError (*Start)( PaStream* ),
-    PaError (*Stop)( PaStream* ),
-    PaError (*Abort)( PaStream* ),
-    PaError (*IsStopped)( PaStream* ),
-    PaError (*IsActive)( PaStream* ),
-    PaTime (*GetTime)( PaStream* ),
-    double (*GetCpuLoad)( PaStream* ),
-    PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ),
-    PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames ),
-    signed long (*GetReadAvailable)( PaStream* stream ),
-    signed long (*GetWriteAvailable)( PaStream* stream ) );
-
-
-/** Dummy Read function for use in interfaces to a callback based streams.
- Pass to the Read parameter of PaUtil_InitializeStreamInterface.
- @return An error code indicating that the function has no effect
- because the stream is a callback stream.
-*/
-PaError PaUtil_DummyRead( PaStream* stream,
-                       void *buffer,
-                       unsigned long frames );
-
-
-/** Dummy Write function for use in an interfaces to callback based streams.
- Pass to the Write parameter of PaUtil_InitializeStreamInterface.
- @return An error code indicating that the function has no effect
- because the stream is a callback stream.
-*/
-PaError PaUtil_DummyWrite( PaStream* stream,
-                       const void *buffer,
-                       unsigned long frames );
-
-
-/** Dummy GetReadAvailable function for use in interfaces to callback based
- streams. Pass to the GetReadAvailable parameter of PaUtil_InitializeStreamInterface.
- @return An error code indicating that the function has no effect
- because the stream is a callback stream.
-*/
-signed long PaUtil_DummyGetReadAvailable( PaStream* stream );
-
-
-/** Dummy GetWriteAvailable function for use in interfaces to callback based
- streams. Pass to the GetWriteAvailable parameter of PaUtil_InitializeStreamInterface.
- @return An error code indicating that the function has no effect
- because the stream is a callback stream.
-*/
-signed long PaUtil_DummyGetWriteAvailable( PaStream* stream );
-
-
-
-/** Dummy GetCpuLoad function for use in an interface to a read/write stream.
- Pass to the GetCpuLoad parameter of PaUtil_InitializeStreamInterface.
- @return Returns 0.
-*/
-double PaUtil_DummyGetCpuLoad( PaStream* stream );
-
-
-/** Non host specific data for a stream. This data is used by pa_front to
- forward to the appropriate functions in the streamInterface structure.
-*/
-typedef struct PaUtilStreamRepresentation {
-    unsigned long magic;    /**< set to PA_STREAM_MAGIC */
-    struct PaUtilStreamRepresentation *nextOpenStream; /**< field used by multi-api code */
-    PaUtilStreamInterface *streamInterface;
-    PaStreamCallback *streamCallback;
-    PaStreamFinishedCallback *streamFinishedCallback;
-    void *userData;
-    PaStreamInfo streamInfo;
-} PaUtilStreamRepresentation;
-
-
-/** Initialize a PaUtilStreamRepresentation structure.
-
- @see PaUtil_InitializeStreamRepresentation
-*/
-void PaUtil_InitializeStreamRepresentation(
-        PaUtilStreamRepresentation *streamRepresentation,
-        PaUtilStreamInterface *streamInterface,
-        PaStreamCallback *streamCallback,
-        void *userData );
-        
-
-/** Clean up a PaUtilStreamRepresentation structure previously initialized
- by a call to PaUtil_InitializeStreamRepresentation.
-
- @see PaUtil_InitializeStreamRepresentation
-*/
-void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation );
-
-
-/** Check that the stream pointer is valid.
-
- @return Returns paNoError if the stream pointer appears to be OK, otherwise
- returns an error indicating the cause of failure.
-*/
-PaError PaUtil_ValidateStreamPointer( PaStream *stream );
-
-
-/** Cast an opaque stream pointer into a pointer to a PaUtilStreamRepresentation.
-
- @see PaUtilStreamRepresentation
-*/
-#define PA_STREAM_REP( stream )\
-    ((PaUtilStreamRepresentation*) (stream) )
-
-
-/** Cast an opaque stream pointer into a pointer to a PaUtilStreamInterface.
-
- @see PaUtilStreamRepresentation, PaUtilStreamInterface
-*/
-#define PA_STREAM_INTERFACE( stream )\
-    PA_STREAM_REP( (stream) )->streamInterface
-
-
-    
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_STREAM_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_STREAM_H

+#define PA_STREAM_H

+/*

+ * $Id: pa_stream.h,v 1.1.2.13 2003/11/01 06:37:28 rossbencina Exp $

+ * Portable Audio I/O Library

+ * stream interface

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+ @brief Interface used by pa_front to virtualize functions which operate on

+ streams.

+*/

+

+

+#include "portaudio.h"

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+#define PA_STREAM_MAGIC (0x18273645)

+

+

+/** A structure representing an (abstract) interface to a host API. Contains

+ pointers to functions which implement the interface.

+

+ All PaStreamInterface functions are guaranteed to be called with a non-null,

+ valid stream parameter.

+*/

+typedef struct {

+    PaError (*Close)( PaStream* stream );

+    PaError (*Start)( PaStream *stream );

+    PaError (*Stop)( PaStream *stream );

+    PaError (*Abort)( PaStream *stream );

+    PaError (*IsStopped)( PaStream *stream );

+    PaError (*IsActive)( PaStream *stream );

+    PaTime (*GetTime)( PaStream *stream );

+    double (*GetCpuLoad)( PaStream* stream );

+    PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames );

+    PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames );

+    signed long (*GetReadAvailable)( PaStream* stream );

+    signed long (*GetWriteAvailable)( PaStream* stream );

+} PaUtilStreamInterface;

+

+

+/** Initialize the fields of a PaUtilStreamInterface structure.

+*/

+void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,

+    PaError (*Close)( PaStream* ),

+    PaError (*Start)( PaStream* ),

+    PaError (*Stop)( PaStream* ),

+    PaError (*Abort)( PaStream* ),

+    PaError (*IsStopped)( PaStream* ),

+    PaError (*IsActive)( PaStream* ),

+    PaTime (*GetTime)( PaStream* ),

+    double (*GetCpuLoad)( PaStream* ),

+    PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ),

+    PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames ),

+    signed long (*GetReadAvailable)( PaStream* stream ),

+    signed long (*GetWriteAvailable)( PaStream* stream ) );

+

+

+/** Dummy Read function for use in interfaces to a callback based streams.

+ Pass to the Read parameter of PaUtil_InitializeStreamInterface.

+ @return An error code indicating that the function has no effect

+ because the stream is a callback stream.

+*/

+PaError PaUtil_DummyRead( PaStream* stream,

+                       void *buffer,

+                       unsigned long frames );

+

+

+/** Dummy Write function for use in an interfaces to callback based streams.

+ Pass to the Write parameter of PaUtil_InitializeStreamInterface.

+ @return An error code indicating that the function has no effect

+ because the stream is a callback stream.

+*/

+PaError PaUtil_DummyWrite( PaStream* stream,

+                       const void *buffer,

+                       unsigned long frames );

+

+

+/** Dummy GetReadAvailable function for use in interfaces to callback based

+ streams. Pass to the GetReadAvailable parameter of PaUtil_InitializeStreamInterface.

+ @return An error code indicating that the function has no effect

+ because the stream is a callback stream.

+*/

+signed long PaUtil_DummyGetReadAvailable( PaStream* stream );

+

+

+/** Dummy GetWriteAvailable function for use in interfaces to callback based

+ streams. Pass to the GetWriteAvailable parameter of PaUtil_InitializeStreamInterface.

+ @return An error code indicating that the function has no effect

+ because the stream is a callback stream.

+*/

+signed long PaUtil_DummyGetWriteAvailable( PaStream* stream );

+

+

+

+/** Dummy GetCpuLoad function for use in an interface to a read/write stream.

+ Pass to the GetCpuLoad parameter of PaUtil_InitializeStreamInterface.

+ @return Returns 0.

+*/

+double PaUtil_DummyGetCpuLoad( PaStream* stream );

+

+

+/** Non host specific data for a stream. This data is used by pa_front to

+ forward to the appropriate functions in the streamInterface structure.

+*/

+typedef struct PaUtilStreamRepresentation {

+    unsigned long magic;    /**< set to PA_STREAM_MAGIC */

+    struct PaUtilStreamRepresentation *nextOpenStream; /**< field used by multi-api code */

+    PaUtilStreamInterface *streamInterface;

+    PaStreamCallback *streamCallback;

+    PaStreamFinishedCallback *streamFinishedCallback;

+    void *userData;

+    PaStreamInfo streamInfo;

+} PaUtilStreamRepresentation;

+

+

+/** Initialize a PaUtilStreamRepresentation structure.

+

+ @see PaUtil_InitializeStreamRepresentation

+*/

+void PaUtil_InitializeStreamRepresentation(

+        PaUtilStreamRepresentation *streamRepresentation,

+        PaUtilStreamInterface *streamInterface,

+        PaStreamCallback *streamCallback,

+        void *userData );

+        

+

+/** Clean up a PaUtilStreamRepresentation structure previously initialized

+ by a call to PaUtil_InitializeStreamRepresentation.

+

+ @see PaUtil_InitializeStreamRepresentation

+*/

+void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation );

+

+

+/** Check that the stream pointer is valid.

+

+ @return Returns paNoError if the stream pointer appears to be OK, otherwise

+ returns an error indicating the cause of failure.

+*/

+PaError PaUtil_ValidateStreamPointer( PaStream *stream );

+

+

+/** Cast an opaque stream pointer into a pointer to a PaUtilStreamRepresentation.

+

+ @see PaUtilStreamRepresentation

+*/

+#define PA_STREAM_REP( stream )\

+    ((PaUtilStreamRepresentation*) (stream) )

+

+

+/** Cast an opaque stream pointer into a pointer to a PaUtilStreamInterface.

+

+ @see PaUtilStreamRepresentation, PaUtilStreamInterface

+*/

+#define PA_STREAM_INTERFACE( stream )\

+    PA_STREAM_REP( (stream) )->streamInterface

+

+

+    

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PA_STREAM_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_trace.c b/pjmedia/src/pjmedia/portaudio/pa_trace.c
index 83514a0..e980e24 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_trace.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_trace.c
@@ -1,88 +1,109 @@
-/*
- * $Id: pa_trace.c,v 1.1.1.1.2.3 2003/09/20 21:09:15 rossbencina Exp $
- * Portable Audio I/O Library Trace Facility
- * Store trace information in real-time for later printing.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Event trace mechanism for debugging.
-*/
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "pa_trace.h"
-
-#if PA_TRACE_REALTIME_EVENTS
-
-static char *traceTextArray[MAX_TRACE_RECORDS];
-static int traceIntArray[MAX_TRACE_RECORDS];
-static int traceIndex = 0;
-static int traceBlock = 0;
-
-/*********************************************************************/
-void PaUtil_ResetTraceMessages()
-{
-    traceIndex = 0;
-}
-
-/*********************************************************************/
-void PaUtil_DumpTraceMessages()
-{
-    int i;
-    int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS;
-
-    printf("DumpTraceMessages: traceIndex = %d\n", traceIndex );
-    for( i=0; i<messageCount; i++ )
-    {
-        printf("%3d: %s = 0x%08X\n",
-               i, traceTextArray[i], traceIntArray[i] );
-    }
-    ResetTraceMessages();
-    fflush(stdout);
-}
-
-/*********************************************************************/
-void PaUtil_AddTraceMessage( const char *msg, int data )
-{
-    if( (traceIndex == PA_MAX_TRACE_RECORDS) && (traceBlock == 0) )
-    {
-        traceBlock = 1;
-        /*  PaUtil_DumpTraceMessages(); */
-    }
-    else if( traceIndex < PA_MAX_TRACE_RECORDS )
-    {
-        traceTextArray[traceIndex] = msg;
-        traceIntArray[traceIndex] = data;
-        traceIndex++;
-    }
-}
-
-#endif /* TRACE_REALTIME_EVENTS */
+/*

+ * $Id: pa_trace.c,v 1.1.1.1.2.3 2003/09/20 21:09:15 rossbencina Exp $

+ * Portable Audio I/O Library Trace Facility

+ * Store trace information in real-time for later printing.

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2000 Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+ @brief Event trace mechanism for debugging.

+*/

+

+

+#include <stdio.h>

+#include <stdlib.h>

+#include <string.h>

+#include "pa_trace.h"

+

+#if PA_TRACE_REALTIME_EVENTS

+

+static char *traceTextArray[MAX_TRACE_RECORDS];

+static int traceIntArray[MAX_TRACE_RECORDS];

+static int traceIndex = 0;

+static int traceBlock = 0;

+

+/*********************************************************************/

+void PaUtil_ResetTraceMessages()

+{

+    traceIndex = 0;

+}

+

+/*********************************************************************/

+void PaUtil_DumpTraceMessages()

+{

+    int i;

+    int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS;

+

+    printf("DumpTraceMessages: traceIndex = %d\n", traceIndex );

+    for( i=0; i<messageCount; i++ )

+    {

+        printf("%3d: %s = 0x%08X\n",

+               i, traceTextArray[i], traceIntArray[i] );

+    }

+    ResetTraceMessages();

+    fflush(stdout);

+}

+

+/*********************************************************************/

+void PaUtil_AddTraceMessage( const char *msg, int data )

+{

+    if( (traceIndex == PA_MAX_TRACE_RECORDS) && (traceBlock == 0) )

+    {

+        traceBlock = 1;

+        /*  PaUtil_DumpTraceMessages(); */

+    }

+    else if( traceIndex < PA_MAX_TRACE_RECORDS )

+    {

+        traceTextArray[traceIndex] = msg;

+        traceIntArray[traceIndex] = data;

+        traceIndex++;

+    }

+}

+

+#endif /* TRACE_REALTIME_EVENTS */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_trace.h b/pjmedia/src/pjmedia/portaudio/pa_trace.h
index f72a78b..0ef6794 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_trace.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_trace.h
@@ -1,70 +1,91 @@
-#ifndef PA_TRACE_H
-#define PA_TRACE_H
-/*
- * $Id: pa_trace.h,v 1.1.1.1.2.3 2003/09/20 21:09:15 rossbencina Exp $
- * Portable Audio I/O Library Trace Facility
- * Store trace information in real-time for later printing.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief Event trace mechanism for debugging.
-
- Allows data to be written to the buffer at interrupt time and dumped later.
-*/
-
-
-#define PA_TRACE_REALTIME_EVENTS     (0)   /* Keep log of various real-time events. */
-#define PA_MAX_TRACE_RECORDS      (2048)
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-#if PA_TRACE_REALTIME_EVENTS
-
-void PaUtil_ResetTraceMessages();
-void PaUtil_AddTraceMessage( const char *msg, int data );
-void PaUtil_DumpTraceMessages();
-    
-#else
-
-#define PaUtil_ResetTraceMessages() /* noop */
-#define PaUtil_AddTraceMessage(msg,data) /* noop */
-#define PaUtil_DumpTraceMessages() /* noop */
-
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* PA_TRACE_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_TRACE_H

+#define PA_TRACE_H

+/*

+ * $Id: pa_trace.h,v 1.1.1.1.2.3 2003/09/20 21:09:15 rossbencina Exp $

+ * Portable Audio I/O Library Trace Facility

+ * Store trace information in real-time for later printing.

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2000 Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+ @brief Event trace mechanism for debugging.

+

+ Allows data to be written to the buffer at interrupt time and dumped later.

+*/

+

+

+#define PA_TRACE_REALTIME_EVENTS     (0)   /* Keep log of various real-time events. */

+#define PA_MAX_TRACE_RECORDS      (2048)

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+#if PA_TRACE_REALTIME_EVENTS

+

+void PaUtil_ResetTraceMessages();

+void PaUtil_AddTraceMessage( const char *msg, int data );

+void PaUtil_DumpTraceMessages();

+    

+#else

+

+#define PaUtil_ResetTraceMessages() /* noop */

+#define PaUtil_AddTraceMessage(msg,data) /* noop */

+#define PaUtil_DumpTraceMessages() /* noop */

+

+#endif

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+

+#endif /* PA_TRACE_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_types.h b/pjmedia/src/pjmedia/portaudio/pa_types.h
index 343dc8c..e8d924f 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_types.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_types.h
@@ -1,65 +1,86 @@
-#ifndef PA_TYPES_H
-#define PA_TYPES_H
-
-/*
-    SIZEOF_SHORT, SIZEOF_INT and SIZEOF_LONG are set by the configure script
-    when it is used. Otherwise we default to the common 32 bit values, if your
-    platform doesn't use configure, and doesn't use the default values below
-    you will need to explicitly define these symbols in your make file.
-
-    A PA_VALIDATE_SIZES macro is provided to assert that the values set in this
-    file are correct.
-*/
-
-#ifndef SIZEOF_SHORT
-#define SIZEOF_SHORT 2
-#endif
-
-#ifndef SIZEOF_INT
-#define SIZEOF_INT 4
-#endif
-
-#ifndef SIZEOF_LONG
-#define SIZEOF_LONG 4
-#endif
-
-
-#if SIZEOF_SHORT == 2
-typedef signed short PaInt16;
-typedef unsigned short PaUint16;
-#elif SIZEOF_INT == 2
-typedef signed int PaInt16;
-typedef unsigned int PaUint16;
-#else
-#error pa_types.h was unable to determine which type to use for 16bit integers on the target platform
-#endif
-
-#if SIZEOF_SHORT == 4
-typedef signed short PaInt32;
-typedef unsigned short PaUint32;
-#elif SIZEOF_INT == 4
-typedef signed int PaInt32;
-typedef unsigned int PaUint32;
-#elif SIZEOF_LONG == 4
-typedef signed long PaInt32;
-typedef unsigned long PaUint32;
-#else
-#error pa_types.h was unable to determine which type to use for 32bit integers on the target platform
-#endif
-
-
-/* PA_VALIDATE_TYPE_SIZES compares the size of the integer types at runtime to
- ensure that PortAudio was configured correctly, and raises an assertion if
- they don't match the expected values. <assert.h> must be included in the
- context in which this macro is used.
-*/
-#define PA_VALIDATE_TYPE_SIZES \
-    { \
-        assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint16 ) == 2 ); \
-        assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt16 ) == 2 ); \
-        assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint32 ) == 4 ); \
-        assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt32 ) == 4 ); \
-    }
-
-
-#endif /* PA_TYPES_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_TYPES_H

+#define PA_TYPES_H

+

+/*

+    SIZEOF_SHORT, SIZEOF_INT and SIZEOF_LONG are set by the configure script

+    when it is used. Otherwise we default to the common 32 bit values, if your

+    platform doesn't use configure, and doesn't use the default values below

+    you will need to explicitly define these symbols in your make file.

+

+    A PA_VALIDATE_SIZES macro is provided to assert that the values set in this

+    file are correct.

+*/

+

+#ifndef SIZEOF_SHORT

+#define SIZEOF_SHORT 2

+#endif

+

+#ifndef SIZEOF_INT

+#define SIZEOF_INT 4

+#endif

+

+#ifndef SIZEOF_LONG

+#define SIZEOF_LONG 4

+#endif

+

+

+#if SIZEOF_SHORT == 2

+typedef signed short PaInt16;

+typedef unsigned short PaUint16;

+#elif SIZEOF_INT == 2

+typedef signed int PaInt16;

+typedef unsigned int PaUint16;

+#else

+#error pa_types.h was unable to determine which type to use for 16bit integers on the target platform

+#endif

+

+#if SIZEOF_SHORT == 4

+typedef signed short PaInt32;

+typedef unsigned short PaUint32;

+#elif SIZEOF_INT == 4

+typedef signed int PaInt32;

+typedef unsigned int PaUint32;

+#elif SIZEOF_LONG == 4

+typedef signed long PaInt32;

+typedef unsigned long PaUint32;

+#else

+#error pa_types.h was unable to determine which type to use for 32bit integers on the target platform

+#endif

+

+

+/* PA_VALIDATE_TYPE_SIZES compares the size of the integer types at runtime to

+ ensure that PortAudio was configured correctly, and raises an assertion if

+ they don't match the expected values. <assert.h> must be included in the

+ context in which this macro is used.

+*/

+#define PA_VALIDATE_TYPE_SIZES \

+    { \

+        assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint16 ) == 2 ); \

+        assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt16 ) == 2 ); \

+        assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint32 ) == 4 ); \

+        assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt32 ) == 4 ); \

+    }

+

+

+#endif /* PA_TYPES_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_unix_hostapis.c b/pjmedia/src/pjmedia/portaudio/pa_unix_hostapis.c
index 9bddc2e..5817af1 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_unix_hostapis.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_unix_hostapis.c
@@ -1,64 +1,85 @@
-/*
- * $Id: pa_unix_hostapis.c,v 1.1.2.5 2003/10/02 12:35:46 pieter Exp $
- * Portable Audio I/O Library UNIX initialization table
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-
-#include "pa_hostapi.h"
-
-PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-/* Added for IRIX, Pieter, oct 2, 2003: */
-PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-
-PaUtilHostApiInitializer *paHostApiInitializers[] =
-    {
-#ifdef PA_USE_OSS
-        PaOSS_Initialize,
-#endif
-
-#ifdef PA_USE_ALSA
-        PaAlsa_Initialize,
-#endif
-
-#ifdef PA_USE_JACK
-        PaJack_Initialize,
-#endif
-                    /* Added for IRIX, Pieter, oct 2, 2003: */
-#ifdef PA_USE_SGI 
-        PaSGI_Initialize,
-#endif
-        0   /* NULL terminated array */
-    };
-
-int paDefaultHostApiIndex = 0;
-
-
+/*

+ * $Id: pa_unix_hostapis.c,v 1.1.2.5 2003/10/02 12:35:46 pieter Exp $

+ * Portable Audio I/O Library UNIX initialization table

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+

+#include "pa_hostapi.h"

+

+PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+/* Added for IRIX, Pieter, oct 2, 2003: */

+PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+

+

+PaUtilHostApiInitializer *paHostApiInitializers[] =

+    {

+#ifdef PA_USE_OSS

+        PaOSS_Initialize,

+#endif

+

+#ifdef PA_USE_ALSA

+        PaAlsa_Initialize,

+#endif

+

+#ifdef PA_USE_JACK

+        PaJack_Initialize,

+#endif

+                    /* Added for IRIX, Pieter, oct 2, 2003: */

+#ifdef PA_USE_SGI 

+        PaSGI_Initialize,

+#endif

+        0   /* NULL terminated array */

+    };

+

+int paDefaultHostApiIndex = 0;

+

+

diff --git a/pjmedia/src/pjmedia/portaudio/pa_unix_oss.c b/pjmedia/src/pjmedia/portaudio/pa_unix_oss.c
index 2490e68..6597657 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_unix_oss.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_unix_oss.c
@@ -1,1918 +1,1939 @@
-/*
- * $Id: pa_unix_oss.c,v 1.6.2.22 2005/03/08 21:26:53 aknudsen Exp $
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- * OSS implementation by:
- *   Douglas Repetto
- *   Phil Burk
- *   Dominic Mazzoni
- *   Arve Knudsen
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <alloca.h>
-#include <malloc.h>
-#include <assert.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/poll.h>
-#include <limits.h>
-#include <semaphore.h>
-
-#ifdef __linux__
-# include <linux/soundcard.h>
-# define DEVICE_NAME_BASE            "/dev/dsp"
-#else
-# include <machine/soundcard.h> /* JH20010905 */
-# define DEVICE_NAME_BASE            "/dev/audio"
-#endif
-
-#include "portaudio.h"
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-#include "pa_unix_util.h"
-
-static int sysErr_;
-static pthread_t mainThread_;
-
-/* Check return value of system call, and map it to PaError */
-#define ENSURE_(expr, code) \
-    do { \
-        if( UNLIKELY( (sysErr_ = (expr)) < 0 ) ) \
-        { \
-            /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
-            if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
-            { \
-                PaUtil_SetLastHostErrorInfo( paALSA, sysErr_, strerror( errno ) ); \
-            } \
-            \
-            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
-            result = (code); \
-            goto error; \
-        } \
-    } while( 0 );
-
-#ifndef AFMT_S16_NE
-#define AFMT_S16_NE  Get_AFMT_S16_NE()
-/*********************************************************************
- * Some versions of OSS do not define AFMT_S16_NE. So check CPU.
- * PowerPC is Big Endian. X86 is Little Endian.
- */
-static int Get_AFMT_S16_NE( void )
-{
-    long testData = 1; 
-    char *ptr = (char *) &testData;
-    int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */
-    return isLittle ? AFMT_S16_LE : AFMT_S16_BE;
-}
-#endif
-
-/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct
-{
-    PaUtilHostApiRepresentation inheritedHostApiRep;
-    PaUtilStreamInterface callbackStreamInterface;
-    PaUtilStreamInterface blockingStreamInterface;
-
-    PaUtilAllocationGroup *allocations;
-
-    PaHostApiIndex hostApiIndex;
-}
-PaOSSHostApiRepresentation;
-
-/** Per-direction structure for PaOssStream.
- *
- * Aspect StreamChannels: In case the user requests to open the same device for both capture and playback,
- * but with different number of channels we will have to adapt between the number of user and host
- * channels for at least one direction, since the configuration space is the same for both directions
- * of an OSS device.
- */
-typedef struct
-{
-    int fd;
-    const char *devName;
-    int userChannelCount, hostChannelCount;
-    int userInterleaved;
-    void *buffer;
-    PaSampleFormat userFormat, hostFormat;
-    double latency;
-    unsigned long hostFrames, numBufs;
-    void **userBuffers; /* For non-interleaved blocking */
-} PaOssStreamComponent;
-
-/** Implementation specific representation of a PaStream.
- *
- */
-typedef struct PaOssStream
-{
-    PaUtilStreamRepresentation streamRepresentation;
-    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
-    PaUtilBufferProcessor bufferProcessor;
-
-    PaUtilThreading threading;
-
-    int sharedDevice;
-    unsigned long framesPerHostBuffer;
-    int triggered;  /* Have the devices been triggered yet (first start) */
-
-    int isActive;
-    int isStopped;
-
-    int lastPosPtr;
-    double lastStreamBytes;
-
-    int framesProcessed;
-
-    double sampleRate;
-
-    int callbackMode;
-    int callbackStop, callbackAbort;
-
-    PaOssStreamComponent *capture, *playback;
-    unsigned long pollTimeout;
-    sem_t semaphore;
-}
-PaOssStream;
-
-typedef enum {
-    StreamMode_In,
-    StreamMode_Out
-} StreamMode;
-
-/* prototypes for functions declared in this file */
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** s,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *streamCallback,
-                           void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi );
-
-
-/** Initialize the OSS API implementation.
- *
- * This function will initialize host API datastructures and query host devices for information.
- *
- * Aspect DeviceCapabilities: Enumeration of host API devices is initiated from here
- *
- * Aspect FreeResources: If an error is encountered under way we have to free each resource allocated in this function,
- * this happens with the usual "error" label.
- */
-PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
-    PaError result = paNoError;
-    PaOSSHostApiRepresentation *ossHostApi = NULL;
-
-    PA_UNLESS( ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) ),
-            paInsufficientMemory );
-    PA_UNLESS( ossHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
-    ossHostApi->hostApiIndex = hostApiIndex;
-
-    /* Initialize host API structure */
-    *hostApi = &ossHostApi->inheritedHostApiRep;
-    (*hostApi)->info.structVersion = 1;
-    (*hostApi)->info.type = paOSS;
-    (*hostApi)->info.name = "OSS";
-    (*hostApi)->Terminate = Terminate;
-    (*hostApi)->OpenStream = OpenStream;
-    (*hostApi)->IsFormatSupported = IsFormatSupported;
-
-    PA_ENSURE( BuildDeviceList( ossHostApi ) );
-
-    PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, GetStreamCpuLoad,
-                                      PaUtil_DummyRead, PaUtil_DummyWrite,
-                                      PaUtil_DummyGetReadAvailable,
-                                      PaUtil_DummyGetWriteAvailable );
-
-    PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
-                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
-    mainThread_ = pthread_self();
-
-    return result;
-
-error:
-    if( ossHostApi )
-    {
-        if( ossHostApi->allocations )
-        {
-            PaUtil_FreeAllAllocations( ossHostApi->allocations );
-            PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
-        }
-                
-        PaUtil_FreeMemory( ossHostApi );
-    }
-    return result;
-}
-
-PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, PaHostApiIndex hostApiIndex, int maxInputChannels,
-        int maxOutputChannels, PaTime defaultLowInputLatency, PaTime defaultLowOutputLatency, PaTime defaultHighInputLatency,
-        PaTime defaultHighOutputLatency, double defaultSampleRate, PaUtilAllocationGroup *allocations  )
-{
-    PaError result = paNoError;
-    
-    deviceInfo->structVersion = 2;
-    if( allocations )
-    {
-        size_t len = strlen( name ) + 1;
-        PA_UNLESS( deviceInfo->name = PaUtil_GroupAllocateMemory( allocations, len ), paInsufficientMemory );
-        strncpy( (char *)deviceInfo->name, name, len );
-    }
-    else
-        deviceInfo->name = name;
-
-    deviceInfo->hostApi = hostApiIndex;
-    deviceInfo->maxInputChannels = maxInputChannels;
-    deviceInfo->maxOutputChannels = maxOutputChannels;
-    deviceInfo->defaultLowInputLatency = defaultLowInputLatency;
-    deviceInfo->defaultLowOutputLatency = defaultLowOutputLatency;
-    deviceInfo->defaultHighInputLatency = defaultHighInputLatency;
-    deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency;
-    deviceInfo->defaultSampleRate = defaultSampleRate;
-
-error:
-    return result;
-}
-
-static PaError QueryDirection( const char *deviceName, StreamMode mode, double *defaultSampleRate, int *maxChannelCount,
-        double *defaultLowLatency, double *defaultHighLatency )
-{
-    PaError result = paNoError;
-    int numChannels, maxNumChannels;
-    int busy = 0;
-    int devHandle = -1;
-    int sr;
-    *maxChannelCount = 0;  /* Default value in case this fails */
-
-    if ( (devHandle = open( deviceName, (mode == StreamMode_In ? O_RDONLY : O_WRONLY) | O_NONBLOCK ))  < 0 )
-    {
-        if( errno == EBUSY || errno == EAGAIN )
-        {
-            PA_DEBUG(( "%s: Device %s busy\n", __FUNCTION__, deviceName ));
-        }
-        else
-        {
-            PA_DEBUG(( "%s: Can't access device: %s\n", __FUNCTION__, strerror( errno ) ));
-        }
-
-        return paDeviceUnavailable;
-    }
-
-    /* Negotiate for the maximum number of channels for this device. PLB20010927
-     * Consider up to 16 as the upper number of channels.
-     * Variable maxNumChannels should contain the actual upper limit after the call.
-     * Thanks to John Lazzaro and Heiko Purnhagen for suggestions.
-     */
-    maxNumChannels = 0;
-    for( numChannels = 1; numChannels <= 16; numChannels++ )
-    {
-        int temp = numChannels;
-        if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 )
-        {
-            busy = EAGAIN == errno || EBUSY == errno;
-            /* ioctl() failed so bail out if we already have stereo */
-            if( maxNumChannels >= 2 )
-                break;
-        }
-        else
-        {
-            /* ioctl() worked but bail out if it does not support numChannels.
-             * We don't want to leave gaps in the numChannels supported.
-             */
-            if( (numChannels > 2) && (temp != numChannels) )
-                break;
-            if( temp > maxNumChannels )
-                maxNumChannels = temp; /* Save maximum. */
-        }
-    }
-    /* A: We're able to open a device for capture if it's busy playing back and vice versa,
-     * but we can't configure anything */
-    if( 0 == maxNumChannels && busy )
-    {
-        result = paDeviceUnavailable;
-        goto error;
-    }
-
-    /* The above negotiation may fail for an old driver so try this older technique. */
-    if( maxNumChannels < 1 )
-    {
-        int stereo = 1;
-        if( ioctl( devHandle, SNDCTL_DSP_STEREO, &stereo ) < 0 )
-        {
-            maxNumChannels = 1;
-        }
-        else
-        {
-            maxNumChannels = (stereo) ? 2 : 1;
-        }
-        PA_DEBUG(( "%s: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", __FUNCTION__, maxNumChannels ))
-    }
-
-    /* During channel negotiation, the last ioctl() may have failed. This can
-     * also cause sample rate negotiation to fail. Hence the following, to return
-     * to a supported number of channels. SG20011005 */
-    {
-        /* use most reasonable default value */
-        int temp = PA_MIN( maxNumChannels, 2 );
-        ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ), paUnanticipatedHostError );
-    }
-
-    /* Get supported sample rate closest to 44100 Hz */
-    if( *defaultSampleRate < 0 )
-    {
-        sr = 44100;
-        if( ioctl( devHandle, SNDCTL_DSP_SPEED, &sr ) < 0 )
-        {
-            result = paUnanticipatedHostError;
-            goto error;
-        }
-
-        *defaultSampleRate = sr;
-    }
-
-    *maxChannelCount = maxNumChannels;
-    /* TODO */
-    *defaultLowLatency = 512. / *defaultSampleRate;
-    *defaultHighLatency = 2048. / *defaultSampleRate;
-
-error:
-    if( devHandle >= 0 )
-        close( devHandle );
-
-    return result;
-}
-
-/** Query OSS device.
- *
- * This is where PaDeviceInfo objects are constructed and filled in with relevant information.
- *
- * Aspect DeviceCapabilities: The inferred device capabilities are recorded in a PaDeviceInfo object that is constructed
- * in place.
- */
-static PaError QueryDevice( char *deviceName, PaOSSHostApiRepresentation *ossApi, PaDeviceInfo **deviceInfo )
-{
-    PaError result = paNoError;
-    double sampleRate = -1.;
-    int maxInputChannels, maxOutputChannels;
-    PaTime defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency;
-    PaError tmpRes = paNoError;
-    int busy = 0;
-    *deviceInfo = NULL;
-
-    /* douglas:
-       we have to do this querying in a slightly different order. apparently
-       some sound cards will give you different info based on their settins. 
-       e.g. a card might give you stereo at 22kHz but only mono at 44kHz.
-       the correct order for OSS is: format, channels, sample rate
-    */
-
-    /* Aspect StreamChannels: The number of channels supported for a device may depend on the mode it is
-     * opened in, it may have more channels available for capture than playback and vice versa. Therefore
-     * we will open the device in both read- and write-only mode to determine the supported number.
-     */
-    if( (tmpRes = QueryDirection( deviceName, StreamMode_In, &sampleRate, &maxInputChannels, &defaultLowInputLatency,
-                &defaultHighInputLatency )) != paNoError )
-    {
-        if( tmpRes != paDeviceUnavailable )
-        {
-            PA_DEBUG(( "%s: Querying device %s for capture failed!\n", __FUNCTION__, deviceName ));
-            /* PA_ENSURE( tmpRes ); */
-        }
-        ++busy;
-    }
-    if( (tmpRes = QueryDirection( deviceName, StreamMode_Out, &sampleRate, &maxOutputChannels, &defaultLowOutputLatency,
-                &defaultHighOutputLatency )) != paNoError )
-    {
-        if( tmpRes != paDeviceUnavailable )
-        {
-            PA_DEBUG(( "%s: Querying device %s for playback failed!\n", __FUNCTION__, deviceName ));
-            /* PA_ENSURE( tmpRes ); */
-        }
-        ++busy;
-    }
-    assert( 0 <= busy && busy <= 2 );
-    if( 2 == busy )     /* Both directions are unavailable to us */
-    {
-        result = paDeviceUnavailable;
-        goto error;
-    }
-
-    PA_UNLESS( *deviceInfo = PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof (PaDeviceInfo) ), paInsufficientMemory );
-    PA_ENSURE( PaUtil_InitializeDeviceInfo( *deviceInfo, deviceName, ossApi->hostApiIndex, maxInputChannels, maxOutputChannels,
-                defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency, sampleRate,
-                ossApi->allocations ) );
-
-error:
-    return result;
-}
-
-/** Query host devices.
- *
- * Loop over host devices and query their capabilitiesu
- *
- * Aspect DeviceCapabilities: This function calls QueryDevice on each device entry and receives a filled in PaDeviceInfo object
- * per device, these are placed in the host api representation's deviceInfos array.
- */
-static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi )
-{
-    PaError result = paNoError;
-    PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;
-    int i;
-    int numDevices = 0, maxDeviceInfos = 1;
-    PaDeviceInfo **deviceInfos = NULL;
-
-    /* These two will be set to the first working input and output device, respectively */
-    commonApi->info.defaultInputDevice = paNoDevice;
-    commonApi->info.defaultOutputDevice = paNoDevice;
-
-    /* Find devices by calling QueryDevice on each
-     * potential device names.  When we find a valid one,
-     * add it to a linked list.
-     * A: Can there only be 10 devices? */
-
-    for( i = 0; i < 10; i++ )
-    {
-       char deviceName[32];
-       PaDeviceInfo *deviceInfo;
-       int testResult;
-       struct stat stbuf;
-
-       if( i == 0 )
-          snprintf(deviceName, sizeof (deviceName), "%s", DEVICE_NAME_BASE);
-       else
-          snprintf(deviceName, sizeof (deviceName), "%s%d", DEVICE_NAME_BASE, i);
-
-       /* PA_DEBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName )); */
-       if( stat( deviceName, &stbuf ) < 0 )
-       {
-           if( ENOENT != errno )
-               PA_DEBUG(( "%s: Error stat'ing %s: %s\n", __FUNCTION__, deviceName, strerror( errno ) ));
-           continue;
-       }
-       if( (testResult = QueryDevice( deviceName, ossApi, &deviceInfo )) != paNoError )
-       {
-           if( testResult != paDeviceUnavailable )
-               PA_ENSURE( testResult );
-
-           continue;
-       }
-
-       ++numDevices;
-       if( !deviceInfos || numDevices > maxDeviceInfos )
-       {
-           maxDeviceInfos *= 2;
-           PA_UNLESS( deviceInfos = (PaDeviceInfo **) realloc( deviceInfos, maxDeviceInfos * sizeof (PaDeviceInfo *) ),
-                   paInsufficientMemory );
-       }
-       deviceInfos[numDevices - 1] = deviceInfo;
-
-       if( commonApi->info.defaultInputDevice == paNoDevice && deviceInfo->maxInputChannels > 0 )
-           commonApi->info.defaultInputDevice = i;
-       if( commonApi->info.defaultOutputDevice == paNoDevice && deviceInfo->maxOutputChannels > 0 )
-           commonApi->info.defaultOutputDevice = i;
-    }
-
-    /* Make an array of PaDeviceInfo pointers out of the linked list */
-
-    PA_DEBUG(("PaOSS %s: Total number of devices found: %d\n", __FUNCTION__, numDevices));
-
-    commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
-        ossApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
-    memcpy( commonApi->deviceInfos, deviceInfos, numDevices * sizeof (PaDeviceInfo *) );
-
-    commonApi->info.deviceCount = numDevices;
-
-error:
-    free( deviceInfos );
-
-    return result;
-}
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
-    PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
-
-    if( ossHostApi->allocations )
-    {
-        PaUtil_FreeAllAllocations( ossHostApi->allocations );
-        PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
-    }
-
-    PaUtil_FreeMemory( ossHostApi );
-}
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate )
-{
-    PaError result = paNoError;
-    PaDeviceIndex device;
-    PaDeviceInfo *deviceInfo;
-    char *deviceName;
-    int inputChannelCount, outputChannelCount;
-    int tempDevHandle = -1;
-    int flags;
-    PaSampleFormat inputSampleFormat, outputSampleFormat;
-    
-    if( inputParameters )
-    {
-        inputChannelCount = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-
-        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that input device can support inputChannelCount */
-        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
-            return paInvalidChannelCount;
-
-        /* validate inputStreamInfo */
-        if( inputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-    }
-    else
-    {
-        inputChannelCount = 0;
-    }
-
-    if( outputParameters )
-    {
-        outputChannelCount = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-        
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-
-        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that output device can support inputChannelCount */
-        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
-            return paInvalidChannelCount;
-
-        /* validate outputStreamInfo */
-        if( outputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-    }
-    else
-    {
-        outputChannelCount = 0;
-    }
-
-    if (inputChannelCount == 0 && outputChannelCount == 0)
-        return paInvalidChannelCount;
-
-    /* if full duplex, make sure that they're the same device */
-
-    if (inputChannelCount > 0 && outputChannelCount > 0 &&
-        inputParameters->device != outputParameters->device)
-        return paInvalidDevice;
-
-    /* if full duplex, also make sure that they're the same number of channels */
-
-    if (inputChannelCount > 0 && outputChannelCount > 0 &&
-        inputChannelCount != outputChannelCount)
-       return paInvalidChannelCount;
-
-    /* open the device so we can do more tests */
-    
-    if( inputChannelCount > 0 )
-    {
-        result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);
-        if (result != paNoError)
-            return result;
-    }
-    else
-    {
-        result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);
-        if (result != paNoError)
-            return result;
-    }
-
-    deviceInfo = hostApi->deviceInfos[device];
-    deviceName = (char *)deviceInfo->name;
-    
-    flags = O_NONBLOCK;
-    if (inputChannelCount > 0 && outputChannelCount > 0)
-       flags |= O_RDWR;
-    else if (inputChannelCount > 0)
-       flags |= O_RDONLY;
-    else
-       flags |= O_WRONLY;
-
-    ENSURE_( tempDevHandle = open( deviceInfo->name, flags ), paDeviceUnavailable );
-
-    /* PaOssStream_Configure will do the rest of the checking for us */
-    /* PA_ENSURE( PaOssStream_Configure( tempDevHandle, deviceName, outputChannelCount, &sampleRate ) ); */
-
-    /* everything succeeded! */
-
- error:
-    if( tempDevHandle >= 0 )
-        close( tempDevHandle );         
-
-    return result;
-}
-
-/** Validate stream parameters.
- *
- * Aspect StreamChannels: We verify that the number of channels is within the allowed range for the device
- */
-static PaError ValidateParameters( const PaStreamParameters *parameters, const PaDeviceInfo *deviceInfo, StreamMode mode )
-{
-    int maxChans;
-
-    assert( parameters );
-
-    if( parameters->device == paUseHostApiSpecificDeviceSpecification )
-    {
-        return paInvalidDevice;
-    }
-
-    maxChans = (mode == StreamMode_In ? deviceInfo->maxInputChannels :
-        deviceInfo->maxOutputChannels);
-    if( parameters->channelCount > maxChans )
-    {
-        return paInvalidChannelCount;
-    }
-
-    return paNoError;
-}
-
-static PaError PaOssStreamComponent_Initialize( PaOssStreamComponent *component, const PaStreamParameters *parameters,
-        int callbackMode, int fd, const char *deviceName )
-{
-    PaError result = paNoError;
-    assert( component );
-
-    memset( component, 0, sizeof (PaOssStreamComponent) );
-
-    component->fd = fd;
-    component->devName = deviceName;
-    component->userChannelCount = parameters->channelCount;
-    component->userFormat = parameters->sampleFormat;
-    component->latency = parameters->suggestedLatency;
-    component->userInterleaved = !(parameters->sampleFormat & paNonInterleaved);
-
-    if( !callbackMode && !component->userInterleaved )
-    {
-        /* Pre-allocate non-interleaved user provided buffers */
-        PA_UNLESS( component->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * component->userChannelCount ),
-                paInsufficientMemory );
-    }
-
-error:
-    return result;
-}
-
-static void PaOssStreamComponent_Terminate( PaOssStreamComponent *component )
-{
-    assert( component );
-
-    if( component->fd >= 0 )
-        close( component->fd );
-    if( component->buffer )
-        PaUtil_FreeMemory( component->buffer );
-
-    if( component->userBuffers )
-        PaUtil_FreeMemory( component->userBuffers );
-
-    PaUtil_FreeMemory( component );
-}
-
-static PaError ModifyBlocking( int fd, int blocking )
-{
-    PaError result = paNoError;
-    int fflags;
-
-    ENSURE_( fflags = fcntl( fd, F_GETFL ), paUnanticipatedHostError );
-
-    if( blocking )
-        fflags &= ~O_NONBLOCK;
-    else
-        fflags |= O_NONBLOCK;
-
-    ENSURE_( fcntl( fd, F_SETFL, fflags ), paUnanticipatedHostError );
-
-error:
-    return result;
-}
-
-static PaError OpenDevices( const char *idevName, const char *odevName, int *idev, int *odev )
-{
-    PaError result = paNoError;
-    int flags = O_NONBLOCK, duplex = 0;
-    int enableBits = 0;
-    *idev = *odev = -1;
-
-    if( idevName && odevName )
-    {
-        duplex = 1;
-        flags |= O_RDWR;
-    }
-    else if( idevName )
-        flags |= O_RDONLY;
-    else
-        flags |= O_WRONLY;
-
-    /* open first in nonblocking mode, in case it's busy...
-     * A: then unset the non-blocking attribute */
-    assert( flags & O_NONBLOCK );
-    if( idevName )
-    {
-        ENSURE_( *idev = open( idevName, flags ), paDeviceUnavailable );
-        PA_ENSURE( ModifyBlocking( *idev, 1 ) ); /* Blocking */
-
-        /* Initially disable */
-        enableBits = ~PCM_ENABLE_INPUT;
-        ENSURE_( ioctl( *idev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
-    }
-    if( odevName )
-    {
-        if( !idevName )
-        {
-            ENSURE_( *odev = open( odevName, flags ), paDeviceUnavailable );
-            PA_ENSURE( ModifyBlocking( *odev, 1 ) ); /* Blocking */
-
-            /* Initially disable */
-            enableBits = ~PCM_ENABLE_OUTPUT;
-            ENSURE_( ioctl( *odev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
-        }
-        else
-        {
-            ENSURE_( *odev = dup( *idev ), paUnanticipatedHostError );
-        }
-    }
-
-error:
-    return result;
-}
-
-static PaError PaOssStream_Initialize( PaOssStream *stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters,
-        PaStreamCallback callback, void *userData, PaStreamFlags streamFlags,
-        PaOSSHostApiRepresentation *ossApi )
-{
-    PaError result = paNoError;
-    int idev, odev;
-    PaUtilHostApiRepresentation *hostApi = &ossApi->inheritedHostApiRep;
-    const char *idevName = NULL, *odevName = NULL;
-
-    assert( stream );
-
-    memset( stream, 0, sizeof (PaOssStream) );
-    stream->isStopped = 1;
-
-    PA_ENSURE( PaUtil_InitializeThreading( &stream->threading ) );
-
-    if( inputParameters && outputParameters )
-    {
-        if( inputParameters->device == outputParameters->device )
-            stream->sharedDevice = 1;
-    }
-
-    if( inputParameters )
-        idevName = hostApi->deviceInfos[inputParameters->device]->name;
-    if( outputParameters )
-        odevName = hostApi->deviceInfos[outputParameters->device]->name;
-    PA_ENSURE( OpenDevices( idevName, odevName, &idev, &odev ) );
-    if( inputParameters )
-    {
-        PA_UNLESS( stream->capture = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
-        PA_ENSURE( PaOssStreamComponent_Initialize( stream->capture, inputParameters, callback != NULL, idev, idevName ) );
-    }
-    if( outputParameters )
-    {
-        PA_UNLESS( stream->playback = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
-        PA_ENSURE( PaOssStreamComponent_Initialize( stream->playback, outputParameters, callback != NULL, odev, odevName ) );
-    }
-
-    if( callback != NULL )
-    {
-        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
-                                               &ossApi->callbackStreamInterface, callback, userData );
-        stream->callbackMode = 1;
-    }
-    else
-    {
-        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
-                                               &ossApi->blockingStreamInterface, callback, userData );
-    }    
-
-    ENSURE_( sem_init( &stream->semaphore, 0, 0 ), paInternalError );
-
-error:
-    return result;
-}
-
-static void PaOssStream_Terminate( PaOssStream *stream )
-{
-    assert( stream );
-
-    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-    PaUtil_TerminateThreading( &stream->threading );
-
-    if( stream->capture )
-        PaOssStreamComponent_Terminate( stream->capture );
-    if( stream->playback )
-        PaOssStreamComponent_Terminate( stream->playback );
-
-    sem_destroy( &stream->semaphore );
-
-    PaUtil_FreeMemory( stream );
-}
-
-/** Translate from PA format to OSS native.
- *
- */
-static PaError Pa2OssFormat( PaSampleFormat paFormat, int *ossFormat )
-{
-    switch( paFormat )
-    {
-        case paUInt8:
-            *ossFormat = AFMT_U8;
-            break;
-        case paInt8:
-            *ossFormat = AFMT_S8;
-            break;
-        case paInt16:
-            *ossFormat = AFMT_S16_NE;
-            break;
-        default:
-            return paInternalError;     /* This shouldn't happen */
-    }
-
-    return paNoError;
-}
-
-/** Return the PA-compatible formats that this device can support.
- *
- */
-static PaError GetAvailableFormats( PaOssStreamComponent *component, PaSampleFormat *availableFormats )
-{
-    PaError result = paNoError;
-    int mask = 0;
-    PaSampleFormat frmts = 0;
-
-    ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETFMTS, &mask ), paUnanticipatedHostError );
-    if( mask & AFMT_U8 )
-        frmts |= paUInt8;
-    if( mask & AFMT_S8 )
-        frmts |= paInt8;
-    if( mask & AFMT_S16_NE )
-        frmts |= paInt16;
-    else
-        result = paSampleFormatNotSupported;
-    
-    *availableFormats = frmts;
-
-error:
-    return result;
-}
-
-static unsigned int PaOssStreamComponent_FrameSize( PaOssStreamComponent *component )
-{
-    return Pa_GetSampleSize( component->hostFormat ) * component->hostChannelCount;
-}
-
-/** Buffer size in bytes.
- *
- */
-static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *component )
-{
-    return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs;
-}
-
-static int CalcHigherLogTwo( int n )
-{
-    int log2 = 0;
-    while( (1<<log2) < n ) log2++;
-    return log2;
-}
-
-static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long framesPerBuffer,
-        StreamMode streamMode, PaOssStreamComponent *master )
-{
-    PaError result = paNoError;
-    int temp, nativeFormat;
-    int sr = (int)sampleRate;
-    PaSampleFormat availableFormats, hostFormat;
-    int chans = component->userChannelCount;
-    int frgmt;
-    int numBufs;
-    int bytesPerBuf;
-    double bufSz;
-    unsigned long fragSz;
-    audio_buf_info bufInfo;
-
-    /* We may have a situation where only one component (the master) is configured, if both point to the same device.
-     * In that case, the second component will copy settings from the other */
-    if( !master )
-    {
-        /* Aspect BufferSettings: If framesPerBuffer is unspecified we have to infer a suitable fragment size.
-         * The hardware need not respect the requested fragment size, so we may have to adapt.
-         */
-        if( framesPerBuffer == paFramesPerBufferUnspecified )
-        { 
-            bufSz = component->latency * sampleRate;
-            fragSz = bufSz / 4;
-        }
-        else
-        {
-            fragSz = framesPerBuffer;
-            bufSz = component->latency * sampleRate + fragSz; /* Latency + 1 buffer */
-        }
-
-        PA_ENSURE( GetAvailableFormats( component, &availableFormats ) );
-        hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, component->userFormat );
-
-        /* OSS demands at least 2 buffers, and 16 bytes per buffer */
-        numBufs = PA_MAX( bufSz / fragSz, 2 );
-        bytesPerBuf = PA_MAX( fragSz * Pa_GetSampleSize( hostFormat ) * chans, 16 );
-
-        /* The fragment parameters are encoded like this:
-         * Most significant byte: number of fragments
-         * Least significant byte: exponent of fragment size (i.e., for 256, 8)
-         */
-        frgmt = (numBufs << 16) + (CalcHigherLogTwo( bytesPerBuf ) & 0xffff);
-        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError );
-
-        /* A: according to the OSS programmer's guide parameters should be set in this order:
-         * format, channels, rate */
-
-        /* This format should be deemed good before we get this far */
-        PA_ENSURE( Pa2OssFormat( hostFormat, &temp ) );
-        nativeFormat = temp;
-        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFMT, &temp ), paUnanticipatedHostError );
-        PA_UNLESS( temp == nativeFormat, paInternalError );
-
-        /* try to set the number of channels */
-        ENSURE_( ioctl( component->fd, SNDCTL_DSP_CHANNELS, &chans ), paSampleFormatNotSupported );   /* XXX: Should be paInvalidChannelCount? */
-        /* It's possible that the minimum number of host channels is greater than what the user requested */
-        PA_UNLESS( chans >= component->userChannelCount, paInvalidChannelCount );
-
-        /* try to set the sample rate */
-        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SPEED, &sr ), paInvalidSampleRate );
-
-        /* reject if there's no sample rate within 1% of the one requested */
-        if( (fabs( sampleRate - sr ) / sampleRate) > 0.01 )
-        {
-            PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));                 
-            PA_ENSURE( paInvalidSampleRate );
-        }
-
-        ENSURE_( ioctl( component->fd, streamMode == StreamMode_In ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &bufInfo ),
-                paUnanticipatedHostError );
-        component->numBufs = bufInfo.fragstotal;
-
-        /* This needs to be the last ioctl call before the first read/write, according to the OSS programmer's guide */
-        ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETBLKSIZE, &bytesPerBuf ), paUnanticipatedHostError );
-
-        component->hostFrames = bytesPerBuf / Pa_GetSampleSize( hostFormat ) / chans;
-        component->hostChannelCount = chans;
-        component->hostFormat = hostFormat;
-    }
-    else
-    {
-        component->hostFormat = master->hostFormat;
-        component->hostFrames = master->hostFrames;
-        component->hostChannelCount = master->hostChannelCount;
-        component->numBufs = master->numBufs;
-    }
-
-    PA_UNLESS( component->buffer = PaUtil_AllocateMemory( PaOssStreamComponent_BufferSize( component ) ),
-            paInsufficientMemory );
-
-error:
-    return result;
-}
-
-static PaError PaOssStreamComponent_Read( PaOssStreamComponent *component, unsigned long *frames )
-{
-    PaError result = paNoError;
-    size_t len = *frames * PaOssStreamComponent_FrameSize( component );
-    ssize_t bytesRead;
-
-    ENSURE_( bytesRead = read( component->fd, component->buffer, len ), paUnanticipatedHostError );
-    *frames = bytesRead / PaOssStreamComponent_FrameSize( component );
-
-error:
-    return result;
-}
-
-static PaError PaOssStreamComponent_Write( PaOssStreamComponent *component, unsigned long *frames )
-{
-    PaError result = paNoError;
-    size_t len = *frames * PaOssStreamComponent_FrameSize( component );
-    ssize_t bytesWritten;
-
-    ENSURE_( bytesWritten = write( component->fd, component->buffer, len ), paUnanticipatedHostError );
-    *frames = bytesWritten / PaOssStreamComponent_FrameSize( component );
-
-error:
-    return result;
-}
-
-/** Configure the stream according to input/output parameters.
- *
- * Aspect StreamChannels: The minimum number of channels supported by the device may exceed that requested by
- * the user, if so we'll record the actual number of host channels and adapt later.
- */
-static PaError PaOssStream_Configure( PaOssStream *stream, double sampleRate, unsigned long framesPerBuffer,
-        double *inputLatency, double *outputLatency )
-{
-    PaError result = paNoError;
-    int duplex = stream->capture && stream->playback;
-    unsigned long framesPerHostBuffer = 0;
-
-    /* We should request full duplex first thing after opening the device */
-    if( duplex && stream->sharedDevice )
-        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETDUPLEX, 0 ), paUnanticipatedHostError );
-
-    if( stream->capture )
-    {
-        PaOssStreamComponent *component = stream->capture;
-        PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_In, NULL );
-
-        assert( component->hostChannelCount > 0 );
-        assert( component->hostFrames > 0 );
-
-        *inputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate;
-    }
-    if( stream->playback )
-    {
-        PaOssStreamComponent *component = stream->playback, *master = stream->sharedDevice ? stream->capture : NULL;
-        PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_Out,
-                    master ) );
-
-        assert( component->hostChannelCount > 0 );
-        assert( component->hostFrames > 0 );
-
-        *outputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate;
-    }
-
-    if( duplex )
-        framesPerHostBuffer = PA_MIN( stream->capture->hostFrames, stream->playback->hostFrames );
-    else if( stream->capture )
-        framesPerHostBuffer = stream->capture->hostFrames;
-    else if( stream->playback )
-        framesPerHostBuffer = stream->playback->hostFrames;
-
-    stream->framesPerHostBuffer = framesPerHostBuffer;
-    stream->pollTimeout = (int) ceil( 1e6 * framesPerHostBuffer / sampleRate );    /* Period in usecs, rounded up */
-
-    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
-error:
-    return result;
-}
-
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-
-/** Open a PA OSS stream.
- *
- * Aspect StreamChannels: The number of channels is specified per direction (in/out), and can differ between the
- * two. However, OSS doesn't support separate configuration spaces for capture and playback so if both
- * directions are the same device we will demand the same number of channels. The number of channels can range
- * from 1 to the maximum supported by the device.
- *
- * Aspect BufferSettings: If framesPerBuffer != paFramesPerBufferUnspecified the number of frames per callback
- * must reflect this, in addition the host latency per device should approximate the corresponding
- * suggestedLatency. Based on these constraints we need to determine a number of frames per host buffer that
- * both capture and playback can agree on (they can be different devices), the buffer processor can adapt
- * between host and user buffer size, but the ratio should preferably be integral.
- */
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** s,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *streamCallback,
-                           void *userData )
-{
-    PaError result = paNoError;
-    PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
-    PaOssStream *stream = NULL;
-    int inputChannelCount = 0, outputChannelCount = 0;
-    PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0, inputHostFormat = 0, outputHostFormat = 0;
-    const PaDeviceInfo *inputDeviceInfo = 0, *outputDeviceInfo = 0;
-    int bpInitialized = 0;
-    double inLatency, outLatency;
-
-    /* validate platform specific flags */
-    if( (streamFlags & paPlatformSpecificFlags) != 0 )
-        return paInvalidFlag; /* unexpected platform specific flag */
-
-    if( inputParameters )
-    {
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-        inputDeviceInfo = hostApi->deviceInfos[inputParameters->device];
-        PA_ENSURE( ValidateParameters( inputParameters, inputDeviceInfo, StreamMode_In ) );
-
-        inputChannelCount = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-    }
-    if( outputParameters )
-    {
-        outputDeviceInfo = hostApi->deviceInfos[outputParameters->device];
-        PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo, StreamMode_Out ) );
-
-        outputChannelCount = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-    }
-
-    /* Aspect StreamChannels: We currently demand that number of input and output channels are the same, if the same
-     * device is opened for both directions
-     */
-    if( inputChannelCount > 0 && outputChannelCount > 0 )
-    {
-        if( inputParameters->device == outputParameters->device )
-        {
-            if( inputParameters->channelCount != outputParameters->channelCount )
-                return paInvalidChannelCount;
-        }
-    }
-    
-    /* allocate and do basic initialization of the stream structure */
-    PA_UNLESS( stream = (PaOssStream*)PaUtil_AllocateMemory( sizeof(PaOssStream) ), paInsufficientMemory );
-    PaOssStream_Initialize( stream, inputParameters, outputParameters, streamCallback, userData, streamFlags, ossHostApi );
-
-    PA_ENSURE( PaOssStream_Configure( stream, sampleRate, framesPerBuffer, &inLatency, &outLatency ) );
-
-    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-        
-    if( inputParameters )
-    {
-        inputHostFormat = stream->capture->hostFormat;
-        stream->streamRepresentation.streamInfo.inputLatency = inLatency +
-            PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ) / sampleRate;
-    }
-    if( outputParameters )
-    {
-        outputHostFormat = stream->playback->hostFormat;
-        stream->streamRepresentation.streamInfo.outputLatency = outLatency +
-            PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ) / sampleRate;
-    }
-
-    /* Initialize buffer processor with fixed host buffer size.
-     * Aspect StreamSampleFormat: Here we commit the user and host sample formats, PA infrastructure will
-     * convert between the two.
-     */
-    PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
-              inputChannelCount, inputSampleFormat, inputHostFormat, outputChannelCount, outputSampleFormat,
-              outputHostFormat, sampleRate, streamFlags, framesPerBuffer, stream->framesPerHostBuffer,
-              paUtilFixedHostBufferSize, streamCallback, userData ) );
-    bpInitialized = 1;
-
-    *s = (PaStream*)stream;
-
-    return result;
-
-error:
-    if( bpInitialized )
-        PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
-    if( stream )
-        PaOssStream_Terminate( stream );
-
-    return result;
-}
-
-/*! Poll on I/O filedescriptors.
-
-  Poll till we've determined there's data for read or write. In the full-duplex case,
-  we don't want to hang around forever waiting for either input or output frames, so
-  whenever we have a timed out filedescriptor we check if we're nearing under/overrun
-  for the other direction (critical limit set at one buffer). If so, we exit the waiting
-  state, and go on with what we got. We align the number of frames on a host buffer
-  boundary because it is possible that the buffer size differs for the two directions and
-  the host buffer size is a compromise between the two.
-  */
-static PaError PaOssStream_WaitForFrames( PaOssStream *stream, unsigned long *frames )
-{
-    PaError result = paNoError;
-    int pollPlayback = 0, pollCapture = 0;
-    int captureAvail = INT_MAX, playbackAvail = INT_MAX, commonAvail;
-    audio_buf_info bufInfo;
-    /* int ofs = 0, nfds = stream->nfds; */
-    fd_set readFds, writeFds;
-    int nfds = 0;
-    struct timeval selectTimeval = {0, 0};
-    unsigned long timeout = stream->pollTimeout;    /* In usecs */
-    int captureFd = -1, playbackFd = -1;
-
-    assert( stream );
-    assert( frames );
-
-    if( stream->capture )
-    {
-        pollCapture = 1;
-        captureFd = stream->capture->fd;
-        /* stream->capture->pfd->events = POLLIN; */
-    }
-    if( stream->playback )
-    {
-        pollPlayback = 1;
-        playbackFd = stream->playback->fd;
-        /* stream->playback->pfd->events = POLLOUT; */
-    }
-
-    FD_ZERO( &readFds );
-    FD_ZERO( &writeFds );
-
-    while( pollPlayback || pollCapture )
-    {
-        pthread_testcancel();
-
-        /* select may modify the timeout parameter */
-        selectTimeval.tv_usec = timeout;
-        nfds = 0;
-
-        if( pollCapture )
-        {
-            FD_SET( captureFd, &readFds );
-            nfds = captureFd + 1;
-        }
-        if( pollPlayback )
-        {
-            FD_SET( playbackFd, &writeFds );
-            nfds = PA_MAX( nfds, playbackFd + 1 );
-        }
-        ENSURE_( select( nfds, &readFds, &writeFds, NULL, &selectTimeval ), paUnanticipatedHostError );
-        /*
-        if( poll( stream->pfds + ofs, nfds, stream->pollTimeout ) < 0 )
-        {
-
-            ENSURE_( -1, paUnanticipatedHostError );
-        }
-        */
-        pthread_testcancel();
-
-        if( pollCapture )
-        {
-            if( FD_ISSET( captureFd, &readFds ) )
-            {
-                FD_CLR( captureFd, &readFds );
-                pollCapture = 0;
-            }
-            /*
-            if( stream->capture->pfd->revents & POLLIN )
-            {
-                --nfds;
-                ++ofs;
-                pollCapture = 0;
-            }
-            */
-            else if( stream->playback ) /* Timed out, go on with playback? */ 
-            {
-                /*PA_DEBUG(( "%s: Trying to poll again for capture frames, pollTimeout: %d\n",
-                            __FUNCTION__, stream->pollTimeout ));*/
-            }
-        }
-        if( pollPlayback )
-        {
-            if( FD_ISSET( playbackFd, &writeFds ) )
-            {
-                FD_CLR( playbackFd, &writeFds );
-                pollPlayback = 0;
-            }
-            /*
-            if( stream->playback->pfd->revents & POLLOUT )
-            {
-                --nfds;
-                pollPlayback = 0;
-            }
-            */
-            else if( stream->capture )  /* Timed out, go on with capture? */
-            {
-                /*PA_DEBUG(( "%s: Trying to poll again for playback frames, pollTimeout: %d\n\n",
-                            __FUNCTION__, stream->pollTimeout ));*/
-            }
-        }
-    }
-
-    if( stream->capture )
-    {
-        ENSURE_( ioctl( captureFd, SNDCTL_DSP_GETISPACE, &bufInfo ), paUnanticipatedHostError );
-        captureAvail = bufInfo.fragments * stream->capture->hostFrames;
-        if( !captureAvail )
-            PA_DEBUG(( "%s: captureAvail: 0\n", __FUNCTION__ ));
-
-        captureAvail = captureAvail == 0 ? INT_MAX : captureAvail;      /* Disregard if zero */
-    }
-    if( stream->playback )
-    {
-        ENSURE_( ioctl( playbackFd, SNDCTL_DSP_GETOSPACE, &bufInfo ), paUnanticipatedHostError );
-        playbackAvail = bufInfo.fragments * stream->playback->hostFrames;
-        if( !playbackAvail )
-        {
-            PA_DEBUG(( "%s: playbackAvail: 0\n", __FUNCTION__ ));
-        }
-
-        playbackAvail = playbackAvail == 0 ? INT_MAX : playbackAvail;      /* Disregard if zero */
-    }
-
-    commonAvail = PA_MIN( captureAvail, playbackAvail );
-    if( commonAvail == INT_MAX )
-        commonAvail = 0;
-    commonAvail -= commonAvail % stream->framesPerHostBuffer;
-
-    assert( commonAvail != INT_MAX );
-    assert( commonAvail >= 0 );
-    *frames = commonAvail;
-
-error:
-    return result;
-}
-
-/** Prepare stream for capture/playback.
- *
- * In order to synchronize capture and playback properly we use the SETTRIGGER command.
- */
-static PaError PaOssStream_Prepare( PaOssStream *stream )
-{
-    PaError result = paNoError;
-    int enableBits = 0;
-
-    if( stream->triggered )
-        return result;
-
-    if( stream->playback )
-    {
-        size_t bufSz = PaOssStreamComponent_BufferSize( stream->playback );
-        memset( stream->playback->buffer, 0, bufSz );
-
-        /* Looks like we have to turn off blocking before we try this, but if we don't fill the buffer
-         * OSS will complain. */
-        PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );
-        while (1)
-        {
-            if( write( stream->playback->fd, stream->playback->buffer, bufSz ) < 0 )
-                break;
-        }
-        PA_ENSURE( ModifyBlocking( stream->playback->fd, 1 ) );
-    }
-
-    if( stream->sharedDevice )
-    {
-        enableBits = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
-        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
-    }
-    else
-    {
-        if( stream->capture )
-        {
-            enableBits = PCM_ENABLE_INPUT;
-            ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
-        }
-        if( stream->playback )
-        {
-            enableBits = PCM_ENABLE_OUTPUT;
-            ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
-        }
-    }
-
-    /* Ok, we have triggered the stream */
-    stream->triggered = 1;
-    
-error:
-    return result;
-}
-
-/** Stop audio processing
- *
- */
-static PaError PaOssStream_Stop( PaOssStream *stream, int abort )
-{
-    PaError result = paNoError;
-
-    /* Looks like the only safe way to stop audio without reopening the device is SNDCTL_DSP_POST.
-     * Also disable capture/playback till the stream is started again */
-    if( stream->capture )
-    {
-        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError );
-    }
-    if( stream->playback && !stream->sharedDevice )
-    {
-        ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError );
-    }
-
-error:
-    return result;
-}
-
-/** Clean up after thread exit.
- *
- * Aspect StreamState: If the user has registered a streamFinishedCallback it will be called here
- */
-static void OnExit( void *data )
-{
-    PaOssStream *stream = (PaOssStream *) data;
-    assert( data );
-
-    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
-
-    PaOssStream_Stop( stream, stream->callbackAbort );
-    
-    PA_DEBUG(( "OnExit: Stoppage\n" ));
-
-    /* Eventually notify user all buffers have played */
-    if( stream->streamRepresentation.streamFinishedCallback )
-        stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
-
-    stream->callbackAbort = 0;      /* Clear state */
-    stream->isActive = 0;
-}
-
-static PaError SetUpBuffers( PaOssStream *stream, unsigned long framesAvail )
-{
-    PaError result = paNoError;
-
-    if( stream->capture )
-    {
-        PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer,
-                stream->capture->hostChannelCount );
-        PaUtil_SetInputFrameCount( &stream->bufferProcessor, framesAvail );
-    }
-    if( stream->playback )
-    {
-        PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer,
-                stream->playback->hostChannelCount );
-        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, framesAvail );
-    }
-
-    return result;
-}
-
-/** Thread procedure for callback processing.
- *
- * Aspect StreamState: StartStream will wait on this to initiate audio processing, useful in case the
- * callback should be used for buffer priming. When the stream is cancelled a separate function will
- * take care of the transition to the Callback Finished state (the stream isn't considered Stopped
- * before StopStream() or AbortStream() are called).
- */
-static void *PaOSS_AudioThreadProc( void *userData )
-{
-    PaError result = paNoError;
-    PaOssStream *stream = (PaOssStream*)userData;
-    unsigned long framesAvail, framesProcessed;
-    int callbackResult = paContinue;
-    int triggered = stream->triggered;  /* See if SNDCTL_DSP_TRIGGER has been issued already */
-    int initiateProcessing = triggered;    /* Already triggered? */
-    PaStreamCallbackFlags cbFlags = 0;  /* We might want to keep state across iterations */
-    
-    /*
-#if ( SOUND_VERSION > 0x030904 )
-        audio_errinfo errinfo;
-#endif
-*/
-    
-    assert( stream );
-
-    pthread_cleanup_push( &OnExit, stream );	/* Execute OnExit when exiting */
-
-    /* The first time the stream is started we use SNDCTL_DSP_TRIGGER to accurately start capture and
-     * playback in sync, when the stream is restarted after being stopped we simply start by reading/
-     * writing.
-     */
-    PA_ENSURE( PaOssStream_Prepare( stream ) );
-
-    /* If we are to initiate processing implicitly by reading/writing data, we start off in blocking mode */
-    if( initiateProcessing )
-    {
-        /* Make sure devices are in blocking mode */
-        if( stream->capture )
-            ModifyBlocking( stream->capture->fd, 1 );
-        if( stream->playback )
-            ModifyBlocking( stream->playback->fd, 1 );
-    }
-
-    while( 1 )
-    {
-        PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */
-
-        pthread_testcancel();
-
-        if( stream->callbackStop && callbackResult == paContinue )
-        {
-            PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
-            callbackResult = paComplete;
-        }
-
-        /* Aspect StreamState: Because of the messy OSS scheme we can't explicitly trigger device start unless
-         * the stream has been recently started, we will have to go right ahead and read/write in blocking
-         * fashion to trigger operation. Therefore we begin with processing one host buffer before we switch
-         * to non-blocking mode.
-         */
-        if( !initiateProcessing )
-        {
-            PA_ENSURE( PaOssStream_WaitForFrames( stream, &framesAvail ) );  /* Wait on available frames */
-            assert( framesAvail % stream->framesPerHostBuffer == 0 );
-        }
-        else
-        {
-            framesAvail = stream->framesPerHostBuffer;
-        }
-
-        while( framesAvail > 0 )
-        {
-            unsigned long frames = framesAvail;
-
-            pthread_testcancel();
-
-            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
-            /* Read data */
-            if ( stream->capture )
-            {
-                PA_ENSURE( PaOssStreamComponent_Read( stream->capture, &frames ) );
-                assert( frames == framesAvail );
-            }
-
-#if ( SOUND_VERSION >= 0x030904 )
-            /*
-               Check with OSS to see if there have been any under/overruns
-               since last time we checked.
-               */
-            /*
-            if( ioctl( stream->deviceHandle, SNDCTL_DSP_GETERROR, &errinfo ) >= 0 )
-            {
-                if( errinfo.play_underruns )
-                    cbFlags |= paOutputUnderflow ;
-                if( errinfo.record_underruns )
-                    cbFlags |= paInputUnderflow ;
-            }
-            else
-                PA_DEBUG(( "SNDCTL_DSP_GETERROR command failed: %s\n", strerror( errno ) ));
-                */
-#endif
-
-            PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
-                    cbFlags );
-            cbFlags = 0;
-            PA_ENSURE( SetUpBuffers( stream, framesAvail ) );
-
-            framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
-                    &callbackResult );
-            assert( framesProcessed == framesAvail );
-            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
-
-            if ( stream->playback )
-            {
-                frames = framesAvail;
-
-                PA_ENSURE( PaOssStreamComponent_Write( stream->playback, &frames ) );
-                assert( frames == framesAvail );
-
-                /* TODO: handle bytesWritten != bytesRequested (slippage?) */
-            }
-
-            framesAvail -= framesProcessed;
-            stream->framesProcessed += framesProcessed;
-
-            if( callbackResult != paContinue )
-                break;
-        }
-
-        if( initiateProcessing || !triggered )
-        {
-            /* Non-blocking */
-            if( stream->capture )
-                PA_ENSURE( ModifyBlocking( stream->capture->fd, 0 ) );
-            if( stream->playback && !stream->sharedDevice )
-                PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );
-
-            initiateProcessing = 0;
-            sem_post( &stream->semaphore );
-        }
-
-        if( callbackResult != paContinue )
-        {
-            stream->callbackAbort = callbackResult == paAbort;
-            if( stream->callbackAbort || PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
-                break;
-        }
-    }
-
-    pthread_cleanup_pop( 1 );
-
-error:
-    pthread_exit( NULL );
-}
-
-/** Close the stream.
- *
- */
-static PaError CloseStream( PaStream* s )
-{
-    PaError result = paNoError;
-    PaOssStream *stream = (PaOssStream*)s;
-
-    assert( stream );
-
-    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
-    PaOssStream_Terminate( stream );
-
-    return result;
-}
-
-/** Start the stream.
- *
- * Aspect StreamState: After returning, the stream shall be in the Active state, implying that an eventual
- * callback will be repeatedly called in a separate thread. If a separate thread is started this function
- * will block untill it has started processing audio, otherwise audio processing is started directly.
- */
-static PaError StartStream( PaStream *s )
-{
-    PaError result = paNoError;
-    PaOssStream *stream = (PaOssStream*)s;
-
-    stream->isActive = 1;
-    stream->isStopped = 0;
-    stream->lastPosPtr = 0;
-    stream->lastStreamBytes = 0;
-    stream->framesProcessed = 0;
-
-    /* only use the thread for callback streams */
-    if( stream->bufferProcessor.streamCallback )
-    {
-        PA_ENSURE( PaUtil_StartThreading( &stream->threading, &PaOSS_AudioThreadProc, stream ) );
-        sem_wait( &stream->semaphore );
-    }
-    else
-        PA_ENSURE( PaOssStream_Prepare( stream ) );
-
-error:
-    return result;
-}
-
-static PaError RealStop( PaOssStream *stream, int abort )
-{
-    PaError result = paNoError;
-
-    if( stream->callbackMode )
-    {
-        if( abort )
-            stream->callbackAbort = 1;
-        else
-            stream->callbackStop = 1;
-
-        PA_ENSURE( PaUtil_CancelThreading( &stream->threading, !abort, NULL ) );
-
-        stream->callbackStop = stream->callbackAbort = 0;
-    }
-    else
-        PA_ENSURE( PaOssStream_Stop( stream, abort ) );
-
-    stream->isStopped = 1;
-
-error:
-    return result;
-}
-
-/** Stop the stream.
- *
- * Aspect StreamState: This will cause the stream to transition to the Stopped state, playing all enqueued
- * buffers.
- */
-static PaError StopStream( PaStream *s )
-{
-    return RealStop( (PaOssStream *)s, 0 );
-}
-
-/** Abort the stream.
- *
- * Aspect StreamState: This will cause the stream to transition to the Stopped state, discarding all enqueued
- * buffers. Note that the buffers are not currently correctly discarded, this is difficult without closing
- * the OSS device.
- */
-static PaError AbortStream( PaStream *s )
-{
-    return RealStop( (PaOssStream *)s, 1 );
-}
-
-/** Is the stream in the Stopped state.
- *
- */
-static PaError IsStreamStopped( PaStream *s )
-{
-    PaOssStream *stream = (PaOssStream*)s;
-
-    return (stream->isStopped);
-}
-
-/** Is the stream in the Active state.
- *
- */
-static PaError IsStreamActive( PaStream *s )
-{
-    PaOssStream *stream = (PaOssStream*)s;
-
-    return (stream->isActive);
-}
-
-static PaTime GetStreamTime( PaStream *s )
-{
-    PaOssStream *stream = (PaOssStream*)s;
-    count_info info;
-    int delta;
-
-    if( stream->playback ) {
-        if( ioctl( stream->playback->fd, SNDCTL_DSP_GETOPTR, &info) == 0 ) {
-            delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF;
-            return ( stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->playback ) / stream->sampleRate;
-        }
-    }
-    else {
-        if (ioctl( stream->capture->fd, SNDCTL_DSP_GETIPTR, &info) == 0) {
-            delta = (info.bytes - stream->lastPosPtr) & 0x000FFFFF;
-            return ( stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->capture ) / stream->sampleRate;
-        }
-    }
-
-    /* the ioctl failed, but we can still give a coarse estimate */
-
-    return stream->framesProcessed / stream->sampleRate;
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
-    PaOssStream *stream = (PaOssStream*)s;
-
-    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-/*
-    As separate stream interfaces are used for blocking and callback
-    streams, the following functions can be guaranteed to only be called
-    for blocking streams.
-*/
-
-
-static PaError ReadStream( PaStream* s,
-                           void *buffer,
-                           unsigned long frames )
-{
-    PaOssStream *stream = (PaOssStream*)s;
-    int bytesRequested, bytesRead;
-    unsigned long framesRequested;
-    void *userBuffer;
-
-    /* If user input is non-interleaved, PaUtil_CopyInput will manipulate the channel pointers,
-     * so we copy the user provided pointers */
-    if( stream->bufferProcessor.userInputIsInterleaved )
-        userBuffer = buffer;
-    else /* Copy channels into local array */
-    {
-        userBuffer = stream->capture->userBuffers;
-        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->capture->userChannelCount );
-    }
-
-    while( frames )
-    {
-        framesRequested = PA_MIN( frames, stream->capture->hostFrames );
-
-	bytesRequested = framesRequested * PaOssStreamComponent_FrameSize( stream->capture );
-	bytesRead = read( stream->capture->fd, stream->capture->buffer, bytesRequested );
-	if ( bytesRequested != bytesRead )
-	    return paUnanticipatedHostError;
-
-	PaUtil_SetInputFrameCount( &stream->bufferProcessor, stream->capture->hostFrames );
-	PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer, stream->capture->hostChannelCount );
-        PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesRequested );
-	frames -= framesRequested;
-    }
-    return paNoError;
-}
-
-
-static PaError WriteStream( PaStream* s,
-                            const void *buffer,
-                            unsigned long frames )
-{
-    PaOssStream *stream = (PaOssStream*)s;
-    int bytesRequested, bytesWritten;
-    unsigned long framesConverted;
-    const void *userBuffer;
-
-    /* If user output is non-interleaved, PaUtil_CopyOutput will manipulate the channel pointers,
-     * so we copy the user provided pointers */
-    if( stream->bufferProcessor.userOutputIsInterleaved )
-        userBuffer = buffer;
-    else /* Copy channels into local array */
-    {
-        userBuffer = stream->playback->userBuffers;
-        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback->userChannelCount );
-    }
-
-    while( frames )
-    {
-	PaUtil_SetOutputFrameCount( &stream->bufferProcessor, stream->playback->hostFrames );
-	PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer, stream->playback->hostChannelCount );
-
-	framesConverted = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames );
-	frames -= framesConverted;
-
-	bytesRequested = framesConverted * PaOssStreamComponent_FrameSize( stream->playback );
-	bytesWritten = write( stream->playback->fd, stream->playback->buffer, bytesRequested );
-
-	if ( bytesRequested != bytesWritten )
-	    return paUnanticipatedHostError;
-    }
-    return paNoError;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
-    PaOssStream *stream = (PaOssStream*)s;
-    audio_buf_info info;
-
-    if( ioctl( stream->capture->fd, SNDCTL_DSP_GETISPACE, &info ) < 0 )
-        return paUnanticipatedHostError;
-    return info.fragments * stream->capture->hostFrames;
-}
-
-
-/* TODO: Compute number of allocated bytes somewhere else, can we use ODELAY with capture */
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
-    PaOssStream *stream = (PaOssStream*)s;
-    int delay = 0;
-
-    if( ioctl( stream->playback->fd, SNDCTL_DSP_GETODELAY, &delay ) < 0 )
-        return paUnanticipatedHostError;
-    
-    return (PaOssStreamComponent_BufferSize( stream->playback ) - delay) / PaOssStreamComponent_FrameSize( stream->playback );
-}
-
+/*

+ * $Id: pa_unix_oss.c,v 1.6.2.22 2005/03/08 21:26:53 aknudsen Exp $

+ * PortAudio Portable Real-Time Audio Library

+ * Latest Version at: http://www.portaudio.com

+ * OSS implementation by:

+ *   Douglas Repetto

+ *   Phil Burk

+ *   Dominic Mazzoni

+ *   Arve Knudsen

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#include <stdio.h>

+#include <string.h>

+#include <math.h>

+#include <fcntl.h>

+#include <sys/ioctl.h>

+#include <unistd.h>

+#include <pthread.h>

+#include <alloca.h>

+#include <malloc.h>

+#include <assert.h>

+#include <errno.h>

+#include <sys/types.h>

+#include <sys/stat.h>

+#include <sys/poll.h>

+#include <limits.h>

+#include <semaphore.h>

+

+#ifdef __linux__

+# include <linux/soundcard.h>

+# define DEVICE_NAME_BASE            "/dev/dsp"

+#else

+# include <machine/soundcard.h> /* JH20010905 */

+# define DEVICE_NAME_BASE            "/dev/audio"

+#endif

+

+#include "portaudio.h"

+#include "pa_util.h"

+#include "pa_allocation.h"

+#include "pa_hostapi.h"

+#include "pa_stream.h"

+#include "pa_cpuload.h"

+#include "pa_process.h"

+#include "pa_unix_util.h"

+

+static int sysErr_;

+static pthread_t mainThread_;

+

+/* Check return value of system call, and map it to PaError */

+#define ENSURE_(expr, code) \

+    do { \

+        if( UNLIKELY( (sysErr_ = (expr)) < 0 ) ) \

+        { \

+            /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \

+            if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \

+            { \

+                PaUtil_SetLastHostErrorInfo( paALSA, sysErr_, strerror( errno ) ); \

+            } \

+            \

+            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \

+            result = (code); \

+            goto error; \

+        } \

+    } while( 0 );

+

+#ifndef AFMT_S16_NE

+#define AFMT_S16_NE  Get_AFMT_S16_NE()

+/*********************************************************************

+ * Some versions of OSS do not define AFMT_S16_NE. So check CPU.

+ * PowerPC is Big Endian. X86 is Little Endian.

+ */

+static int Get_AFMT_S16_NE( void )

+{

+    long testData = 1; 

+    char *ptr = (char *) &testData;

+    int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */

+    return isLittle ? AFMT_S16_LE : AFMT_S16_BE;

+}

+#endif

+

+/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */

+

+typedef struct

+{

+    PaUtilHostApiRepresentation inheritedHostApiRep;

+    PaUtilStreamInterface callbackStreamInterface;

+    PaUtilStreamInterface blockingStreamInterface;

+

+    PaUtilAllocationGroup *allocations;

+

+    PaHostApiIndex hostApiIndex;

+}

+PaOSSHostApiRepresentation;

+

+/** Per-direction structure for PaOssStream.

+ *

+ * Aspect StreamChannels: In case the user requests to open the same device for both capture and playback,

+ * but with different number of channels we will have to adapt between the number of user and host

+ * channels for at least one direction, since the configuration space is the same for both directions

+ * of an OSS device.

+ */

+typedef struct

+{

+    int fd;

+    const char *devName;

+    int userChannelCount, hostChannelCount;

+    int userInterleaved;

+    void *buffer;

+    PaSampleFormat userFormat, hostFormat;

+    double latency;

+    unsigned long hostFrames, numBufs;

+    void **userBuffers; /* For non-interleaved blocking */

+} PaOssStreamComponent;

+

+/** Implementation specific representation of a PaStream.

+ *

+ */

+typedef struct PaOssStream

+{

+    PaUtilStreamRepresentation streamRepresentation;

+    PaUtilCpuLoadMeasurer cpuLoadMeasurer;

+    PaUtilBufferProcessor bufferProcessor;

+

+    PaUtilThreading threading;

+

+    int sharedDevice;

+    unsigned long framesPerHostBuffer;

+    int triggered;  /* Have the devices been triggered yet (first start) */

+

+    int isActive;

+    int isStopped;

+

+    int lastPosPtr;

+    double lastStreamBytes;

+

+    int framesProcessed;

+

+    double sampleRate;

+

+    int callbackMode;

+    int callbackStop, callbackAbort;

+

+    PaOssStreamComponent *capture, *playback;

+    unsigned long pollTimeout;

+    sem_t semaphore;

+}

+PaOssStream;

+

+typedef enum {

+    StreamMode_In,

+    StreamMode_Out

+} StreamMode;

+

+/* prototypes for functions declared in this file */

+

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate );

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** s,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *streamCallback,

+                           void *userData );

+static PaError CloseStream( PaStream* stream );

+static PaError StartStream( PaStream *stream );

+static PaError StopStream( PaStream *stream );

+static PaError AbortStream( PaStream *stream );

+static PaError IsStreamStopped( PaStream *s );

+static PaError IsStreamActive( PaStream *stream );

+static PaTime GetStreamTime( PaStream *stream );

+static double GetStreamCpuLoad( PaStream* stream );

+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );

+static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );

+static signed long GetStreamReadAvailable( PaStream* stream );

+static signed long GetStreamWriteAvailable( PaStream* stream );

+static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi );

+

+

+/** Initialize the OSS API implementation.

+ *

+ * This function will initialize host API datastructures and query host devices for information.

+ *

+ * Aspect DeviceCapabilities: Enumeration of host API devices is initiated from here

+ *

+ * Aspect FreeResources: If an error is encountered under way we have to free each resource allocated in this function,

+ * this happens with the usual "error" label.

+ */

+PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )

+{

+    PaError result = paNoError;

+    PaOSSHostApiRepresentation *ossHostApi = NULL;

+

+    PA_UNLESS( ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) ),

+            paInsufficientMemory );

+    PA_UNLESS( ossHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );

+    ossHostApi->hostApiIndex = hostApiIndex;

+

+    /* Initialize host API structure */

+    *hostApi = &ossHostApi->inheritedHostApiRep;

+    (*hostApi)->info.structVersion = 1;

+    (*hostApi)->info.type = paOSS;

+    (*hostApi)->info.name = "OSS";

+    (*hostApi)->Terminate = Terminate;

+    (*hostApi)->OpenStream = OpenStream;

+    (*hostApi)->IsFormatSupported = IsFormatSupported;

+

+    PA_ENSURE( BuildDeviceList( ossHostApi ) );

+

+    PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream,

+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, GetStreamCpuLoad,

+                                      PaUtil_DummyRead, PaUtil_DummyWrite,

+                                      PaUtil_DummyGetReadAvailable,

+                                      PaUtil_DummyGetWriteAvailable );

+

+    PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream,

+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, PaUtil_DummyGetCpuLoad,

+                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );

+

+    mainThread_ = pthread_self();

+

+    return result;

+

+error:

+    if( ossHostApi )

+    {

+        if( ossHostApi->allocations )

+        {

+            PaUtil_FreeAllAllocations( ossHostApi->allocations );

+            PaUtil_DestroyAllocationGroup( ossHostApi->allocations );

+        }

+                

+        PaUtil_FreeMemory( ossHostApi );

+    }

+    return result;

+}

+

+PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, PaHostApiIndex hostApiIndex, int maxInputChannels,

+        int maxOutputChannels, PaTime defaultLowInputLatency, PaTime defaultLowOutputLatency, PaTime defaultHighInputLatency,

+        PaTime defaultHighOutputLatency, double defaultSampleRate, PaUtilAllocationGroup *allocations  )

+{

+    PaError result = paNoError;

+    

+    deviceInfo->structVersion = 2;

+    if( allocations )

+    {

+        size_t len = strlen( name ) + 1;

+        PA_UNLESS( deviceInfo->name = PaUtil_GroupAllocateMemory( allocations, len ), paInsufficientMemory );

+        strncpy( (char *)deviceInfo->name, name, len );

+    }

+    else

+        deviceInfo->name = name;

+

+    deviceInfo->hostApi = hostApiIndex;

+    deviceInfo->maxInputChannels = maxInputChannels;

+    deviceInfo->maxOutputChannels = maxOutputChannels;

+    deviceInfo->defaultLowInputLatency = defaultLowInputLatency;

+    deviceInfo->defaultLowOutputLatency = defaultLowOutputLatency;

+    deviceInfo->defaultHighInputLatency = defaultHighInputLatency;

+    deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency;

+    deviceInfo->defaultSampleRate = defaultSampleRate;

+

+error:

+    return result;

+}

+

+static PaError QueryDirection( const char *deviceName, StreamMode mode, double *defaultSampleRate, int *maxChannelCount,

+        double *defaultLowLatency, double *defaultHighLatency )

+{

+    PaError result = paNoError;

+    int numChannels, maxNumChannels;

+    int busy = 0;

+    int devHandle = -1;

+    int sr;

+    *maxChannelCount = 0;  /* Default value in case this fails */

+

+    if ( (devHandle = open( deviceName, (mode == StreamMode_In ? O_RDONLY : O_WRONLY) | O_NONBLOCK ))  < 0 )

+    {

+        if( errno == EBUSY || errno == EAGAIN )

+        {

+            PA_DEBUG(( "%s: Device %s busy\n", __FUNCTION__, deviceName ));

+        }

+        else

+        {

+            PA_DEBUG(( "%s: Can't access device: %s\n", __FUNCTION__, strerror( errno ) ));

+        }

+

+        return paDeviceUnavailable;

+    }

+

+    /* Negotiate for the maximum number of channels for this device. PLB20010927

+     * Consider up to 16 as the upper number of channels.

+     * Variable maxNumChannels should contain the actual upper limit after the call.

+     * Thanks to John Lazzaro and Heiko Purnhagen for suggestions.

+     */

+    maxNumChannels = 0;

+    for( numChannels = 1; numChannels <= 16; numChannels++ )

+    {

+        int temp = numChannels;

+        if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 )

+        {

+            busy = EAGAIN == errno || EBUSY == errno;

+            /* ioctl() failed so bail out if we already have stereo */

+            if( maxNumChannels >= 2 )

+                break;

+        }

+        else

+        {

+            /* ioctl() worked but bail out if it does not support numChannels.

+             * We don't want to leave gaps in the numChannels supported.

+             */

+            if( (numChannels > 2) && (temp != numChannels) )

+                break;

+            if( temp > maxNumChannels )

+                maxNumChannels = temp; /* Save maximum. */

+        }

+    }

+    /* A: We're able to open a device for capture if it's busy playing back and vice versa,

+     * but we can't configure anything */

+    if( 0 == maxNumChannels && busy )

+    {

+        result = paDeviceUnavailable;

+        goto error;

+    }

+

+    /* The above negotiation may fail for an old driver so try this older technique. */

+    if( maxNumChannels < 1 )

+    {

+        int stereo = 1;

+        if( ioctl( devHandle, SNDCTL_DSP_STEREO, &stereo ) < 0 )

+        {

+            maxNumChannels = 1;

+        }

+        else

+        {

+            maxNumChannels = (stereo) ? 2 : 1;

+        }

+        PA_DEBUG(( "%s: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", __FUNCTION__, maxNumChannels ))

+    }

+

+    /* During channel negotiation, the last ioctl() may have failed. This can

+     * also cause sample rate negotiation to fail. Hence the following, to return

+     * to a supported number of channels. SG20011005 */

+    {

+        /* use most reasonable default value */

+        int temp = PA_MIN( maxNumChannels, 2 );

+        ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ), paUnanticipatedHostError );

+    }

+

+    /* Get supported sample rate closest to 44100 Hz */

+    if( *defaultSampleRate < 0 )

+    {

+        sr = 44100;

+        if( ioctl( devHandle, SNDCTL_DSP_SPEED, &sr ) < 0 )

+        {

+            result = paUnanticipatedHostError;

+            goto error;

+        }

+

+        *defaultSampleRate = sr;

+    }

+

+    *maxChannelCount = maxNumChannels;

+    /* TODO */

+    *defaultLowLatency = 512. / *defaultSampleRate;

+    *defaultHighLatency = 2048. / *defaultSampleRate;

+

+error:

+    if( devHandle >= 0 )

+        close( devHandle );

+

+    return result;

+}

+

+/** Query OSS device.

+ *

+ * This is where PaDeviceInfo objects are constructed and filled in with relevant information.

+ *

+ * Aspect DeviceCapabilities: The inferred device capabilities are recorded in a PaDeviceInfo object that is constructed

+ * in place.

+ */

+static PaError QueryDevice( char *deviceName, PaOSSHostApiRepresentation *ossApi, PaDeviceInfo **deviceInfo )

+{

+    PaError result = paNoError;

+    double sampleRate = -1.;

+    int maxInputChannels, maxOutputChannels;

+    PaTime defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency;

+    PaError tmpRes = paNoError;

+    int busy = 0;

+    *deviceInfo = NULL;

+

+    /* douglas:

+       we have to do this querying in a slightly different order. apparently

+       some sound cards will give you different info based on their settins. 

+       e.g. a card might give you stereo at 22kHz but only mono at 44kHz.

+       the correct order for OSS is: format, channels, sample rate

+    */

+

+    /* Aspect StreamChannels: The number of channels supported for a device may depend on the mode it is

+     * opened in, it may have more channels available for capture than playback and vice versa. Therefore

+     * we will open the device in both read- and write-only mode to determine the supported number.

+     */

+    if( (tmpRes = QueryDirection( deviceName, StreamMode_In, &sampleRate, &maxInputChannels, &defaultLowInputLatency,

+                &defaultHighInputLatency )) != paNoError )

+    {

+        if( tmpRes != paDeviceUnavailable )

+        {

+            PA_DEBUG(( "%s: Querying device %s for capture failed!\n", __FUNCTION__, deviceName ));

+            /* PA_ENSURE( tmpRes ); */

+        }

+        ++busy;

+    }

+    if( (tmpRes = QueryDirection( deviceName, StreamMode_Out, &sampleRate, &maxOutputChannels, &defaultLowOutputLatency,

+                &defaultHighOutputLatency )) != paNoError )

+    {

+        if( tmpRes != paDeviceUnavailable )

+        {

+            PA_DEBUG(( "%s: Querying device %s for playback failed!\n", __FUNCTION__, deviceName ));

+            /* PA_ENSURE( tmpRes ); */

+        }

+        ++busy;

+    }

+    assert( 0 <= busy && busy <= 2 );

+    if( 2 == busy )     /* Both directions are unavailable to us */

+    {

+        result = paDeviceUnavailable;

+        goto error;

+    }

+

+    PA_UNLESS( *deviceInfo = PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof (PaDeviceInfo) ), paInsufficientMemory );

+    PA_ENSURE( PaUtil_InitializeDeviceInfo( *deviceInfo, deviceName, ossApi->hostApiIndex, maxInputChannels, maxOutputChannels,

+                defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency, sampleRate,

+                ossApi->allocations ) );

+

+error:

+    return result;

+}

+

+/** Query host devices.

+ *

+ * Loop over host devices and query their capabilitiesu

+ *

+ * Aspect DeviceCapabilities: This function calls QueryDevice on each device entry and receives a filled in PaDeviceInfo object

+ * per device, these are placed in the host api representation's deviceInfos array.

+ */

+static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi )

+{

+    PaError result = paNoError;

+    PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;

+    int i;

+    int numDevices = 0, maxDeviceInfos = 1;

+    PaDeviceInfo **deviceInfos = NULL;

+

+    /* These two will be set to the first working input and output device, respectively */

+    commonApi->info.defaultInputDevice = paNoDevice;

+    commonApi->info.defaultOutputDevice = paNoDevice;

+

+    /* Find devices by calling QueryDevice on each

+     * potential device names.  When we find a valid one,

+     * add it to a linked list.

+     * A: Can there only be 10 devices? */

+

+    for( i = 0; i < 10; i++ )

+    {

+       char deviceName[32];

+       PaDeviceInfo *deviceInfo;

+       int testResult;

+       struct stat stbuf;

+

+       if( i == 0 )

+          snprintf(deviceName, sizeof (deviceName), "%s", DEVICE_NAME_BASE);

+       else

+          snprintf(deviceName, sizeof (deviceName), "%s%d", DEVICE_NAME_BASE, i);

+

+       /* PA_DEBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName )); */

+       if( stat( deviceName, &stbuf ) < 0 )

+       {

+           if( ENOENT != errno )

+               PA_DEBUG(( "%s: Error stat'ing %s: %s\n", __FUNCTION__, deviceName, strerror( errno ) ));

+           continue;

+       }

+       if( (testResult = QueryDevice( deviceName, ossApi, &deviceInfo )) != paNoError )

+       {

+           if( testResult != paDeviceUnavailable )

+               PA_ENSURE( testResult );

+

+           continue;

+       }

+

+       ++numDevices;

+       if( !deviceInfos || numDevices > maxDeviceInfos )

+       {

+           maxDeviceInfos *= 2;

+           PA_UNLESS( deviceInfos = (PaDeviceInfo **) realloc( deviceInfos, maxDeviceInfos * sizeof (PaDeviceInfo *) ),

+                   paInsufficientMemory );

+       }

+       deviceInfos[numDevices - 1] = deviceInfo;

+

+       if( commonApi->info.defaultInputDevice == paNoDevice && deviceInfo->maxInputChannels > 0 )

+           commonApi->info.defaultInputDevice = i;

+       if( commonApi->info.defaultOutputDevice == paNoDevice && deviceInfo->maxOutputChannels > 0 )

+           commonApi->info.defaultOutputDevice = i;

+    }

+

+    /* Make an array of PaDeviceInfo pointers out of the linked list */

+

+    PA_DEBUG(("PaOSS %s: Total number of devices found: %d\n", __FUNCTION__, numDevices));

+

+    commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(

+        ossApi->allocations, sizeof(PaDeviceInfo*) * numDevices );

+    memcpy( commonApi->deviceInfos, deviceInfos, numDevices * sizeof (PaDeviceInfo *) );

+

+    commonApi->info.deviceCount = numDevices;

+

+error:

+    free( deviceInfos );

+

+    return result;

+}

+

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )

+{

+    PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;

+

+    if( ossHostApi->allocations )

+    {

+        PaUtil_FreeAllAllocations( ossHostApi->allocations );

+        PaUtil_DestroyAllocationGroup( ossHostApi->allocations );

+    }

+

+    PaUtil_FreeMemory( ossHostApi );

+}

+

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate )

+{

+    PaError result = paNoError;

+    PaDeviceIndex device;

+    PaDeviceInfo *deviceInfo;

+    char *deviceName;

+    int inputChannelCount, outputChannelCount;

+    int tempDevHandle = -1;

+    int flags;

+    PaSampleFormat inputSampleFormat, outputSampleFormat;

+    

+    if( inputParameters )

+    {

+        inputChannelCount = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+

+        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that input device can support inputChannelCount */

+        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )

+            return paInvalidChannelCount;

+

+        /* validate inputStreamInfo */

+        if( inputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */

+    }

+    else

+    {

+        inputChannelCount = 0;

+    }

+

+    if( outputParameters )

+    {

+        outputChannelCount = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+        

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+

+        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that output device can support inputChannelCount */

+        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )

+            return paInvalidChannelCount;

+

+        /* validate outputStreamInfo */

+        if( outputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */

+    }

+    else

+    {

+        outputChannelCount = 0;

+    }

+

+    if (inputChannelCount == 0 && outputChannelCount == 0)

+        return paInvalidChannelCount;

+

+    /* if full duplex, make sure that they're the same device */

+

+    if (inputChannelCount > 0 && outputChannelCount > 0 &&

+        inputParameters->device != outputParameters->device)

+        return paInvalidDevice;

+

+    /* if full duplex, also make sure that they're the same number of channels */

+

+    if (inputChannelCount > 0 && outputChannelCount > 0 &&

+        inputChannelCount != outputChannelCount)

+       return paInvalidChannelCount;

+

+    /* open the device so we can do more tests */

+    

+    if( inputChannelCount > 0 )

+    {

+        result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);

+        if (result != paNoError)

+            return result;

+    }

+    else

+    {

+        result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);

+        if (result != paNoError)

+            return result;

+    }

+

+    deviceInfo = hostApi->deviceInfos[device];

+    deviceName = (char *)deviceInfo->name;

+    

+    flags = O_NONBLOCK;

+    if (inputChannelCount > 0 && outputChannelCount > 0)

+       flags |= O_RDWR;

+    else if (inputChannelCount > 0)

+       flags |= O_RDONLY;

+    else

+       flags |= O_WRONLY;

+

+    ENSURE_( tempDevHandle = open( deviceInfo->name, flags ), paDeviceUnavailable );

+

+    /* PaOssStream_Configure will do the rest of the checking for us */

+    /* PA_ENSURE( PaOssStream_Configure( tempDevHandle, deviceName, outputChannelCount, &sampleRate ) ); */

+

+    /* everything succeeded! */

+

+ error:

+    if( tempDevHandle >= 0 )

+        close( tempDevHandle );         

+

+    return result;

+}

+

+/** Validate stream parameters.

+ *

+ * Aspect StreamChannels: We verify that the number of channels is within the allowed range for the device

+ */

+static PaError ValidateParameters( const PaStreamParameters *parameters, const PaDeviceInfo *deviceInfo, StreamMode mode )

+{

+    int maxChans;

+

+    assert( parameters );

+

+    if( parameters->device == paUseHostApiSpecificDeviceSpecification )

+    {

+        return paInvalidDevice;

+    }

+

+    maxChans = (mode == StreamMode_In ? deviceInfo->maxInputChannels :

+        deviceInfo->maxOutputChannels);

+    if( parameters->channelCount > maxChans )

+    {

+        return paInvalidChannelCount;

+    }

+

+    return paNoError;

+}

+

+static PaError PaOssStreamComponent_Initialize( PaOssStreamComponent *component, const PaStreamParameters *parameters,

+        int callbackMode, int fd, const char *deviceName )

+{

+    PaError result = paNoError;

+    assert( component );

+

+    memset( component, 0, sizeof (PaOssStreamComponent) );

+

+    component->fd = fd;

+    component->devName = deviceName;

+    component->userChannelCount = parameters->channelCount;

+    component->userFormat = parameters->sampleFormat;

+    component->latency = parameters->suggestedLatency;

+    component->userInterleaved = !(parameters->sampleFormat & paNonInterleaved);

+

+    if( !callbackMode && !component->userInterleaved )

+    {

+        /* Pre-allocate non-interleaved user provided buffers */

+        PA_UNLESS( component->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * component->userChannelCount ),

+                paInsufficientMemory );

+    }

+

+error:

+    return result;

+}

+

+static void PaOssStreamComponent_Terminate( PaOssStreamComponent *component )

+{

+    assert( component );

+

+    if( component->fd >= 0 )

+        close( component->fd );

+    if( component->buffer )

+        PaUtil_FreeMemory( component->buffer );

+

+    if( component->userBuffers )

+        PaUtil_FreeMemory( component->userBuffers );

+

+    PaUtil_FreeMemory( component );

+}

+

+static PaError ModifyBlocking( int fd, int blocking )

+{

+    PaError result = paNoError;

+    int fflags;

+

+    ENSURE_( fflags = fcntl( fd, F_GETFL ), paUnanticipatedHostError );

+

+    if( blocking )

+        fflags &= ~O_NONBLOCK;

+    else

+        fflags |= O_NONBLOCK;

+

+    ENSURE_( fcntl( fd, F_SETFL, fflags ), paUnanticipatedHostError );

+

+error:

+    return result;

+}

+

+static PaError OpenDevices( const char *idevName, const char *odevName, int *idev, int *odev )

+{

+    PaError result = paNoError;

+    int flags = O_NONBLOCK, duplex = 0;

+    int enableBits = 0;

+    *idev = *odev = -1;

+

+    if( idevName && odevName )

+    {

+        duplex = 1;

+        flags |= O_RDWR;

+    }

+    else if( idevName )

+        flags |= O_RDONLY;

+    else

+        flags |= O_WRONLY;

+

+    /* open first in nonblocking mode, in case it's busy...

+     * A: then unset the non-blocking attribute */

+    assert( flags & O_NONBLOCK );

+    if( idevName )

+    {

+        ENSURE_( *idev = open( idevName, flags ), paDeviceUnavailable );

+        PA_ENSURE( ModifyBlocking( *idev, 1 ) ); /* Blocking */

+

+        /* Initially disable */

+        enableBits = ~PCM_ENABLE_INPUT;

+        ENSURE_( ioctl( *idev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );

+    }

+    if( odevName )

+    {

+        if( !idevName )

+        {

+            ENSURE_( *odev = open( odevName, flags ), paDeviceUnavailable );

+            PA_ENSURE( ModifyBlocking( *odev, 1 ) ); /* Blocking */

+

+            /* Initially disable */

+            enableBits = ~PCM_ENABLE_OUTPUT;

+            ENSURE_( ioctl( *odev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );

+        }

+        else

+        {

+            ENSURE_( *odev = dup( *idev ), paUnanticipatedHostError );

+        }

+    }

+

+error:

+    return result;

+}

+

+static PaError PaOssStream_Initialize( PaOssStream *stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters,

+        PaStreamCallback callback, void *userData, PaStreamFlags streamFlags,

+        PaOSSHostApiRepresentation *ossApi )

+{

+    PaError result = paNoError;

+    int idev, odev;

+    PaUtilHostApiRepresentation *hostApi = &ossApi->inheritedHostApiRep;

+    const char *idevName = NULL, *odevName = NULL;

+

+    assert( stream );

+

+    memset( stream, 0, sizeof (PaOssStream) );

+    stream->isStopped = 1;

+

+    PA_ENSURE( PaUtil_InitializeThreading( &stream->threading ) );

+

+    if( inputParameters && outputParameters )

+    {

+        if( inputParameters->device == outputParameters->device )

+            stream->sharedDevice = 1;

+    }

+

+    if( inputParameters )

+        idevName = hostApi->deviceInfos[inputParameters->device]->name;

+    if( outputParameters )

+        odevName = hostApi->deviceInfos[outputParameters->device]->name;

+    PA_ENSURE( OpenDevices( idevName, odevName, &idev, &odev ) );

+    if( inputParameters )

+    {

+        PA_UNLESS( stream->capture = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );

+        PA_ENSURE( PaOssStreamComponent_Initialize( stream->capture, inputParameters, callback != NULL, idev, idevName ) );

+    }

+    if( outputParameters )

+    {

+        PA_UNLESS( stream->playback = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );

+        PA_ENSURE( PaOssStreamComponent_Initialize( stream->playback, outputParameters, callback != NULL, odev, odevName ) );

+    }

+

+    if( callback != NULL )

+    {

+        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,

+                                               &ossApi->callbackStreamInterface, callback, userData );

+        stream->callbackMode = 1;

+    }

+    else

+    {

+        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,

+                                               &ossApi->blockingStreamInterface, callback, userData );

+    }    

+

+    ENSURE_( sem_init( &stream->semaphore, 0, 0 ), paInternalError );

+

+error:

+    return result;

+}

+

+static void PaOssStream_Terminate( PaOssStream *stream )

+{

+    assert( stream );

+

+    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );

+    PaUtil_TerminateThreading( &stream->threading );

+

+    if( stream->capture )

+        PaOssStreamComponent_Terminate( stream->capture );

+    if( stream->playback )

+        PaOssStreamComponent_Terminate( stream->playback );

+

+    sem_destroy( &stream->semaphore );

+

+    PaUtil_FreeMemory( stream );

+}

+

+/** Translate from PA format to OSS native.

+ *

+ */

+static PaError Pa2OssFormat( PaSampleFormat paFormat, int *ossFormat )

+{

+    switch( paFormat )

+    {

+        case paUInt8:

+            *ossFormat = AFMT_U8;

+            break;

+        case paInt8:

+            *ossFormat = AFMT_S8;

+            break;

+        case paInt16:

+            *ossFormat = AFMT_S16_NE;

+            break;

+        default:

+            return paInternalError;     /* This shouldn't happen */

+    }

+

+    return paNoError;

+}

+

+/** Return the PA-compatible formats that this device can support.

+ *

+ */

+static PaError GetAvailableFormats( PaOssStreamComponent *component, PaSampleFormat *availableFormats )

+{

+    PaError result = paNoError;

+    int mask = 0;

+    PaSampleFormat frmts = 0;

+

+    ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETFMTS, &mask ), paUnanticipatedHostError );

+    if( mask & AFMT_U8 )

+        frmts |= paUInt8;

+    if( mask & AFMT_S8 )

+        frmts |= paInt8;

+    if( mask & AFMT_S16_NE )

+        frmts |= paInt16;

+    else

+        result = paSampleFormatNotSupported;

+    

+    *availableFormats = frmts;

+

+error:

+    return result;

+}

+

+static unsigned int PaOssStreamComponent_FrameSize( PaOssStreamComponent *component )

+{

+    return Pa_GetSampleSize( component->hostFormat ) * component->hostChannelCount;

+}

+

+/** Buffer size in bytes.

+ *

+ */

+static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *component )

+{

+    return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs;

+}

+

+static int CalcHigherLogTwo( int n )

+{

+    int log2 = 0;

+    while( (1<<log2) < n ) log2++;

+    return log2;

+}

+

+static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long framesPerBuffer,

+        StreamMode streamMode, PaOssStreamComponent *master )

+{

+    PaError result = paNoError;

+    int temp, nativeFormat;

+    int sr = (int)sampleRate;

+    PaSampleFormat availableFormats, hostFormat;

+    int chans = component->userChannelCount;

+    int frgmt;

+    int numBufs;

+    int bytesPerBuf;

+    double bufSz;

+    unsigned long fragSz;

+    audio_buf_info bufInfo;

+

+    /* We may have a situation where only one component (the master) is configured, if both point to the same device.

+     * In that case, the second component will copy settings from the other */

+    if( !master )

+    {

+        /* Aspect BufferSettings: If framesPerBuffer is unspecified we have to infer a suitable fragment size.

+         * The hardware need not respect the requested fragment size, so we may have to adapt.

+         */

+        if( framesPerBuffer == paFramesPerBufferUnspecified )

+        { 

+            bufSz = component->latency * sampleRate;

+            fragSz = bufSz / 4;

+        }

+        else

+        {

+            fragSz = framesPerBuffer;

+            bufSz = component->latency * sampleRate + fragSz; /* Latency + 1 buffer */

+        }

+

+        PA_ENSURE( GetAvailableFormats( component, &availableFormats ) );

+        hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, component->userFormat );

+

+        /* OSS demands at least 2 buffers, and 16 bytes per buffer */

+        numBufs = PA_MAX( bufSz / fragSz, 2 );

+        bytesPerBuf = PA_MAX( fragSz * Pa_GetSampleSize( hostFormat ) * chans, 16 );

+

+        /* The fragment parameters are encoded like this:

+         * Most significant byte: number of fragments

+         * Least significant byte: exponent of fragment size (i.e., for 256, 8)

+         */

+        frgmt = (numBufs << 16) + (CalcHigherLogTwo( bytesPerBuf ) & 0xffff);

+        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError );

+

+        /* A: according to the OSS programmer's guide parameters should be set in this order:

+         * format, channels, rate */

+

+        /* This format should be deemed good before we get this far */

+        PA_ENSURE( Pa2OssFormat( hostFormat, &temp ) );

+        nativeFormat = temp;

+        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFMT, &temp ), paUnanticipatedHostError );

+        PA_UNLESS( temp == nativeFormat, paInternalError );

+

+        /* try to set the number of channels */

+        ENSURE_( ioctl( component->fd, SNDCTL_DSP_CHANNELS, &chans ), paSampleFormatNotSupported );   /* XXX: Should be paInvalidChannelCount? */

+        /* It's possible that the minimum number of host channels is greater than what the user requested */

+        PA_UNLESS( chans >= component->userChannelCount, paInvalidChannelCount );

+

+        /* try to set the sample rate */

+        ENSURE_( ioctl( component->fd, SNDCTL_DSP_SPEED, &sr ), paInvalidSampleRate );

+

+        /* reject if there's no sample rate within 1% of the one requested */

+        if( (fabs( sampleRate - sr ) / sampleRate) > 0.01 )

+        {

+            PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));                 

+            PA_ENSURE( paInvalidSampleRate );

+        }

+

+        ENSURE_( ioctl( component->fd, streamMode == StreamMode_In ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &bufInfo ),

+                paUnanticipatedHostError );

+        component->numBufs = bufInfo.fragstotal;

+

+        /* This needs to be the last ioctl call before the first read/write, according to the OSS programmer's guide */

+        ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETBLKSIZE, &bytesPerBuf ), paUnanticipatedHostError );

+

+        component->hostFrames = bytesPerBuf / Pa_GetSampleSize( hostFormat ) / chans;

+        component->hostChannelCount = chans;

+        component->hostFormat = hostFormat;

+    }

+    else

+    {

+        component->hostFormat = master->hostFormat;

+        component->hostFrames = master->hostFrames;

+        component->hostChannelCount = master->hostChannelCount;

+        component->numBufs = master->numBufs;

+    }

+

+    PA_UNLESS( component->buffer = PaUtil_AllocateMemory( PaOssStreamComponent_BufferSize( component ) ),

+            paInsufficientMemory );

+

+error:

+    return result;

+}

+

+static PaError PaOssStreamComponent_Read( PaOssStreamComponent *component, unsigned long *frames )

+{

+    PaError result = paNoError;

+    size_t len = *frames * PaOssStreamComponent_FrameSize( component );

+    ssize_t bytesRead;

+

+    ENSURE_( bytesRead = read( component->fd, component->buffer, len ), paUnanticipatedHostError );

+    *frames = bytesRead / PaOssStreamComponent_FrameSize( component );

+

+error:

+    return result;

+}

+

+static PaError PaOssStreamComponent_Write( PaOssStreamComponent *component, unsigned long *frames )

+{

+    PaError result = paNoError;

+    size_t len = *frames * PaOssStreamComponent_FrameSize( component );

+    ssize_t bytesWritten;

+

+    ENSURE_( bytesWritten = write( component->fd, component->buffer, len ), paUnanticipatedHostError );

+    *frames = bytesWritten / PaOssStreamComponent_FrameSize( component );

+

+error:

+    return result;

+}

+

+/** Configure the stream according to input/output parameters.

+ *

+ * Aspect StreamChannels: The minimum number of channels supported by the device may exceed that requested by

+ * the user, if so we'll record the actual number of host channels and adapt later.

+ */

+static PaError PaOssStream_Configure( PaOssStream *stream, double sampleRate, unsigned long framesPerBuffer,

+        double *inputLatency, double *outputLatency )

+{

+    PaError result = paNoError;

+    int duplex = stream->capture && stream->playback;

+    unsigned long framesPerHostBuffer = 0;

+

+    /* We should request full duplex first thing after opening the device */

+    if( duplex && stream->sharedDevice )

+        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETDUPLEX, 0 ), paUnanticipatedHostError );

+

+    if( stream->capture )

+    {

+        PaOssStreamComponent *component = stream->capture;

+        PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_In, NULL );

+

+        assert( component->hostChannelCount > 0 );

+        assert( component->hostFrames > 0 );

+

+        *inputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate;

+    }

+    if( stream->playback )

+    {

+        PaOssStreamComponent *component = stream->playback, *master = stream->sharedDevice ? stream->capture : NULL;

+        PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_Out,

+                    master ) );

+

+        assert( component->hostChannelCount > 0 );

+        assert( component->hostFrames > 0 );

+

+        *outputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate;

+    }

+

+    if( duplex )

+        framesPerHostBuffer = PA_MIN( stream->capture->hostFrames, stream->playback->hostFrames );

+    else if( stream->capture )

+        framesPerHostBuffer = stream->capture->hostFrames;

+    else if( stream->playback )

+        framesPerHostBuffer = stream->playback->hostFrames;

+

+    stream->framesPerHostBuffer = framesPerHostBuffer;

+    stream->pollTimeout = (int) ceil( 1e6 * framesPerHostBuffer / sampleRate );    /* Period in usecs, rounded up */

+

+    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;

+

+error:

+    return result;

+}

+

+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */

+

+/** Open a PA OSS stream.

+ *

+ * Aspect StreamChannels: The number of channels is specified per direction (in/out), and can differ between the

+ * two. However, OSS doesn't support separate configuration spaces for capture and playback so if both

+ * directions are the same device we will demand the same number of channels. The number of channels can range

+ * from 1 to the maximum supported by the device.

+ *

+ * Aspect BufferSettings: If framesPerBuffer != paFramesPerBufferUnspecified the number of frames per callback

+ * must reflect this, in addition the host latency per device should approximate the corresponding

+ * suggestedLatency. Based on these constraints we need to determine a number of frames per host buffer that

+ * both capture and playback can agree on (they can be different devices), the buffer processor can adapt

+ * between host and user buffer size, but the ratio should preferably be integral.

+ */

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** s,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *streamCallback,

+                           void *userData )

+{

+    PaError result = paNoError;

+    PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;

+    PaOssStream *stream = NULL;

+    int inputChannelCount = 0, outputChannelCount = 0;

+    PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0, inputHostFormat = 0, outputHostFormat = 0;

+    const PaDeviceInfo *inputDeviceInfo = 0, *outputDeviceInfo = 0;

+    int bpInitialized = 0;

+    double inLatency, outLatency;

+

+    /* validate platform specific flags */

+    if( (streamFlags & paPlatformSpecificFlags) != 0 )

+        return paInvalidFlag; /* unexpected platform specific flag */

+

+    if( inputParameters )

+    {

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+        inputDeviceInfo = hostApi->deviceInfos[inputParameters->device];

+        PA_ENSURE( ValidateParameters( inputParameters, inputDeviceInfo, StreamMode_In ) );

+

+        inputChannelCount = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+    }

+    if( outputParameters )

+    {

+        outputDeviceInfo = hostApi->deviceInfos[outputParameters->device];

+        PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo, StreamMode_Out ) );

+

+        outputChannelCount = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+    }

+

+    /* Aspect StreamChannels: We currently demand that number of input and output channels are the same, if the same

+     * device is opened for both directions

+     */

+    if( inputChannelCount > 0 && outputChannelCount > 0 )

+    {

+        if( inputParameters->device == outputParameters->device )

+        {

+            if( inputParameters->channelCount != outputParameters->channelCount )

+                return paInvalidChannelCount;

+        }

+    }

+    

+    /* allocate and do basic initialization of the stream structure */

+    PA_UNLESS( stream = (PaOssStream*)PaUtil_AllocateMemory( sizeof(PaOssStream) ), paInsufficientMemory );

+    PaOssStream_Initialize( stream, inputParameters, outputParameters, streamCallback, userData, streamFlags, ossHostApi );

+

+    PA_ENSURE( PaOssStream_Configure( stream, sampleRate, framesPerBuffer, &inLatency, &outLatency ) );

+

+    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );

+        

+    if( inputParameters )

+    {

+        inputHostFormat = stream->capture->hostFormat;

+        stream->streamRepresentation.streamInfo.inputLatency = inLatency +

+            PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ) / sampleRate;

+    }

+    if( outputParameters )

+    {

+        outputHostFormat = stream->playback->hostFormat;

+        stream->streamRepresentation.streamInfo.outputLatency = outLatency +

+            PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ) / sampleRate;

+    }

+

+    /* Initialize buffer processor with fixed host buffer size.

+     * Aspect StreamSampleFormat: Here we commit the user and host sample formats, PA infrastructure will

+     * convert between the two.

+     */

+    PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,

+              inputChannelCount, inputSampleFormat, inputHostFormat, outputChannelCount, outputSampleFormat,

+              outputHostFormat, sampleRate, streamFlags, framesPerBuffer, stream->framesPerHostBuffer,

+              paUtilFixedHostBufferSize, streamCallback, userData ) );

+    bpInitialized = 1;

+

+    *s = (PaStream*)stream;

+

+    return result;

+

+error:

+    if( bpInitialized )

+        PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );

+    if( stream )

+        PaOssStream_Terminate( stream );

+

+    return result;

+}

+

+/*! Poll on I/O filedescriptors.

+

+  Poll till we've determined there's data for read or write. In the full-duplex case,

+  we don't want to hang around forever waiting for either input or output frames, so

+  whenever we have a timed out filedescriptor we check if we're nearing under/overrun

+  for the other direction (critical limit set at one buffer). If so, we exit the waiting

+  state, and go on with what we got. We align the number of frames on a host buffer

+  boundary because it is possible that the buffer size differs for the two directions and

+  the host buffer size is a compromise between the two.

+  */

+static PaError PaOssStream_WaitForFrames( PaOssStream *stream, unsigned long *frames )

+{

+    PaError result = paNoError;

+    int pollPlayback = 0, pollCapture = 0;

+    int captureAvail = INT_MAX, playbackAvail = INT_MAX, commonAvail;

+    audio_buf_info bufInfo;

+    /* int ofs = 0, nfds = stream->nfds; */

+    fd_set readFds, writeFds;

+    int nfds = 0;

+    struct timeval selectTimeval = {0, 0};

+    unsigned long timeout = stream->pollTimeout;    /* In usecs */

+    int captureFd = -1, playbackFd = -1;

+

+    assert( stream );

+    assert( frames );

+

+    if( stream->capture )

+    {

+        pollCapture = 1;

+        captureFd = stream->capture->fd;

+        /* stream->capture->pfd->events = POLLIN; */

+    }

+    if( stream->playback )

+    {

+        pollPlayback = 1;

+        playbackFd = stream->playback->fd;

+        /* stream->playback->pfd->events = POLLOUT; */

+    }

+

+    FD_ZERO( &readFds );

+    FD_ZERO( &writeFds );

+

+    while( pollPlayback || pollCapture )

+    {

+        pthread_testcancel();

+

+        /* select may modify the timeout parameter */

+        selectTimeval.tv_usec = timeout;

+        nfds = 0;

+

+        if( pollCapture )

+        {

+            FD_SET( captureFd, &readFds );

+            nfds = captureFd + 1;

+        }

+        if( pollPlayback )

+        {

+            FD_SET( playbackFd, &writeFds );

+            nfds = PA_MAX( nfds, playbackFd + 1 );

+        }

+        ENSURE_( select( nfds, &readFds, &writeFds, NULL, &selectTimeval ), paUnanticipatedHostError );

+        /*

+        if( poll( stream->pfds + ofs, nfds, stream->pollTimeout ) < 0 )

+        {

+

+            ENSURE_( -1, paUnanticipatedHostError );

+        }

+        */

+        pthread_testcancel();

+

+        if( pollCapture )

+        {

+            if( FD_ISSET( captureFd, &readFds ) )

+            {

+                FD_CLR( captureFd, &readFds );

+                pollCapture = 0;

+            }

+            /*

+            if( stream->capture->pfd->revents & POLLIN )

+            {

+                --nfds;

+                ++ofs;

+                pollCapture = 0;

+            }

+            */

+            else if( stream->playback ) /* Timed out, go on with playback? */ 

+            {

+                /*PA_DEBUG(( "%s: Trying to poll again for capture frames, pollTimeout: %d\n",

+                            __FUNCTION__, stream->pollTimeout ));*/

+            }

+        }

+        if( pollPlayback )

+        {

+            if( FD_ISSET( playbackFd, &writeFds ) )

+            {

+                FD_CLR( playbackFd, &writeFds );

+                pollPlayback = 0;

+            }

+            /*

+            if( stream->playback->pfd->revents & POLLOUT )

+            {

+                --nfds;

+                pollPlayback = 0;

+            }

+            */

+            else if( stream->capture )  /* Timed out, go on with capture? */

+            {

+                /*PA_DEBUG(( "%s: Trying to poll again for playback frames, pollTimeout: %d\n\n",

+                            __FUNCTION__, stream->pollTimeout ));*/

+            }

+        }

+    }

+

+    if( stream->capture )

+    {

+        ENSURE_( ioctl( captureFd, SNDCTL_DSP_GETISPACE, &bufInfo ), paUnanticipatedHostError );

+        captureAvail = bufInfo.fragments * stream->capture->hostFrames;

+        if( !captureAvail )

+            PA_DEBUG(( "%s: captureAvail: 0\n", __FUNCTION__ ));

+

+        captureAvail = captureAvail == 0 ? INT_MAX : captureAvail;      /* Disregard if zero */

+    }

+    if( stream->playback )

+    {

+        ENSURE_( ioctl( playbackFd, SNDCTL_DSP_GETOSPACE, &bufInfo ), paUnanticipatedHostError );

+        playbackAvail = bufInfo.fragments * stream->playback->hostFrames;

+        if( !playbackAvail )

+        {

+            PA_DEBUG(( "%s: playbackAvail: 0\n", __FUNCTION__ ));

+        }

+

+        playbackAvail = playbackAvail == 0 ? INT_MAX : playbackAvail;      /* Disregard if zero */

+    }

+

+    commonAvail = PA_MIN( captureAvail, playbackAvail );

+    if( commonAvail == INT_MAX )

+        commonAvail = 0;

+    commonAvail -= commonAvail % stream->framesPerHostBuffer;

+

+    assert( commonAvail != INT_MAX );

+    assert( commonAvail >= 0 );

+    *frames = commonAvail;

+

+error:

+    return result;

+}

+

+/** Prepare stream for capture/playback.

+ *

+ * In order to synchronize capture and playback properly we use the SETTRIGGER command.

+ */

+static PaError PaOssStream_Prepare( PaOssStream *stream )

+{

+    PaError result = paNoError;

+    int enableBits = 0;

+

+    if( stream->triggered )

+        return result;

+

+    if( stream->playback )

+    {

+        size_t bufSz = PaOssStreamComponent_BufferSize( stream->playback );

+        memset( stream->playback->buffer, 0, bufSz );

+

+        /* Looks like we have to turn off blocking before we try this, but if we don't fill the buffer

+         * OSS will complain. */

+        PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );

+        while (1)

+        {

+            if( write( stream->playback->fd, stream->playback->buffer, bufSz ) < 0 )

+                break;

+        }

+        PA_ENSURE( ModifyBlocking( stream->playback->fd, 1 ) );

+    }

+

+    if( stream->sharedDevice )

+    {

+        enableBits = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;

+        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );

+    }

+    else

+    {

+        if( stream->capture )

+        {

+            enableBits = PCM_ENABLE_INPUT;

+            ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );

+        }

+        if( stream->playback )

+        {

+            enableBits = PCM_ENABLE_OUTPUT;

+            ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );

+        }

+    }

+

+    /* Ok, we have triggered the stream */

+    stream->triggered = 1;

+    

+error:

+    return result;

+}

+

+/** Stop audio processing

+ *

+ */

+static PaError PaOssStream_Stop( PaOssStream *stream, int abort )

+{

+    PaError result = paNoError;

+

+    /* Looks like the only safe way to stop audio without reopening the device is SNDCTL_DSP_POST.

+     * Also disable capture/playback till the stream is started again */

+    if( stream->capture )

+    {

+        ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError );

+    }

+    if( stream->playback && !stream->sharedDevice )

+    {

+        ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError );

+    }

+

+error:

+    return result;

+}

+

+/** Clean up after thread exit.

+ *

+ * Aspect StreamState: If the user has registered a streamFinishedCallback it will be called here

+ */

+static void OnExit( void *data )

+{

+    PaOssStream *stream = (PaOssStream *) data;

+    assert( data );

+

+    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );

+

+    PaOssStream_Stop( stream, stream->callbackAbort );

+    

+    PA_DEBUG(( "OnExit: Stoppage\n" ));

+

+    /* Eventually notify user all buffers have played */

+    if( stream->streamRepresentation.streamFinishedCallback )

+        stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );

+

+    stream->callbackAbort = 0;      /* Clear state */

+    stream->isActive = 0;

+}

+

+static PaError SetUpBuffers( PaOssStream *stream, unsigned long framesAvail )

+{

+    PaError result = paNoError;

+

+    if( stream->capture )

+    {

+        PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer,

+                stream->capture->hostChannelCount );

+        PaUtil_SetInputFrameCount( &stream->bufferProcessor, framesAvail );

+    }

+    if( stream->playback )

+    {

+        PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer,

+                stream->playback->hostChannelCount );

+        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, framesAvail );

+    }

+

+    return result;

+}

+

+/** Thread procedure for callback processing.

+ *

+ * Aspect StreamState: StartStream will wait on this to initiate audio processing, useful in case the

+ * callback should be used for buffer priming. When the stream is cancelled a separate function will

+ * take care of the transition to the Callback Finished state (the stream isn't considered Stopped

+ * before StopStream() or AbortStream() are called).

+ */

+static void *PaOSS_AudioThreadProc( void *userData )

+{

+    PaError result = paNoError;

+    PaOssStream *stream = (PaOssStream*)userData;

+    unsigned long framesAvail, framesProcessed;

+    int callbackResult = paContinue;

+    int triggered = stream->triggered;  /* See if SNDCTL_DSP_TRIGGER has been issued already */

+    int initiateProcessing = triggered;    /* Already triggered? */

+    PaStreamCallbackFlags cbFlags = 0;  /* We might want to keep state across iterations */

+    

+    /*

+#if ( SOUND_VERSION > 0x030904 )

+        audio_errinfo errinfo;

+#endif

+*/

+    

+    assert( stream );

+

+    pthread_cleanup_push( &OnExit, stream );	/* Execute OnExit when exiting */

+

+    /* The first time the stream is started we use SNDCTL_DSP_TRIGGER to accurately start capture and

+     * playback in sync, when the stream is restarted after being stopped we simply start by reading/

+     * writing.

+     */

+    PA_ENSURE( PaOssStream_Prepare( stream ) );

+

+    /* If we are to initiate processing implicitly by reading/writing data, we start off in blocking mode */

+    if( initiateProcessing )

+    {

+        /* Make sure devices are in blocking mode */

+        if( stream->capture )

+            ModifyBlocking( stream->capture->fd, 1 );

+        if( stream->playback )

+            ModifyBlocking( stream->playback->fd, 1 );

+    }

+

+    while( 1 )

+    {

+        PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */

+

+        pthread_testcancel();

+

+        if( stream->callbackStop && callbackResult == paContinue )

+        {

+            PA_DEBUG(( "Setting callbackResult to paComplete\n" ));

+            callbackResult = paComplete;

+        }

+

+        /* Aspect StreamState: Because of the messy OSS scheme we can't explicitly trigger device start unless

+         * the stream has been recently started, we will have to go right ahead and read/write in blocking

+         * fashion to trigger operation. Therefore we begin with processing one host buffer before we switch

+         * to non-blocking mode.

+         */

+        if( !initiateProcessing )

+        {

+            PA_ENSURE( PaOssStream_WaitForFrames( stream, &framesAvail ) );  /* Wait on available frames */

+            assert( framesAvail % stream->framesPerHostBuffer == 0 );

+        }

+        else

+        {

+            framesAvail = stream->framesPerHostBuffer;

+        }

+

+        while( framesAvail > 0 )

+        {

+            unsigned long frames = framesAvail;

+

+            pthread_testcancel();

+

+            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

+

+            /* Read data */

+            if ( stream->capture )

+            {

+                PA_ENSURE( PaOssStreamComponent_Read( stream->capture, &frames ) );

+                assert( frames == framesAvail );

+            }

+

+#if ( SOUND_VERSION >= 0x030904 )

+            /*

+               Check with OSS to see if there have been any under/overruns

+               since last time we checked.

+               */

+            /*

+            if( ioctl( stream->deviceHandle, SNDCTL_DSP_GETERROR, &errinfo ) >= 0 )

+            {

+                if( errinfo.play_underruns )

+                    cbFlags |= paOutputUnderflow ;

+                if( errinfo.record_underruns )

+                    cbFlags |= paInputUnderflow ;

+            }

+            else

+                PA_DEBUG(( "SNDCTL_DSP_GETERROR command failed: %s\n", strerror( errno ) ));

+                */

+#endif

+

+            PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,

+                    cbFlags );

+            cbFlags = 0;

+            PA_ENSURE( SetUpBuffers( stream, framesAvail ) );

+

+            framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,

+                    &callbackResult );

+            assert( framesProcessed == framesAvail );

+            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );

+

+            if ( stream->playback )

+            {

+                frames = framesAvail;

+

+                PA_ENSURE( PaOssStreamComponent_Write( stream->playback, &frames ) );

+                assert( frames == framesAvail );

+

+                /* TODO: handle bytesWritten != bytesRequested (slippage?) */

+            }

+

+            framesAvail -= framesProcessed;

+            stream->framesProcessed += framesProcessed;

+

+            if( callbackResult != paContinue )

+                break;

+        }

+

+        if( initiateProcessing || !triggered )

+        {

+            /* Non-blocking */

+            if( stream->capture )

+                PA_ENSURE( ModifyBlocking( stream->capture->fd, 0 ) );

+            if( stream->playback && !stream->sharedDevice )

+                PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );

+

+            initiateProcessing = 0;

+            sem_post( &stream->semaphore );

+        }

+

+        if( callbackResult != paContinue )

+        {

+            stream->callbackAbort = callbackResult == paAbort;

+            if( stream->callbackAbort || PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )

+                break;

+        }

+    }

+

+    pthread_cleanup_pop( 1 );

+

+error:

+    pthread_exit( NULL );

+}

+

+/** Close the stream.

+ *

+ */

+static PaError CloseStream( PaStream* s )

+{

+    PaError result = paNoError;

+    PaOssStream *stream = (PaOssStream*)s;

+

+    assert( stream );

+

+    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );

+    PaOssStream_Terminate( stream );

+

+    return result;

+}

+

+/** Start the stream.

+ *

+ * Aspect StreamState: After returning, the stream shall be in the Active state, implying that an eventual

+ * callback will be repeatedly called in a separate thread. If a separate thread is started this function

+ * will block untill it has started processing audio, otherwise audio processing is started directly.

+ */

+static PaError StartStream( PaStream *s )

+{

+    PaError result = paNoError;

+    PaOssStream *stream = (PaOssStream*)s;

+

+    stream->isActive = 1;

+    stream->isStopped = 0;

+    stream->lastPosPtr = 0;

+    stream->lastStreamBytes = 0;

+    stream->framesProcessed = 0;

+

+    /* only use the thread for callback streams */

+    if( stream->bufferProcessor.streamCallback )

+    {

+        PA_ENSURE( PaUtil_StartThreading( &stream->threading, &PaOSS_AudioThreadProc, stream ) );

+        sem_wait( &stream->semaphore );

+    }

+    else

+        PA_ENSURE( PaOssStream_Prepare( stream ) );

+

+error:

+    return result;

+}

+

+static PaError RealStop( PaOssStream *stream, int abort )

+{

+    PaError result = paNoError;

+

+    if( stream->callbackMode )

+    {

+        if( abort )

+            stream->callbackAbort = 1;

+        else

+            stream->callbackStop = 1;

+

+        PA_ENSURE( PaUtil_CancelThreading( &stream->threading, !abort, NULL ) );

+

+        stream->callbackStop = stream->callbackAbort = 0;

+    }

+    else

+        PA_ENSURE( PaOssStream_Stop( stream, abort ) );

+

+    stream->isStopped = 1;

+

+error:

+    return result;

+}

+

+/** Stop the stream.

+ *

+ * Aspect StreamState: This will cause the stream to transition to the Stopped state, playing all enqueued

+ * buffers.

+ */

+static PaError StopStream( PaStream *s )

+{

+    return RealStop( (PaOssStream *)s, 0 );

+}

+

+/** Abort the stream.

+ *

+ * Aspect StreamState: This will cause the stream to transition to the Stopped state, discarding all enqueued

+ * buffers. Note that the buffers are not currently correctly discarded, this is difficult without closing

+ * the OSS device.

+ */

+static PaError AbortStream( PaStream *s )

+{

+    return RealStop( (PaOssStream *)s, 1 );

+}

+

+/** Is the stream in the Stopped state.

+ *

+ */

+static PaError IsStreamStopped( PaStream *s )

+{

+    PaOssStream *stream = (PaOssStream*)s;

+

+    return (stream->isStopped);

+}

+

+/** Is the stream in the Active state.

+ *

+ */

+static PaError IsStreamActive( PaStream *s )

+{

+    PaOssStream *stream = (PaOssStream*)s;

+

+    return (stream->isActive);

+}

+

+static PaTime GetStreamTime( PaStream *s )

+{

+    PaOssStream *stream = (PaOssStream*)s;

+    count_info info;

+    int delta;

+

+    if( stream->playback ) {

+        if( ioctl( stream->playback->fd, SNDCTL_DSP_GETOPTR, &info) == 0 ) {

+            delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF;

+            return ( stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->playback ) / stream->sampleRate;

+        }

+    }

+    else {

+        if (ioctl( stream->capture->fd, SNDCTL_DSP_GETIPTR, &info) == 0) {

+            delta = (info.bytes - stream->lastPosPtr) & 0x000FFFFF;

+            return ( stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->capture ) / stream->sampleRate;

+        }

+    }

+

+    /* the ioctl failed, but we can still give a coarse estimate */

+

+    return stream->framesProcessed / stream->sampleRate;

+}

+

+

+static double GetStreamCpuLoad( PaStream* s )

+{

+    PaOssStream *stream = (PaOssStream*)s;

+

+    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );

+}

+

+

+/*

+    As separate stream interfaces are used for blocking and callback

+    streams, the following functions can be guaranteed to only be called

+    for blocking streams.

+*/

+

+

+static PaError ReadStream( PaStream* s,

+                           void *buffer,

+                           unsigned long frames )

+{

+    PaOssStream *stream = (PaOssStream*)s;

+    int bytesRequested, bytesRead;

+    unsigned long framesRequested;

+    void *userBuffer;

+

+    /* If user input is non-interleaved, PaUtil_CopyInput will manipulate the channel pointers,

+     * so we copy the user provided pointers */

+    if( stream->bufferProcessor.userInputIsInterleaved )

+        userBuffer = buffer;

+    else /* Copy channels into local array */

+    {

+        userBuffer = stream->capture->userBuffers;

+        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->capture->userChannelCount );

+    }

+

+    while( frames )

+    {

+        framesRequested = PA_MIN( frames, stream->capture->hostFrames );

+

+	bytesRequested = framesRequested * PaOssStreamComponent_FrameSize( stream->capture );

+	bytesRead = read( stream->capture->fd, stream->capture->buffer, bytesRequested );

+	if ( bytesRequested != bytesRead )

+	    return paUnanticipatedHostError;

+

+	PaUtil_SetInputFrameCount( &stream->bufferProcessor, stream->capture->hostFrames );

+	PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer, stream->capture->hostChannelCount );

+        PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesRequested );

+	frames -= framesRequested;

+    }

+    return paNoError;

+}

+

+

+static PaError WriteStream( PaStream* s,

+                            const void *buffer,

+                            unsigned long frames )

+{

+    PaOssStream *stream = (PaOssStream*)s;

+    int bytesRequested, bytesWritten;

+    unsigned long framesConverted;

+    const void *userBuffer;

+

+    /* If user output is non-interleaved, PaUtil_CopyOutput will manipulate the channel pointers,

+     * so we copy the user provided pointers */

+    if( stream->bufferProcessor.userOutputIsInterleaved )

+        userBuffer = buffer;

+    else /* Copy channels into local array */

+    {

+        userBuffer = stream->playback->userBuffers;

+        memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback->userChannelCount );

+    }

+

+    while( frames )

+    {

+	PaUtil_SetOutputFrameCount( &stream->bufferProcessor, stream->playback->hostFrames );

+	PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer, stream->playback->hostChannelCount );

+

+	framesConverted = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames );

+	frames -= framesConverted;

+

+	bytesRequested = framesConverted * PaOssStreamComponent_FrameSize( stream->playback );

+	bytesWritten = write( stream->playback->fd, stream->playback->buffer, bytesRequested );

+

+	if ( bytesRequested != bytesWritten )

+	    return paUnanticipatedHostError;

+    }

+    return paNoError;

+}

+

+

+static signed long GetStreamReadAvailable( PaStream* s )

+{

+    PaOssStream *stream = (PaOssStream*)s;

+    audio_buf_info info;

+

+    if( ioctl( stream->capture->fd, SNDCTL_DSP_GETISPACE, &info ) < 0 )

+        return paUnanticipatedHostError;

+    return info.fragments * stream->capture->hostFrames;

+}

+

+

+/* TODO: Compute number of allocated bytes somewhere else, can we use ODELAY with capture */

+static signed long GetStreamWriteAvailable( PaStream* s )

+{

+    PaOssStream *stream = (PaOssStream*)s;

+    int delay = 0;

+

+    if( ioctl( stream->playback->fd, SNDCTL_DSP_GETODELAY, &delay ) < 0 )

+        return paUnanticipatedHostError;

+    

+    return (PaOssStreamComponent_BufferSize( stream->playback ) - delay) / PaOssStreamComponent_FrameSize( stream->playback );

+}

+

diff --git a/pjmedia/src/pjmedia/portaudio/pa_unix_util.c b/pjmedia/src/pjmedia/portaudio/pa_unix_util.c
index f45848f..55f83f7 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_unix_util.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_unix_util.c
@@ -1,175 +1,196 @@
-/*
- * $Id: pa_unix_util.c,v 1.1.2.7 2005/03/31 15:02:48 aknudsen Exp $
- * Portable Audio I/O Library
- * UNIX platform-specific support functions
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
- 
-#include <pthread.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <assert.h>
-#include <string.h> /* For memset */
-
-#include "pa_util.h"
-#include "pa_unix_util.h"
-
-/*
-   Track memory allocations to avoid leaks.
- */
-
-#if PA_TRACK_MEMORY
-static int numAllocations_ = 0;
-#endif
-
-
-void *PaUtil_AllocateMemory( long size )
-{
-    void *result = malloc( size );
-
-#if PA_TRACK_MEMORY
-    if( result != NULL ) numAllocations_ += 1;
-#endif
-    return result;
-}
-
-
-void PaUtil_FreeMemory( void *block )
-{
-    if( block != NULL )
-    {
-        free( block );
-#if PA_TRACK_MEMORY
-        numAllocations_ -= 1;
-#endif
-
-    }
-}
-
-
-int PaUtil_CountCurrentlyAllocatedBlocks( void )
-{
-#if PA_TRACK_MEMORY
-    return numAllocations_;
-#else
-    return 0;
-#endif
-}
-
-
-void Pa_Sleep( long msec )
-{
-    while( msec > 999 )     /* For OpenBSD and IRIX, argument */
-        {                   /* to usleep must be < 1000000.   */
-        usleep( 999000 );
-        msec -= 999;
-        }
-    usleep( msec * 1000 );
-}
-
-/*            *** NOT USED YET: ***
-static int usePerformanceCounter_;
-static double microsecondsPerTick_;
-*/
-
-void PaUtil_InitializeClock( void )
-{
-    /* TODO */
-}
-
-
-PaTime PaUtil_GetTime( void )
-{
-    struct timeval tv;
-    gettimeofday( &tv, NULL );
-    return (PaTime) tv.tv_usec / 1000000. + tv.tv_sec;
-}
-
-PaError PaUtil_InitializeThreading( PaUtilThreading *threading )
-{
-    (void) paUtilErr_;
-    return paNoError;
-}
-
-void PaUtil_TerminateThreading( PaUtilThreading *threading )
-{
-}
-
-PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data )
-{
-    pthread_create( &threading->callbackThread, NULL, threadRoutine, data );
-    return paNoError;
-}
-
-PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult )
-{
-    PaError result = paNoError;
-    void *pret;
-
-    if( exitResult )
-        *exitResult = paNoError;
-
-    /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
-    if( !wait )
-        pthread_cancel( threading->callbackThread );   /* XXX: Safe to call this if the thread has exited on its own? */
-    pthread_join( threading->callbackThread, &pret );
-
-#ifdef PTHREAD_CANCELED
-    if( pret && PTHREAD_CANCELED != pret )
-#else
-    /* !wait means the thread may have been canceled */
-    if( pret && wait )
-#endif
-    {
-        if( exitResult )
-            *exitResult = *(PaError *) pret;
-        free( pret );
-    }
-
-    return result;
-}
-
-/*
-static void *CanaryFunc( void *userData )
-{
-    const unsigned intervalMsec = 1000;
-    PaUtilThreading *th = (PaUtilThreading *) userData;
-
-    while( 1 )
-    {
-        th->canaryTime = PaUtil_GetTime();
-
-        pthread_testcancel();
-        Pa_Sleep( intervalMsec );
-    }
-
-    pthread_exit( NULL );
-}
-*/
+/*

+ * $Id: pa_unix_util.c,v 1.1.2.7 2005/03/31 15:02:48 aknudsen Exp $

+ * Portable Audio I/O Library

+ * UNIX platform-specific support functions

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2000 Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+ 

+#include <pthread.h>

+#include <unistd.h>

+#include <stdlib.h>

+#include <sys/time.h>

+#include <assert.h>

+#include <string.h> /* For memset */

+

+#include "pa_util.h"

+#include "pa_unix_util.h"

+

+/*

+   Track memory allocations to avoid leaks.

+ */

+

+#if PA_TRACK_MEMORY

+static int numAllocations_ = 0;

+#endif

+

+

+void *PaUtil_AllocateMemory( long size )

+{

+    void *result = malloc( size );

+

+#if PA_TRACK_MEMORY

+    if( result != NULL ) numAllocations_ += 1;

+#endif

+    return result;

+}

+

+

+void PaUtil_FreeMemory( void *block )

+{

+    if( block != NULL )

+    {

+        free( block );

+#if PA_TRACK_MEMORY

+        numAllocations_ -= 1;

+#endif

+

+    }

+}

+

+

+int PaUtil_CountCurrentlyAllocatedBlocks( void )

+{

+#if PA_TRACK_MEMORY

+    return numAllocations_;

+#else

+    return 0;

+#endif

+}

+

+

+void Pa_Sleep( long msec )

+{

+    while( msec > 999 )     /* For OpenBSD and IRIX, argument */

+        {                   /* to usleep must be < 1000000.   */

+        usleep( 999000 );

+        msec -= 999;

+        }

+    usleep( msec * 1000 );

+}

+

+/*            *** NOT USED YET: ***

+static int usePerformanceCounter_;

+static double microsecondsPerTick_;

+*/

+

+void PaUtil_InitializeClock( void )

+{

+    /* TODO */

+}

+

+

+PaTime PaUtil_GetTime( void )

+{

+    struct timeval tv;

+    gettimeofday( &tv, NULL );

+    return (PaTime) tv.tv_usec / 1000000. + tv.tv_sec;

+}

+

+PaError PaUtil_InitializeThreading( PaUtilThreading *threading )

+{

+    (void) paUtilErr_;

+    return paNoError;

+}

+

+void PaUtil_TerminateThreading( PaUtilThreading *threading )

+{

+}

+

+PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data )

+{

+    pthread_create( &threading->callbackThread, NULL, threadRoutine, data );

+    return paNoError;

+}

+

+PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult )

+{

+    PaError result = paNoError;

+    void *pret;

+

+    if( exitResult )

+        *exitResult = paNoError;

+

+    /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */

+    if( !wait )

+        pthread_cancel( threading->callbackThread );   /* XXX: Safe to call this if the thread has exited on its own? */

+    pthread_join( threading->callbackThread, &pret );

+

+#ifdef PTHREAD_CANCELED

+    if( pret && PTHREAD_CANCELED != pret )

+#else

+    /* !wait means the thread may have been canceled */

+    if( pret && wait )

+#endif

+    {

+        if( exitResult )

+            *exitResult = *(PaError *) pret;

+        free( pret );

+    }

+

+    return result;

+}

+

+/*

+static void *CanaryFunc( void *userData )

+{

+    const unsigned intervalMsec = 1000;

+    PaUtilThreading *th = (PaUtilThreading *) userData;

+

+    while( 1 )

+    {

+        th->canaryTime = PaUtil_GetTime();

+

+        pthread_testcancel();

+        Pa_Sleep( intervalMsec );

+    }

+

+    pthread_exit( NULL );

+}

+*/

diff --git a/pjmedia/src/pjmedia/portaudio/pa_unix_util.h b/pjmedia/src/pjmedia/portaudio/pa_unix_util.h
index 01dda01..c51f3bb 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_unix_util.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_unix_util.h
@@ -1,73 +1,94 @@
-#ifndef PA_UNIX_UTIL_H
-#define PA_UNIX_UTIL_H
-
-#include "pa_cpuload.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-#define PA_MIN(x,y) ( (x) < (y) ? (x) : (y) )
-#define PA_MAX(x,y) ( (x) > (y) ? (x) : (y) )
-
-/* Utilize GCC branch prediction for error tests */
-#if defined __GNUC__ && __GNUC__ >= 3
-#define UNLIKELY(expr) __builtin_expect( (expr), 0 )
-#else
-#define UNLIKELY(expr) (expr)
-#endif
-
-#define STRINGIZE_HELPER(expr) #expr
-#define STRINGIZE(expr) STRINGIZE_HELPER(expr)
-
-#define PA_UNLESS(expr, code) \
-    do { \
-        if( UNLIKELY( (expr) == 0 ) ) \
-        { \
-            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
-            result = (code); \
-            goto error; \
-        } \
-    } while (0);
-
-static PaError paUtilErr_;          /* Used with PA_ENSURE */
-
-/* Check PaError */
-#define PA_ENSURE(expr) \
-    do { \
-        if( UNLIKELY( (paUtilErr_ = (expr)) < paNoError ) ) \
-        { \
-            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
-            result = paUtilErr_; \
-            goto error; \
-        } \
-    } while (0);
-
-typedef struct {
-    pthread_t callbackThread;
-} PaUtilThreading;
-
-PaError PaUtil_InitializeThreading( PaUtilThreading *threading );
-void PaUtil_TerminateThreading( PaUtilThreading *threading );
-PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data );
-PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult );
-
-/* State accessed by utility functions */
-
-/*
-void PaUnix_SetRealtimeScheduling( int rt );
-
-void PaUtil_InitializeThreading( PaUtilThreading *th, PaUtilCpuLoadMeasurer *clm );
-
-PaError PaUtil_CreateCallbackThread( PaUtilThreading *th, void *(*CallbackThreadFunc)( void * ), PaStream *s );
-
-PaError PaUtil_KillCallbackThread( PaUtilThreading *th, PaError *exitResult );
-
-void PaUtil_CallbackUpdate( PaUtilThreading *th );
-*/
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_UNIX_UTIL_H

+#define PA_UNIX_UTIL_H

+

+#include "pa_cpuload.h"

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+#define PA_MIN(x,y) ( (x) < (y) ? (x) : (y) )

+#define PA_MAX(x,y) ( (x) > (y) ? (x) : (y) )

+

+/* Utilize GCC branch prediction for error tests */

+#if defined __GNUC__ && __GNUC__ >= 3

+#define UNLIKELY(expr) __builtin_expect( (expr), 0 )

+#else

+#define UNLIKELY(expr) (expr)

+#endif

+

+#define STRINGIZE_HELPER(expr) #expr

+#define STRINGIZE(expr) STRINGIZE_HELPER(expr)

+

+#define PA_UNLESS(expr, code) \

+    do { \

+        if( UNLIKELY( (expr) == 0 ) ) \

+        { \

+            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \

+            result = (code); \

+            goto error; \

+        } \

+    } while (0);

+

+static PaError paUtilErr_;          /* Used with PA_ENSURE */

+

+/* Check PaError */

+#define PA_ENSURE(expr) \

+    do { \

+        if( UNLIKELY( (paUtilErr_ = (expr)) < paNoError ) ) \

+        { \

+            PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \

+            result = paUtilErr_; \

+            goto error; \

+        } \

+    } while (0);

+

+typedef struct {

+    pthread_t callbackThread;

+} PaUtilThreading;

+

+PaError PaUtil_InitializeThreading( PaUtilThreading *threading );

+void PaUtil_TerminateThreading( PaUtilThreading *threading );

+PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data );

+PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult );

+

+/* State accessed by utility functions */

+

+/*

+void PaUnix_SetRealtimeScheduling( int rt );

+

+void PaUtil_InitializeThreading( PaUtilThreading *th, PaUtilCpuLoadMeasurer *clm );

+

+PaError PaUtil_CreateCallbackThread( PaUtilThreading *th, void *(*CallbackThreadFunc)( void * ), PaStream *s );

+

+PaError PaUtil_KillCallbackThread( PaUtilThreading *th, PaError *exitResult );

+

+void PaUtil_CallbackUpdate( PaUtilThreading *th );

+*/

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif

diff --git a/pjmedia/src/pjmedia/portaudio/pa_util.h b/pjmedia/src/pjmedia/portaudio/pa_util.h
index 149fbca..a311d7e 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_util.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_util.h
@@ -1,167 +1,188 @@
-#ifndef PA_UTIL_H
-#define PA_UTIL_H
-/*
- * $Id: pa_util.h,v 1.1.2.12 2003/09/20 21:09:55 rossbencina Exp $
- * Portable Audio I/O Library implementation utilities header
- * common implementation utilities and interfaces
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
-    @brief Prototypes for utility functions used by PortAudio implementations.
-
-    @todo Document and adhere to the alignment guarantees provided by
-    PaUtil_AllocateMemory().
-*/
-
-
-#include "portaudio.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-struct PaUtilHostApiRepresentation;
-
-
-/** Retrieve a specific host API representation. This function can be used
- by implementations to retrieve a pointer to their representation in
- host api specific extension functions which aren't passed a rep pointer
- by pa_front.c.
-
- @param hostApi A pointer to a host API represenation pointer. Apon success
- this will receive the requested representation pointer.
-
- @param type A valid host API type identifier.
-
- @returns An error code. If the result is PaNoError then a pointer to the
- requested host API representation will be stored in *hostApi. If the host API
- specified by type is not found, this function returns paHostApiNotFound.
-*/
-PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,
-        PaHostApiTypeId type );
-
-
-/** Convert a PortAudio device index into a host API specific device index.
- @param hostApiDevice Pointer to a device index, on success this will recieve the
- converted device index value.
- @param device The PortAudio device index to convert.
- @param hostApi The host api which the index should be converted for.
-
- @returns On success returns PaNoError and places the converted index in the
- hostApiDevice parameter.
-*/
-PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
-        PaDeviceIndex *hostApiDevice, PaDeviceIndex device,
-        struct PaUtilHostApiRepresentation *hostApi );
-
-
-/** Set the host error information returned by Pa_GetLastHostErrorInfo. This
- function and the paUnanticipatedHostError error code should be used as a
- last resort.  Implementors should use existing PA error codes where possible,
- or nominate new ones. Note that at it is always better to use
- PaUtil_SetLastHostErrorInfo() and paUnanticipatedHostError than to return an
- ambiguous or inaccurate PaError code.
-
- @param hostApiType  The host API which encountered the error (ie of the caller)
-
- @param errorCode The error code returned by the native API function.
-
- @param errorText A string describing the error. PaUtil_SetLastHostErrorInfo
- makes a copy of the string, so it is not necessary for the pointer to remain
- valid after the call to PaUtil_SetLastHostErrorInfo() returns.
-
-*/
-void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
-        const char *errorText );
-
-
-        
-/** PA_DEBUG() provides a simple debug message printing facility. The macro
- passes it's argument to a printf-like function called PaUtil_DebugPrint()
- which prints to stderr and always flushes the stream after printing.
- Because preprocessor macros cannot directly accept variable length argument
- lists, calls to the macro must include an additional set of parenthesis, eg:
- PA_DEBUG(("errorno: %d", 1001 ));
-*/
-
-void PaUtil_DebugPrint( const char *format, ... );
-
-#if (0) /* set to 1 to print debug messages */
-#define PA_DEBUG(x) PaUtil_DebugPrint x ;
-#else
-#define PA_DEBUG(x)
-#endif
-
-
-/* the following functions are implemented in a platform platform specific
- .c file
-*/
-
-/** Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */
-void *PaUtil_AllocateMemory( long size );
-
-
-/** Realease block if non-NULL. block may be NULL */
-void PaUtil_FreeMemory( void *block );
-
-
-/** Return the number of currently allocated blocks. This function can be
- used for detecting memory leaks.
-
- @note Allocations will only be tracked if PA_TRACK_MEMORY is #defined. If
- it isn't, this function will always return 0.
-*/
-int PaUtil_CountCurrentlyAllocatedBlocks( void );
-
-
-/** Initialize the clock used by PaUtil_GetTime(). Call this before calling
- PaUtil_GetTime.
-
- @see PaUtil_GetTime
-*/
-void PaUtil_InitializeClock( void );
-
-
-/** Return the system time in seconds. Used to implement CPU load functions
-
- @see PaUtil_InitializeClock
-*/
-double PaUtil_GetTime( void );
-
-
-/* void Pa_Sleep( long msec );  must also be implemented in per-platform .c file */
-
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_UTIL_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_UTIL_H

+#define PA_UTIL_H

+/*

+ * $Id: pa_util.h,v 1.1.2.12 2003/09/20 21:09:55 rossbencina Exp $

+ * Portable Audio I/O Library implementation utilities header

+ * common implementation utilities and interfaces

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+    @brief Prototypes for utility functions used by PortAudio implementations.

+

+    @todo Document and adhere to the alignment guarantees provided by

+    PaUtil_AllocateMemory().

+*/

+

+

+#include "portaudio.h"

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+struct PaUtilHostApiRepresentation;

+

+

+/** Retrieve a specific host API representation. This function can be used

+ by implementations to retrieve a pointer to their representation in

+ host api specific extension functions which aren't passed a rep pointer

+ by pa_front.c.

+

+ @param hostApi A pointer to a host API represenation pointer. Apon success

+ this will receive the requested representation pointer.

+

+ @param type A valid host API type identifier.

+

+ @returns An error code. If the result is PaNoError then a pointer to the

+ requested host API representation will be stored in *hostApi. If the host API

+ specified by type is not found, this function returns paHostApiNotFound.

+*/

+PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,

+        PaHostApiTypeId type );

+

+

+/** Convert a PortAudio device index into a host API specific device index.

+ @param hostApiDevice Pointer to a device index, on success this will recieve the

+ converted device index value.

+ @param device The PortAudio device index to convert.

+ @param hostApi The host api which the index should be converted for.

+

+ @returns On success returns PaNoError and places the converted index in the

+ hostApiDevice parameter.

+*/

+PaError PaUtil_DeviceIndexToHostApiDeviceIndex(

+        PaDeviceIndex *hostApiDevice, PaDeviceIndex device,

+        struct PaUtilHostApiRepresentation *hostApi );

+

+

+/** Set the host error information returned by Pa_GetLastHostErrorInfo. This

+ function and the paUnanticipatedHostError error code should be used as a

+ last resort.  Implementors should use existing PA error codes where possible,

+ or nominate new ones. Note that at it is always better to use

+ PaUtil_SetLastHostErrorInfo() and paUnanticipatedHostError than to return an

+ ambiguous or inaccurate PaError code.

+

+ @param hostApiType  The host API which encountered the error (ie of the caller)

+

+ @param errorCode The error code returned by the native API function.

+

+ @param errorText A string describing the error. PaUtil_SetLastHostErrorInfo

+ makes a copy of the string, so it is not necessary for the pointer to remain

+ valid after the call to PaUtil_SetLastHostErrorInfo() returns.

+

+*/

+void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,

+        const char *errorText );

+

+

+        

+/** PA_DEBUG() provides a simple debug message printing facility. The macro

+ passes it's argument to a printf-like function called PaUtil_DebugPrint()

+ which prints to stderr and always flushes the stream after printing.

+ Because preprocessor macros cannot directly accept variable length argument

+ lists, calls to the macro must include an additional set of parenthesis, eg:

+ PA_DEBUG(("errorno: %d", 1001 ));

+*/

+

+void PaUtil_DebugPrint( const char *format, ... );

+

+#if (0) /* set to 1 to print debug messages */

+#define PA_DEBUG(x) PaUtil_DebugPrint x ;

+#else

+#define PA_DEBUG(x)

+#endif

+

+

+/* the following functions are implemented in a platform platform specific

+ .c file

+*/

+

+/** Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */

+void *PaUtil_AllocateMemory( long size );

+

+

+/** Realease block if non-NULL. block may be NULL */

+void PaUtil_FreeMemory( void *block );

+

+

+/** Return the number of currently allocated blocks. This function can be

+ used for detecting memory leaks.

+

+ @note Allocations will only be tracked if PA_TRACK_MEMORY is #defined. If

+ it isn't, this function will always return 0.

+*/

+int PaUtil_CountCurrentlyAllocatedBlocks( void );

+

+

+/** Initialize the clock used by PaUtil_GetTime(). Call this before calling

+ PaUtil_GetTime.

+

+ @see PaUtil_GetTime

+*/

+void PaUtil_InitializeClock( void );

+

+

+/** Return the system time in seconds. Used to implement CPU load functions

+

+ @see PaUtil_InitializeClock

+*/

+double PaUtil_GetTime( void );

+

+

+/* void Pa_Sleep( long msec );  must also be implemented in per-platform .c file */

+

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PA_UTIL_H */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_ds.c b/pjmedia/src/pjmedia/portaudio/pa_win_ds.c
index 940867d..eb9d409 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_win_ds.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_win_ds.c
@@ -1,1828 +1,1849 @@
-/*
- * $Id: pa_win_ds.c,v 1.1.2.49 2004/05/16 04:08:55 rossbencina Exp $
- * Portable Audio I/O Library DirectSound implementation
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
-
-    @todo implement paInputOverflow callback status flag
-    
-    @todo implement paNeverDropInput.
-
-    @todo implement host api specific extension to set i/o buffer sizes in frames
-
-    @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.)
-
-    @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
-
-    @todo audit handling of DirectSound result codes - in many cases we could convert a HRESULT into
-        a native portaudio error code. Standard DirectSound result codes are documented at msdn.
-
-    @todo implement IsFormatSupported
-
-    @todo check that CoInitialize() CoUninitialize() are always correctly
-        paired, even in error cases.
-
-    @todo call PaUtil_SetLastHostErrorInfo with a specific error string (currently just "DSound error").
-
-    @todo make sure all buffers have been played before stopping the stream
-        when the stream callback returns paComplete
-
-    old TODOs from phil, need to work out if these have been done:
-        O- fix "patest_stop.c"
-*/
-
-#include <stdio.h>
-#include <string.h> /* strlen() */
-
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
-#include "dsound_wrapper.h"
-
-#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
-#pragma comment( lib, "dsound.lib" )
-#pragma comment( lib, "winmm.lib" )
-#endif
-
-
-#define PRINT(x) /* { printf x; fflush(stdout); } */
-#define ERR_RPT(x) PRINT(x)
-#define DBUG(x)  /* PRINT(x) */
-#define DBUGX(x) /* PRINT(x) */
-
-#define PA_USE_HIGH_LATENCY   (0)
-#if PA_USE_HIGH_LATENCY
-#define PA_WIN_9X_LATENCY     (500)
-#define PA_WIN_NT_LATENCY     (600)
-#else
-#define PA_WIN_9X_LATENCY     (140)
-#define PA_WIN_NT_LATENCY     (280)
-#endif
-
-#define PA_WIN_WDM_LATENCY       (120)
-
-#define SECONDS_PER_MSEC      (0.001)
-#define MSEC_PER_SECOND       (1000)
-
-/* prototypes for functions declared in this file */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** s,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *streamCallback,
-                           void *userData );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-
-
-/* FIXME: should convert hr to a string */
-#define PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ) \
-    PaUtil_SetLastHostErrorInfo( paDirectSound, hr, "DirectSound error" )
-
-/************************************************* DX Prototypes **********/
-static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID,
-                                     LPCTSTR lpszDesc,
-                                     LPCTSTR lpszDrvName,
-                                     LPVOID lpContext );
-
-/************************************************************************************/
-/********************** Structures **************************************************/
-/************************************************************************************/
-/* PaWinDsHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct PaWinDsDeviceInfo
-{
-    GUID                             guid;
-    GUID                            *lpGUID;
-    double                           sampleRates[3];
-} PaWinDsDeviceInfo;
-
-typedef struct
-{
-    PaUtilHostApiRepresentation inheritedHostApiRep;
-    PaUtilStreamInterface    callbackStreamInterface;
-    PaUtilStreamInterface    blockingStreamInterface;
-
-    PaUtilAllocationGroup   *allocations;
-
-    /* implementation specific data goes here */
-    PaWinDsDeviceInfo       *winDsDeviceInfos;
-
-} PaWinDsHostApiRepresentation;
-
-/* PaWinDsStream - a stream data structure specifically for this implementation */
-
-typedef struct PaWinDsStream
-{
-    PaUtilStreamRepresentation streamRepresentation;
-    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
-    PaUtilBufferProcessor bufferProcessor;
-
-/* DirectSound specific data. */
-    DSoundWrapper    directSoundWrapper;
-    MMRESULT         timerID;
-    BOOL             ifInsideCallback;  /* Test for reentrancy. */
-    int              framesPerDSBuffer;
-    double           framesWritten;
-    double           secondsPerHostByte; /* Used to optimize latency calculation for outTime */
-
-    PaStreamCallbackFlags callbackFlags;
-    
-/* FIXME - move all below to PaUtilStreamRepresentation */
-    volatile int     isStarted;
-    volatile int     isActive;
-    volatile int     stopProcessing; /* stop thread once existing buffers have been returned */
-    volatile int     abortProcessing; /* stop thread immediately */
-} PaWinDsStream;
-
-
-/************************************************************************************
-** Duplicate the input string using the allocations allocator.
-** A NULL string is converted to a zero length string.
-** If memory cannot be allocated, NULL is returned.
-**/
-static char *DuplicateDeviceNameString( PaUtilAllocationGroup *allocations, const char* src )
-{
-    char *result = 0;
-    
-    if( src != NULL )
-    {
-        size_t len = strlen(src);
-        result = (char*)PaUtil_GroupAllocateMemory( allocations, (long)(len + 1) );
-        if( result )
-            memcpy( (void *) result, src, len+1 );
-    }
-    else
-    {
-        result = (char*)PaUtil_GroupAllocateMemory( allocations, 1 );
-        if( result )
-            result[0] = '\0';
-    }
-
-    return result;
-}
-
-/************************************************************************************
-** DSDeviceNameAndGUID, DSDeviceNameAndGUIDVector used for collecting preliminary
-** information during device enumeration.
-*/
-typedef struct DSDeviceNameAndGUID{
-    char *name; // allocated from parent's allocations, never deleted by this structure
-    GUID guid;
-    LPGUID lpGUID;
-} DSDeviceNameAndGUID;
-
-typedef struct DSDeviceNameAndGUIDVector{
-    PaUtilAllocationGroup *allocations;
-    PaError enumerationError;
-
-    int count;
-    int free;
-    DSDeviceNameAndGUID *items; // Allocated using LocalAlloc()
-} DSDeviceNameAndGUIDVector;
-
-static PaError InitializeDSDeviceNameAndGUIDVector(
-        DSDeviceNameAndGUIDVector *guidVector, PaUtilAllocationGroup *allocations )
-{
-    PaError result = paNoError;
-
-    guidVector->allocations = allocations;
-    guidVector->enumerationError = paNoError;
-
-    guidVector->count = 0;
-    guidVector->free = 8;
-    guidVector->items = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * guidVector->free );
-    if( guidVector->items == NULL )
-        result = paInsufficientMemory;
-    
-    return result;
-}
-
-static PaError ExpandDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector )
-{
-    PaError result = paNoError;
-    DSDeviceNameAndGUID *newItems;
-    int i;
-    
-    /* double size of vector */
-    int size = guidVector->count + guidVector->free;
-    guidVector->free += size;
-
-    newItems = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * size * 2 );
-    if( newItems == NULL )
-    {
-        result = paInsufficientMemory;
-    }
-    else
-    {
-        for( i=0; i < guidVector->count; ++i )
-        {
-            newItems[i].name = guidVector->items[i].name;
-            if( guidVector->items[i].lpGUID == NULL )
-            {
-                newItems[i].lpGUID = NULL;
-            }
-            else
-            {
-                newItems[i].lpGUID = &newItems[i].guid;
-                memcpy( &newItems[i].guid, guidVector->items[i].lpGUID, sizeof(GUID) );;
-            }
-        }
-
-        LocalFree( guidVector->items );
-        guidVector->items = newItems;
-    }                                
-
-    return result;
-}
-
-/*
-    it's safe to call DSDeviceNameAndGUIDVector multiple times
-*/
-static PaError TerminateDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector )
-{
-    PaError result = paNoError;
-
-    if( guidVector->items != NULL )
-    {
-        if( LocalFree( guidVector->items ) != NULL )
-            result = paInsufficientMemory;              /** @todo this isn't the correct error to return from a deallocation failure */
-
-        guidVector->items = NULL;
-    }
-
-    return result;
-}
-
-/************************************************************************************
-** Collect preliminary device information during DirectSound enumeration 
-*/
-static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID,
-                                     LPCTSTR lpszDesc,
-                                     LPCTSTR lpszDrvName,
-                                     LPVOID lpContext )
-{
-    DSDeviceNameAndGUIDVector *namesAndGUIDs = (DSDeviceNameAndGUIDVector*)lpContext;
-    PaError error;
-
-    (void) lpszDrvName; /* unused variable */
-
-    if( namesAndGUIDs->free == 0 )
-    {
-        error = ExpandDSDeviceNameAndGUIDVector( namesAndGUIDs );
-        if( error != paNoError )
-        {
-            namesAndGUIDs->enumerationError = error;
-            return FALSE;
-        }
-    }
-    
-    /* Set GUID pointer, copy GUID to storage in DSDeviceNameAndGUIDVector. */
-    if( lpGUID == NULL )
-    {
-        namesAndGUIDs->items[namesAndGUIDs->count].lpGUID = NULL;
-    }
-    else
-    {
-        namesAndGUIDs->items[namesAndGUIDs->count].lpGUID =
-                &namesAndGUIDs->items[namesAndGUIDs->count].guid;
-      
-        memcpy( &namesAndGUIDs->items[namesAndGUIDs->count].guid, lpGUID, sizeof(GUID) );
-    }
-
-    namesAndGUIDs->items[namesAndGUIDs->count].name =
-            DuplicateDeviceNameString( namesAndGUIDs->allocations, lpszDesc );
-    if( namesAndGUIDs->items[namesAndGUIDs->count].name == NULL )
-    {
-        namesAndGUIDs->enumerationError = paInsufficientMemory;
-        return FALSE;
-    }
-
-    ++namesAndGUIDs->count;
-    --namesAndGUIDs->free;
-    
-    return TRUE;
-}
-
-
-#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_  (13) /* must match array length below */
-static double defaultSampleRateSearchOrder_[] =
-    { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0,
-        16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
-
-
-/************************************************************************************
-** Extract capabilities from an output device, and add it to the device info list
-** if successful. This function assumes that there is enough room in the
-** device info list to accomodate all entries.
-**
-** The device will not be added to the device list if any errors are encountered.
-*/
-static PaError AddOutputDeviceInfoFromDirectSound(
-        PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID )
-{
-    PaUtilHostApiRepresentation  *hostApi = &winDsHostApi->inheritedHostApiRep;
-    PaDeviceInfo                 *deviceInfo = hostApi->deviceInfos[hostApi->info.deviceCount];
-    PaWinDsDeviceInfo            *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[hostApi->info.deviceCount];
-    HRESULT                       hr;
-    LPDIRECTSOUND                 lpDirectSound;
-    DSCAPS                        caps;
-    int                           deviceOK = TRUE;
-    PaError                       result = paNoError;
-    int                           i;
-    
-    /* Copy GUID to the device info structure. Set pointer. */
-    if( lpGUID == NULL )
-    {
-        winDsDeviceInfo->lpGUID = NULL;
-    }
-    else
-    {
-        memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) );
-        winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid;
-    }
-
-    
-    /* Create a DirectSound object for the specified GUID
-        Note that using CoCreateInstance doesn't work on windows CE.
-    */
-    hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &lpDirectSound, NULL );
-
-    /** try using CoCreateInstance because DirectSoundCreate was hanging under
-        some circumstances - note this was probably related to the
-        #define BOOL short bug which has now been fixed
-        @todo delete this comment and the following code once we've ensured
-        there is no bug.
-    */
-    /*
-    hr = CoCreateInstance( &CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
-            &IID_IDirectSound, (void**)&lpDirectSound );
-
-    if( hr == S_OK )
-    {
-        hr = IDirectSound_Initialize( lpDirectSound, lpGUID );
-    }
-    */
-    
-    if( hr != DS_OK )
-    {
-        DBUG(("Cannot create DirectSound for %s. Result = 0x%x\n", name, hr ));
-        deviceOK = FALSE;
-    }
-    else
-    {
-        /* Query device characteristics. */
-        memset( &caps, 0, sizeof(caps) ); 
-        caps.dwSize = sizeof(caps);
-        hr = IDirectSound_GetCaps( lpDirectSound, &caps );
-        if( hr != DS_OK )
-        {
-            DBUG(("Cannot GetCaps() for DirectSound device %s. Result = 0x%x\n", name, hr ));
-            deviceOK = FALSE;
-        }
-        else
-        {
-
-#ifndef PA_NO_WMME
-            if( caps.dwFlags & DSCAPS_EMULDRIVER )
-            {
-                /* If WMME supported, then reject Emulated drivers because they are lousy. */
-                deviceOK = FALSE;
-            }
-#endif
-
-            if( deviceOK )
-            {
-                deviceInfo->maxInputChannels = 0;
-                /* Mono or stereo device? */
-                deviceInfo->maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
-
-                deviceInfo->defaultLowInputLatency = 0.;    /** @todo IMPLEMENT ME */
-                deviceInfo->defaultLowOutputLatency = 0.;   /** @todo IMPLEMENT ME */
-                deviceInfo->defaultHighInputLatency = 0.;   /** @todo IMPLEMENT ME */
-                deviceInfo->defaultHighOutputLatency = 0.;  /** @todo IMPLEMENT ME */
-                
-                /* initialize defaultSampleRate */
-                
-                if( caps.dwFlags & DSCAPS_CONTINUOUSRATE )
-                {
-                    /* initialize to caps.dwMaxSecondarySampleRate incase none of the standard rates match */
-                    deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;
-
-                    for( i = 0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i )
-                    {
-                        if( defaultSampleRateSearchOrder_[i] >= caps.dwMinSecondarySampleRate
-                                && defaultSampleRateSearchOrder_[i] <= caps.dwMaxSecondarySampleRate ){
-
-                            deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[i];
-                            break;
-                        }
-                    }
-                }
-                else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate )
-                {
-                    if( caps.dwMinSecondarySampleRate == 0 )
-                    {
-                        /*
-                        ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !!
-                        ** But it supports continuous sampling.
-                        ** So fake range of rates, and hope it really supports it.
-                        */
-                        deviceInfo->defaultSampleRate = 44100.0f;
-
-                        DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex ));
-                    }
-                    else
-                    {
-	                    deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;
-                    }
-                }
-                else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) )
-                {
-                    /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000.
-                    ** But we know that they really support a range of rates!
-                    ** So when we see a ridiculous set of rates, assume it is a range.
-                    */
-                  deviceInfo->defaultSampleRate = 44100.0f;
-                  DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex ));
-                }
-                else deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;
-
-
-                //printf( "min %d max %d\n", caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate );
-                // dwFlags | DSCAPS_CONTINUOUSRATE 
-            }
-        }
-
-        IDirectSound_Release( lpDirectSound );
-    }
-
-    if( deviceOK )
-    {
-        deviceInfo->name = name;
-
-        if( lpGUID == NULL )
-            hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
-            
-        hostApi->info.deviceCount++;
-    }
-
-    return result;
-}
-
-
-/************************************************************************************
-** Extract capabilities from an input device, and add it to the device info list
-** if successful. This function assumes that there is enough room in the
-** device info list to accomodate all entries.
-**
-** The device will not be added to the device list if any errors are encountered.
-*/
-static PaError AddInputDeviceInfoFromDirectSoundCapture(
-        PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID )
-{
-    PaUtilHostApiRepresentation  *hostApi = &winDsHostApi->inheritedHostApiRep;
-    PaDeviceInfo                 *deviceInfo = hostApi->deviceInfos[hostApi->info.deviceCount];
-    PaWinDsDeviceInfo            *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[hostApi->info.deviceCount];
-    HRESULT                       hr;
-    LPDIRECTSOUNDCAPTURE          lpDirectSoundCapture;
-    DSCCAPS                       caps;
-    int                           deviceOK = TRUE;
-    PaError                       result = paNoError;
-    
-    /* Copy GUID to the device info structure. Set pointer. */
-    if( lpGUID == NULL )
-    {
-        winDsDeviceInfo->lpGUID = NULL;
-    }
-    else
-    {
-        winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid;
-        memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) );
-    }
-
-
-    hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL );
-
-    /** try using CoCreateInstance because DirectSoundCreate was hanging under
-        some circumstances - note this was probably related to the
-        #define BOOL short bug which has now been fixed
-        @todo delete this comment and the following code once we've ensured
-        there is no bug.
-    */
-    /*
-    hr = CoCreateInstance( &CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
-            &IID_IDirectSoundCapture, (void**)&lpDirectSoundCapture );
-    */
-    if( hr != DS_OK )
-    {
-        DBUG(("Cannot create Capture for %s. Result = 0x%x\n", name, hr ));
-        deviceOK = FALSE;
-    }
-    else
-    {
-        /* Query device characteristics. */
-        memset( &caps, 0, sizeof(caps) );
-        caps.dwSize = sizeof(caps);
-        hr = IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps );
-        if( hr != DS_OK )
-        {
-            DBUG(("Cannot GetCaps() for Capture device %s. Result = 0x%x\n", name, hr ));
-            deviceOK = FALSE;
-        }
-        else
-        {
-#ifndef PA_NO_WMME
-            if( caps.dwFlags & DSCAPS_EMULDRIVER )
-            {
-                /* If WMME supported, then reject Emulated drivers because they are lousy. */
-                deviceOK = FALSE;
-            }
-#endif
-
-            if( deviceOK )
-            {
-                deviceInfo->maxInputChannels = caps.dwChannels;
-                deviceInfo->maxOutputChannels = 0;
-
-                deviceInfo->defaultLowInputLatency = 0.;    /** @todo IMPLEMENT ME */
-                deviceInfo->defaultLowOutputLatency = 0.;   /** @todo IMPLEMENT ME */
-                deviceInfo->defaultHighInputLatency = 0.;   /** @todo IMPLEMENT ME */
-                deviceInfo->defaultHighOutputLatency = 0.;  /** @todo IMPLEMENT ME */
-
-/*  constants from a WINE patch by Francois Gouget, see:
-    http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html
-
-    ---
-    Date: Fri, 14 May 2004 10:38:12 +0200 (CEST)
-    From: Francois Gouget <fgouget@ ... .fr>
-    To: Ross Bencina <rbencina@ ... .au>
-    Subject: Re: Permission to use wine 48/96 wave patch in BSD licensed library
-
-    [snip]
-
-    I give you permission to use the patch below under the BSD license.
-    http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html
-
-    [snip]
-*/
-#ifndef WAVE_FORMAT_48M08
-#define WAVE_FORMAT_48M08      0x00001000    /* 48     kHz, Mono,   8-bit  */
-#define WAVE_FORMAT_48S08      0x00002000    /* 48     kHz, Stereo, 8-bit  */
-#define WAVE_FORMAT_48M16      0x00004000    /* 48     kHz, Mono,   16-bit */
-#define WAVE_FORMAT_48S16      0x00008000    /* 48     kHz, Stereo, 16-bit */
-#define WAVE_FORMAT_96M08      0x00010000    /* 96     kHz, Mono,   8-bit  */
-#define WAVE_FORMAT_96S08      0x00020000    /* 96     kHz, Stereo, 8-bit  */
-#define WAVE_FORMAT_96M16      0x00040000    /* 96     kHz, Mono,   16-bit */
-#define WAVE_FORMAT_96S16      0x00080000    /* 96     kHz, Stereo, 16-bit */
-#endif
-
-                /* defaultSampleRate */
-                if( caps.dwChannels == 2 )
-                {
-                    if( caps.dwFormats & WAVE_FORMAT_4S16 )
-                        deviceInfo->defaultSampleRate = 44100.0;
-                    else if( caps.dwFormats & WAVE_FORMAT_48S16 )
-                        deviceInfo->defaultSampleRate = 48000.0;
-                    else if( caps.dwFormats & WAVE_FORMAT_2S16 )
-                        deviceInfo->defaultSampleRate = 22050.0;
-                    else if( caps.dwFormats & WAVE_FORMAT_1S16 )
-                        deviceInfo->defaultSampleRate = 11025.0;
-                    else if( caps.dwFormats & WAVE_FORMAT_96S16 )
-                        deviceInfo->defaultSampleRate = 96000.0;
-                    else
-                        deviceInfo->defaultSampleRate = 0.;
-                }
-                else if( caps.dwChannels == 1 )
-                {
-                    if( caps.dwFormats & WAVE_FORMAT_4M16 )
-                        deviceInfo->defaultSampleRate = 44100.0;
-                    else if( caps.dwFormats & WAVE_FORMAT_48M16 )
-                        deviceInfo->defaultSampleRate = 48000.0;
-                    else if( caps.dwFormats & WAVE_FORMAT_2M16 )
-                        deviceInfo->defaultSampleRate = 22050.0;
-                    else if( caps.dwFormats & WAVE_FORMAT_1M16 )
-                        deviceInfo->defaultSampleRate = 11025.0;
-                    else if( caps.dwFormats & WAVE_FORMAT_96M16 )
-                        deviceInfo->defaultSampleRate = 96000.0;
-                    else
-                        deviceInfo->defaultSampleRate = 0.;
-                }
-                else deviceInfo->defaultSampleRate = 0.;
-            }
-        }
-        
-        IDirectSoundCapture_Release( lpDirectSoundCapture );
-    }
-
-    if( deviceOK )
-    {
-        deviceInfo->name = name;
-
-        if( lpGUID == NULL )
-            hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
-
-        hostApi->info.deviceCount++;
-    }
-
-    return result;
-}
-
-
-/***********************************************************************************/
-PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
-    PaError result = paNoError;
-    int i, deviceCount;
-    PaWinDsHostApiRepresentation *winDsHostApi;
-    DSDeviceNameAndGUIDVector inputNamesAndGUIDs, outputNamesAndGUIDs;
-    PaDeviceInfo *deviceInfoArray;
-
-    HRESULT hr = CoInitialize(NULL);        /** @todo: should uninitialize too */
-    if( FAILED(hr) ){
-        return paUnanticipatedHostError;
-    }            
-
-    /* initialise guid vectors so they can be safely deleted on error */
-    inputNamesAndGUIDs.items = NULL;
-    outputNamesAndGUIDs.items = NULL;
-
-    DSW_InitializeDSoundEntryPoints();
-
-    winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) );
-    if( !winDsHostApi )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    winDsHostApi->allocations = PaUtil_CreateAllocationGroup();
-    if( !winDsHostApi->allocations )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    *hostApi = &winDsHostApi->inheritedHostApiRep;
-    (*hostApi)->info.structVersion = 1;
-    (*hostApi)->info.type = paDirectSound;
-    (*hostApi)->info.name = "Windows DirectSound";
-    
-    (*hostApi)->info.deviceCount = 0;
-    (*hostApi)->info.defaultInputDevice = paNoDevice;
-    (*hostApi)->info.defaultOutputDevice = paNoDevice;
-
-    
-/* DSound - enumerate devices to count them and to gather their GUIDs */
-
-
-    result = InitializeDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs, winDsHostApi->allocations );
-    if( result != paNoError )
-        goto error;
-
-    result = InitializeDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs, winDsHostApi->allocations );
-    if( result != paNoError )
-        goto error;
-
-    dswDSoundEntryPoints.DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&inputNamesAndGUIDs );
-
-    dswDSoundEntryPoints.DirectSoundEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&outputNamesAndGUIDs );
-
-    if( inputNamesAndGUIDs.enumerationError != paNoError )
-    {
-        result = inputNamesAndGUIDs.enumerationError;
-        goto error;
-    }
-
-    if( outputNamesAndGUIDs.enumerationError != paNoError )
-    {
-        result = outputNamesAndGUIDs.enumerationError;
-        goto error;
-    }
-
-    deviceCount = inputNamesAndGUIDs.count + outputNamesAndGUIDs.count;
-
-    if( deviceCount > 0 )
-    {
-        /* allocate array for pointers to PaDeviceInfo structs */
-        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
-                winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
-        if( !(*hostApi)->deviceInfos )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        /* allocate all PaDeviceInfo structs in a contiguous block */
-        deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
-                winDsHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
-        if( !deviceInfoArray )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        /* allocate all DSound specific info structs in a contiguous block */
-        winDsHostApi->winDsDeviceInfos = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory(
-                winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount );
-        if( !winDsHostApi->winDsDeviceInfos )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        for( i=0; i < deviceCount; ++i )
-        {
-            PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
-            deviceInfo->structVersion = 2;
-            deviceInfo->hostApi = hostApiIndex;
-            deviceInfo->name = 0;
-            (*hostApi)->deviceInfos[i] = deviceInfo;
-        }
-
-        for( i=0; i< inputNamesAndGUIDs.count; ++i )
-        {
-            result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi,
-                    inputNamesAndGUIDs.items[i].name,
-                    inputNamesAndGUIDs.items[i].lpGUID );
-            if( result != paNoError )
-                goto error;
-        }
-
-        for( i=0; i< outputNamesAndGUIDs.count; ++i )
-        {
-            result = AddOutputDeviceInfoFromDirectSound( winDsHostApi,
-                    outputNamesAndGUIDs.items[i].name,
-                    outputNamesAndGUIDs.items[i].lpGUID );
-            if( result != paNoError )
-                goto error;
-        }
-    }    
-
-    result = TerminateDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs );
-    if( result != paNoError )
-        goto error;
-
-    result = TerminateDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs );
-    if( result != paNoError )
-        goto error;
-
-    
-    (*hostApi)->Terminate = Terminate;
-    (*hostApi)->OpenStream = OpenStream;
-    (*hostApi)->IsFormatSupported = IsFormatSupported;
-
-    PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, GetStreamCpuLoad,
-                                      PaUtil_DummyRead, PaUtil_DummyWrite,
-                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
-    PaUtil_InitializeStreamInterface( &winDsHostApi->blockingStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
-                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
-    return result;
-
-error:
-    if( winDsHostApi )
-    {
-        if( winDsHostApi->allocations )
-        {
-            PaUtil_FreeAllAllocations( winDsHostApi->allocations );
-            PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
-        }
-                
-        PaUtil_FreeMemory( winDsHostApi );
-    }
-
-    TerminateDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs );
-    TerminateDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs );
-
-    return result;
-}
-
-
-/***********************************************************************************/
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
-    PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
-
-    /*
-        IMPLEMENT ME:
-            - clean up any resources not handled by the allocation group
-    */
-
-    if( winDsHostApi->allocations )
-    {
-        PaUtil_FreeAllAllocations( winDsHostApi->allocations );
-        PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
-    }
-
-    PaUtil_FreeMemory( winDsHostApi );
-
-    DSW_TerminateDSoundEntryPoints();
-
-    CoUninitialize();
-}
-
-
-/* Set minimal latency based on whether NT or Win95.
- * NT has higher latency.
- */
-static int PaWinDS_GetMinSystemLatency( void )
-{
-    int minLatencyMsec;
-    /* Set minimal latency based on whether NT or other OS.
-     * NT has higher latency.
-     */
-    OSVERSIONINFO osvi;
-	osvi.dwOSVersionInfoSize = sizeof( osvi );
-	GetVersionEx( &osvi );
-    DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId ));
-    DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion ));
-    DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion ));
-    /* Check for NT */
-	if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
-	{
-		minLatencyMsec = PA_WIN_NT_LATENCY;
-	}
-	else if(osvi.dwMajorVersion >= 5)
-	{
-		minLatencyMsec = PA_WIN_WDM_LATENCY;
-	}
-	else
-	{
-		minLatencyMsec = PA_WIN_9X_LATENCY;
-	}
-    return minLatencyMsec;
-}
-
-/***********************************************************************************/
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate )
-{
-    int inputChannelCount, outputChannelCount;
-    PaSampleFormat inputSampleFormat, outputSampleFormat;
-    
-    if( inputParameters )
-    {
-        inputChannelCount = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-
-        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that input device can support inputChannelCount */
-        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
-            return paInvalidChannelCount;
-
-        /* validate inputStreamInfo */
-        if( inputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-    }
-    else
-    {
-        inputChannelCount = 0;
-    }
-
-    if( outputParameters )
-    {
-        outputChannelCount = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-        
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-
-        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that output device can support inputChannelCount */
-        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
-            return paInvalidChannelCount;
-
-        /* validate outputStreamInfo */
-        if( outputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-    }
-    else
-    {
-        outputChannelCount = 0;
-    }
-    
-    /*
-        IMPLEMENT ME:
-
-            - if a full duplex stream is requested, check that the combination
-                of input and output parameters is supported if necessary
-
-            - check that the device supports sampleRate
-
-        Because the buffer adapter handles conversion between all standard
-        sample formats, the following checks are only required if paCustomFormat
-        is implemented, or under some other unusual conditions.
-
-            - check that input device can support inputSampleFormat, or that
-                we have the capability to convert from outputSampleFormat to
-                a native format
-
-            - check that output device can support outputSampleFormat, or that
-                we have the capability to convert from outputSampleFormat to
-                a native format
-    */
-
-    return paFormatIsSupported;
-}
-
-
-/*************************************************************************
-** Determine minimum number of buffers required for this host based
-** on minimum latency. Latency can be optionally set by user by setting
-** an environment variable. For example, to set latency to 200 msec, put:
-**
-**    set PA_MIN_LATENCY_MSEC=200
-**
-** in the AUTOEXEC.BAT file and reboot.
-** If the environment variable is not set, then the latency will be determined
-** based on the OS. Windows NT has higher latency than Win95.
-*/
-#define PA_LATENCY_ENV_NAME  ("PA_MIN_LATENCY_MSEC")
-#define PA_ENV_BUF_SIZE  (32)
-
-static int PaWinDs_GetMinLatencyFrames( double sampleRate )
-{
-    char      envbuf[PA_ENV_BUF_SIZE];
-    DWORD     hresult;
-    int       minLatencyMsec = 0;
-
-    /* Let user determine minimal latency by setting environment variable. */
-    hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE );
-    if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
-    {
-        minLatencyMsec = atoi( envbuf );
-    }
-    else
-    {
-        minLatencyMsec = PaWinDS_GetMinSystemLatency();
-#if PA_USE_HIGH_LATENCY
-        PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
-#endif
-
-    }
-
-    return (int) (minLatencyMsec * sampleRate * SECONDS_PER_MSEC);
-}
-
-#ifndef NDEBUG
-#define EZ  = 0
-#else
-#define EZ
-#endif
-
-/***********************************************************************************/
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** s,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *streamCallback,
-                           void *userData )
-{
-    PaError result = paNoError;
-    PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
-    PaWinDsStream *stream = 0;
-    int inputChannelCount, outputChannelCount;
-    PaSampleFormat inputSampleFormat EZ, outputSampleFormat EZ;
-    PaSampleFormat hostInputSampleFormat EZ, hostOutputSampleFormat EZ;
-    unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames;
-
-    if( inputParameters )
-    {
-        inputChannelCount = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-        suggestedInputLatencyFrames = (unsigned long)(inputParameters->suggestedLatency * sampleRate);
-
-        /* IDEA: the following 3 checks could be performed by default by pa_front
-            unless some flag indicated otherwise */
-            
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that input device can support inputChannelCount */
-        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
-            return paInvalidChannelCount;
-            
-        /* validate hostApiSpecificStreamInfo */
-        if( inputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-    }
-    else
-    {
-        inputChannelCount = 0;
-        suggestedInputLatencyFrames = 0;
-    }
-
-
-    if( outputParameters )
-    {
-        outputChannelCount = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-        suggestedOutputLatencyFrames = (unsigned long)(outputParameters->suggestedLatency * sampleRate);
-
-        /* unless alternate device specification is supported, reject the use of
-            paUseHostApiSpecificDeviceSpecification */
-        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
-            return paInvalidDevice;
-
-        /* check that output device can support inputChannelCount */
-        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
-            return paInvalidChannelCount;
-
-        /* validate hostApiSpecificStreamInfo */
-        if( outputParameters->hostApiSpecificStreamInfo )
-            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */            
-    }
-    else
-    {
-        outputChannelCount = 0;
-        suggestedOutputLatencyFrames = 0;
-    }
-
-
-    /*
-        IMPLEMENT ME:
-
-        ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() )
-
-            - check that input device can support inputSampleFormat, or that
-                we have the capability to convert from outputSampleFormat to
-                a native format
-
-            - check that output device can support outputSampleFormat, or that
-                we have the capability to convert from outputSampleFormat to
-                a native format
-
-            - if a full duplex stream is requested, check that the combination
-                of input and output parameters is supported
-
-            - check that the device supports sampleRate
-
-            - alter sampleRate to a close allowable rate if possible / necessary
-
-            - validate suggestedInputLatency and suggestedOutputLatency parameters,
-                use default values where necessary
-    */
-
-
-    /* validate platform specific flags */
-    if( (streamFlags & paPlatformSpecificFlags) != 0 )
-        return paInvalidFlag; /* unexpected platform specific flag */
-
-
-    stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) );
-    if( !stream )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    if( streamCallback )
-    {
-        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
-                                               &winDsHostApi->callbackStreamInterface, streamCallback, userData );
-    }
-    else
-    {
-        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
-                                               &winDsHostApi->blockingStreamInterface, streamCallback, userData );
-    }
-    
-    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
-
-    if( inputParameters )
-    {
-        /* IMPLEMENT ME - establish which  host formats are available */
-        hostInputSampleFormat =
-            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputParameters->sampleFormat );
-    }
-
-    if( outputParameters )
-    {
-        /* IMPLEMENT ME - establish which  host formats are available */
-        hostOutputSampleFormat =
-            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputParameters->sampleFormat );
-    }
-    
-    result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
-                    inputChannelCount, inputSampleFormat, hostInputSampleFormat,
-                    outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
-                    sampleRate, streamFlags, framesPerBuffer,
-                    framesPerBuffer, /* ignored in paUtilVariableHostBufferSizePartialUsageAllowed mode. */
-                /* This next mode is required because DS can split the host buffer when it wraps around. */
-                    paUtilVariableHostBufferSizePartialUsageAllowed,
-                    streamCallback, userData );
-    if( result != paNoError )
-        goto error;
-
-
-    stream->streamRepresentation.streamInfo.inputLatency =
-            PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);   /* FIXME: not initialised anywhere else */
-    stream->streamRepresentation.streamInfo.outputLatency =
-            PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);    /* FIXME: not initialised anywhere else */
-    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
-    
-/* DirectSound specific initialization */
-    {
-        HRESULT          hr;
-        int              bytesPerDirectSoundBuffer;
-        DSoundWrapper   *dsw;
-        int              userLatencyFrames;
-        int              minLatencyFrames;
-
-        stream->timerID = 0;
-        dsw = &stream->directSoundWrapper;
-        DSW_Init( dsw );
-
-    /* Get system minimum latency. */
-        minLatencyFrames = PaWinDs_GetMinLatencyFrames( sampleRate );
-
-    /* Let user override latency by passing latency parameter. */
-        userLatencyFrames = (suggestedInputLatencyFrames > suggestedOutputLatencyFrames)
-                    ? suggestedInputLatencyFrames
-                    : suggestedOutputLatencyFrames;
-        if( userLatencyFrames > 0 ) minLatencyFrames = userLatencyFrames;
-
-    /* Calculate stream->framesPerDSBuffer depending on framesPerBuffer */
-        if( framesPerBuffer == paFramesPerBufferUnspecified )
-        {
-        /* App support variable framesPerBuffer */
-            stream->framesPerDSBuffer = minLatencyFrames;
-
-            stream->streamRepresentation.streamInfo.outputLatency = (double)(minLatencyFrames - 1) / sampleRate;
-        }
-        else
-        {
-        /* Round up to number of buffers needed to guarantee that latency. */
-            int numUserBuffers = (minLatencyFrames + framesPerBuffer - 1) / framesPerBuffer;
-            if( numUserBuffers < 1 ) numUserBuffers = 1;
-            numUserBuffers += 1; /* So we have latency worth of buffers ahead of current buffer. */
-            stream->framesPerDSBuffer = framesPerBuffer * numUserBuffers;
-
-            stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerBuffer * (numUserBuffers-1)) / sampleRate;
-        }
-
-        {
-            /** @todo REVIEW: this calculation seems incorrect to me - rossb. */
-            int msecLatency = (int) ((stream->framesPerDSBuffer * MSEC_PER_SECOND) / sampleRate);
-            PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", stream->framesPerDSBuffer, msecLatency ));
-        }
-
-
-        /* ------------------ OUTPUT */
-        if( outputParameters )
-        {
-            /*
-            PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ outputParameters->device ];
-            DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", outputParameters->device));
-            */
-            
-            bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * outputParameters->channelCount * sizeof(short);
-            if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
-            {
-                result = paBufferTooSmall;
-                goto error;
-            }
-            else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
-            {
-                result = paBufferTooBig;
-                goto error;
-            }
-
-
-            hr = dswDSoundEntryPoints.DirectSoundCreate( winDsHostApi->winDsDeviceInfos[outputParameters->device].lpGUID,
-                &dsw->dsw_pDirectSound,   NULL );
-            if( hr != DS_OK )
-            {
-                ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n"));
-                result = paUnanticipatedHostError;
-                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
-                goto error;
-            }
-            hr = DSW_InitOutputBuffer( dsw,
-                                       (unsigned long) (sampleRate + 0.5),
-                                       (WORD)outputParameters->channelCount, bytesPerDirectSoundBuffer );
-            DBUG(("DSW_InitOutputBuffer() returns %x\n", hr));
-            if( hr != DS_OK )
-            {
-                result = paUnanticipatedHostError;
-                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
-                goto error;
-            }
-            /* Calculate value used in latency calculation to avoid real-time divides. */
-            stream->secondsPerHostByte = 1.0 /
-                (stream->bufferProcessor.bytesPerHostOutputSample *
-                outputChannelCount * sampleRate);
-        }
-
-        /* ------------------ INPUT */
-        if( inputParameters )
-        {
-            /*
-            PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ inputParameters->device ];
-            DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", inputParameters->device));
-            */
-            
-            bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * inputParameters->channelCount * sizeof(short);
-            if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
-            {
-                result = paBufferTooSmall;
-                goto error;
-            }
-            else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
-            {
-                result = paBufferTooBig;
-                goto error;
-            }
-
-            hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( winDsHostApi->winDsDeviceInfos[inputParameters->device].lpGUID,
-                &dsw->dsw_pDirectSoundCapture,   NULL );
-            if( hr != DS_OK )
-            {
-                ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));
-                result = paUnanticipatedHostError;
-                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
-                goto error;
-            }
-            hr = DSW_InitInputBuffer( dsw,
-                                      (unsigned long) (sampleRate + 0.5),
-                                      (WORD)inputParameters->channelCount, bytesPerDirectSoundBuffer );
-            DBUG(("DSW_InitInputBuffer() returns %x\n", hr));
-            if( hr != DS_OK )
-            {
-                ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));
-                result = paUnanticipatedHostError;
-                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
-                goto error;
-            }
-        }
-
-    }
-
-    *s = (PaStream*)stream;
-
-    return result;
-
-error:
-    if( stream )
-        PaUtil_FreeMemory( stream );
-
-    return result;
-}
-
-
-/***********************************************************************************/
-static PaError Pa_TimeSlice( PaWinDsStream *stream )
-{
-    PaError           result = 0;   /* FIXME: this should be declared int and this function should also return that type (same as stream callback return type)*/
-    DSoundWrapper    *dsw;
-    long              numFrames = 0;
-    long              bytesEmpty = 0;
-    long              bytesFilled = 0;
-    long              bytesToXfer = 0;
-    long              framesToXfer = 0;
-    long              numInFramesReady = 0;
-    long              numOutFramesReady = 0;
-    long              bytesProcessed;
-    HRESULT           hresult;
-    double            outputLatency = 0;
-    PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */
-    
-/* Input */
-    LPBYTE            lpInBuf1 = NULL;
-    LPBYTE            lpInBuf2 = NULL;
-    DWORD             dwInSize1 = 0;
-    DWORD             dwInSize2 = 0;
-/* Output */
-    LPBYTE            lpOutBuf1 = NULL;
-    LPBYTE            lpOutBuf2 = NULL;
-    DWORD             dwOutSize1 = 0;
-    DWORD             dwOutSize2 = 0;
-
-    dsw = &stream->directSoundWrapper;
-
-    /* How much input data is available? */
-    if( stream->bufferProcessor.inputChannelCount > 0 )
-    {
-        DSW_QueryInputFilled( dsw, &bytesFilled );
-        framesToXfer = numInFramesReady = bytesFilled / dsw->dsw_BytesPerInputFrame;
-        outputLatency = ((double)bytesFilled) * stream->secondsPerHostByte;
-
-        /** @todo Check for overflow */
-    }
-
-    /* How much output room is available? */
-    if( stream->bufferProcessor.outputChannelCount > 0 )
-    {
-        UINT previousUnderflowCount = dsw->dsw_OutputUnderflows;
-        DSW_QueryOutputSpace( dsw, &bytesEmpty );
-        framesToXfer = numOutFramesReady = bytesEmpty / dsw->dsw_BytesPerOutputFrame;
-
-        /* Check for underflow */
-        if( dsw->dsw_OutputUnderflows != previousUnderflowCount )
-            stream->callbackFlags |= paOutputUnderflow;
-    }
-
-    if( (numInFramesReady > 0) && (numOutFramesReady > 0) )
-    {
-        framesToXfer = (numOutFramesReady < numInFramesReady) ? numOutFramesReady : numInFramesReady;
-    }
-
-    if( framesToXfer > 0 )
-    {
-
-        PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
-    /* The outputBufferDacTime parameter should indicates the time at which
-        the first sample of the output buffer is heard at the DACs. */
-        timeInfo.currentTime = PaUtil_GetTime();
-        timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency;
-
-
-        PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, stream->callbackFlags );
-        stream->callbackFlags = 0;
-        
-    /* Input */
-        if( stream->bufferProcessor.inputChannelCount > 0 )
-        {
-            bytesToXfer = framesToXfer * dsw->dsw_BytesPerInputFrame;
-            hresult = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer,
-                dsw->dsw_ReadOffset, bytesToXfer,
-                (void **) &lpInBuf1, &dwInSize1,
-                (void **) &lpInBuf2, &dwInSize2, 0);
-            if (hresult != DS_OK)
-            {
-                ERR_RPT(("DirectSound IDirectSoundCaptureBuffer_Lock failed, hresult = 0x%x\n",hresult));
-                result = paUnanticipatedHostError;
-                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
-                goto error2;
-            }
-
-            numFrames = dwInSize1 / dsw->dsw_BytesPerInputFrame;
-            PaUtil_SetInputFrameCount( &stream->bufferProcessor, numFrames );
-            PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf1, 0 );
-        /* Is input split into two regions. */
-            if( dwInSize2 > 0 )
-            {
-                numFrames = dwInSize2 / dsw->dsw_BytesPerInputFrame;
-                PaUtil_Set2ndInputFrameCount( &stream->bufferProcessor, numFrames );
-                PaUtil_Set2ndInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf2, 0 );
-            }
-        }
-
-    /* Output */
-        if( stream->bufferProcessor.outputChannelCount > 0 )
-        {
-            bytesToXfer = framesToXfer * dsw->dsw_BytesPerOutputFrame;
-            hresult = IDirectSoundBuffer_Lock ( dsw->dsw_OutputBuffer,
-                dsw->dsw_WriteOffset, bytesToXfer,
-                (void **) &lpOutBuf1, &dwOutSize1,
-                (void **) &lpOutBuf2, &dwOutSize2, 0);
-            if (hresult != DS_OK)
-            {
-                ERR_RPT(("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n",hresult));
-                result = paUnanticipatedHostError;
-                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
-                goto error1;
-            }
-
-            numFrames = dwOutSize1 / dsw->dsw_BytesPerOutputFrame;
-            PaUtil_SetOutputFrameCount( &stream->bufferProcessor, numFrames );
-            PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf1, 0 );
-
-        /* Is output split into two regions. */
-            if( dwOutSize2 > 0 )
-            {
-                numFrames = dwOutSize2 / dsw->dsw_BytesPerOutputFrame;
-                PaUtil_Set2ndOutputFrameCount( &stream->bufferProcessor, numFrames );
-                PaUtil_Set2ndInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf2, 0 );
-            }
-        }
-
-        result = paContinue;
-        numFrames = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &result );
-        stream->framesWritten += numFrames;
-        
-        if( stream->bufferProcessor.outputChannelCount > 0 )
-        {
-        /* FIXME: an underflow could happen here */
-
-        /* Update our buffer offset and unlock sound buffer */
-            bytesProcessed = numFrames * dsw->dsw_BytesPerOutputFrame;
-            dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + bytesProcessed) % dsw->dsw_OutputSize;
-            IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2);
-            dsw->dsw_FramesWritten += numFrames;
-        }
-
-error1:
-        if( stream->bufferProcessor.inputChannelCount > 0 )
-        {
-        /* FIXME: an overflow could happen here */
-
-        /* Update our buffer offset and unlock sound buffer */
-            bytesProcessed = numFrames * dsw->dsw_BytesPerInputFrame;
-            dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + bytesProcessed) % dsw->dsw_InputSize;
-            IDirectSoundCaptureBuffer_Unlock( dsw->dsw_InputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2);
-        }
-error2:
-
-        PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, numFrames );
-
-    }
-    
-    return result;
-}
-/*******************************************************************/
-static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
-{
-    PaWinDsStream *stream;
-
-    /* suppress unused variable warnings */
-    (void) uID;
-    (void) uMsg;
-    (void) dw1;
-    (void) dw2;
-    
-    stream = (PaWinDsStream *) dwUser;
-    if( stream == NULL ) return;
-
-    if( stream->isActive )
-    {
-        if( stream->abortProcessing )
-        {
-            stream->isActive = 0;
-        }
-        else if( stream->stopProcessing )
-        {
-            DSoundWrapper   *dsw = &stream->directSoundWrapper;
-            if( stream->bufferProcessor.outputChannelCount > 0 )
-            {
-                DSW_ZeroEmptySpace( dsw );
-                /* clear isActive when all sound played */
-                if( dsw->dsw_FramesPlayed >= stream->framesWritten )
-                {
-                    stream->isActive = 0;
-                }
-            }
-            else
-            {
-                stream->isActive = 0;
-            }
-        }
-        else
-        {
-            if( Pa_TimeSlice( stream ) != 0)  /* Call time slice independant of timing method. */
-            {
-                /* FIXME implement handling of paComplete and paAbort if possible */
-                stream->stopProcessing = 1;
-            }
-        }
-
-        if( !stream->isActive ){
-            if( stream->streamRepresentation.streamFinishedCallback != 0 )
-                stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
-        }
-    }
-}
-
-/***********************************************************************************
-    When CloseStream() is called, the multi-api layer ensures that
-    the stream has already been stopped or aborted.
-*/
-static PaError CloseStream( PaStream* s )
-{
-    PaError result = paNoError;
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-
-    DSW_Term( &stream->directSoundWrapper );
-
-    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
-    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-    PaUtil_FreeMemory( stream );
-
-    return result;
-}
-
-/***********************************************************************************/
-static PaError StartStream( PaStream *s )
-{
-    PaError          result = paNoError;
-    PaWinDsStream   *stream = (PaWinDsStream*)s;
-    HRESULT          hr;
-
-    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
-    
-    if( stream->bufferProcessor.inputChannelCount > 0 )
-    {
-        hr = DSW_StartInput( &stream->directSoundWrapper );
-        DBUG(("StartStream: DSW_StartInput returned = 0x%X.\n", hr));
-        if( hr != DS_OK )
-        {
-            result = paUnanticipatedHostError;
-            PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
-            goto error;
-        }
-    }
-
-    stream->framesWritten = 0;
-    stream->callbackFlags = 0;
-
-    stream->abortProcessing = 0;
-    stream->stopProcessing = 0;
-    stream->isActive = 1;
-
-    if( stream->bufferProcessor.outputChannelCount > 0 )
-    {
-        /* Give user callback a chance to pre-fill buffer. REVIEW - i thought we weren't pre-filling, rb. */
-        result = Pa_TimeSlice( stream );
-        if( result != paNoError ) return result; // FIXME - what if finished?
-
-        hr = DSW_StartOutput( &stream->directSoundWrapper );
-        DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
-        if( hr != DS_OK )
-        {
-            result = paUnanticipatedHostError;
-            PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
-            goto error;
-        }
-    }
-
-
-    /* Create timer that will wake us up so we can fill the DSound buffer. */
-    {
-        int resolution;
-        int framesPerWakeup = stream->framesPerDSBuffer / 4;
-        int msecPerWakeup = MSEC_PER_SECOND * framesPerWakeup / (int) stream->streamRepresentation.streamInfo.sampleRate;
-        if( msecPerWakeup < 10 ) msecPerWakeup = 10;
-        else if( msecPerWakeup > 100 ) msecPerWakeup = 100;
-        resolution = msecPerWakeup/4;
-        stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
-                                             (DWORD) stream, TIME_PERIODIC );
-    }
-    if( stream->timerID == 0 )
-    {
-        stream->isActive = 0;
-        result = paUnanticipatedHostError;
-        PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
-        goto error;
-    }
-
-    stream->isStarted = TRUE;
-
-error:
-    return result;
-}
-
-
-/***********************************************************************************/
-static PaError StopStream( PaStream *s )
-{
-    PaError result = paNoError;
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-    HRESULT          hr;
-    int timeoutMsec;
-
-    stream->stopProcessing = 1;
-    /* Set timeout at 20% beyond maximum time we might wait. */
-    timeoutMsec = (int) (1200.0 * stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate);
-    while( stream->isActive && (timeoutMsec > 0)  )
-    {
-        Sleep(10);
-        timeoutMsec -= 10;
-    }
-    if( stream->timerID != 0 )
-    {
-	timeKillEvent(stream->timerID);  /* Stop callback timer. */
-        stream->timerID = 0;
-    }
-
-
-    if( stream->bufferProcessor.outputChannelCount > 0 )
-    {
-        hr = DSW_StopOutput( &stream->directSoundWrapper );
-    }
-
-    if( stream->bufferProcessor.inputChannelCount > 0 )
-    {
-        hr = DSW_StopInput( &stream->directSoundWrapper );
-    }
-
-    stream->isStarted = FALSE;
-
-    return result;
-}
-
-
-/***********************************************************************************/
-static PaError AbortStream( PaStream *s )
-{
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-
-    stream->abortProcessing = 1;
-    return StopStream( s );
-}
-
-
-/***********************************************************************************/
-static PaError IsStreamStopped( PaStream *s )
-{
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-
-    return !stream->isStarted;
-}
-
-
-/***********************************************************************************/
-static PaError IsStreamActive( PaStream *s )
-{
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-
-    return stream->isActive;
-}
-
-/***********************************************************************************/
-static PaTime GetStreamTime( PaStream *s )
-{
-    /* suppress unused variable warnings */
-    (void) s;
-
-    
-/*
-    new behavior for GetStreamTime is to return a stream based seconds clock
-    used for the outTime parameter to the callback.
-    FIXME: delete this comment when the other unnecessary related code has
-    been cleaned from this file.
-
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-    DSoundWrapper   *dsw;
-    dsw = &stream->directSoundWrapper;
-    return dsw->dsw_FramesPlayed;
-*/
-    return PaUtil_GetTime();
-}
-
-
-/***********************************************************************************/
-static double GetStreamCpuLoad( PaStream* s )
-{
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-
-    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-
-/***********************************************************************************
-    As separate stream interfaces are used for blocking and callback
-    streams, the following functions can be guaranteed to only be called
-    for blocking streams.
-*/
-
-static PaError ReadStream( PaStream* s,
-                           void *buffer,
-                           unsigned long frames )
-{
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) buffer;
-    (void) frames;
-    (void) stream;
-
-    /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
-    return paNoError;
-}
-
-
-/***********************************************************************************/
-static PaError WriteStream( PaStream* s,
-                            const void *buffer,
-                            unsigned long frames )
-{
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) buffer;
-    (void) frames;
-    (void) stream;
-
-    /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
-    return paNoError;
-}
-
-
-/***********************************************************************************/
-static signed long GetStreamReadAvailable( PaStream* s )
-{
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) stream;
-
-    /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
-    return 0;
-}
-
-
-/***********************************************************************************/
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
-    PaWinDsStream *stream = (PaWinDsStream*)s;
-
-    /* suppress unused variable warnings */
-    (void) stream;
-    
-    /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
-    return 0;
-}
-
-
-
+/*

+ * $Id: pa_win_ds.c,v 1.1.2.49 2004/05/16 04:08:55 rossbencina Exp $

+ * Portable Audio I/O Library DirectSound implementation

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+

+    @todo implement paInputOverflow callback status flag

+    

+    @todo implement paNeverDropInput.

+

+    @todo implement host api specific extension to set i/o buffer sizes in frames

+

+    @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.)

+

+    @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable

+

+    @todo audit handling of DirectSound result codes - in many cases we could convert a HRESULT into

+        a native portaudio error code. Standard DirectSound result codes are documented at msdn.

+

+    @todo implement IsFormatSupported

+

+    @todo check that CoInitialize() CoUninitialize() are always correctly

+        paired, even in error cases.

+

+    @todo call PaUtil_SetLastHostErrorInfo with a specific error string (currently just "DSound error").

+

+    @todo make sure all buffers have been played before stopping the stream

+        when the stream callback returns paComplete

+

+    old TODOs from phil, need to work out if these have been done:

+        O- fix "patest_stop.c"

+*/

+

+#include <stdio.h>

+#include <string.h> /* strlen() */

+

+#include "pa_util.h"

+#include "pa_allocation.h"

+#include "pa_hostapi.h"

+#include "pa_stream.h"

+#include "pa_cpuload.h"

+#include "pa_process.h"

+

+#include "dsound_wrapper.h"

+

+#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */

+#pragma comment( lib, "dsound.lib" )

+#pragma comment( lib, "winmm.lib" )

+#endif

+

+

+#define PRINT(x) /* { printf x; fflush(stdout); } */

+#define ERR_RPT(x) PRINT(x)

+#define DBUG(x)  /* PRINT(x) */

+#define DBUGX(x) /* PRINT(x) */

+

+#define PA_USE_HIGH_LATENCY   (0)

+#if PA_USE_HIGH_LATENCY

+#define PA_WIN_9X_LATENCY     (500)

+#define PA_WIN_NT_LATENCY     (600)

+#else

+#define PA_WIN_9X_LATENCY     (140)

+#define PA_WIN_NT_LATENCY     (280)

+#endif

+

+#define PA_WIN_WDM_LATENCY       (120)

+

+#define SECONDS_PER_MSEC      (0.001)

+#define MSEC_PER_SECOND       (1000)

+

+/* prototypes for functions declared in this file */

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** s,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *streamCallback,

+                           void *userData );

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate );

+static PaError CloseStream( PaStream* stream );

+static PaError StartStream( PaStream *stream );

+static PaError StopStream( PaStream *stream );

+static PaError AbortStream( PaStream *stream );

+static PaError IsStreamStopped( PaStream *s );

+static PaError IsStreamActive( PaStream *stream );

+static PaTime GetStreamTime( PaStream *stream );

+static double GetStreamCpuLoad( PaStream* stream );

+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );

+static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );

+static signed long GetStreamReadAvailable( PaStream* stream );

+static signed long GetStreamWriteAvailable( PaStream* stream );

+

+

+/* FIXME: should convert hr to a string */

+#define PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ) \

+    PaUtil_SetLastHostErrorInfo( paDirectSound, hr, "DirectSound error" )

+

+/************************************************* DX Prototypes **********/

+static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID,

+                                     LPCTSTR lpszDesc,

+                                     LPCTSTR lpszDrvName,

+                                     LPVOID lpContext );

+

+/************************************************************************************/

+/********************** Structures **************************************************/

+/************************************************************************************/

+/* PaWinDsHostApiRepresentation - host api datastructure specific to this implementation */

+

+typedef struct PaWinDsDeviceInfo

+{

+    GUID                             guid;

+    GUID                            *lpGUID;

+    double                           sampleRates[3];

+} PaWinDsDeviceInfo;

+

+typedef struct

+{

+    PaUtilHostApiRepresentation inheritedHostApiRep;

+    PaUtilStreamInterface    callbackStreamInterface;

+    PaUtilStreamInterface    blockingStreamInterface;

+

+    PaUtilAllocationGroup   *allocations;

+

+    /* implementation specific data goes here */

+    PaWinDsDeviceInfo       *winDsDeviceInfos;

+

+} PaWinDsHostApiRepresentation;

+

+/* PaWinDsStream - a stream data structure specifically for this implementation */

+

+typedef struct PaWinDsStream

+{

+    PaUtilStreamRepresentation streamRepresentation;

+    PaUtilCpuLoadMeasurer cpuLoadMeasurer;

+    PaUtilBufferProcessor bufferProcessor;

+

+/* DirectSound specific data. */

+    DSoundWrapper    directSoundWrapper;

+    MMRESULT         timerID;

+    BOOL             ifInsideCallback;  /* Test for reentrancy. */

+    int              framesPerDSBuffer;

+    double           framesWritten;

+    double           secondsPerHostByte; /* Used to optimize latency calculation for outTime */

+

+    PaStreamCallbackFlags callbackFlags;

+    

+/* FIXME - move all below to PaUtilStreamRepresentation */

+    volatile int     isStarted;

+    volatile int     isActive;

+    volatile int     stopProcessing; /* stop thread once existing buffers have been returned */

+    volatile int     abortProcessing; /* stop thread immediately */

+} PaWinDsStream;

+

+

+/************************************************************************************

+** Duplicate the input string using the allocations allocator.

+** A NULL string is converted to a zero length string.

+** If memory cannot be allocated, NULL is returned.

+**/

+static char *DuplicateDeviceNameString( PaUtilAllocationGroup *allocations, const char* src )

+{

+    char *result = 0;

+    

+    if( src != NULL )

+    {

+        size_t len = strlen(src);

+        result = (char*)PaUtil_GroupAllocateMemory( allocations, (long)(len + 1) );

+        if( result )

+            memcpy( (void *) result, src, len+1 );

+    }

+    else

+    {

+        result = (char*)PaUtil_GroupAllocateMemory( allocations, 1 );

+        if( result )

+            result[0] = '\0';

+    }

+

+    return result;

+}

+

+/************************************************************************************

+** DSDeviceNameAndGUID, DSDeviceNameAndGUIDVector used for collecting preliminary

+** information during device enumeration.

+*/

+typedef struct DSDeviceNameAndGUID{

+    char *name; // allocated from parent's allocations, never deleted by this structure

+    GUID guid;

+    LPGUID lpGUID;

+} DSDeviceNameAndGUID;

+

+typedef struct DSDeviceNameAndGUIDVector{

+    PaUtilAllocationGroup *allocations;

+    PaError enumerationError;

+

+    int count;

+    int free;

+    DSDeviceNameAndGUID *items; // Allocated using LocalAlloc()

+} DSDeviceNameAndGUIDVector;

+

+static PaError InitializeDSDeviceNameAndGUIDVector(

+        DSDeviceNameAndGUIDVector *guidVector, PaUtilAllocationGroup *allocations )

+{

+    PaError result = paNoError;

+

+    guidVector->allocations = allocations;

+    guidVector->enumerationError = paNoError;

+

+    guidVector->count = 0;

+    guidVector->free = 8;

+    guidVector->items = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * guidVector->free );

+    if( guidVector->items == NULL )

+        result = paInsufficientMemory;

+    

+    return result;

+}

+

+static PaError ExpandDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector )

+{

+    PaError result = paNoError;

+    DSDeviceNameAndGUID *newItems;

+    int i;

+    

+    /* double size of vector */

+    int size = guidVector->count + guidVector->free;

+    guidVector->free += size;

+

+    newItems = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * size * 2 );

+    if( newItems == NULL )

+    {

+        result = paInsufficientMemory;

+    }

+    else

+    {

+        for( i=0; i < guidVector->count; ++i )

+        {

+            newItems[i].name = guidVector->items[i].name;

+            if( guidVector->items[i].lpGUID == NULL )

+            {

+                newItems[i].lpGUID = NULL;

+            }

+            else

+            {

+                newItems[i].lpGUID = &newItems[i].guid;

+                memcpy( &newItems[i].guid, guidVector->items[i].lpGUID, sizeof(GUID) );;

+            }

+        }

+

+        LocalFree( guidVector->items );

+        guidVector->items = newItems;

+    }                                

+

+    return result;

+}

+

+/*

+    it's safe to call DSDeviceNameAndGUIDVector multiple times

+*/

+static PaError TerminateDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector )

+{

+    PaError result = paNoError;

+

+    if( guidVector->items != NULL )

+    {

+        if( LocalFree( guidVector->items ) != NULL )

+            result = paInsufficientMemory;              /** @todo this isn't the correct error to return from a deallocation failure */

+

+        guidVector->items = NULL;

+    }

+

+    return result;

+}

+

+/************************************************************************************

+** Collect preliminary device information during DirectSound enumeration 

+*/

+static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID,

+                                     LPCTSTR lpszDesc,

+                                     LPCTSTR lpszDrvName,

+                                     LPVOID lpContext )

+{

+    DSDeviceNameAndGUIDVector *namesAndGUIDs = (DSDeviceNameAndGUIDVector*)lpContext;

+    PaError error;

+

+    (void) lpszDrvName; /* unused variable */

+

+    if( namesAndGUIDs->free == 0 )

+    {

+        error = ExpandDSDeviceNameAndGUIDVector( namesAndGUIDs );

+        if( error != paNoError )

+        {

+            namesAndGUIDs->enumerationError = error;

+            return FALSE;

+        }

+    }

+    

+    /* Set GUID pointer, copy GUID to storage in DSDeviceNameAndGUIDVector. */

+    if( lpGUID == NULL )

+    {

+        namesAndGUIDs->items[namesAndGUIDs->count].lpGUID = NULL;

+    }

+    else

+    {

+        namesAndGUIDs->items[namesAndGUIDs->count].lpGUID =

+                &namesAndGUIDs->items[namesAndGUIDs->count].guid;

+      

+        memcpy( &namesAndGUIDs->items[namesAndGUIDs->count].guid, lpGUID, sizeof(GUID) );

+    }

+

+    namesAndGUIDs->items[namesAndGUIDs->count].name =

+            DuplicateDeviceNameString( namesAndGUIDs->allocations, lpszDesc );

+    if( namesAndGUIDs->items[namesAndGUIDs->count].name == NULL )

+    {

+        namesAndGUIDs->enumerationError = paInsufficientMemory;

+        return FALSE;

+    }

+

+    ++namesAndGUIDs->count;

+    --namesAndGUIDs->free;

+    

+    return TRUE;

+}

+

+

+#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_  (13) /* must match array length below */

+static double defaultSampleRateSearchOrder_[] =

+    { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0,

+        16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };

+

+

+/************************************************************************************

+** Extract capabilities from an output device, and add it to the device info list

+** if successful. This function assumes that there is enough room in the

+** device info list to accomodate all entries.

+**

+** The device will not be added to the device list if any errors are encountered.

+*/

+static PaError AddOutputDeviceInfoFromDirectSound(

+        PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID )

+{

+    PaUtilHostApiRepresentation  *hostApi = &winDsHostApi->inheritedHostApiRep;

+    PaDeviceInfo                 *deviceInfo = hostApi->deviceInfos[hostApi->info.deviceCount];

+    PaWinDsDeviceInfo            *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[hostApi->info.deviceCount];

+    HRESULT                       hr;

+    LPDIRECTSOUND                 lpDirectSound;

+    DSCAPS                        caps;

+    int                           deviceOK = TRUE;

+    PaError                       result = paNoError;

+    int                           i;

+    

+    /* Copy GUID to the device info structure. Set pointer. */

+    if( lpGUID == NULL )

+    {

+        winDsDeviceInfo->lpGUID = NULL;

+    }

+    else

+    {

+        memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) );

+        winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid;

+    }

+

+    

+    /* Create a DirectSound object for the specified GUID

+        Note that using CoCreateInstance doesn't work on windows CE.

+    */

+    hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &lpDirectSound, NULL );

+

+    /** try using CoCreateInstance because DirectSoundCreate was hanging under

+        some circumstances - note this was probably related to the

+        #define BOOL short bug which has now been fixed

+        @todo delete this comment and the following code once we've ensured

+        there is no bug.

+    */

+    /*

+    hr = CoCreateInstance( &CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,

+            &IID_IDirectSound, (void**)&lpDirectSound );

+

+    if( hr == S_OK )

+    {

+        hr = IDirectSound_Initialize( lpDirectSound, lpGUID );

+    }

+    */

+    

+    if( hr != DS_OK )

+    {

+        DBUG(("Cannot create DirectSound for %s. Result = 0x%x\n", name, hr ));

+        deviceOK = FALSE;

+    }

+    else

+    {

+        /* Query device characteristics. */

+        memset( &caps, 0, sizeof(caps) ); 

+        caps.dwSize = sizeof(caps);

+        hr = IDirectSound_GetCaps( lpDirectSound, &caps );

+        if( hr != DS_OK )

+        {

+            DBUG(("Cannot GetCaps() for DirectSound device %s. Result = 0x%x\n", name, hr ));

+            deviceOK = FALSE;

+        }

+        else

+        {

+

+#ifndef PA_NO_WMME

+            if( caps.dwFlags & DSCAPS_EMULDRIVER )

+            {

+                /* If WMME supported, then reject Emulated drivers because they are lousy. */

+                deviceOK = FALSE;

+            }

+#endif

+

+            if( deviceOK )

+            {

+                deviceInfo->maxInputChannels = 0;

+                /* Mono or stereo device? */

+                deviceInfo->maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;

+

+                deviceInfo->defaultLowInputLatency = 0.;    /** @todo IMPLEMENT ME */

+                deviceInfo->defaultLowOutputLatency = 0.;   /** @todo IMPLEMENT ME */

+                deviceInfo->defaultHighInputLatency = 0.;   /** @todo IMPLEMENT ME */

+                deviceInfo->defaultHighOutputLatency = 0.;  /** @todo IMPLEMENT ME */

+                

+                /* initialize defaultSampleRate */

+                

+                if( caps.dwFlags & DSCAPS_CONTINUOUSRATE )

+                {

+                    /* initialize to caps.dwMaxSecondarySampleRate incase none of the standard rates match */

+                    deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;

+

+                    for( i = 0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i )

+                    {

+                        if( defaultSampleRateSearchOrder_[i] >= caps.dwMinSecondarySampleRate

+                                && defaultSampleRateSearchOrder_[i] <= caps.dwMaxSecondarySampleRate ){

+

+                            deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[i];

+                            break;

+                        }

+                    }

+                }

+                else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate )

+                {

+                    if( caps.dwMinSecondarySampleRate == 0 )

+                    {

+                        /*

+                        ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !!

+                        ** But it supports continuous sampling.

+                        ** So fake range of rates, and hope it really supports it.

+                        */

+                        deviceInfo->defaultSampleRate = 44100.0f;

+

+                        DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex ));

+                    }

+                    else

+                    {

+	                    deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;

+                    }

+                }

+                else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) )

+                {

+                    /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000.

+                    ** But we know that they really support a range of rates!

+                    ** So when we see a ridiculous set of rates, assume it is a range.

+                    */

+                  deviceInfo->defaultSampleRate = 44100.0f;

+                  DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex ));

+                }

+                else deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;

+

+

+                //printf( "min %d max %d\n", caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate );

+                // dwFlags | DSCAPS_CONTINUOUSRATE 

+            }

+        }

+

+        IDirectSound_Release( lpDirectSound );

+    }

+

+    if( deviceOK )

+    {

+        deviceInfo->name = name;

+

+        if( lpGUID == NULL )

+            hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;

+            

+        hostApi->info.deviceCount++;

+    }

+

+    return result;

+}

+

+

+/************************************************************************************

+** Extract capabilities from an input device, and add it to the device info list

+** if successful. This function assumes that there is enough room in the

+** device info list to accomodate all entries.

+**

+** The device will not be added to the device list if any errors are encountered.

+*/

+static PaError AddInputDeviceInfoFromDirectSoundCapture(

+        PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID )

+{

+    PaUtilHostApiRepresentation  *hostApi = &winDsHostApi->inheritedHostApiRep;

+    PaDeviceInfo                 *deviceInfo = hostApi->deviceInfos[hostApi->info.deviceCount];

+    PaWinDsDeviceInfo            *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[hostApi->info.deviceCount];

+    HRESULT                       hr;

+    LPDIRECTSOUNDCAPTURE          lpDirectSoundCapture;

+    DSCCAPS                       caps;

+    int                           deviceOK = TRUE;

+    PaError                       result = paNoError;

+    

+    /* Copy GUID to the device info structure. Set pointer. */

+    if( lpGUID == NULL )

+    {

+        winDsDeviceInfo->lpGUID = NULL;

+    }

+    else

+    {

+        winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid;

+        memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) );

+    }

+

+

+    hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL );

+

+    /** try using CoCreateInstance because DirectSoundCreate was hanging under

+        some circumstances - note this was probably related to the

+        #define BOOL short bug which has now been fixed

+        @todo delete this comment and the following code once we've ensured

+        there is no bug.

+    */

+    /*

+    hr = CoCreateInstance( &CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,

+            &IID_IDirectSoundCapture, (void**)&lpDirectSoundCapture );

+    */

+    if( hr != DS_OK )

+    {

+        DBUG(("Cannot create Capture for %s. Result = 0x%x\n", name, hr ));

+        deviceOK = FALSE;

+    }

+    else

+    {

+        /* Query device characteristics. */

+        memset( &caps, 0, sizeof(caps) );

+        caps.dwSize = sizeof(caps);

+        hr = IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps );

+        if( hr != DS_OK )

+        {

+            DBUG(("Cannot GetCaps() for Capture device %s. Result = 0x%x\n", name, hr ));

+            deviceOK = FALSE;

+        }

+        else

+        {

+#ifndef PA_NO_WMME

+            if( caps.dwFlags & DSCAPS_EMULDRIVER )

+            {

+                /* If WMME supported, then reject Emulated drivers because they are lousy. */

+                deviceOK = FALSE;

+            }

+#endif

+

+            if( deviceOK )

+            {

+                deviceInfo->maxInputChannels = caps.dwChannels;

+                deviceInfo->maxOutputChannels = 0;

+

+                deviceInfo->defaultLowInputLatency = 0.;    /** @todo IMPLEMENT ME */

+                deviceInfo->defaultLowOutputLatency = 0.;   /** @todo IMPLEMENT ME */

+                deviceInfo->defaultHighInputLatency = 0.;   /** @todo IMPLEMENT ME */

+                deviceInfo->defaultHighOutputLatency = 0.;  /** @todo IMPLEMENT ME */

+

+/*  constants from a WINE patch by Francois Gouget, see:

+    http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html

+

+    ---

+    Date: Fri, 14 May 2004 10:38:12 +0200 (CEST)

+    From: Francois Gouget <fgouget@ ... .fr>

+    To: Ross Bencina <rbencina@ ... .au>

+    Subject: Re: Permission to use wine 48/96 wave patch in BSD licensed library

+

+    [snip]

+

+    I give you permission to use the patch below under the BSD license.

+    http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html

+

+    [snip]

+*/

+#ifndef WAVE_FORMAT_48M08

+#define WAVE_FORMAT_48M08      0x00001000    /* 48     kHz, Mono,   8-bit  */

+#define WAVE_FORMAT_48S08      0x00002000    /* 48     kHz, Stereo, 8-bit  */

+#define WAVE_FORMAT_48M16      0x00004000    /* 48     kHz, Mono,   16-bit */

+#define WAVE_FORMAT_48S16      0x00008000    /* 48     kHz, Stereo, 16-bit */

+#define WAVE_FORMAT_96M08      0x00010000    /* 96     kHz, Mono,   8-bit  */

+#define WAVE_FORMAT_96S08      0x00020000    /* 96     kHz, Stereo, 8-bit  */

+#define WAVE_FORMAT_96M16      0x00040000    /* 96     kHz, Mono,   16-bit */

+#define WAVE_FORMAT_96S16      0x00080000    /* 96     kHz, Stereo, 16-bit */

+#endif

+

+                /* defaultSampleRate */

+                if( caps.dwChannels == 2 )

+                {

+                    if( caps.dwFormats & WAVE_FORMAT_4S16 )

+                        deviceInfo->defaultSampleRate = 44100.0;

+                    else if( caps.dwFormats & WAVE_FORMAT_48S16 )

+                        deviceInfo->defaultSampleRate = 48000.0;

+                    else if( caps.dwFormats & WAVE_FORMAT_2S16 )

+                        deviceInfo->defaultSampleRate = 22050.0;

+                    else if( caps.dwFormats & WAVE_FORMAT_1S16 )

+                        deviceInfo->defaultSampleRate = 11025.0;

+                    else if( caps.dwFormats & WAVE_FORMAT_96S16 )

+                        deviceInfo->defaultSampleRate = 96000.0;

+                    else

+                        deviceInfo->defaultSampleRate = 0.;

+                }

+                else if( caps.dwChannels == 1 )

+                {

+                    if( caps.dwFormats & WAVE_FORMAT_4M16 )

+                        deviceInfo->defaultSampleRate = 44100.0;

+                    else if( caps.dwFormats & WAVE_FORMAT_48M16 )

+                        deviceInfo->defaultSampleRate = 48000.0;

+                    else if( caps.dwFormats & WAVE_FORMAT_2M16 )

+                        deviceInfo->defaultSampleRate = 22050.0;

+                    else if( caps.dwFormats & WAVE_FORMAT_1M16 )

+                        deviceInfo->defaultSampleRate = 11025.0;

+                    else if( caps.dwFormats & WAVE_FORMAT_96M16 )

+                        deviceInfo->defaultSampleRate = 96000.0;

+                    else

+                        deviceInfo->defaultSampleRate = 0.;

+                }

+                else deviceInfo->defaultSampleRate = 0.;

+            }

+        }

+        

+        IDirectSoundCapture_Release( lpDirectSoundCapture );

+    }

+

+    if( deviceOK )

+    {

+        deviceInfo->name = name;

+

+        if( lpGUID == NULL )

+            hostApi->info.defaultInputDevice = hostApi->info.deviceCount;

+

+        hostApi->info.deviceCount++;

+    }

+

+    return result;

+}

+

+

+/***********************************************************************************/

+PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )

+{

+    PaError result = paNoError;

+    int i, deviceCount;

+    PaWinDsHostApiRepresentation *winDsHostApi;

+    DSDeviceNameAndGUIDVector inputNamesAndGUIDs, outputNamesAndGUIDs;

+    PaDeviceInfo *deviceInfoArray;

+

+    HRESULT hr = CoInitialize(NULL);        /** @todo: should uninitialize too */

+    if( FAILED(hr) ){

+        return paUnanticipatedHostError;

+    }            

+

+    /* initialise guid vectors so they can be safely deleted on error */

+    inputNamesAndGUIDs.items = NULL;

+    outputNamesAndGUIDs.items = NULL;

+

+    DSW_InitializeDSoundEntryPoints();

+

+    winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) );

+    if( !winDsHostApi )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    winDsHostApi->allocations = PaUtil_CreateAllocationGroup();

+    if( !winDsHostApi->allocations )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    *hostApi = &winDsHostApi->inheritedHostApiRep;

+    (*hostApi)->info.structVersion = 1;

+    (*hostApi)->info.type = paDirectSound;

+    (*hostApi)->info.name = "Windows DirectSound";

+    

+    (*hostApi)->info.deviceCount = 0;

+    (*hostApi)->info.defaultInputDevice = paNoDevice;

+    (*hostApi)->info.defaultOutputDevice = paNoDevice;

+

+    

+/* DSound - enumerate devices to count them and to gather their GUIDs */

+

+

+    result = InitializeDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs, winDsHostApi->allocations );

+    if( result != paNoError )

+        goto error;

+

+    result = InitializeDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs, winDsHostApi->allocations );

+    if( result != paNoError )

+        goto error;

+

+    dswDSoundEntryPoints.DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&inputNamesAndGUIDs );

+

+    dswDSoundEntryPoints.DirectSoundEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&outputNamesAndGUIDs );

+

+    if( inputNamesAndGUIDs.enumerationError != paNoError )

+    {

+        result = inputNamesAndGUIDs.enumerationError;

+        goto error;

+    }

+

+    if( outputNamesAndGUIDs.enumerationError != paNoError )

+    {

+        result = outputNamesAndGUIDs.enumerationError;

+        goto error;

+    }

+

+    deviceCount = inputNamesAndGUIDs.count + outputNamesAndGUIDs.count;

+

+    if( deviceCount > 0 )

+    {

+        /* allocate array for pointers to PaDeviceInfo structs */

+        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(

+                winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );

+        if( !(*hostApi)->deviceInfos )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        /* allocate all PaDeviceInfo structs in a contiguous block */

+        deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(

+                winDsHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );

+        if( !deviceInfoArray )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        /* allocate all DSound specific info structs in a contiguous block */

+        winDsHostApi->winDsDeviceInfos = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory(

+                winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount );

+        if( !winDsHostApi->winDsDeviceInfos )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        for( i=0; i < deviceCount; ++i )

+        {

+            PaDeviceInfo *deviceInfo = &deviceInfoArray[i];

+            deviceInfo->structVersion = 2;

+            deviceInfo->hostApi = hostApiIndex;

+            deviceInfo->name = 0;

+            (*hostApi)->deviceInfos[i] = deviceInfo;

+        }

+

+        for( i=0; i< inputNamesAndGUIDs.count; ++i )

+        {

+            result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi,

+                    inputNamesAndGUIDs.items[i].name,

+                    inputNamesAndGUIDs.items[i].lpGUID );

+            if( result != paNoError )

+                goto error;

+        }

+

+        for( i=0; i< outputNamesAndGUIDs.count; ++i )

+        {

+            result = AddOutputDeviceInfoFromDirectSound( winDsHostApi,

+                    outputNamesAndGUIDs.items[i].name,

+                    outputNamesAndGUIDs.items[i].lpGUID );

+            if( result != paNoError )

+                goto error;

+        }

+    }    

+

+    result = TerminateDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs );

+    if( result != paNoError )

+        goto error;

+

+    result = TerminateDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs );

+    if( result != paNoError )

+        goto error;

+

+    

+    (*hostApi)->Terminate = Terminate;

+    (*hostApi)->OpenStream = OpenStream;

+    (*hostApi)->IsFormatSupported = IsFormatSupported;

+

+    PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,

+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, GetStreamCpuLoad,

+                                      PaUtil_DummyRead, PaUtil_DummyWrite,

+                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );

+

+    PaUtil_InitializeStreamInterface( &winDsHostApi->blockingStreamInterface, CloseStream, StartStream,

+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, PaUtil_DummyGetCpuLoad,

+                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );

+

+    return result;

+

+error:

+    if( winDsHostApi )

+    {

+        if( winDsHostApi->allocations )

+        {

+            PaUtil_FreeAllAllocations( winDsHostApi->allocations );

+            PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );

+        }

+                

+        PaUtil_FreeMemory( winDsHostApi );

+    }

+

+    TerminateDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs );

+    TerminateDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs );

+

+    return result;

+}

+

+

+/***********************************************************************************/

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )

+{

+    PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;

+

+    /*

+        IMPLEMENT ME:

+            - clean up any resources not handled by the allocation group

+    */

+

+    if( winDsHostApi->allocations )

+    {

+        PaUtil_FreeAllAllocations( winDsHostApi->allocations );

+        PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );

+    }

+

+    PaUtil_FreeMemory( winDsHostApi );

+

+    DSW_TerminateDSoundEntryPoints();

+

+    CoUninitialize();

+}

+

+

+/* Set minimal latency based on whether NT or Win95.

+ * NT has higher latency.

+ */

+static int PaWinDS_GetMinSystemLatency( void )

+{

+    int minLatencyMsec;

+    /* Set minimal latency based on whether NT or other OS.

+     * NT has higher latency.

+     */

+    OSVERSIONINFO osvi;

+	osvi.dwOSVersionInfoSize = sizeof( osvi );

+	GetVersionEx( &osvi );

+    DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId ));

+    DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion ));

+    DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion ));

+    /* Check for NT */

+	if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )

+	{

+		minLatencyMsec = PA_WIN_NT_LATENCY;

+	}

+	else if(osvi.dwMajorVersion >= 5)

+	{

+		minLatencyMsec = PA_WIN_WDM_LATENCY;

+	}

+	else

+	{

+		minLatencyMsec = PA_WIN_9X_LATENCY;

+	}

+    return minLatencyMsec;

+}

+

+/***********************************************************************************/

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate )

+{

+    int inputChannelCount, outputChannelCount;

+    PaSampleFormat inputSampleFormat, outputSampleFormat;

+    

+    if( inputParameters )

+    {

+        inputChannelCount = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+

+        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that input device can support inputChannelCount */

+        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )

+            return paInvalidChannelCount;

+

+        /* validate inputStreamInfo */

+        if( inputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */

+    }

+    else

+    {

+        inputChannelCount = 0;

+    }

+

+    if( outputParameters )

+    {

+        outputChannelCount = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+        

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+

+        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that output device can support inputChannelCount */

+        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )

+            return paInvalidChannelCount;

+

+        /* validate outputStreamInfo */

+        if( outputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */

+    }

+    else

+    {

+        outputChannelCount = 0;

+    }

+    

+    /*

+        IMPLEMENT ME:

+

+            - if a full duplex stream is requested, check that the combination

+                of input and output parameters is supported if necessary

+

+            - check that the device supports sampleRate

+

+        Because the buffer adapter handles conversion between all standard

+        sample formats, the following checks are only required if paCustomFormat

+        is implemented, or under some other unusual conditions.

+

+            - check that input device can support inputSampleFormat, or that

+                we have the capability to convert from outputSampleFormat to

+                a native format

+

+            - check that output device can support outputSampleFormat, or that

+                we have the capability to convert from outputSampleFormat to

+                a native format

+    */

+

+    return paFormatIsSupported;

+}

+

+

+/*************************************************************************

+** Determine minimum number of buffers required for this host based

+** on minimum latency. Latency can be optionally set by user by setting

+** an environment variable. For example, to set latency to 200 msec, put:

+**

+**    set PA_MIN_LATENCY_MSEC=200

+**

+** in the AUTOEXEC.BAT file and reboot.

+** If the environment variable is not set, then the latency will be determined

+** based on the OS. Windows NT has higher latency than Win95.

+*/

+#define PA_LATENCY_ENV_NAME  ("PA_MIN_LATENCY_MSEC")

+#define PA_ENV_BUF_SIZE  (32)

+

+static int PaWinDs_GetMinLatencyFrames( double sampleRate )

+{

+    char      envbuf[PA_ENV_BUF_SIZE];

+    DWORD     hresult;

+    int       minLatencyMsec = 0;

+

+    /* Let user determine minimal latency by setting environment variable. */

+    hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE );

+    if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )

+    {

+        minLatencyMsec = atoi( envbuf );

+    }

+    else

+    {

+        minLatencyMsec = PaWinDS_GetMinSystemLatency();

+#if PA_USE_HIGH_LATENCY

+        PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));

+#endif

+

+    }

+

+    return (int) (minLatencyMsec * sampleRate * SECONDS_PER_MSEC);

+}

+

+#ifndef NDEBUG

+#define EZ  = 0

+#else

+#define EZ

+#endif

+

+/***********************************************************************************/

+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */

+

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** s,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *streamCallback,

+                           void *userData )

+{

+    PaError result = paNoError;

+    PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;

+    PaWinDsStream *stream = 0;

+    int inputChannelCount, outputChannelCount;

+    PaSampleFormat inputSampleFormat EZ, outputSampleFormat EZ;

+    PaSampleFormat hostInputSampleFormat EZ, hostOutputSampleFormat EZ;

+    unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames;

+

+    if( inputParameters )

+    {

+        inputChannelCount = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+        suggestedInputLatencyFrames = (unsigned long)(inputParameters->suggestedLatency * sampleRate);

+

+        /* IDEA: the following 3 checks could be performed by default by pa_front

+            unless some flag indicated otherwise */

+            

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that input device can support inputChannelCount */

+        if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )

+            return paInvalidChannelCount;

+            

+        /* validate hostApiSpecificStreamInfo */

+        if( inputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */

+    }

+    else

+    {

+        inputChannelCount = 0;

+        suggestedInputLatencyFrames = 0;

+    }

+

+

+    if( outputParameters )

+    {

+        outputChannelCount = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+        suggestedOutputLatencyFrames = (unsigned long)(outputParameters->suggestedLatency * sampleRate);

+

+        /* unless alternate device specification is supported, reject the use of

+            paUseHostApiSpecificDeviceSpecification */

+        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )

+            return paInvalidDevice;

+

+        /* check that output device can support inputChannelCount */

+        if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )

+            return paInvalidChannelCount;

+

+        /* validate hostApiSpecificStreamInfo */

+        if( outputParameters->hostApiSpecificStreamInfo )

+            return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */            

+    }

+    else

+    {

+        outputChannelCount = 0;

+        suggestedOutputLatencyFrames = 0;

+    }

+

+

+    /*

+        IMPLEMENT ME:

+

+        ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() )

+

+            - check that input device can support inputSampleFormat, or that

+                we have the capability to convert from outputSampleFormat to

+                a native format

+

+            - check that output device can support outputSampleFormat, or that

+                we have the capability to convert from outputSampleFormat to

+                a native format

+

+            - if a full duplex stream is requested, check that the combination

+                of input and output parameters is supported

+

+            - check that the device supports sampleRate

+

+            - alter sampleRate to a close allowable rate if possible / necessary

+

+            - validate suggestedInputLatency and suggestedOutputLatency parameters,

+                use default values where necessary

+    */

+

+

+    /* validate platform specific flags */

+    if( (streamFlags & paPlatformSpecificFlags) != 0 )

+        return paInvalidFlag; /* unexpected platform specific flag */

+

+

+    stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) );

+    if( !stream )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    if( streamCallback )

+    {

+        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,

+                                               &winDsHostApi->callbackStreamInterface, streamCallback, userData );

+    }

+    else

+    {

+        PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,

+                                               &winDsHostApi->blockingStreamInterface, streamCallback, userData );

+    }

+    

+    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );

+

+

+    if( inputParameters )

+    {

+        /* IMPLEMENT ME - establish which  host formats are available */

+        hostInputSampleFormat =

+            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputParameters->sampleFormat );

+    }

+

+    if( outputParameters )

+    {

+        /* IMPLEMENT ME - establish which  host formats are available */

+        hostOutputSampleFormat =

+            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputParameters->sampleFormat );

+    }

+    

+    result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,

+                    inputChannelCount, inputSampleFormat, hostInputSampleFormat,

+                    outputChannelCount, outputSampleFormat, hostOutputSampleFormat,

+                    sampleRate, streamFlags, framesPerBuffer,

+                    framesPerBuffer, /* ignored in paUtilVariableHostBufferSizePartialUsageAllowed mode. */

+                /* This next mode is required because DS can split the host buffer when it wraps around. */

+                    paUtilVariableHostBufferSizePartialUsageAllowed,

+                    streamCallback, userData );

+    if( result != paNoError )

+        goto error;

+

+

+    stream->streamRepresentation.streamInfo.inputLatency =

+            PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);   /* FIXME: not initialised anywhere else */

+    stream->streamRepresentation.streamInfo.outputLatency =

+            PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);    /* FIXME: not initialised anywhere else */

+    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;

+

+    

+/* DirectSound specific initialization */

+    {

+        HRESULT          hr;

+        int              bytesPerDirectSoundBuffer;

+        DSoundWrapper   *dsw;

+        int              userLatencyFrames;

+        int              minLatencyFrames;

+

+        stream->timerID = 0;

+        dsw = &stream->directSoundWrapper;

+        DSW_Init( dsw );

+

+    /* Get system minimum latency. */

+        minLatencyFrames = PaWinDs_GetMinLatencyFrames( sampleRate );

+

+    /* Let user override latency by passing latency parameter. */

+        userLatencyFrames = (suggestedInputLatencyFrames > suggestedOutputLatencyFrames)

+                    ? suggestedInputLatencyFrames

+                    : suggestedOutputLatencyFrames;

+        if( userLatencyFrames > 0 ) minLatencyFrames = userLatencyFrames;

+

+    /* Calculate stream->framesPerDSBuffer depending on framesPerBuffer */

+        if( framesPerBuffer == paFramesPerBufferUnspecified )

+        {

+        /* App support variable framesPerBuffer */

+            stream->framesPerDSBuffer = minLatencyFrames;

+

+            stream->streamRepresentation.streamInfo.outputLatency = (double)(minLatencyFrames - 1) / sampleRate;

+        }

+        else

+        {

+        /* Round up to number of buffers needed to guarantee that latency. */

+            int numUserBuffers = (minLatencyFrames + framesPerBuffer - 1) / framesPerBuffer;

+            if( numUserBuffers < 1 ) numUserBuffers = 1;

+            numUserBuffers += 1; /* So we have latency worth of buffers ahead of current buffer. */

+            stream->framesPerDSBuffer = framesPerBuffer * numUserBuffers;

+

+            stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerBuffer * (numUserBuffers-1)) / sampleRate;

+        }

+

+        {

+            /** @todo REVIEW: this calculation seems incorrect to me - rossb. */

+            int msecLatency = (int) ((stream->framesPerDSBuffer * MSEC_PER_SECOND) / sampleRate);

+            PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", stream->framesPerDSBuffer, msecLatency ));

+        }

+

+

+        /* ------------------ OUTPUT */

+        if( outputParameters )

+        {

+            /*

+            PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ outputParameters->device ];

+            DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", outputParameters->device));

+            */

+            

+            bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * outputParameters->channelCount * sizeof(short);

+            if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )

+            {

+                result = paBufferTooSmall;

+                goto error;

+            }

+            else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )

+            {

+                result = paBufferTooBig;

+                goto error;

+            }

+

+

+            hr = dswDSoundEntryPoints.DirectSoundCreate( winDsHostApi->winDsDeviceInfos[outputParameters->device].lpGUID,

+                &dsw->dsw_pDirectSound,   NULL );

+            if( hr != DS_OK )

+            {

+                ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n"));

+                result = paUnanticipatedHostError;

+                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );

+                goto error;

+            }

+            hr = DSW_InitOutputBuffer( dsw,

+                                       (unsigned long) (sampleRate + 0.5),

+                                       (WORD)outputParameters->channelCount, bytesPerDirectSoundBuffer );

+            DBUG(("DSW_InitOutputBuffer() returns %x\n", hr));

+            if( hr != DS_OK )

+            {

+                result = paUnanticipatedHostError;

+                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );

+                goto error;

+            }

+            /* Calculate value used in latency calculation to avoid real-time divides. */

+            stream->secondsPerHostByte = 1.0 /

+                (stream->bufferProcessor.bytesPerHostOutputSample *

+                outputChannelCount * sampleRate);

+        }

+

+        /* ------------------ INPUT */

+        if( inputParameters )

+        {

+            /*

+            PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ inputParameters->device ];

+            DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", inputParameters->device));

+            */

+            

+            bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * inputParameters->channelCount * sizeof(short);

+            if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )

+            {

+                result = paBufferTooSmall;

+                goto error;

+            }

+            else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )

+            {

+                result = paBufferTooBig;

+                goto error;

+            }

+

+            hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( winDsHostApi->winDsDeviceInfos[inputParameters->device].lpGUID,

+                &dsw->dsw_pDirectSoundCapture,   NULL );

+            if( hr != DS_OK )

+            {

+                ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));

+                result = paUnanticipatedHostError;

+                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );

+                goto error;

+            }

+            hr = DSW_InitInputBuffer( dsw,

+                                      (unsigned long) (sampleRate + 0.5),

+                                      (WORD)inputParameters->channelCount, bytesPerDirectSoundBuffer );

+            DBUG(("DSW_InitInputBuffer() returns %x\n", hr));

+            if( hr != DS_OK )

+            {

+                ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));

+                result = paUnanticipatedHostError;

+                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );

+                goto error;

+            }

+        }

+

+    }

+

+    *s = (PaStream*)stream;

+

+    return result;

+

+error:

+    if( stream )

+        PaUtil_FreeMemory( stream );

+

+    return result;

+}

+

+

+/***********************************************************************************/

+static PaError Pa_TimeSlice( PaWinDsStream *stream )

+{

+    PaError           result = 0;   /* FIXME: this should be declared int and this function should also return that type (same as stream callback return type)*/

+    DSoundWrapper    *dsw;

+    long              numFrames = 0;

+    long              bytesEmpty = 0;

+    long              bytesFilled = 0;

+    long              bytesToXfer = 0;

+    long              framesToXfer = 0;

+    long              numInFramesReady = 0;

+    long              numOutFramesReady = 0;

+    long              bytesProcessed;

+    HRESULT           hresult;

+    double            outputLatency = 0;

+    PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */

+    

+/* Input */

+    LPBYTE            lpInBuf1 = NULL;

+    LPBYTE            lpInBuf2 = NULL;

+    DWORD             dwInSize1 = 0;

+    DWORD             dwInSize2 = 0;

+/* Output */

+    LPBYTE            lpOutBuf1 = NULL;

+    LPBYTE            lpOutBuf2 = NULL;

+    DWORD             dwOutSize1 = 0;

+    DWORD             dwOutSize2 = 0;

+

+    dsw = &stream->directSoundWrapper;

+

+    /* How much input data is available? */

+    if( stream->bufferProcessor.inputChannelCount > 0 )

+    {

+        DSW_QueryInputFilled( dsw, &bytesFilled );

+        framesToXfer = numInFramesReady = bytesFilled / dsw->dsw_BytesPerInputFrame;

+        outputLatency = ((double)bytesFilled) * stream->secondsPerHostByte;

+

+        /** @todo Check for overflow */

+    }

+

+    /* How much output room is available? */

+    if( stream->bufferProcessor.outputChannelCount > 0 )

+    {

+        UINT previousUnderflowCount = dsw->dsw_OutputUnderflows;

+        DSW_QueryOutputSpace( dsw, &bytesEmpty );

+        framesToXfer = numOutFramesReady = bytesEmpty / dsw->dsw_BytesPerOutputFrame;

+

+        /* Check for underflow */

+        if( dsw->dsw_OutputUnderflows != previousUnderflowCount )

+            stream->callbackFlags |= paOutputUnderflow;

+    }

+

+    if( (numInFramesReady > 0) && (numOutFramesReady > 0) )

+    {

+        framesToXfer = (numOutFramesReady < numInFramesReady) ? numOutFramesReady : numInFramesReady;

+    }

+

+    if( framesToXfer > 0 )

+    {

+

+        PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

+

+    /* The outputBufferDacTime parameter should indicates the time at which

+        the first sample of the output buffer is heard at the DACs. */

+        timeInfo.currentTime = PaUtil_GetTime();

+        timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency;

+

+

+        PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, stream->callbackFlags );

+        stream->callbackFlags = 0;

+        

+    /* Input */

+        if( stream->bufferProcessor.inputChannelCount > 0 )

+        {

+            bytesToXfer = framesToXfer * dsw->dsw_BytesPerInputFrame;

+            hresult = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer,

+                dsw->dsw_ReadOffset, bytesToXfer,

+                (void **) &lpInBuf1, &dwInSize1,

+                (void **) &lpInBuf2, &dwInSize2, 0);

+            if (hresult != DS_OK)

+            {

+                ERR_RPT(("DirectSound IDirectSoundCaptureBuffer_Lock failed, hresult = 0x%x\n",hresult));

+                result = paUnanticipatedHostError;

+                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );

+                goto error2;

+            }

+

+            numFrames = dwInSize1 / dsw->dsw_BytesPerInputFrame;

+            PaUtil_SetInputFrameCount( &stream->bufferProcessor, numFrames );

+            PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf1, 0 );

+        /* Is input split into two regions. */

+            if( dwInSize2 > 0 )

+            {

+                numFrames = dwInSize2 / dsw->dsw_BytesPerInputFrame;

+                PaUtil_Set2ndInputFrameCount( &stream->bufferProcessor, numFrames );

+                PaUtil_Set2ndInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf2, 0 );

+            }

+        }

+

+    /* Output */

+        if( stream->bufferProcessor.outputChannelCount > 0 )

+        {

+            bytesToXfer = framesToXfer * dsw->dsw_BytesPerOutputFrame;

+            hresult = IDirectSoundBuffer_Lock ( dsw->dsw_OutputBuffer,

+                dsw->dsw_WriteOffset, bytesToXfer,

+                (void **) &lpOutBuf1, &dwOutSize1,

+                (void **) &lpOutBuf2, &dwOutSize2, 0);

+            if (hresult != DS_OK)

+            {

+                ERR_RPT(("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n",hresult));

+                result = paUnanticipatedHostError;

+                PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );

+                goto error1;

+            }

+

+            numFrames = dwOutSize1 / dsw->dsw_BytesPerOutputFrame;

+            PaUtil_SetOutputFrameCount( &stream->bufferProcessor, numFrames );

+            PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf1, 0 );

+

+        /* Is output split into two regions. */

+            if( dwOutSize2 > 0 )

+            {

+                numFrames = dwOutSize2 / dsw->dsw_BytesPerOutputFrame;

+                PaUtil_Set2ndOutputFrameCount( &stream->bufferProcessor, numFrames );

+                PaUtil_Set2ndInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf2, 0 );

+            }

+        }

+

+        result = paContinue;

+        numFrames = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &result );

+        stream->framesWritten += numFrames;

+        

+        if( stream->bufferProcessor.outputChannelCount > 0 )

+        {

+        /* FIXME: an underflow could happen here */

+

+        /* Update our buffer offset and unlock sound buffer */

+            bytesProcessed = numFrames * dsw->dsw_BytesPerOutputFrame;

+            dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + bytesProcessed) % dsw->dsw_OutputSize;

+            IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2);

+            dsw->dsw_FramesWritten += numFrames;

+        }

+

+error1:

+        if( stream->bufferProcessor.inputChannelCount > 0 )

+        {

+        /* FIXME: an overflow could happen here */

+

+        /* Update our buffer offset and unlock sound buffer */

+            bytesProcessed = numFrames * dsw->dsw_BytesPerInputFrame;

+            dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + bytesProcessed) % dsw->dsw_InputSize;

+            IDirectSoundCaptureBuffer_Unlock( dsw->dsw_InputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2);

+        }

+error2:

+

+        PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, numFrames );

+

+    }

+    

+    return result;

+}

+/*******************************************************************/

+static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)

+{

+    PaWinDsStream *stream;

+

+    /* suppress unused variable warnings */

+    (void) uID;

+    (void) uMsg;

+    (void) dw1;

+    (void) dw2;

+    

+    stream = (PaWinDsStream *) dwUser;

+    if( stream == NULL ) return;

+

+    if( stream->isActive )

+    {

+        if( stream->abortProcessing )

+        {

+            stream->isActive = 0;

+        }

+        else if( stream->stopProcessing )

+        {

+            DSoundWrapper   *dsw = &stream->directSoundWrapper;

+            if( stream->bufferProcessor.outputChannelCount > 0 )

+            {

+                DSW_ZeroEmptySpace( dsw );

+                /* clear isActive when all sound played */

+                if( dsw->dsw_FramesPlayed >= stream->framesWritten )

+                {

+                    stream->isActive = 0;

+                }

+            }

+            else

+            {

+                stream->isActive = 0;

+            }

+        }

+        else

+        {

+            if( Pa_TimeSlice( stream ) != 0)  /* Call time slice independant of timing method. */

+            {

+                /* FIXME implement handling of paComplete and paAbort if possible */

+                stream->stopProcessing = 1;

+            }

+        }

+

+        if( !stream->isActive ){

+            if( stream->streamRepresentation.streamFinishedCallback != 0 )

+                stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );

+        }

+    }

+}

+

+/***********************************************************************************

+    When CloseStream() is called, the multi-api layer ensures that

+    the stream has already been stopped or aborted.

+*/

+static PaError CloseStream( PaStream* s )

+{

+    PaError result = paNoError;

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+

+    DSW_Term( &stream->directSoundWrapper );

+

+    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );

+    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );

+    PaUtil_FreeMemory( stream );

+

+    return result;

+}

+

+/***********************************************************************************/

+static PaError StartStream( PaStream *s )

+{

+    PaError          result = paNoError;

+    PaWinDsStream   *stream = (PaWinDsStream*)s;

+    HRESULT          hr;

+

+    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );

+    

+    if( stream->bufferProcessor.inputChannelCount > 0 )

+    {

+        hr = DSW_StartInput( &stream->directSoundWrapper );

+        DBUG(("StartStream: DSW_StartInput returned = 0x%X.\n", hr));

+        if( hr != DS_OK )

+        {

+            result = paUnanticipatedHostError;

+            PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );

+            goto error;

+        }

+    }

+

+    stream->framesWritten = 0;

+    stream->callbackFlags = 0;

+

+    stream->abortProcessing = 0;

+    stream->stopProcessing = 0;

+    stream->isActive = 1;

+

+    if( stream->bufferProcessor.outputChannelCount > 0 )

+    {

+        /* Give user callback a chance to pre-fill buffer. REVIEW - i thought we weren't pre-filling, rb. */

+        result = Pa_TimeSlice( stream );

+        if( result != paNoError ) return result; // FIXME - what if finished?

+

+        hr = DSW_StartOutput( &stream->directSoundWrapper );

+        DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));

+        if( hr != DS_OK )

+        {

+            result = paUnanticipatedHostError;

+            PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );

+            goto error;

+        }

+    }

+

+

+    /* Create timer that will wake us up so we can fill the DSound buffer. */

+    {

+        int resolution;

+        int framesPerWakeup = stream->framesPerDSBuffer / 4;

+        int msecPerWakeup = MSEC_PER_SECOND * framesPerWakeup / (int) stream->streamRepresentation.streamInfo.sampleRate;

+        if( msecPerWakeup < 10 ) msecPerWakeup = 10;

+        else if( msecPerWakeup > 100 ) msecPerWakeup = 100;

+        resolution = msecPerWakeup/4;

+        stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback,

+                                             (DWORD) stream, TIME_PERIODIC );

+    }

+    if( stream->timerID == 0 )

+    {

+        stream->isActive = 0;

+        result = paUnanticipatedHostError;

+        PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );

+        goto error;

+    }

+

+    stream->isStarted = TRUE;

+

+error:

+    return result;

+}

+

+

+/***********************************************************************************/

+static PaError StopStream( PaStream *s )

+{

+    PaError result = paNoError;

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+    HRESULT          hr;

+    int timeoutMsec;

+

+    stream->stopProcessing = 1;

+    /* Set timeout at 20% beyond maximum time we might wait. */

+    timeoutMsec = (int) (1200.0 * stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate);

+    while( stream->isActive && (timeoutMsec > 0)  )

+    {

+        Sleep(10);

+        timeoutMsec -= 10;

+    }

+    if( stream->timerID != 0 )

+    {

+	timeKillEvent(stream->timerID);  /* Stop callback timer. */

+        stream->timerID = 0;

+    }

+

+

+    if( stream->bufferProcessor.outputChannelCount > 0 )

+    {

+        hr = DSW_StopOutput( &stream->directSoundWrapper );

+    }

+

+    if( stream->bufferProcessor.inputChannelCount > 0 )

+    {

+        hr = DSW_StopInput( &stream->directSoundWrapper );

+    }

+

+    stream->isStarted = FALSE;

+

+    return result;

+}

+

+

+/***********************************************************************************/

+static PaError AbortStream( PaStream *s )

+{

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+

+    stream->abortProcessing = 1;

+    return StopStream( s );

+}

+

+

+/***********************************************************************************/

+static PaError IsStreamStopped( PaStream *s )

+{

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+

+    return !stream->isStarted;

+}

+

+

+/***********************************************************************************/

+static PaError IsStreamActive( PaStream *s )

+{

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+

+    return stream->isActive;

+}

+

+/***********************************************************************************/

+static PaTime GetStreamTime( PaStream *s )

+{

+    /* suppress unused variable warnings */

+    (void) s;

+

+    

+/*

+    new behavior for GetStreamTime is to return a stream based seconds clock

+    used for the outTime parameter to the callback.

+    FIXME: delete this comment when the other unnecessary related code has

+    been cleaned from this file.

+

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+    DSoundWrapper   *dsw;

+    dsw = &stream->directSoundWrapper;

+    return dsw->dsw_FramesPlayed;

+*/

+    return PaUtil_GetTime();

+}

+

+

+/***********************************************************************************/

+static double GetStreamCpuLoad( PaStream* s )

+{

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+

+    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );

+}

+

+

+

+/***********************************************************************************

+    As separate stream interfaces are used for blocking and callback

+    streams, the following functions can be guaranteed to only be called

+    for blocking streams.

+*/

+

+static PaError ReadStream( PaStream* s,

+                           void *buffer,

+                           unsigned long frames )

+{

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) buffer;

+    (void) frames;

+    (void) stream;

+

+    /* IMPLEMENT ME, see portaudio.h for required behavior*/

+

+    return paNoError;

+}

+

+

+/***********************************************************************************/

+static PaError WriteStream( PaStream* s,

+                            const void *buffer,

+                            unsigned long frames )

+{

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) buffer;

+    (void) frames;

+    (void) stream;

+

+    /* IMPLEMENT ME, see portaudio.h for required behavior*/

+

+    return paNoError;

+}

+

+

+/***********************************************************************************/

+static signed long GetStreamReadAvailable( PaStream* s )

+{

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) stream;

+

+    /* IMPLEMENT ME, see portaudio.h for required behavior*/

+

+    return 0;

+}

+

+

+/***********************************************************************************/

+static signed long GetStreamWriteAvailable( PaStream* s )

+{

+    PaWinDsStream *stream = (PaWinDsStream*)s;

+

+    /* suppress unused variable warnings */

+    (void) stream;

+    

+    /* IMPLEMENT ME, see portaudio.h for required behavior*/

+

+    return 0;

+}

+

+

+

diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c b/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c
index 4e07fee..b95af51 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c
@@ -1,86 +1,107 @@
-/*
- * $Id: pa_win_hostapis.c,v 1.1.2.10 2004/09/08 17:31:37 rossbencina Exp $
- * Portable Audio I/O Library Windows initialization table
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
-    Win32 host API initialization function table.
-
-    @todo Consider using PA_USE_WMME etc instead of PA_NO_WMME. This is what
-    the Unix version does, we should consider being consistent.
-*/
-
-
-#include <pa_hostapi.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-PaUtilHostApiInitializer *paHostApiInitializers[] =
-    {
-
-#ifndef PA_NO_WMME
-        PaWinMme_Initialize,
-#endif
-
-#ifndef PA_NO_DS
-        PaWinDs_Initialize,
-#endif
-
-#ifndef PA_NO_ASIO
-        PaAsio_Initialize,
-#endif
-
-/*
-#ifndef PA_NO_WDMKS
-        PaWinWdm_Initialize,
-#endif
-*/
-
-        PaSkeleton_Initialize, /* just for testing */
-
-        0   /* NULL terminated array */
-    };
-
-
-int paDefaultHostApiIndex = 0;
-
+/*

+ * $Id: pa_win_hostapis.c,v 1.1.2.10 2004/09/08 17:31:37 rossbencina Exp $

+ * Portable Audio I/O Library Windows initialization table

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+    Win32 host API initialization function table.

+

+    @todo Consider using PA_USE_WMME etc instead of PA_NO_WMME. This is what

+    the Unix version does, we should consider being consistent.

+*/

+

+

+#include <pa_hostapi.h>

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+

+

+PaUtilHostApiInitializer *paHostApiInitializers[] =

+    {

+

+#ifndef PA_NO_WMME

+        PaWinMme_Initialize,

+#endif

+

+#ifndef PA_NO_DS

+        PaWinDs_Initialize,

+#endif

+

+#ifndef PA_NO_ASIO

+        PaAsio_Initialize,

+#endif

+

+/*

+#ifndef PA_NO_WDMKS

+        PaWinWdm_Initialize,

+#endif

+*/

+

+        PaSkeleton_Initialize, /* just for testing */

+

+        0   /* NULL terminated array */

+    };

+

+

+int paDefaultHostApiIndex = 0;

+

diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_util.c b/pjmedia/src/pjmedia/portaudio/pa_win_util.c
index 0395e5c..9f7fd33 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_win_util.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_win_util.c
@@ -1,134 +1,155 @@
-/*
- * $Id: pa_win_util.c,v 1.1.2.7 2003/09/15 18:30:26 rossbencina Exp $
- * Portable Audio I/O Library
- * Win32 platform-specific support functions
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- Win32 platform-specific support functions.
-
-    @todo Implement workaround for QueryPerformanceCounter() skipping forward
-    bug. (see msdn kb Q274323).
-*/
- 
-#include <windows.h>
-#include <mmsystem.h> /* for timeGetTime() */
-
-#include "pa_util.h"
-
-
-/*
-   Track memory allocations to avoid leaks.
- */
-
-#if PA_TRACK_MEMORY
-static int numAllocations_ = 0;
-#endif
-
-
-void *PaUtil_AllocateMemory( long size )
-{
-    void *result = GlobalAlloc( GPTR, size );
-
-#if PA_TRACK_MEMORY
-    if( result != NULL ) numAllocations_ += 1;
-#endif
-    return result;
-}
-
-
-void PaUtil_FreeMemory( void *block )
-{
-    if( block != NULL )
-    {
-        GlobalFree( block );
-#if PA_TRACK_MEMORY
-        numAllocations_ -= 1;
-#endif
-
-    }
-}
-
-
-int PaUtil_CountCurrentlyAllocatedBlocks( void )
-{
-#if PA_TRACK_MEMORY
-    return numAllocations_;
-#else
-    return 0;
-#endif
-}
-
-
-void Pa_Sleep( long msec )
-{
-    Sleep( msec );
-}
-
-static int usePerformanceCounter_;
-static double secondsPerTick_;
-
-void PaUtil_InitializeClock( void )
-{
-    LARGE_INTEGER ticksPerSecond;
-
-    if( QueryPerformanceFrequency( &ticksPerSecond ) != 0 )
-    {
-        usePerformanceCounter_ = 1;
-        secondsPerTick_ = 1.0 / (double)ticksPerSecond.QuadPart;
-    }
-    else
-    {
-        usePerformanceCounter_ = 0;
-    }
-}
-
-
-double PaUtil_GetTime( void )
-{
-    LARGE_INTEGER time;
-
-    if( usePerformanceCounter_ )
-    {
-        /* FIXME:
-            according to this knowledge-base article, QueryPerformanceCounter
-            can skip forward by seconds!
-            http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&
-
-            it may be better to use the rtdsc instruction using inline asm,
-            however then a method is needed to calculate a ticks/seconds ratio.
-        */
-        QueryPerformanceCounter( &time );
-        return time.QuadPart * secondsPerTick_;
-    }
-    else
-    {
-        return timeGetTime() * .001;
-    }
-}
+/*

+ * $Id: pa_win_util.c,v 1.1.2.7 2003/09/15 18:30:26 rossbencina Exp $

+ * Portable Audio I/O Library

+ * Win32 platform-specific support functions

+ *

+ * Based on the Open Source API proposed by Ross Bencina

+ * Copyright (c) 1999-2000 Ross Bencina

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/** @file

+ Win32 platform-specific support functions.

+

+    @todo Implement workaround for QueryPerformanceCounter() skipping forward

+    bug. (see msdn kb Q274323).

+*/

+ 

+#include <windows.h>

+#include <mmsystem.h> /* for timeGetTime() */

+

+#include "pa_util.h"

+

+

+/*

+   Track memory allocations to avoid leaks.

+ */

+

+#if PA_TRACK_MEMORY

+static int numAllocations_ = 0;

+#endif

+

+

+void *PaUtil_AllocateMemory( long size )

+{

+    void *result = GlobalAlloc( GPTR, size );

+

+#if PA_TRACK_MEMORY

+    if( result != NULL ) numAllocations_ += 1;

+#endif

+    return result;

+}

+

+

+void PaUtil_FreeMemory( void *block )

+{

+    if( block != NULL )

+    {

+        GlobalFree( block );

+#if PA_TRACK_MEMORY

+        numAllocations_ -= 1;

+#endif

+

+    }

+}

+

+

+int PaUtil_CountCurrentlyAllocatedBlocks( void )

+{

+#if PA_TRACK_MEMORY

+    return numAllocations_;

+#else

+    return 0;

+#endif

+}

+

+

+void Pa_Sleep( long msec )

+{

+    Sleep( msec );

+}

+

+static int usePerformanceCounter_;

+static double secondsPerTick_;

+

+void PaUtil_InitializeClock( void )

+{

+    LARGE_INTEGER ticksPerSecond;

+

+    if( QueryPerformanceFrequency( &ticksPerSecond ) != 0 )

+    {

+        usePerformanceCounter_ = 1;

+        secondsPerTick_ = 1.0 / (double)ticksPerSecond.QuadPart;

+    }

+    else

+    {

+        usePerformanceCounter_ = 0;

+    }

+}

+

+

+double PaUtil_GetTime( void )

+{

+    LARGE_INTEGER time;

+

+    if( usePerformanceCounter_ )

+    {

+        /* FIXME:

+            according to this knowledge-base article, QueryPerformanceCounter

+            can skip forward by seconds!

+            http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&

+

+            it may be better to use the rtdsc instruction using inline asm,

+            however then a method is needed to calculate a ticks/seconds ratio.

+        */

+        QueryPerformanceCounter( &time );

+        return time.QuadPart * secondsPerTick_;

+    }

+    else

+    {

+        return timeGetTime() * .001;

+    }

+}

diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_wmme.c b/pjmedia/src/pjmedia/portaudio/pa_win_wmme.c
index c3d7fe6..82c9078 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_win_wmme.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_win_wmme.c
@@ -1,3623 +1,3644 @@
-/*
- * $Id: pa_win_wmme.c,v 1.6.2.86 2004/02/21 11:38:28 rossbencina Exp $
- * pa_win_wmme.c
- * Implementation of PortAudio for Windows MultiMedia Extensions (WMME)       
- *                                                                                         
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Authors: Ross Bencina and Phil Burk
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-/* Modification History:
- PLB = Phil Burk
- JM = Julien Maillard
- RDB = Ross Bencina
- PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer)
- PLB20010413 - check for excessive numbers of channels
- PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
-               including conditional inclusion of memory.h,
-               and explicit typecasting on memory allocation
- PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory
- PLB20010816 - pass process instead of thread to SetPriorityClass()
- PLB20010927 - use number of frames instead of real-time for CPULoad calculation.
- JM20020118 - prevent hung thread when buffers underflow.
- PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount
- RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init
- RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices
-               refactoring, renaming and fixed a few edge case bugs
- RDB20020531 - converted to V19 framework
- ** NOTE  maintanance history is now stored in CVS **
-*/
-
-/** @file
-	
-	@todo Fix buffer catch up code, can sometimes get stuck (perhaps fixed now,
-            needs to be reviewed and tested.)
-
-    @todo implement paInputUnderflow, paOutputOverflow streamCallback statusFlags, paNeverDropInput.
-
-    @todo BUG: PA_MME_SET_LAST_WAVEIN/OUT_ERROR is used in functions which may
-                be called asynchronously from the callback thread. this is bad.
-
-    @todo implement inputBufferAdcTime in callback thread
-
-    @todo review/fix error recovery and cleanup in marked functions
-
-    @todo implement timeInfo for stream priming
-
-    @todo handle the case where the callback returns paAbort or paComplete during stream priming.
-
-    @todo review input overflow and output underflow handling in ReadStream and WriteStream
-
-Non-critical stuff for the future:
-
-    @todo Investigate supporting host buffer formats > 16 bits
-    
-    @todo define UNICODE and _UNICODE in the project settings and see what breaks
-
-*/
-
-/*
-    How it works:
-
-    For both callback and blocking read/write streams we open the MME devices
-    in CALLBACK_EVENT mode. In this mode, MME signals an Event object whenever
-    it has finished with a buffer (either filled it for input, or played it
-    for output). Where necessary we block waiting for Event objects using
-    WaitMultipleObjects().
-
-    When implementing a PA callback stream, we set up a high priority thread
-    which waits on the MME buffer Events and drains/fills the buffers when
-    they are ready.
-
-    When implementing a PA blocking read/write stream, we simply wait on these
-    Events (when necessary) inside the ReadStream() and WriteStream() functions.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <windows.h>
-#include <mmsystem.h>
-#include <process.h>
-#include <assert.h>
-/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
-#ifndef __MWERKS__
-#include <malloc.h>
-#include <memory.h>
-#endif /* __MWERKS__ */
-
-#include "portaudio.h"
-#include "pa_trace.h"
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
-#include "pa_win_wmme.h"
-
-#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
-#pragma comment(lib, "winmm.lib")
-#endif
-
-/************************************************* Constants ********/
-
-#define PA_MME_USE_HIGH_DEFAULT_LATENCY_    (0)  /* For debugging glitches. */
-
-#if PA_MME_USE_HIGH_DEFAULT_LATENCY_
- #define PA_MME_WIN_9X_DEFAULT_LATENCY_                     (0.4)
- #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_               (4)
- #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_	(4)
- #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_	(4)
- #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_	(16)
- #define PA_MME_MAX_HOST_BUFFER_SECS_				        (0.3)       /* Do not exceed unless user buffer exceeds */
- #define PA_MME_MAX_HOST_BUFFER_BYTES_				        (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
-#else
- #define PA_MME_WIN_9X_DEFAULT_LATENCY_                     (0.2)
- #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_               (2)
- #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_	(3)
- #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_	(2)
- #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_	(16)
- #define PA_MME_MAX_HOST_BUFFER_SECS_				        (0.1)       /* Do not exceed unless user buffer exceeds */
- #define PA_MME_MAX_HOST_BUFFER_BYTES_				        (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
-#endif
-
-/* Use higher latency for NT because it is even worse at real-time
-   operation than Win9x.
-*/
-#define PA_MME_WIN_NT_DEFAULT_LATENCY_      (PA_MME_WIN_9X_DEFAULT_LATENCY_ * 2)
-#define PA_MME_WIN_WDM_DEFAULT_LATENCY_     (PA_MME_WIN_9X_DEFAULT_LATENCY_)
-
-
-#define PA_MME_MIN_TIMEOUT_MSEC_        (1000)
-
-static const char constInputMapperSuffix_[] = " - Input";
-static const char constOutputMapperSuffix_[] = " - Output";
-
-/********************************************************************/
-
-typedef struct PaWinMmeStream PaWinMmeStream;     /* forward declaration */
-
-/* prototypes for functions declared in this file */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** stream,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *streamCallback,
-                           void *userData );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-
-
-/* macros for setting last host error information */
-
-#ifdef UNICODE
-
-#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
-    {                                                                   \
-        wchar_t mmeErrorTextWide[ MAXERRORLENGTH ];                     \
-        char mmeErrorText[ MAXERRORLENGTH ];                            \
-        waveInGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH );   \
-        WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
-            mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL );  \
-        PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText );   \
-    }
-
-#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
-    {                                                                   \
-        wchar_t mmeErrorTextWide[ MAXERRORLENGTH ];                     \
-        char mmeErrorText[ MAXERRORLENGTH ];                            \
-        waveOutGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH );  \
-        WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
-            mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL );  \
-        PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText );   \
-    }
-    
-#else /* !UNICODE */
-
-#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
-    {                                                                   \
-        char mmeErrorText[ MAXERRORLENGTH ];                            \
-        waveInGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH );   \
-        PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText );   \
-    }
-
-#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
-    {                                                                   \
-        char mmeErrorText[ MAXERRORLENGTH ];                            \
-        waveOutGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH );  \
-        PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText );   \
-    }
-
-#endif /* UNICODE */
-
-
-static void PaMme_SetLastSystemError( DWORD errorCode )
-{
-    char *lpMsgBuf;
-    FormatMessage(
-        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-        NULL,
-        errorCode,
-        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-        (LPTSTR) &lpMsgBuf,
-        0,
-        NULL
-    );
-    PaUtil_SetLastHostErrorInfo( paMME, errorCode, lpMsgBuf );
-    LocalFree( lpMsgBuf );
-}
-
-#define PA_MME_SET_LAST_SYSTEM_ERROR( errorCode ) \
-    PaMme_SetLastSystemError( errorCode )
-
-
-/* PaError returning wrappers for some commonly used win32 functions
-    note that we allow passing a null ptr to have no effect.
-*/
-
-static PaError CreateEventWithPaError( HANDLE *handle,
-        LPSECURITY_ATTRIBUTES lpEventAttributes,
-        BOOL bManualReset,
-        BOOL bInitialState,
-        LPCTSTR lpName )
-{
-    PaError result = paNoError;
-
-    *handle = NULL;
-    
-    *handle = CreateEvent( lpEventAttributes, bManualReset, bInitialState, lpName );
-    if( *handle == NULL )
-    {
-        result = paUnanticipatedHostError;
-        PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
-    }
-
-    return result;
-}
-
-
-static PaError ResetEventWithPaError( HANDLE handle )
-{
-    PaError result = paNoError;
-
-    if( handle )
-    {
-        if( ResetEvent( handle ) == 0 )
-        {
-            result = paUnanticipatedHostError;
-            PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
-        }
-    }
-
-    return result;
-}
-
-
-static PaError CloseHandleWithPaError( HANDLE handle )
-{
-    PaError result = paNoError;
-    
-    if( handle )
-    {
-        if( CloseHandle( handle ) == 0 )
-        {
-            result = paUnanticipatedHostError;
-            PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
-        }
-    }
-    
-    return result;
-}
-
-
-/* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct
-{
-    PaUtilHostApiRepresentation inheritedHostApiRep;
-    PaUtilStreamInterface callbackStreamInterface;
-    PaUtilStreamInterface blockingStreamInterface;
-
-    PaUtilAllocationGroup *allocations;
-    
-    int inputDeviceCount, outputDeviceCount;
-
-    /** winMmeDeviceIds is an array of WinMme device ids.
-        fields in the range [0, inputDeviceCount) are input device ids,
-        and [inputDeviceCount, inputDeviceCount + outputDeviceCount) are output
-        device ids.
-     */ 
-    UINT *winMmeDeviceIds;
-}
-PaWinMmeHostApiRepresentation;
-
-
-typedef struct
-{
-    PaDeviceInfo inheritedDeviceInfo;
-    DWORD dwFormats; /**<< standard formats bitmask from the WAVEINCAPS and WAVEOUTCAPS structures */
-}
-PaWinMmeDeviceInfo;
-
-
-/*************************************************************************
- * Returns recommended device ID.
- * On the PC, the recommended device can be specified by the user by
- * setting an environment variable. For example, to use device #1.
- *
- *    set PA_RECOMMENDED_OUTPUT_DEVICE=1
- *
- * The user should first determine the available device ID by using
- * the supplied application "pa_devs".
- */
-#define PA_ENV_BUF_SIZE_  (32)
-#define PA_REC_IN_DEV_ENV_NAME_  ("PA_RECOMMENDED_INPUT_DEVICE")
-#define PA_REC_OUT_DEV_ENV_NAME_  ("PA_RECOMMENDED_OUTPUT_DEVICE")
-static PaDeviceIndex GetEnvDefaultDeviceID( char *envName )
-{
-    PaDeviceIndex recommendedIndex = paNoDevice;
-    DWORD   hresult;
-    char    envbuf[PA_ENV_BUF_SIZE_];
-
-#ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */
-
-    /* Let user determine default device by setting environment variable. */
-    hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE_ );
-    if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) )
-    {
-        recommendedIndex = atoi( envbuf );
-    }
-#endif
-
-    return recommendedIndex;
-}
-
-
-static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *hostApi )
-{
-    PaDeviceIndex device;
-
-    /* input */
-    device = GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME_ );
-    if( device != paNoDevice &&
-            ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
-            hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxInputChannels > 0 )
-    {
-        hostApi->inheritedHostApiRep.info.defaultInputDevice = device;
-    }
-
-    /* output */
-    device = GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME_ );
-    if( device != paNoDevice &&
-            ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
-            hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxOutputChannels > 0 )
-    {
-        hostApi->inheritedHostApiRep.info.defaultOutputDevice = device;
-    }
-}
-
-
-/** Convert external PA ID to a windows multimedia device ID
-*/
-static UINT LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device )
-{
-    assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount );
-
-	return hostApi->winMmeDeviceIds[ device ];
-}
-
-
-static PaError QueryInputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )
-{
-    MMRESULT mmresult;
-    
-    switch( mmresult = waveInOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )
-    {
-        case MMSYSERR_NOERROR:
-            return paNoError;
-        case MMSYSERR_ALLOCATED:    /* Specified resource is already allocated. */
-            return paDeviceUnavailable;
-        case MMSYSERR_NODRIVER:	    /* No device driver is present. */
-            return paDeviceUnavailable;
-        case MMSYSERR_NOMEM:	    /* Unable to allocate or lock memory. */
-            return paInsufficientMemory;
-        case WAVERR_BADFORMAT:      /* Attempted to open with an unsupported waveform-audio format. */
-            return paSampleFormatNotSupported;
-                    
-        case MMSYSERR_BADDEVICEID:	/* Specified device identifier is out of range. */
-            /* falls through */
-        default:
-            PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-            return paUnanticipatedHostError;
-    }
-}
-
-
-static PaError QueryOutputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )
-{
-    MMRESULT mmresult;
-    
-    switch( mmresult = waveOutOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )
-    {
-        case MMSYSERR_NOERROR:
-            return paNoError;
-        case MMSYSERR_ALLOCATED:    /* Specified resource is already allocated. */
-            return paDeviceUnavailable;
-        case MMSYSERR_NODRIVER:	    /* No device driver is present. */
-            return paDeviceUnavailable;
-        case MMSYSERR_NOMEM:	    /* Unable to allocate or lock memory. */
-            return paInsufficientMemory;
-        case WAVERR_BADFORMAT:      /* Attempted to open with an unsupported waveform-audio format. */
-            return paSampleFormatNotSupported;
-                    
-        case MMSYSERR_BADDEVICEID:	/* Specified device identifier is out of range. */
-            /* falls through */
-        default:
-            PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
-            return paUnanticipatedHostError;
-    }
-}
-
-
-static PaError QueryFormatSupported( PaDeviceInfo *deviceInfo,
-        PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*),
-        int winMmeDeviceId, int channels, double sampleRate )
-{
-    PaWinMmeDeviceInfo *winMmeDeviceInfo = (PaWinMmeDeviceInfo*)deviceInfo;
-    WAVEFORMATEX waveFormatEx;
-    
-    if( sampleRate == 11025.0
-        && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1M16))
-            || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1S16)) ) ){
-
-        return paNoError;
-    }
-
-    if( sampleRate == 22050.0
-        && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2M16))
-            || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2S16)) ) ){
-
-        return paNoError;
-    }
-
-    if( sampleRate == 44100.0
-        && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4M16))
-            || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4S16)) ) ){
-
-        return paNoError;
-    }
-
-    waveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
-    waveFormatEx.nChannels = (WORD)channels;
-    waveFormatEx.nSamplesPerSec = (DWORD)sampleRate;
-    waveFormatEx.nAvgBytesPerSec = waveFormatEx.nSamplesPerSec * channels * sizeof(short);
-    waveFormatEx.nBlockAlign = (WORD)(channels * sizeof(short));
-    waveFormatEx.wBitsPerSample = 16;
-    waveFormatEx.cbSize = 0;
-
-    return waveFormatExQueryFunction( winMmeDeviceId, &waveFormatEx );
-}
-
-
-#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_  (13) /* must match array length below */
-static double defaultSampleRateSearchOrder_[] =
-    { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0,
-        16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
-
-static void DetectDefaultSampleRate( PaWinMmeDeviceInfo *winMmeDeviceInfo, int winMmeDeviceId,
-        PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*), int maxChannels )
-{
-    PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
-    int i;
-    
-    deviceInfo->defaultSampleRate = 0.;
-
-    for( i=0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i )
-    {
-        double sampleRate = defaultSampleRateSearchOrder_[ i ]; 
-        PaError paerror = QueryFormatSupported( deviceInfo, waveFormatExQueryFunction, winMmeDeviceId, maxChannels, sampleRate );
-        if( paerror == paNoError )
-        {
-            deviceInfo->defaultSampleRate = sampleRate;
-            break;
-        }
-    }
-}
-
-
-static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
-        PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeInputDeviceId, int *success )
-{
-    PaError result = paNoError;
-    char *deviceName; /* non-const ptr */
-    MMRESULT mmresult;
-    WAVEINCAPS wic;
-    PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
-    
-    *success = 0;
-
-    mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) );
-    if( mmresult == MMSYSERR_NOMEM )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-    else if( mmresult != MMSYSERR_NOERROR )
-    {
-        /* instead of returning paUnanticipatedHostError we return
-            paNoError, but leave success set as 0. This allows
-            Pa_Initialize to just ignore this device, without failing
-            the entire initialisation process.
-        */
-        return paNoError;
-    }           
-
-    if( winMmeInputDeviceId == WAVE_MAPPER )
-    {
-        /* Append I/O suffix to WAVE_MAPPER device. */
-        deviceName = (char *)PaUtil_GroupAllocateMemory(
-                    winMmeHostApi->allocations, strlen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_) );
-        if( !deviceName )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-        strcpy( deviceName, wic.szPname );
-        strcat( deviceName, constInputMapperSuffix_ );
-    }
-    else
-    {
-        deviceName = (char*)PaUtil_GroupAllocateMemory(
-                    winMmeHostApi->allocations, strlen( wic.szPname ) + 1 );
-        if( !deviceName )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-        strcpy( deviceName, wic.szPname  );
-    }
-    deviceInfo->name = deviceName;
-
-    deviceInfo->maxInputChannels = wic.wChannels;
-    /* Sometimes a device can return a rediculously large number of channels.
-     * This happened with an SBLive card on a Windows ME box.
-     * If that happens, then force it to 2 channels.  PLB20010413
-     */
-    if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) )
-    {
-        PA_DEBUG(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxInputChannels ));
-        deviceInfo->maxInputChannels = 2;
-    }
-
-    winMmeDeviceInfo->dwFormats = wic.dwFormats;
-
-    DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId,
-            QueryInputWaveFormatEx, deviceInfo->maxInputChannels );
-
-    *success = 1;
-    
-error:
-    return result;
-}
-
-
-static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
-        PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeOutputDeviceId, int *success )
-{
-    PaError result = paNoError;
-    char *deviceName; /* non-const ptr */
-    MMRESULT mmresult;
-    WAVEOUTCAPS woc;
-    PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
-    
-    *success = 0;
-
-    mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) );
-    if( mmresult == MMSYSERR_NOMEM )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-    else if( mmresult != MMSYSERR_NOERROR )
-    {
-        /* instead of returning paUnanticipatedHostError we return
-            paNoError, but leave success set as 0. This allows
-            Pa_Initialize to just ignore this device, without failing
-            the entire initialisation process.
-        */
-        return paNoError;
-    }
-
-    if( winMmeOutputDeviceId == WAVE_MAPPER )
-    {
-        /* Append I/O suffix to WAVE_MAPPER device. */
-        deviceName = (char *)PaUtil_GroupAllocateMemory(
-                    winMmeHostApi->allocations, strlen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_) );
-        if( !deviceName )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-        strcpy( deviceName, woc.szPname );
-        strcat( deviceName, constOutputMapperSuffix_ );
-    }
-    else
-    {
-        deviceName = (char*)PaUtil_GroupAllocateMemory(
-                    winMmeHostApi->allocations, strlen( woc.szPname ) + 1 );
-        if( !deviceName )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-        strcpy( deviceName, woc.szPname  );
-    }
-    deviceInfo->name = deviceName;
-
-    deviceInfo->maxOutputChannels = woc.wChannels;
-    /* Sometimes a device can return a rediculously large number of channels.
-     * This happened with an SBLive card on a Windows ME box.
-     * It also happens on Win XP!
-     */
-    if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) )
-    {
-        PA_DEBUG(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));
-        deviceInfo->maxOutputChannels = 2;
-    }
-
-    winMmeDeviceInfo->dwFormats = woc.dwFormats;
-
-    DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId,
-            QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels );
-
-    *success = 1;
-    
-error:
-    return result;
-}
-
-
-static void GetDefaultLatencies( PaTime *defaultLowLatency, PaTime *defaultHighLatency )
-{
-    OSVERSIONINFO osvi;
-    osvi.dwOSVersionInfoSize = sizeof( osvi );
-	GetVersionEx( &osvi );
-
-    /* Check for NT */
-    if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
-    {
-        *defaultLowLatency = PA_MME_WIN_NT_DEFAULT_LATENCY_;
-    }
-    else if(osvi.dwMajorVersion >= 5)
-    {
-        *defaultLowLatency  = PA_MME_WIN_WDM_DEFAULT_LATENCY_;
-    }
-    else
-    {
-        *defaultLowLatency  = PA_MME_WIN_9X_DEFAULT_LATENCY_;
-    }     
-
-    *defaultHighLatency = *defaultLowLatency * 2;
-}
-
-
-PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
-    PaError result = paNoError;
-    int i;
-    PaWinMmeHostApiRepresentation *winMmeHostApi;
-    int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount;
-    PaWinMmeDeviceInfo *deviceInfoArray;
-    int deviceInfoInitializationSucceeded;
-    PaTime defaultLowLatency, defaultHighLatency;
-
-    winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) );
-    if( !winMmeHostApi )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    winMmeHostApi->allocations = PaUtil_CreateAllocationGroup();
-    if( !winMmeHostApi->allocations )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    *hostApi = &winMmeHostApi->inheritedHostApiRep;
-    (*hostApi)->info.structVersion = 1;
-    (*hostApi)->info.type = paMME;
-    (*hostApi)->info.name = "MME";
-
-    
-    /* initialise device counts and default devices under the assumption that
-        there are no devices. These values are incremented below if and when
-        devices are successfully initialized.
-    */
-    (*hostApi)->info.deviceCount = 0;
-    (*hostApi)->info.defaultInputDevice = paNoDevice;
-    (*hostApi)->info.defaultOutputDevice = paNoDevice;
-    winMmeHostApi->inputDeviceCount = 0;
-    winMmeHostApi->outputDeviceCount = 0;
-
-
-    maximumPossibleDeviceCount = 0;
-
-    inputDeviceCount = waveInGetNumDevs();
-    if( inputDeviceCount > 0 )
-    	maximumPossibleDeviceCount += inputDeviceCount + 1;	/* assume there is a WAVE_MAPPER */
-
-    outputDeviceCount = waveOutGetNumDevs();
-    if( outputDeviceCount > 0 )
-	    maximumPossibleDeviceCount += outputDeviceCount + 1;	/* assume there is a WAVE_MAPPER */
-
-
-    if( maximumPossibleDeviceCount > 0 ){
-
-        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
-                winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount );
-        if( !(*hostApi)->deviceInfos )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        /* allocate all device info structs in a contiguous block */
-        deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory(
-                winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount );
-        if( !deviceInfoArray )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        winMmeHostApi->winMmeDeviceIds = (UINT*)PaUtil_GroupAllocateMemory(
-                winMmeHostApi->allocations, sizeof(int) * maximumPossibleDeviceCount );
-        if( !winMmeHostApi->winMmeDeviceIds )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency );
-
-        if( inputDeviceCount > 0 ){
-            /* -1 is the WAVE_MAPPER */
-            for( i = -1; i < inputDeviceCount; ++i ){
-                UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
-                PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
-                PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
-                deviceInfo->structVersion = 2;
-                deviceInfo->hostApi = hostApiIndex;
-
-                deviceInfo->maxInputChannels = 0;
-                deviceInfo->maxOutputChannels = 0;
-
-                deviceInfo->defaultLowInputLatency = defaultLowLatency;
-                deviceInfo->defaultLowOutputLatency = defaultLowLatency;
-                deviceInfo->defaultHighInputLatency = defaultHighLatency;
-                deviceInfo->defaultHighOutputLatency = defaultHighLatency;
-
-                result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo,
-                        winMmeDeviceId, &deviceInfoInitializationSucceeded );
-                if( result != paNoError )
-                    goto error;
-
-                if( deviceInfoInitializationSucceeded ){
-                    if( (*hostApi)->info.defaultInputDevice == paNoDevice )
-                        (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
-
-                    winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId;
-                    (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
-
-                    winMmeHostApi->inputDeviceCount++;
-                    (*hostApi)->info.deviceCount++;
-                }
-            }
-        }
-
-        if( outputDeviceCount > 0 ){
-            /* -1 is the WAVE_MAPPER */
-            for( i = -1; i < outputDeviceCount; ++i ){
-                UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
-                PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
-                PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
-                deviceInfo->structVersion = 2;
-                deviceInfo->hostApi = hostApiIndex;
-
-                deviceInfo->maxInputChannels = 0;
-                deviceInfo->maxOutputChannels = 0;
-
-                deviceInfo->defaultLowInputLatency = defaultLowLatency;
-                deviceInfo->defaultLowOutputLatency = defaultLowLatency;
-                deviceInfo->defaultHighInputLatency = defaultHighLatency;
-                deviceInfo->defaultHighOutputLatency = defaultHighLatency; 
-
-                result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo,
-                        winMmeDeviceId, &deviceInfoInitializationSucceeded );
-                if( result != paNoError )
-                    goto error;
-
-                if( deviceInfoInitializationSucceeded ){
-                    if( (*hostApi)->info.defaultOutputDevice == paNoDevice )
-                        (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
-
-                    winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId;
-                    (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
-
-                    winMmeHostApi->outputDeviceCount++;
-                    (*hostApi)->info.deviceCount++;
-                }
-            }
-        }
-    }
-    
-
-    InitializeDefaultDeviceIdsFromEnv( winMmeHostApi );
-
-    (*hostApi)->Terminate = Terminate;
-    (*hostApi)->OpenStream = OpenStream;
-    (*hostApi)->IsFormatSupported = IsFormatSupported;
-
-    PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, GetStreamCpuLoad,
-                                      PaUtil_DummyRead, PaUtil_DummyWrite,
-                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
-    PaUtil_InitializeStreamInterface( &winMmeHostApi->blockingStreamInterface, CloseStream, StartStream,
-                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
-                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
-                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
-    return result;
-
-error:
-    if( winMmeHostApi )
-    {
-        if( winMmeHostApi->allocations )
-        {
-            PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
-            PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
-        }
-        
-        PaUtil_FreeMemory( winMmeHostApi );
-    }
-
-    return result;
-}
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
-    PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
-
-    if( winMmeHostApi->allocations )
-    {
-        PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
-        PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
-    }
-
-    PaUtil_FreeMemory( winMmeHostApi );
-}
-
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
-                                  const PaStreamParameters *inputParameters,
-                                  const PaStreamParameters *outputParameters,
-                                  double sampleRate )
-{
-    PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
-    PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo;
-    int inputChannelCount, outputChannelCount;
-    int inputMultipleDeviceChannelCount, outputMultipleDeviceChannelCount;
-    PaSampleFormat inputSampleFormat, outputSampleFormat;
-    PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;
-    UINT winMmeInputDeviceId, winMmeOutputDeviceId;
-    unsigned int i;
-    PaError paerror;
-
-    /* The calls to QueryFormatSupported below are intended to detect invalid
-        sample rates. If we assume that the channel count and format are OK,
-        then the only thing that could fail is the sample rate. This isn't
-        strictly true, but I can't think of a better way to test that the
-        sample rate is valid.
-    */  
-    
-    if( inputParameters )
-    {
-        inputChannelCount = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-        inputStreamInfo = inputParameters->hostApiSpecificStreamInfo;
-        
-        /* all standard sample formats are supported by the buffer adapter,
-             this implementation doesn't support any custom sample formats */
-        if( inputSampleFormat & paCustomFormat )
-            return paSampleFormatNotSupported;
-
-        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification
-                && inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) )
-        {
-            inputMultipleDeviceChannelCount = 0;
-            for( i=0; i< inputStreamInfo->deviceCount; ++i )
-            {
-                inputMultipleDeviceChannelCount += inputStreamInfo->devices[i].channelCount;
-                    
-                inputDeviceInfo = hostApi->deviceInfos[ inputStreamInfo->devices[i].device ];
-
-                /* check that input device can support inputChannelCount */
-                if( inputStreamInfo->devices[i].channelCount <= 0
-                        || inputStreamInfo->devices[i].channelCount > inputDeviceInfo->maxInputChannels )
-                    return paInvalidChannelCount;
-
-                /* test for valid sample rate, see comment above */
-                winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputStreamInfo->devices[i].device );
-                paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, winMmeInputDeviceId, inputStreamInfo->devices[i].channelCount, sampleRate );
-                if( paerror != paNoError )
-                    return paInvalidSampleRate;
-            }
-                
-            if( inputMultipleDeviceChannelCount != inputChannelCount )
-                return paIncompatibleHostApiSpecificStreamInfo;                  
-        }
-        else
-        {
-            if( inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) )
-                return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the input device */
-
-            inputDeviceInfo = hostApi->deviceInfos[ inputParameters->device ];
-
-            /* check that input device can support inputChannelCount */
-            if( inputChannelCount > inputDeviceInfo->maxInputChannels )
-                return paInvalidChannelCount;
-
-            /* test for valid sample rate, see comment above */
-            winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputParameters->device );
-            paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, winMmeInputDeviceId, inputChannelCount, sampleRate );
-            if( paerror != paNoError )
-                return paInvalidSampleRate;
-        }
-    }
-
-    if( outputParameters )
-    {
-        outputChannelCount = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-        outputStreamInfo = outputParameters->hostApiSpecificStreamInfo;
-
-        /* all standard sample formats are supported by the buffer adapter,
-            this implementation doesn't support any custom sample formats */
-        if( outputSampleFormat & paCustomFormat )
-            return paSampleFormatNotSupported;
-
-        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification
-                && outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) )
-        {
-            outputMultipleDeviceChannelCount = 0;
-            for( i=0; i< outputStreamInfo->deviceCount; ++i )
-            {
-                outputMultipleDeviceChannelCount += outputStreamInfo->devices[i].channelCount;
-                    
-                outputDeviceInfo = hostApi->deviceInfos[ outputStreamInfo->devices[i].device ];
-
-                /* check that output device can support outputChannelCount */
-                if( outputStreamInfo->devices[i].channelCount <= 0
-                        || outputStreamInfo->devices[i].channelCount > outputDeviceInfo->maxOutputChannels )
-                    return paInvalidChannelCount;
-
-                /* test for valid sample rate, see comment above */
-                winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputStreamInfo->devices[i].device );
-                paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, winMmeOutputDeviceId, outputStreamInfo->devices[i].channelCount, sampleRate );
-                if( paerror != paNoError )
-                    return paInvalidSampleRate;
-            }
-                
-            if( outputMultipleDeviceChannelCount != outputChannelCount )
-                return paIncompatibleHostApiSpecificStreamInfo;            
-        }
-        else
-        {
-            if( outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) )
-                return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the output device */
-
-            outputDeviceInfo = hostApi->deviceInfos[ outputParameters->device ];
-
-            /* check that output device can support outputChannelCount */
-            if( outputChannelCount > outputDeviceInfo->maxOutputChannels )
-                return paInvalidChannelCount;
-
-            /* test for valid sample rate, see comment above */
-            winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputParameters->device );
-            paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, winMmeOutputDeviceId, outputChannelCount, sampleRate );
-            if( paerror != paNoError )
-                return paInvalidSampleRate;
-        }
-    }
-    
-    /*
-            - if a full duplex stream is requested, check that the combination
-                of input and output parameters is supported
-
-            - check that the device supports sampleRate
-
-            for mme all we can do is test that the input and output devices
-            support the requested sample rate and number of channels. we
-            cannot test for full duplex compatibility.
-    */                                             
-
-    return paFormatIsSupported;
-}
-
-
-
-static void SelectBufferSizeAndCount( unsigned long baseBufferSize,
-    unsigned long requestedLatency,
-    unsigned long baseBufferCount, unsigned long minimumBufferCount,
-    unsigned long maximumBufferSize, unsigned long *hostBufferSize,
-    unsigned long *hostBufferCount )
-{
-    unsigned long sizeMultiplier, bufferCount, latency;
-    unsigned long nextLatency, nextBufferSize;
-    int baseBufferSizeIsPowerOfTwo;
-    
-    sizeMultiplier = 1;
-    bufferCount = baseBufferCount;
-
-    /* count-1 below because latency is always determined by one less
-        than the total number of buffers.
-    */
-    latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);
-
-    if( latency > requestedLatency )
-    {
-
-        /* reduce number of buffers without falling below suggested latency */
-
-        nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2);
-        while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency )
-        {
-            --bufferCount;
-            nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2);
-        }
-
-    }else if( latency < requestedLatency ){
-
-        baseBufferSizeIsPowerOfTwo = (! (baseBufferSize & (baseBufferSize - 1)));
-        if( baseBufferSizeIsPowerOfTwo ){
-
-            /* double size of buffers without exceeding requestedLatency */
-
-            nextBufferSize = (baseBufferSize * (sizeMultiplier*2));
-            nextLatency = nextBufferSize * (bufferCount-1);
-            while( nextBufferSize <= maximumBufferSize
-                    && nextLatency < requestedLatency )
-            {
-                sizeMultiplier *= 2;
-                nextBufferSize = (baseBufferSize * (sizeMultiplier*2));
-                nextLatency = nextBufferSize * (bufferCount-1);
-            }   
-
-        }else{
-
-            /* increase size of buffers upto first excess of requestedLatency */
-
-            nextBufferSize = (baseBufferSize * (sizeMultiplier+1));
-            nextLatency = nextBufferSize * (bufferCount-1);
-            while( nextBufferSize <= maximumBufferSize
-                    && nextLatency < requestedLatency )
-            {
-                ++sizeMultiplier;
-                nextBufferSize = (baseBufferSize * (sizeMultiplier+1));
-                nextLatency = nextBufferSize * (bufferCount-1);
-            }
-
-            if( nextLatency < requestedLatency )
-                ++sizeMultiplier;            
-        }
-
-        /* increase number of buffers until requestedLatency is reached */
-
-        latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);
-        while( latency < requestedLatency )
-        {
-            ++bufferCount;
-            latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);
-        }
-    }
-
-    *hostBufferSize = baseBufferSize * sizeMultiplier;
-    *hostBufferCount = bufferCount;
-}
-
-
-static void ReselectBufferCount( unsigned long bufferSize,
-    unsigned long requestedLatency,
-    unsigned long baseBufferCount, unsigned long minimumBufferCount,
-    unsigned long *hostBufferCount )
-{
-    unsigned long bufferCount, latency;
-    unsigned long nextLatency;
-
-    bufferCount = baseBufferCount;
-
-    /* count-1 below because latency is always determined by one less
-        than the total number of buffers.
-    */
-    latency = bufferSize * (bufferCount-1);
-
-    if( latency > requestedLatency )
-    {
-        /* reduce number of buffers without falling below suggested latency */
-
-        nextLatency = bufferSize * (bufferCount-2);
-        while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency )
-        {
-            --bufferCount;
-            nextLatency = bufferSize * (bufferCount-2);
-        }
-
-    }else if( latency < requestedLatency ){
-
-        /* increase number of buffers until requestedLatency is reached */
-
-        latency = bufferSize * (bufferCount-1);
-        while( latency < requestedLatency )
-        {
-            ++bufferCount;
-            latency = bufferSize * (bufferCount-1);
-        }                                                         
-    }
-
-    *hostBufferCount = bufferCount;
-}
-
-
-/* CalculateBufferSettings() fills the framesPerHostInputBuffer, hostInputBufferCount,
-   framesPerHostOutputBuffer and hostOutputBufferCount parameters based on the values
-   of the other parameters.
-*/
-
-static PaError CalculateBufferSettings(
-        unsigned long *framesPerHostInputBuffer, unsigned long *hostInputBufferCount,
-        unsigned long *framesPerHostOutputBuffer, unsigned long *hostOutputBufferCount,
-        int inputChannelCount, PaSampleFormat hostInputSampleFormat,
-        PaTime suggestedInputLatency, PaWinMmeStreamInfo *inputStreamInfo,
-        int outputChannelCount, PaSampleFormat hostOutputSampleFormat,
-        PaTime suggestedOutputLatency, PaWinMmeStreamInfo *outputStreamInfo,
-        double sampleRate, unsigned long framesPerBuffer )
-{
-    PaError result = paNoError;
-    int effectiveInputChannelCount, effectiveOutputChannelCount;
-    int hostInputFrameSize = 0;
-    unsigned int i;
-    
-    if( inputChannelCount > 0 )
-    {
-        int hostInputSampleSize = Pa_GetSampleSize( hostInputSampleFormat );
-        if( hostInputSampleSize < 0 )
-        {
-            result = hostInputSampleSize;
-            goto error;
-        }
-
-        if( inputStreamInfo
-                && ( inputStreamInfo->flags & paWinMmeUseMultipleDevices ) )
-        {
-            /* set effectiveInputChannelCount to the largest number of
-                channels on any one device.
-            */
-            effectiveInputChannelCount = 0;
-            for( i=0; i< inputStreamInfo->deviceCount; ++i )
-            {
-                if( inputStreamInfo->devices[i].channelCount > effectiveInputChannelCount )
-                    effectiveInputChannelCount = inputStreamInfo->devices[i].channelCount;
-            }
-        }
-        else
-        {
-            effectiveInputChannelCount = inputChannelCount;
-        }
-
-        hostInputFrameSize = hostInputSampleSize * effectiveInputChannelCount;
-
-        if( inputStreamInfo
-                && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
-        {
-            if( inputStreamInfo->bufferCount <= 0
-                    || inputStreamInfo->framesPerBuffer <= 0 )
-            {
-                result = paIncompatibleHostApiSpecificStreamInfo;
-                goto error;
-            }
-
-            *framesPerHostInputBuffer = inputStreamInfo->framesPerBuffer;
-            *hostInputBufferCount = inputStreamInfo->bufferCount;
-        }
-        else
-        {
-            unsigned long hostBufferSizeBytes, hostBufferCount;
-            unsigned long minimumBufferCount = (outputChannelCount > 0)
-                    ? PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_
-                    : PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_;
-
-            unsigned long maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostInputFrameSize);
-            if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )
-                maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;
-
-            /* compute the following in bytes, then convert back to frames */
-
-            SelectBufferSizeAndCount(
-                ((framesPerBuffer == paFramesPerBufferUnspecified)
-                    ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_
-                    : framesPerBuffer ) * hostInputFrameSize, /* baseBufferSize */
-                ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */
-                4, /* baseBufferCount */
-                minimumBufferCount, maximumBufferSize,
-                &hostBufferSizeBytes, &hostBufferCount );
-
-            *framesPerHostInputBuffer = hostBufferSizeBytes / hostInputFrameSize;
-            *hostInputBufferCount = hostBufferCount;
-        }
-    }
-    else
-    {
-        *framesPerHostInputBuffer = 0;
-        *hostInputBufferCount = 0;
-    }
-
-    if( outputChannelCount > 0 )
-    {
-        if( outputStreamInfo
-                && ( outputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
-        {
-            if( outputStreamInfo->bufferCount <= 0
-                    || outputStreamInfo->framesPerBuffer <= 0 )
-            {
-                result = paIncompatibleHostApiSpecificStreamInfo;
-                goto error;
-            }
-
-            *framesPerHostOutputBuffer = outputStreamInfo->framesPerBuffer;
-            *hostOutputBufferCount = outputStreamInfo->bufferCount;
-
-            
-            if( inputChannelCount > 0 ) /* full duplex */
-            {
-                if( *framesPerHostInputBuffer != *framesPerHostOutputBuffer )
-                {
-                    if( inputStreamInfo
-                            && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
-                    { 
-                        /* a custom StreamInfo was used for specifying both input
-                            and output buffer sizes, the larger buffer size
-                            must be a multiple of the smaller buffer size */
-
-                        if( *framesPerHostInputBuffer < *framesPerHostOutputBuffer )
-                        {
-                            if( *framesPerHostOutputBuffer % *framesPerHostInputBuffer != 0 )
-                            {
-                                result = paIncompatibleHostApiSpecificStreamInfo;
-                                goto error;
-                            }
-                        }
-                        else
-                        {
-                            assert( *framesPerHostInputBuffer > *framesPerHostOutputBuffer );
-                            if( *framesPerHostInputBuffer % *framesPerHostOutputBuffer != 0 )
-                            {
-                                result = paIncompatibleHostApiSpecificStreamInfo;
-                                goto error;
-                            }
-                        }                        
-                    }
-                    else
-                    {
-                        /* a custom StreamInfo was not used for specifying the input buffer size,
-                            so use the output buffer size, and approximately the same latency. */
-
-                        *framesPerHostInputBuffer = *framesPerHostOutputBuffer;
-                        *hostInputBufferCount = (((unsigned long)(suggestedInputLatency * sampleRate)) / *framesPerHostInputBuffer) + 1;
-
-                        if( *hostInputBufferCount < PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ )
-                            *hostInputBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
-                    }
-                }
-            }
-        }
-        else
-        {
-            unsigned long hostBufferSizeBytes, hostBufferCount;
-            unsigned long minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
-            unsigned long maximumBufferSize;
-            int hostOutputFrameSize;
-            int hostOutputSampleSize;
-
-            hostOutputSampleSize = Pa_GetSampleSize( hostOutputSampleFormat );
-            if( hostOutputSampleSize < 0 )
-            {
-                result = hostOutputSampleSize;
-                goto error;
-            }
-
-            if( outputStreamInfo
-                && ( outputStreamInfo->flags & paWinMmeUseMultipleDevices ) )
-            {
-                /* set effectiveOutputChannelCount to the largest number of
-                    channels on any one device.
-                */
-                effectiveOutputChannelCount = 0;
-                for( i=0; i< outputStreamInfo->deviceCount; ++i )
-                {
-                    if( outputStreamInfo->devices[i].channelCount > effectiveOutputChannelCount )
-                        effectiveOutputChannelCount = outputStreamInfo->devices[i].channelCount;
-                }
-            }
-            else
-            {
-                effectiveOutputChannelCount = outputChannelCount;
-            }
-
-            hostOutputFrameSize = hostOutputSampleSize * effectiveOutputChannelCount;
-            
-            maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostOutputFrameSize);
-            if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )
-                maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;
-
-
-            /* compute the following in bytes, then convert back to frames */
-
-            SelectBufferSizeAndCount(
-                ((framesPerBuffer == paFramesPerBufferUnspecified)
-                    ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_
-                    : framesPerBuffer ) * hostOutputFrameSize, /* baseBufferSize */
-                ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
-                4, /* baseBufferCount */
-                minimumBufferCount,
-                maximumBufferSize,
-                &hostBufferSizeBytes, &hostBufferCount );
-
-            *framesPerHostOutputBuffer = hostBufferSizeBytes / hostOutputFrameSize;
-            *hostOutputBufferCount = hostBufferCount;
-
-
-            if( inputChannelCount > 0 )
-            {
-                /* ensure that both input and output buffer sizes are the same.
-                    if they don't match at this stage, choose the smallest one
-                    and use that for input and output
-                */
-
-                if( *framesPerHostOutputBuffer != *framesPerHostInputBuffer )
-                {
-                    if( framesPerHostInputBuffer < framesPerHostOutputBuffer )
-                    {
-                        unsigned long framesPerHostBuffer = *framesPerHostInputBuffer;
-                        
-                        minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
-                        ReselectBufferCount(
-                            framesPerHostBuffer * hostOutputFrameSize, /* bufferSize */
-                            ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
-                            4, /* baseBufferCount */
-                            minimumBufferCount,
-                            &hostBufferCount );
-
-                        *framesPerHostOutputBuffer = framesPerHostBuffer;
-                        *hostOutputBufferCount = hostBufferCount;
-                    }
-                    else
-                    {
-                        unsigned long framesPerHostBuffer = *framesPerHostOutputBuffer;
-                        
-                        minimumBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
-                        ReselectBufferCount(
-                            framesPerHostBuffer * hostInputFrameSize, /* bufferSize */
-                            ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */
-                            4, /* baseBufferCount */
-                            minimumBufferCount,
-                            &hostBufferCount );
-
-                        *framesPerHostInputBuffer = framesPerHostBuffer;
-                        *hostInputBufferCount = hostBufferCount;
-                    }
-                }   
-            }
-        }
-    }
-    else
-    {
-        *framesPerHostOutputBuffer = 0;
-        *hostOutputBufferCount = 0;
-    }
-
-error:
-    return result;
-}
-
-
-typedef struct
-{
-    HANDLE bufferEvent;
-    void *waveHandles;
-    unsigned int deviceCount;
-    /* unsigned int channelCount; */
-    WAVEHDR **waveHeaders;                  /* waveHeaders[device][buffer] */
-    unsigned int bufferCount;
-    unsigned int currentBufferIndex;
-    unsigned int framesPerBuffer;
-    unsigned int framesUsedInCurrentBuffer;
-}PaWinMmeSingleDirectionHandlesAndBuffers;
-
-/* prototypes for functions operating on PaWinMmeSingleDirectionHandlesAndBuffers */
-
-static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers );
-static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
-        PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
-        unsigned long bytesPerHostSample,
-        double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
-        unsigned int deviceCount, int isInput );
-static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError );
-static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
-        unsigned long hostBufferCount,
-        PaSampleFormat hostSampleFormat,
-        unsigned long framesPerHostBuffer,
-        PaWinMmeDeviceAndChannelCount *devices,
-        int isInput );
-static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput );
-
-
-static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
-{
-    handlesAndBuffers->bufferEvent = 0;
-    handlesAndBuffers->waveHandles = 0;
-    handlesAndBuffers->deviceCount = 0;
-    handlesAndBuffers->waveHeaders = 0;
-    handlesAndBuffers->bufferCount = 0;
-}    
-
-static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
-        PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
-        unsigned long bytesPerHostSample,
-        double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
-        unsigned int deviceCount, int isInput )
-{
-    PaError result;
-    MMRESULT mmresult;
-    unsigned long bytesPerFrame;
-    WAVEFORMATEX wfx;
-    signed int i;
-
-    /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()
-        has already been called to zero some fields */       
-
-    result = CreateEventWithPaError( &handlesAndBuffers->bufferEvent, NULL, FALSE, FALSE, NULL );
-    if( result != paNoError ) goto error;
-
-    if( isInput )
-        handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * deviceCount );
-    else
-        handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * deviceCount );
-    if( !handlesAndBuffers->waveHandles )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    handlesAndBuffers->deviceCount = deviceCount;
-
-    for( i = 0; i < (signed int)deviceCount; ++i )
-    {
-        if( isInput )
-            ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] = 0;
-        else
-            ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0;
-    }
-
-    wfx.wFormatTag = WAVE_FORMAT_PCM;
-    wfx.nSamplesPerSec = (DWORD) sampleRate;
-    wfx.cbSize = 0;
-    
-    for( i = 0; i < (signed int)deviceCount; ++i )
-    {
-        UINT winMmeDeviceId;
-
-        winMmeDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, devices[i].device );
-        wfx.nChannels = (WORD)devices[i].channelCount;
-
-        bytesPerFrame = wfx.nChannels * bytesPerHostSample;
-
-        wfx.nAvgBytesPerSec = (DWORD)(bytesPerFrame * sampleRate);
-        wfx.nBlockAlign = (WORD)bytesPerFrame;
-        wfx.wBitsPerSample = (WORD)((bytesPerFrame/wfx.nChannels) * 8);
-
-        /* REVIEW: consider not firing an event for input when a full duplex
-            stream is being used. this would probably depend on the
-            neverDropInput flag. */
-
-        if( isInput )
-            mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
-                               (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );
-        else
-            mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
-                                (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );
-
-        if( mmresult != MMSYSERR_NOERROR )
-        {
-            switch( mmresult )
-            {
-                case MMSYSERR_ALLOCATED:    /* Specified resource is already allocated. */
-                    result = paDeviceUnavailable;
-                    break;
-                case MMSYSERR_NODRIVER:	    /* No device driver is present. */
-                    result = paDeviceUnavailable;
-                    break;
-                case MMSYSERR_NOMEM:	    /* Unable to allocate or lock memory. */
-                    result = paInsufficientMemory;
-                    break;
-
-                case MMSYSERR_BADDEVICEID:	/* Specified device identifier is out of range. */
-                    /* falls through */
-                case WAVERR_BADFORMAT:      /* Attempted to open with an unsupported waveform-audio format. */
-                    /* falls through */
-                default:
-                    result = paUnanticipatedHostError;
-                    if( isInput )
-                    {
-                        PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-                    }
-                    else
-                    {
-                        PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
-                    }
-            }
-            goto error;
-        }
-    }
-
-    return result;
-
-error:
-    TerminateWaveHandles( handlesAndBuffers, isInput, 1 /* currentlyProcessingAnError */ );
-
-    return result;
-}
-
-
-static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError )
-{
-    PaError result = paNoError;
-    MMRESULT mmresult;
-    signed int i;
-    
-    if( handlesAndBuffers->waveHandles )
-    {
-        for( i = handlesAndBuffers->deviceCount-1; i >= 0; --i )
-        {
-            if( isInput )
-            {
-                if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] )
-                    mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] );
-            }
-            else
-            {
-                if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] )
-                    mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] );
-            }
-
-            if( mmresult != MMSYSERR_NOERROR &&
-                !currentlyProcessingAnError ) /* don't update the error state if we're already processing an error */
-            {
-                result = paUnanticipatedHostError;
-                if( isInput )
-                {
-                    PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-                }
-                else
-                {
-                    PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
-                }
-                /* note that we don't break here, we try to continue closing devices */
-            }
-        }
-
-        PaUtil_FreeMemory( handlesAndBuffers->waveHandles );
-        handlesAndBuffers->waveHandles = 0;
-    }
-
-    if( handlesAndBuffers->bufferEvent )
-    {
-        result = CloseHandleWithPaError( handlesAndBuffers->bufferEvent );
-        handlesAndBuffers->bufferEvent = 0;
-    }
-    
-    return result;
-}
-
-
-static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
-        unsigned long hostBufferCount,
-        PaSampleFormat hostSampleFormat,
-        unsigned long framesPerHostBuffer,
-        PaWinMmeDeviceAndChannelCount *devices,
-        int isInput )
-{
-    PaError result = paNoError;
-    MMRESULT mmresult;
-    WAVEHDR *deviceWaveHeaders;
-    signed int i, j;
-
-    /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()
-        has already been called to zero some fields */
-        
-
-    /* allocate an array of pointers to arrays of wave headers, one array of
-        wave headers per device */
-    handlesAndBuffers->waveHeaders = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * handlesAndBuffers->deviceCount );
-    if( !handlesAndBuffers->waveHeaders )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-    
-    for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i )
-        handlesAndBuffers->waveHeaders[i] = 0;
-
-    handlesAndBuffers->bufferCount = hostBufferCount;
-
-    for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i )
-    {
-        int bufferBytes = Pa_GetSampleSize( hostSampleFormat ) *
-                framesPerHostBuffer * devices[i].channelCount;
-        if( bufferBytes < 0 )
-        {
-            result = paInternalError;
-            goto error;
-        }
-
-        /* Allocate an array of wave headers for device i */
-        deviceWaveHeaders = (WAVEHDR *) PaUtil_AllocateMemory( sizeof(WAVEHDR)*hostBufferCount );
-        if( !deviceWaveHeaders )
-        {
-            result = paInsufficientMemory;
-            goto error;
-        }
-
-        for( j=0; j < (signed int)hostBufferCount; ++j )
-            deviceWaveHeaders[j].lpData = 0;
-
-        handlesAndBuffers->waveHeaders[i] = deviceWaveHeaders;
-
-        /* Allocate a buffer for each wave header */
-        for( j=0; j < (signed int)hostBufferCount; ++j )
-        {
-            deviceWaveHeaders[j].lpData = (char *)PaUtil_AllocateMemory( bufferBytes );
-            if( !deviceWaveHeaders[j].lpData )
-            {
-                result = paInsufficientMemory;
-                goto error;
-            }
-            deviceWaveHeaders[j].dwBufferLength = bufferBytes;
-            deviceWaveHeaders[j].dwUser = 0xFFFFFFFF; /* indicates that *PrepareHeader() has not yet been called, for error clean up code */
-
-            if( isInput )
-            {
-                mmresult = waveInPrepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
-                if( mmresult != MMSYSERR_NOERROR )
-                {
-                    result = paUnanticipatedHostError;
-                    PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-                    goto error;
-                }
-            }
-            else /* output */
-            {
-                mmresult = waveOutPrepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
-                if( mmresult != MMSYSERR_NOERROR )
-                {
-                    result = paUnanticipatedHostError;
-                    PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-                    goto error;
-                }
-            }
-            deviceWaveHeaders[j].dwUser = devices[i].channelCount;
-        }
-    }
-
-    return result;
-
-error:
-    TerminateWaveHeaders( handlesAndBuffers, isInput );
-    
-    return result;
-}
-
-
-static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput )
-{
-    signed int i, j;
-    WAVEHDR *deviceWaveHeaders;
-    
-    if( handlesAndBuffers->waveHeaders )
-    {
-        for( i = handlesAndBuffers->deviceCount-1; i >= 0 ; --i )
-        {
-            deviceWaveHeaders = handlesAndBuffers->waveHeaders[i];  /* wave headers for device i */
-            if( deviceWaveHeaders )
-            {
-                for( j = handlesAndBuffers->bufferCount-1; j >= 0; --j )
-                {
-                    if( deviceWaveHeaders[j].lpData )
-                    {
-                        if( deviceWaveHeaders[j].dwUser != 0xFFFFFFFF )
-                        {
-                            if( isInput )
-                                waveInUnprepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
-                            else
-                                waveOutUnprepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
-                        }
-
-                        PaUtil_FreeMemory( deviceWaveHeaders[j].lpData );
-                    }
-                }
-
-                PaUtil_FreeMemory( deviceWaveHeaders );
-            }
-        }
-
-        PaUtil_FreeMemory( handlesAndBuffers->waveHeaders );
-        handlesAndBuffers->waveHeaders = 0;
-    }
-}
-
-
-
-/* PaWinMmeStream - a stream data structure specifically for this implementation */
-/* note that struct PaWinMmeStream is typedeffed to PaWinMmeStream above. */
-struct PaWinMmeStream
-{
-    PaUtilStreamRepresentation streamRepresentation;
-    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
-    PaUtilBufferProcessor bufferProcessor;
-
-    int primeStreamUsingCallback;
-
-    PaWinMmeSingleDirectionHandlesAndBuffers input;
-    PaWinMmeSingleDirectionHandlesAndBuffers output;
-
-    /* Processing thread management -------------- */
-    HANDLE abortEvent;
-    HANDLE processingThread;
-    DWORD processingThreadId;
-
-    char throttleProcessingThreadOnOverload; /* 0 -> don't throtte, non-0 -> throttle */
-    int processingThreadPriority;
-    int highThreadPriority;
-    int throttledThreadPriority;
-    unsigned long throttledSleepMsecs;
-
-    int isStopped;
-    volatile int isActive;
-    volatile int stopProcessing; /* stop thread once existing buffers have been returned */
-    volatile int abortProcessing; /* stop thread immediately */
-
-    DWORD allBuffersDurationMs; /* used to calculate timeouts */
-};
-
-/* updates deviceCount if PaWinMmeUseMultipleDevices is used */
-
-static PaError ValidateWinMmeSpecificStreamInfo(
-        const PaStreamParameters *streamParameters,
-        const PaWinMmeStreamInfo *streamInfo,
-        char *throttleProcessingThreadOnOverload,
-        unsigned long *deviceCount )
-{
-	if( streamInfo )
-	{
-	    if( streamInfo->size != sizeof( PaWinMmeStreamInfo )
-	            || streamInfo->version != 1 )
-	    {
-	        return paIncompatibleHostApiSpecificStreamInfo;
-	    }
-
-	    if( streamInfo->flags & paWinMmeDontThrottleOverloadedProcessingThread )
-	        *throttleProcessingThreadOnOverload = 0;
-            
-	    if( streamInfo->flags & paWinMmeUseMultipleDevices )
-	    {
-	        if( streamParameters->device != paUseHostApiSpecificDeviceSpecification )
-	            return paInvalidDevice;
-	
-			*deviceCount = streamInfo->deviceCount;
-		}	
-	}
-
-	return paNoError;
-}
-
-static PaError RetrieveDevicesFromStreamParameters(
-        struct PaUtilHostApiRepresentation *hostApi,
-        const PaStreamParameters *streamParameters,
-        const PaWinMmeStreamInfo *streamInfo,
-        PaWinMmeDeviceAndChannelCount *devices,
-        unsigned long deviceCount )
-{
-    PaError result = paNoError;
-    unsigned int i;
-    int totalChannelCount;
-    PaDeviceIndex hostApiDevice;
-    
-	if( streamInfo && streamInfo->flags & paWinMmeUseMultipleDevices )
-	{
-		totalChannelCount = 0;
-	    for( i=0; i < deviceCount; ++i )
-	    {
-	        /* validate that the device number is within range */
-	        result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
-	                        streamInfo->devices[i].device, hostApi );
-	        if( result != paNoError )
-	            return result;
-	        
-	        devices[i].device = hostApiDevice;
-	        devices[i].channelCount = streamInfo->devices[i].channelCount;
-	
-	        totalChannelCount += devices[i].channelCount;
-	    }
-	
-	    if( totalChannelCount != streamParameters->channelCount )
-	    {
-	        /* channelCount must match total channels specified by multiple devices */
-	        return paInvalidChannelCount; /* REVIEW use of this error code */
-	    }
-	}	
-	else
-	{		
-	    devices[0].device = streamParameters->device;
-	    devices[0].channelCount = streamParameters->channelCount;
-	}
-
-    return result;
-}
-
-static PaError ValidateInputChannelCounts(
-        struct PaUtilHostApiRepresentation *hostApi,
-        PaWinMmeDeviceAndChannelCount *devices,
-        unsigned long deviceCount )
-{
-    unsigned int i;
-
-	for( i=0; i < deviceCount; ++i )
-	{
-		if( devices[i].channelCount < 1 || devices[i].channelCount
-					> hostApi->deviceInfos[ devices[i].device ]->maxInputChannels )
-        	return paInvalidChannelCount;
-	}
-
-    return paNoError;
-}
-
-static PaError ValidateOutputChannelCounts(
-        struct PaUtilHostApiRepresentation *hostApi,
-        PaWinMmeDeviceAndChannelCount *devices,
-        unsigned long deviceCount )
-{
-    unsigned int i;
-
-	for( i=0; i < deviceCount; ++i )
-	{
-		if( devices[i].channelCount < 1 || devices[i].channelCount
-					> hostApi->deviceInfos[ devices[i].device ]->maxOutputChannels )
-        	return paInvalidChannelCount;
-	}
-
-    return paNoError;
-}
-
-
-/* the following macros are intended to improve the readability of the following code */
-#define PA_IS_INPUT_STREAM_( stream ) ( stream ->input.waveHandles )
-#define PA_IS_OUTPUT_STREAM_( stream ) ( stream ->output.waveHandles )
-#define PA_IS_FULL_DUPLEX_STREAM_( stream ) ( stream ->input.waveHandles && stream ->output.waveHandles )
-#define PA_IS_HALF_DUPLEX_STREAM_( stream ) ( !(stream ->input.waveHandles && stream ->output.waveHandles) )
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
-                           PaStream** s,
-                           const PaStreamParameters *inputParameters,
-                           const PaStreamParameters *outputParameters,
-                           double sampleRate,
-                           unsigned long framesPerBuffer,
-                           PaStreamFlags streamFlags,
-                           PaStreamCallback *streamCallback,
-                           void *userData )
-{
-    PaError result;
-    PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
-    PaWinMmeStream *stream = 0;
-    int bufferProcessorIsInitialized = 0;
-    int streamRepresentationIsInitialized = 0;
-    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
-    int inputChannelCount, outputChannelCount;
-    PaSampleFormat inputSampleFormat, outputSampleFormat;
-    double suggestedInputLatency, suggestedOutputLatency;
-    PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;
-    unsigned long framesPerHostInputBuffer;
-    unsigned long hostInputBufferCount;
-    unsigned long framesPerHostOutputBuffer;
-    unsigned long hostOutputBufferCount;
-    unsigned long framesPerBufferProcessorCall;
-    PaWinMmeDeviceAndChannelCount *inputDevices = 0;  /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */
-    unsigned long inputDeviceCount = 0;            
-    PaWinMmeDeviceAndChannelCount *outputDevices = 0;
-    unsigned long outputDeviceCount = 0;                /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */
-    char throttleProcessingThreadOnOverload = 1;
-
-    
-    if( inputParameters )
-    {
-		inputChannelCount = inputParameters->channelCount;
-        inputSampleFormat = inputParameters->sampleFormat;
-        suggestedInputLatency = inputParameters->suggestedLatency;
-
-      	inputDeviceCount = 1;
-
-		/* validate input hostApiSpecificStreamInfo */
-        inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
-		result = ValidateWinMmeSpecificStreamInfo( inputParameters, inputStreamInfo,
-				&throttleProcessingThreadOnOverload,
-				&inputDeviceCount );
-		if( result != paNoError ) return result;
-
-		inputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * inputDeviceCount );
-        if( !inputDevices ) return paInsufficientMemory;
-
-		result = RetrieveDevicesFromStreamParameters( hostApi, inputParameters, inputStreamInfo, inputDevices, inputDeviceCount );
-		if( result != paNoError ) return result;
-
-		result = ValidateInputChannelCounts( hostApi, inputDevices, inputDeviceCount );
-		if( result != paNoError ) return result;
-
-        hostInputSampleFormat =
-            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
-	}
-    else
-    {
-        inputChannelCount = 0;
-        inputSampleFormat = 0;
-        suggestedInputLatency = 0.;
-        inputStreamInfo = 0;
-        hostInputSampleFormat = 0;
-    }
-
-
-    if( outputParameters )
-    {
-        outputChannelCount = outputParameters->channelCount;
-        outputSampleFormat = outputParameters->sampleFormat;
-        suggestedOutputLatency = outputParameters->suggestedLatency;
-
-        outputDeviceCount = 1;
-
-		/* validate output hostApiSpecificStreamInfo */
-        outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
-		result = ValidateWinMmeSpecificStreamInfo( outputParameters, outputStreamInfo,
-				&throttleProcessingThreadOnOverload,
-				&outputDeviceCount );
-		if( result != paNoError ) return result;
-
-		outputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * outputDeviceCount );
-        if( !outputDevices ) return paInsufficientMemory;
-
-		result = RetrieveDevicesFromStreamParameters( hostApi, outputParameters, outputStreamInfo, outputDevices, outputDeviceCount );
-		if( result != paNoError ) return result;
-
-		result = ValidateOutputChannelCounts( hostApi, outputDevices, outputDeviceCount );
-		if( result != paNoError ) return result;
-
-        hostOutputSampleFormat =
-            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
-    }
-    else
-    {
-        outputChannelCount = 0;
-        outputSampleFormat = 0;
-        outputStreamInfo = 0;
-        hostOutputSampleFormat = 0;
-        suggestedOutputLatency = 0.;
-    }
-
-
-    /*
-        IMPLEMENT ME:
-            - alter sampleRate to a close allowable rate if possible / necessary
-    */
-
-
-    /* validate platform specific flags */
-    if( (streamFlags & paPlatformSpecificFlags) != 0 )
-        return paInvalidFlag; /* unexpected platform specific flag */
-
-
-    result = CalculateBufferSettings( &framesPerHostInputBuffer, &hostInputBufferCount,
-                &framesPerHostOutputBuffer, &hostOutputBufferCount,
-                inputChannelCount, hostInputSampleFormat, suggestedInputLatency, inputStreamInfo,
-                outputChannelCount, hostOutputSampleFormat, suggestedOutputLatency, outputStreamInfo,
-                sampleRate, framesPerBuffer );
-    if( result != paNoError ) goto error;
-
-
-    stream = (PaWinMmeStream*)PaUtil_AllocateMemory( sizeof(PaWinMmeStream) );
-    if( !stream )
-    {
-        result = paInsufficientMemory;
-        goto error;
-    }
-
-    InitializeSingleDirectionHandlesAndBuffers( &stream->input );
-    InitializeSingleDirectionHandlesAndBuffers( &stream->output );
-
-    stream->abortEvent = 0;
-    stream->processingThread = 0;
-
-    stream->throttleProcessingThreadOnOverload = throttleProcessingThreadOnOverload;
-
-    PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
-                                           ( (streamCallback)
-                                            ? &winMmeHostApi->callbackStreamInterface
-                                            : &winMmeHostApi->blockingStreamInterface ),
-                                           streamCallback, userData );
-    streamRepresentationIsInitialized = 1;
-
-    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
-
-    if( inputParameters && outputParameters ) /* full duplex */
-    {
-        if( framesPerHostInputBuffer < framesPerHostOutputBuffer )
-        {
-            assert( (framesPerHostOutputBuffer % framesPerHostInputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */
-
-            framesPerBufferProcessorCall = framesPerHostInputBuffer;
-        }
-        else
-        {
-            assert( (framesPerHostInputBuffer % framesPerHostOutputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */
-            
-            framesPerBufferProcessorCall = framesPerHostOutputBuffer;
-        }
-    }
-    else if( inputParameters )
-    {
-        framesPerBufferProcessorCall = framesPerHostInputBuffer;
-    }
-    else if( outputParameters )
-    {
-        framesPerBufferProcessorCall = framesPerHostOutputBuffer;
-    }
-
-    stream->input.framesPerBuffer = framesPerHostInputBuffer;
-    stream->output.framesPerBuffer = framesPerHostOutputBuffer;
-
-    result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
-                    inputChannelCount, inputSampleFormat, hostInputSampleFormat,
-                    outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
-                    sampleRate, streamFlags, framesPerBuffer,
-                    framesPerBufferProcessorCall, paUtilFixedHostBufferSize,
-                    streamCallback, userData );
-    if( result != paNoError ) goto error;
-    
-    bufferProcessorIsInitialized = 1;
-
-    stream->streamRepresentation.streamInfo.inputLatency =
-            (double)(PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)
-                +(framesPerHostInputBuffer * (hostInputBufferCount-1))) / sampleRate;
-    stream->streamRepresentation.streamInfo.outputLatency =
-            (double)(PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)
-                +(framesPerHostOutputBuffer * (hostOutputBufferCount-1))) / sampleRate;
-    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
-    stream->primeStreamUsingCallback = ( (streamFlags&paPrimeOutputBuffersUsingStreamCallback) && streamCallback ) ? 1 : 0;
-
-    /* time to sleep when throttling due to >100% cpu usage.
-        -a quater of a buffer's duration */
-    stream->throttledSleepMsecs =
-            (unsigned long)(stream->bufferProcessor.framesPerHostBuffer *
-             stream->bufferProcessor.samplePeriod * .25 * 1000);
-
-    stream->isStopped = 1;
-    stream->isActive = 0;
-
-
-    /* for maximum compatibility with multi-device multichannel drivers,
-        we first open all devices, then we prepare all buffers, finally
-        we start all devices ( in StartStream() ). teardown in reverse order.
-    */
-
-    if( inputParameters )
-    {
-        result = InitializeWaveHandles( winMmeHostApi, &stream->input,
-                stream->bufferProcessor.bytesPerHostInputSample, sampleRate,
-                inputDevices, inputDeviceCount, 1 /* isInput */ );
-        if( result != paNoError ) goto error;
-    }
-    
-    if( outputParameters )
-    {
-        result = InitializeWaveHandles( winMmeHostApi, &stream->output,
-                stream->bufferProcessor.bytesPerHostOutputSample, sampleRate,
-                outputDevices, outputDeviceCount, 0 /* isInput */ );
-        if( result != paNoError ) goto error;
-    }
-
-    if( inputParameters )
-    {
-        result = InitializeWaveHeaders( &stream->input, hostInputBufferCount,
-                hostInputSampleFormat, framesPerHostInputBuffer, inputDevices, 1 /* isInput */ );
-        if( result != paNoError ) goto error;
-    }
-
-    if( outputParameters )
-    {
-        result = InitializeWaveHeaders( &stream->output, hostOutputBufferCount,
-                hostOutputSampleFormat, framesPerHostOutputBuffer, outputDevices, 0 /* not isInput */ );
-        if( result != paNoError ) goto error;
-
-        stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostOutputBuffer * stream->output.bufferCount) / sampleRate);
-    }
-    else
-    {
-        stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostInputBuffer * stream->input.bufferCount) / sampleRate);
-    }
-
-    
-    if( streamCallback )
-    {
-        /* abort event is only needed for callback streams */
-        result = CreateEventWithPaError( &stream->abortEvent, NULL, TRUE, FALSE, NULL );
-        if( result != paNoError ) goto error;
-    }
-
-    *s = (PaStream*)stream;
-
-    return result;
-
-error:
-
-    if( stream )
-    {
-        if( stream->abortEvent )
-            CloseHandle( stream->abortEvent );
-            
-        TerminateWaveHeaders( &stream->output, 0 /* not isInput */ );
-        TerminateWaveHeaders( &stream->input, 1 /* isInput */ );
-
-        TerminateWaveHandles( &stream->output, 0 /* not isInput */, 1 /* currentlyProcessingAnError */ );
-        TerminateWaveHandles( &stream->input, 1 /* isInput */, 1 /* currentlyProcessingAnError */ );
-
-        if( bufferProcessorIsInitialized )
-            PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
-
-        if( streamRepresentationIsInitialized )
-            PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-
-        PaUtil_FreeMemory( stream );
-    }
-
-    return result;
-}
-
-
-/* return non-zero if all current buffers are done */
-static int BuffersAreDone( WAVEHDR **waveHeaders, unsigned int deviceCount, int bufferIndex )
-{
-    unsigned int i;
-    
-    for( i=0; i < deviceCount; ++i )
-    {
-        if( !(waveHeaders[i][ bufferIndex ].dwFlags & WHDR_DONE) )
-        {
-            return 0;
-        }         
-    }
-
-    return 1;
-}
-
-static int CurrentInputBuffersAreDone( PaWinMmeStream *stream )
-{
-    return BuffersAreDone( stream->input.waveHeaders, stream->input.deviceCount, stream->input.currentBufferIndex );
-}
-
-static int CurrentOutputBuffersAreDone( PaWinMmeStream *stream )
-{
-    return BuffersAreDone( stream->output.waveHeaders, stream->output.deviceCount, stream->output.currentBufferIndex );
-}
-
-
-/* return non-zero if any buffers are queued */
-static int NoBuffersAreQueued( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
-{
-    unsigned int i, j;
-
-    if( handlesAndBuffers->waveHandles )
-    {
-        for( i=0; i < handlesAndBuffers->bufferCount; ++i )
-        {
-            for( j=0; j < handlesAndBuffers->deviceCount; ++j )
-            {
-                if( !( handlesAndBuffers->waveHeaders[ j ][ i ].dwFlags & WHDR_DONE) )
-                {
-                    return 0;
-                }
-            }
-        }
-    }
-
-    return 1;
-}
-
-
-#define PA_CIRCULAR_INCREMENT_( current, max )\
-    ( (((current) + 1) >= (max)) ? (0) : (current+1) )
-
-#define PA_CIRCULAR_DECREMENT_( current, max )\
-    ( ((current) == 0) ? ((max)-1) : (current-1) )
-    
-
-static signed long GetAvailableFrames( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
-{
-    signed long result = 0;
-    unsigned int i;
-    
-    if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, handlesAndBuffers->currentBufferIndex ) )
-    {
-        /* we could calculate the following in O(1) if we kept track of the
-            last done buffer */
-        result = handlesAndBuffers->framesPerBuffer - handlesAndBuffers->framesUsedInCurrentBuffer;
-
-        i = PA_CIRCULAR_INCREMENT_( handlesAndBuffers->currentBufferIndex, handlesAndBuffers->bufferCount );
-        while( i != handlesAndBuffers->currentBufferIndex )
-        {
-            if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, i ) )
-            {
-                result += handlesAndBuffers->framesPerBuffer;
-                i = PA_CIRCULAR_INCREMENT_( i, handlesAndBuffers->bufferCount );
-            }
-            else
-                break;
-        }
-    }
-
-    return result;
-}
-
-
-static PaError AdvanceToNextInputBuffer( PaWinMmeStream *stream )
-{
-    PaError result = paNoError;
-    MMRESULT mmresult;
-    unsigned int i;
-
-    for( i=0; i < stream->input.deviceCount; ++i )
-    {
-        mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[i],
-                                    &stream->input.waveHeaders[i][ stream->input.currentBufferIndex ],
-                                    sizeof(WAVEHDR) );
-        if( mmresult != MMSYSERR_NOERROR )
-        {
-            result = paUnanticipatedHostError;
-            PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-        }
-    }
-
-    stream->input.currentBufferIndex =
-            PA_CIRCULAR_INCREMENT_( stream->input.currentBufferIndex, stream->input.bufferCount );
-
-    stream->input.framesUsedInCurrentBuffer = 0;
-
-    return result;
-}
-
-
-static PaError AdvanceToNextOutputBuffer( PaWinMmeStream *stream )
-{
-    PaError result = paNoError;
-    MMRESULT mmresult;
-    unsigned int i;
-
-    for( i=0; i < stream->output.deviceCount; ++i )
-    {
-        mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[i],
-                                 &stream->output.waveHeaders[i][ stream->output.currentBufferIndex ],
-                                 sizeof(WAVEHDR) );
-        if( mmresult != MMSYSERR_NOERROR )
-        {
-            result = paUnanticipatedHostError;
-            PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
-        }
-    }
-
-    stream->output.currentBufferIndex =
-            PA_CIRCULAR_INCREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount );
-
-    stream->output.framesUsedInCurrentBuffer = 0;
-    
-    return result;
-}
-
-
-/* requeue all but the most recent input with the driver. Used for catching
-    up after a total input buffer underrun */
-static PaError CatchUpInputBuffers( PaWinMmeStream *stream )
-{
-    PaError result = paNoError;
-    unsigned int i;
-    
-    for( i=0; i < stream->input.bufferCount - 1; ++i )
-    {
-        result = AdvanceToNextInputBuffer( stream );
-        if( result != paNoError )
-            break;
-    }
-
-    return result;
-}
-
-
-/* take the most recent output and duplicate it to all other output buffers
-    and requeue them. Used for catching up after a total output buffer underrun.
-*/
-static PaError CatchUpOutputBuffers( PaWinMmeStream *stream )
-{
-    PaError result = paNoError;
-    unsigned int i, j;
-    unsigned int previousBufferIndex =
-            PA_CIRCULAR_DECREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount );
-
-    for( i=0; i < stream->output.bufferCount - 1; ++i )
-    {
-        for( j=0; j < stream->output.deviceCount; ++j )
-        {
-            if( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData
-                    != stream->output.waveHeaders[j][ previousBufferIndex ].lpData )
-            {
-                CopyMemory( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData,
-                            stream->output.waveHeaders[j][ previousBufferIndex ].lpData,
-                            stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].dwBufferLength );
-            }
-        }
-
-        result = AdvanceToNextOutputBuffer( stream );
-        if( result != paNoError )
-            break;
-    }
-
-    return result;
-}
-
-
-static DWORD WINAPI ProcessingThreadProc( void *pArg )
-{
-    PaWinMmeStream *stream = (PaWinMmeStream *)pArg;
-    HANDLE events[3];
-    int eventCount = 0;
-    DWORD result = paNoError;
-    DWORD waitResult;
-    DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);
-    int hostBuffersAvailable;
-    signed int hostInputBufferIndex, hostOutputBufferIndex;
-    PaStreamCallbackFlags statusFlags;
-    int callbackResult;
-    int done = 0;
-    unsigned int channel, i;
-    unsigned long framesProcessed;
-    
-    /* prepare event array for call to WaitForMultipleObjects() */
-    if( stream->input.bufferEvent )
-        events[eventCount++] = stream->input.bufferEvent;
-    if( stream->output.bufferEvent )
-        events[eventCount++] = stream->output.bufferEvent;
-    events[eventCount++] = stream->abortEvent;
-
-    statusFlags = 0; /** @todo support paInputUnderflow, paOutputOverflow and paNeverDropInput */
-    
-    /* loop until something causes us to stop */
-    do{
-        /* wait for MME to signal that a buffer is available, or for
-            the PA abort event to be signaled.
-
-          When this indicates that one or more buffers are available
-          NoBuffersAreQueued() and Current*BuffersAreDone are used below to
-          poll for additional done buffers. NoBuffersAreQueued() will fail
-          to identify an underrun/overflow if the driver doesn't mark all done
-          buffers prior to signalling the event. Some drivers do this
-          (eg RME Digi96, and others don't eg VIA PC 97 input). This isn't a
-          huge problem, it just means that we won't always be able to detect
-          underflow/overflow.
-        */
-        waitResult = WaitForMultipleObjects( eventCount, events, FALSE /* wait all = FALSE */, timeout );
-        if( waitResult == WAIT_FAILED )
-        {
-            result = paUnanticipatedHostError;
-            /** @todo FIXME/REVIEW: can't return host error info from an asyncronous thread */
-            done = 1;
-        }
-        else if( waitResult == WAIT_TIMEOUT )
-        {
-            /* if a timeout is encountered, continue */
-        }
-
-        if( stream->abortProcessing )
-        {
-            /* Pa_AbortStream() has been called, stop processing immediately */
-            done = 1;
-        }
-        else if( stream->stopProcessing )
-        {
-            /* Pa_StopStream() has been called or the user callback returned
-                non-zero, processing will continue until all output buffers
-                are marked as done. The stream will stop immediately if it
-                is input-only.
-            */
-
-            if( PA_IS_OUTPUT_STREAM_(stream) )
-            {
-                if( NoBuffersAreQueued( &stream->output ) )
-                    done = 1; /* Will cause thread to return. */
-            }
-            else
-            {
-                /* input only stream */
-                done = 1; /* Will cause thread to return. */
-            }
-        }
-        else
-        {
-            hostBuffersAvailable = 1;
-
-            /* process all available host buffers */
-            do
-            {
-                hostInputBufferIndex = -1;
-                hostOutputBufferIndex = -1;
-                
-                if( PA_IS_INPUT_STREAM_(stream) )
-                {
-                    if( CurrentInputBuffersAreDone( stream ) )
-                    {
-                        if( NoBuffersAreQueued( &stream->input ) )
-                        {
-                            /** @todo
-                               if all of the other buffers are also ready then
-                               we discard all but the most recent. This is an
-                               input buffer overflow. FIXME: these buffers should
-                               be passed to the callback in a paNeverDropInput
-                               stream.
-
-                               note that it is also possible for an input overflow
-                               to happen while the callback is processing a buffer.
-                               that is handled further down.
-                            */
-                            result = CatchUpInputBuffers( stream );
-                            if( result != paNoError )
-                                done = 1;
-
-                            statusFlags |= paInputOverflow;
-                        }
-
-                        hostInputBufferIndex = stream->input.currentBufferIndex;
-                    }
-                }
-
-                if( PA_IS_OUTPUT_STREAM_(stream) )
-                {
-                    if( CurrentOutputBuffersAreDone( stream ) )
-                    {
-                        /* ok, we have an output buffer */
-                        
-                        if( NoBuffersAreQueued( &stream->output ) )
-                        {
-                            /*
-                            if all of the other buffers are also ready, catch up by copying
-                            the most recently generated buffer into all but one of the output
-                            buffers.
-
-                            note that this catch up code only handles the case where all
-                            buffers have been played out due to this thread not having
-                            woken up at all. a more common case occurs when this thread
-                            is woken up, processes one buffer, but takes too long, and as
-                            a result all the other buffers have become un-queued. that
-                            case is handled further down.
-                            */
-
-                            result = CatchUpOutputBuffers( stream );
-                            if( result != paNoError )
-                                done = 1;
-
-                            statusFlags |= paOutputUnderflow;
-                        }
-
-                        hostOutputBufferIndex = stream->output.currentBufferIndex;
-                    }
-                }
-
-               
-                if( (PA_IS_FULL_DUPLEX_STREAM_(stream) && hostInputBufferIndex != -1 && hostOutputBufferIndex != -1) ||
-                        (PA_IS_HALF_DUPLEX_STREAM_(stream) && ( hostInputBufferIndex != -1 || hostOutputBufferIndex != -1 ) ) )
-                {
-                    PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */
-
-
-                    if( PA_IS_OUTPUT_STREAM_(stream) )
-                    {
-                        /* set timeInfo.currentTime and calculate timeInfo.outputBufferDacTime
-                            from the current wave out position */
-                        MMTIME mmtime;
-                        double timeBeforeGetPosition, timeAfterGetPosition;
-                        double time;
-                        long framesInBufferRing; 		
-                        long writePosition;
-                        long playbackPosition;
-                        HWAVEOUT firstWaveOutDevice = ((HWAVEOUT*)stream->output.waveHandles)[0];
-                        
-                        mmtime.wType = TIME_SAMPLES;
-                        timeBeforeGetPosition = PaUtil_GetTime();
-                        waveOutGetPosition( firstWaveOutDevice, &mmtime, sizeof(MMTIME) );
-                        timeAfterGetPosition = PaUtil_GetTime();
-
-                        timeInfo.currentTime = timeAfterGetPosition;
-
-                        /* approximate time at which wave out position was measured
-                            as half way between timeBeforeGetPosition and timeAfterGetPosition */
-                        time = timeBeforeGetPosition + (timeAfterGetPosition - timeBeforeGetPosition) * .5;
-                        
-                        framesInBufferRing = stream->output.bufferCount * stream->bufferProcessor.framesPerHostBuffer;
-                        playbackPosition = mmtime.u.sample % framesInBufferRing;
-
-                        writePosition = stream->output.currentBufferIndex * stream->bufferProcessor.framesPerHostBuffer
-                                + stream->output.framesUsedInCurrentBuffer;
-                       
-                        if( playbackPosition >= writePosition ){
-                            timeInfo.outputBufferDacTime =
-                                    time + ((double)( writePosition + (framesInBufferRing - playbackPosition) ) * stream->bufferProcessor.samplePeriod );
-                        }else{
-                            timeInfo.outputBufferDacTime =
-                                    time + ((double)( writePosition - playbackPosition ) * stream->bufferProcessor.samplePeriod );
-                        }
-                    }
-
-
-                    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
-                    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, statusFlags  );
-
-                    /* reset status flags once they have been passed to the buffer processor */
-                    statusFlags = 0;
-
-                    if( PA_IS_INPUT_STREAM_(stream) )
-                    {
-                        PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
-
-                        channel = 0;
-                        for( i=0; i<stream->input.deviceCount; ++i )
-                        {
-                             /* we have stored the number of channels in the buffer in dwUser */
-                            int channelCount = stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser;
-                            
-                            PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,
-                                    stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData +
-                                        stream->input.framesUsedInCurrentBuffer * channelCount *
-                                        stream->bufferProcessor.bytesPerHostInputSample,
-                                    channelCount );
-                                    
-
-                            channel += channelCount;
-                        }
-                    }
-
-                    if( PA_IS_OUTPUT_STREAM_(stream) )
-                    {
-                        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
-                        
-                        channel = 0;
-                        for( i=0; i<stream->output.deviceCount; ++i )
-                        {
-                            /* we have stored the number of channels in the buffer in dwUser */
-                            int channelCount = stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;
-
-                            PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
-                                    stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +
-                                        stream->output.framesUsedInCurrentBuffer * channelCount *
-                                        stream->bufferProcessor.bytesPerHostOutputSample,
-                                    channelCount );
-
-                            channel += channelCount;
-                        }
-                    }
-
-                    callbackResult = paContinue;
-                    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
-
-                    stream->input.framesUsedInCurrentBuffer += framesProcessed;
-                    stream->output.framesUsedInCurrentBuffer += framesProcessed;
-
-                    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
-
-                    if( callbackResult == paContinue )
-                    {
-                        /* nothing special to do */
-                    }
-                    else if( callbackResult == paAbort )
-                    {
-                        stream->abortProcessing = 1;
-                        done = 1;
-                        /** @todo FIXME: should probably reset the output device immediately once the callback returns paAbort */
-                        result = paNoError;
-                    }
-                    else
-                    {
-                        /* User callback has asked us to stop with paComplete or other non-zero value */
-                        stream->stopProcessing = 1; /* stop once currently queued audio has finished */
-                        result = paNoError;
-                    }
-
-
-                    if( PA_IS_INPUT_STREAM_(stream)
-                            && stream->stopProcessing == 0 && stream->abortProcessing == 0
-                            && stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer )
-                    {
-                        if( NoBuffersAreQueued( &stream->input ) )
-                        {
-                            /** @todo need to handle PaNeverDropInput here where necessary */
-                            result = CatchUpInputBuffers( stream );
-                            if( result != paNoError )
-                                done = 1;
-
-                            statusFlags |= paInputOverflow;
-                        }
-
-                        result = AdvanceToNextInputBuffer( stream );
-                        if( result != paNoError )
-                            done = 1;
-                    }
-
-                    
-                    if( PA_IS_OUTPUT_STREAM_(stream) && !stream->abortProcessing )
-                    {
-                        if( stream->stopProcessing &&
-                                stream->output.framesUsedInCurrentBuffer < stream->output.framesPerBuffer )
-                        {
-                            /* zero remaining samples in output output buffer and flush */
-
-                            stream->output.framesUsedInCurrentBuffer += PaUtil_ZeroOutput( &stream->bufferProcessor,
-                                    stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
-
-                            /* we send the entire buffer to the output devices, but we could
-                                just send a partial buffer, rather than zeroing the unused
-                                samples.
-                            */
-                        }
-
-                        if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer )
-                        {
-                            /* check for underflow before enquing the just-generated buffer,
-                                but recover from underflow after enquing it. This ensures
-                                that the most recent audio segment is repeated */
-                            int outputUnderflow = NoBuffersAreQueued( &stream->output );
-
-                            result = AdvanceToNextOutputBuffer( stream );
-                            if( result != paNoError )
-                                done = 1;
-
-                            if( outputUnderflow && !done && !stream->stopProcessing )
-                            {
-                                /* Recover from underflow in the case where the
-                                    underflow occured while processing the buffer
-                                    we just finished */
-
-                                result = CatchUpOutputBuffers( stream );
-                                if( result != paNoError )
-                                    done = 1;
-
-                                statusFlags |= paOutputUnderflow;
-                            }
-                        }
-                    }
-                    
-                    if( stream->throttleProcessingThreadOnOverload != 0 )
-                    {
-                        if( stream->stopProcessing || stream->abortProcessing )
-                        {
-                            if( stream->processingThreadPriority != stream->highThreadPriority )
-                            {
-                                SetThreadPriority( stream->processingThread, stream->highThreadPriority );
-                                stream->processingThreadPriority = stream->highThreadPriority;
-                            }
-                        }
-                        else if( PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) > 1. )
-                        {
-                            if( stream->processingThreadPriority != stream->throttledThreadPriority )
-                            {
-                                SetThreadPriority( stream->processingThread, stream->throttledThreadPriority );
-                                stream->processingThreadPriority = stream->throttledThreadPriority;
-                            }
-
-                            /* sleep to give other processes a go */
-                            Sleep( stream->throttledSleepMsecs );
-                        }
-                        else
-                        {
-                            if( stream->processingThreadPriority != stream->highThreadPriority )
-                            {
-                                SetThreadPriority( stream->processingThread, stream->highThreadPriority );
-                                stream->processingThreadPriority = stream->highThreadPriority;
-                            }
-                        }
-                    }
-                }
-                else
-                {
-                    hostBuffersAvailable = 0;
-                }
-            }
-            while( hostBuffersAvailable &&
-                    stream->stopProcessing == 0 &&
-                    stream->abortProcessing == 0 &&
-                    !done );
-        }
-    }
-    while( !done );
-
-    stream->isActive = 0;
-
-    if( stream->streamRepresentation.streamFinishedCallback != 0 )
-        stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
-
-    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
-    
-    return result;
-}
-
-
-/*
-    When CloseStream() is called, the multi-api layer ensures that
-    the stream has already been stopped or aborted.
-*/
-static PaError CloseStream( PaStream* s )
-{
-    PaError result;
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
-    result = CloseHandleWithPaError( stream->abortEvent );
-    if( result != paNoError ) goto error;
-    
-    TerminateWaveHeaders( &stream->output, 0 /* not isInput */ );
-    TerminateWaveHeaders( &stream->input, 1 /* isInput */ );
-
-    TerminateWaveHandles( &stream->output, 0 /* not isInput */, 0 /* not currentlyProcessingAnError */ );
-    TerminateWaveHandles( &stream->input, 1 /* isInput */, 0 /* not currentlyProcessingAnError */ );
-    
-    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
-    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-    PaUtil_FreeMemory( stream );
-
-error:
-    /** @todo REVIEW: what is the best way to clean up a stream if an error is detected? */
-    return result;
-}
-
-
-static PaError StartStream( PaStream *s )
-{
-    PaError result;
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-    MMRESULT mmresult;
-    unsigned int i, j;
-    int callbackResult;
-	unsigned int channel;
- 	unsigned long framesProcessed;
-	PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement this for stream priming */
-    
-    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
-    
-    if( PA_IS_INPUT_STREAM_(stream) )
-    {
-        for( i=0; i<stream->input.bufferCount; ++i )
-        {
-            for( j=0; j<stream->input.deviceCount; ++j )
-            {
-                mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[j], &stream->input.waveHeaders[j][i], sizeof(WAVEHDR) );
-                if( mmresult != MMSYSERR_NOERROR )
-                {
-                    result = paUnanticipatedHostError;
-                    PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-                    goto error;
-                }
-            }
-        }
-        stream->input.currentBufferIndex = 0;
-        stream->input.framesUsedInCurrentBuffer = 0;
-    }
-
-    if( PA_IS_OUTPUT_STREAM_(stream) )
-    {
-        for( i=0; i<stream->output.deviceCount; ++i )
-        {
-            if( (mmresult = waveOutPause( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR )
-            {
-                result = paUnanticipatedHostError;
-                PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
-                goto error;
-            }
-        }
-
-        for( i=0; i<stream->output.bufferCount; ++i )
-        {
-            if( stream->primeStreamUsingCallback )
-            {
-
-                stream->output.framesUsedInCurrentBuffer = 0;
-                do{
-
-                    PaUtil_BeginBufferProcessing( &stream->bufferProcessor,
-                            &timeInfo,
-                            paPrimingOutput | ((stream->input.bufferCount > 0 ) ? paInputUnderflow : 0));
-
-                    if( stream->input.bufferCount > 0 )
-                        PaUtil_SetNoInput( &stream->bufferProcessor );
-
-                    PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
-
-                    channel = 0;
-                    for( j=0; j<stream->output.deviceCount; ++j )
-                    {
-                        /* we have stored the number of channels in the buffer in dwUser */
-                        int channelCount = stream->output.waveHeaders[j][i].dwUser;
-
-                        PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
-                                stream->output.waveHeaders[j][i].lpData +
-                                stream->output.framesUsedInCurrentBuffer * channelCount *
-                                stream->bufferProcessor.bytesPerHostOutputSample,
-                                channelCount );
-
-                        /* we have stored the number of channels in the buffer in dwUser */
-                        channel += channelCount;
-                    }
-
-                    callbackResult = paContinue;
-                    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
-                    stream->output.framesUsedInCurrentBuffer += framesProcessed;
-
-                    if( callbackResult != paContinue )
-                    {
-                        /** @todo fix this, what do we do if callback result is non-zero during stream
-                            priming?
-
-                            for complete: play out primed waveHeaders as usual
-                            for abort: clean up immediately.
-                       */
-                    }
-
-                }while( stream->output.framesUsedInCurrentBuffer != stream->output.framesPerBuffer );
-
-            }
-            else
-            {
-                for( j=0; j<stream->output.deviceCount; ++j )
-                {
-                    ZeroMemory( stream->output.waveHeaders[j][i].lpData, stream->output.waveHeaders[j][i].dwBufferLength );
-                }
-            }   
-
-            /* we queue all channels of a single buffer frame (accross all
-                devices, because some multidevice multichannel drivers work
-                better this way */
-            for( j=0; j<stream->output.deviceCount; ++j )
-            {
-                mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[j], &stream->output.waveHeaders[j][i], sizeof(WAVEHDR) );
-                if( mmresult != MMSYSERR_NOERROR )
-                {
-                    result = paUnanticipatedHostError;
-                    PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
-                    goto error;
-                }
-            }
-        }
-        stream->output.currentBufferIndex = 0;
-        stream->output.framesUsedInCurrentBuffer = 0;
-    }
-
-
-    stream->isStopped = 0;
-    stream->isActive = 1;
-    stream->stopProcessing = 0;
-    stream->abortProcessing = 0;
-
-    result = ResetEventWithPaError( stream->input.bufferEvent );
-    if( result != paNoError ) goto error;
-
-    result = ResetEventWithPaError( stream->output.bufferEvent );
-    if( result != paNoError ) goto error;
-    
-    
-    if( stream->streamRepresentation.streamCallback )
-    {
-        /* callback stream */
-
-        result = ResetEventWithPaError( stream->abortEvent );
-        if( result != paNoError ) goto error;
-
-        /* Create thread that waits for audio buffers to be ready for processing. */
-        stream->processingThread = CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId );
-        if( !stream->processingThread )
-        {
-            result = paUnanticipatedHostError;
-            PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
-            goto error;
-        }
-
-        /** @todo could have mme specific stream parameters to allow the user
-            to set the callback thread priorities */
-        stream->highThreadPriority = THREAD_PRIORITY_TIME_CRITICAL;
-        stream->throttledThreadPriority = THREAD_PRIORITY_NORMAL;
-
-        if( !SetThreadPriority( stream->processingThread, stream->highThreadPriority ) )
-        {
-            result = paUnanticipatedHostError;
-            PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
-            goto error;
-        }
-        stream->processingThreadPriority = stream->highThreadPriority;
-    }
-    else
-    {
-        /* blocking read/write stream */
-
-    }
-
-    if( PA_IS_INPUT_STREAM_(stream) )
-    {
-        for( i=0; i < stream->input.deviceCount; ++i )
-        {
-            mmresult = waveInStart( ((HWAVEIN*)stream->input.waveHandles)[i] );
-            PA_DEBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult));
-            if( mmresult != MMSYSERR_NOERROR )
-            {
-                result = paUnanticipatedHostError;
-                PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-                goto error;
-            }
-        }
-    }
-
-    if( PA_IS_OUTPUT_STREAM_(stream) )
-    {
-        for( i=0; i < stream->output.deviceCount; ++i )
-        {
-            if( (mmresult = waveOutRestart( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR )
-            {
-                result = paUnanticipatedHostError;
-                PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
-                goto error;
-            }
-        }
-    }
-
-    return result;
-
-error:
-    /** @todo FIXME: implement recovery as best we can
-    This should involve rolling back to a state as-if this function had never been called
-    */
-    return result;
-}
-
-
-static PaError StopStream( PaStream *s )
-{
-    PaError result = paNoError;
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-    int timeout;
-    DWORD waitResult;
-    MMRESULT mmresult;
-    signed int hostOutputBufferIndex;
-    unsigned int channel, waitCount, i;                  
-    
-    /** @todo
-        REVIEW: the error checking in this function needs review. the basic
-        idea is to return from this function in a known state - for example
-        there is no point avoiding calling waveInReset just because
-        the thread times out.
-    */
-
-    if( stream->processingThread )
-    {
-        /* callback stream */
-
-        /* Tell processing thread to stop generating more data and to let current data play out. */
-        stream->stopProcessing = 1;
-
-        /* Calculate timeOut longer than longest time it could take to return all buffers. */
-        timeout = (int)(stream->allBuffersDurationMs * 1.5);
-        if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )
-            timeout = PA_MME_MIN_TIMEOUT_MSEC_;
-
-        PA_DEBUG(("WinMME StopStream: waiting for background thread.\n"));
-
-        waitResult = WaitForSingleObject( stream->processingThread, timeout );
-        if( waitResult == WAIT_TIMEOUT )
-        {
-            /* try to abort */
-            stream->abortProcessing = 1;
-            SetEvent( stream->abortEvent );
-            waitResult = WaitForSingleObject( stream->processingThread, timeout );
-            if( waitResult == WAIT_TIMEOUT )
-            {
-                PA_DEBUG(("WinMME StopStream: timed out while waiting for background thread to finish.\n"));
-                result = paTimedOut;
-            }
-        }
-
-        CloseHandle( stream->processingThread );
-        stream->processingThread = NULL;
-    }
-    else
-    {
-        /* blocking read / write stream */
-
-        if( PA_IS_OUTPUT_STREAM_(stream) )
-        {
-            if( stream->output.framesUsedInCurrentBuffer > 0 )
-            {
-                /* there are still unqueued frames in the current buffer, so flush them */
-
-                hostOutputBufferIndex = stream->output.currentBufferIndex;
-
-                PaUtil_SetOutputFrameCount( &stream->bufferProcessor,
-                        stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
-                
-                channel = 0;
-                for( i=0; i<stream->output.deviceCount; ++i )
-                {
-                    /* we have stored the number of channels in the buffer in dwUser */
-                    int channelCount = stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;
-
-                    PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
-                            stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +
-                                stream->output.framesUsedInCurrentBuffer * channelCount *
-                                stream->bufferProcessor.bytesPerHostOutputSample,
-                            channelCount );
-
-                    channel += channelCount;
-                }
-
-                PaUtil_ZeroOutput( &stream->bufferProcessor,
-                        stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
-
-                /* we send the entire buffer to the output devices, but we could
-                    just send a partial buffer, rather than zeroing the unused
-                    samples.
-                */
-                AdvanceToNextOutputBuffer( stream );
-            }
-            
-
-            timeout = (stream->allBuffersDurationMs / stream->output.bufferCount) + 1;
-            if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )
-                timeout = PA_MME_MIN_TIMEOUT_MSEC_;
-
-            waitCount = 0;
-            while( !NoBuffersAreQueued( &stream->output ) && waitCount <= stream->output.bufferCount )
-            {
-                /* wait for MME to signal that a buffer is available */
-                waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout );
-                if( waitResult == WAIT_FAILED )
-                {
-                    break;
-                }
-                else if( waitResult == WAIT_TIMEOUT )
-                {
-                    /* keep waiting */
-                }
-
-                ++waitCount;
-            }
-        }
-    }
-
-    if( PA_IS_OUTPUT_STREAM_(stream) )
-    {
-        for( i =0; i < stream->output.deviceCount; ++i )
-        {
-            mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] );
-            if( mmresult != MMSYSERR_NOERROR )
-            {
-                result = paUnanticipatedHostError;
-                PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
-            }
-        }
-    }
-
-    if( PA_IS_INPUT_STREAM_(stream) )
-    {
-        for( i=0; i < stream->input.deviceCount; ++i )
-        {
-            mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] );
-            if( mmresult != MMSYSERR_NOERROR )
-            {
-                result = paUnanticipatedHostError;
-                PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-            }
-        }
-    }
-
-    stream->isStopped = 1;
-    stream->isActive = 0;
-
-    return result;
-}
-
-
-static PaError AbortStream( PaStream *s )
-{
-    PaError result = paNoError;
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-    int timeout;
-    DWORD waitResult;
-    MMRESULT mmresult;
-    unsigned int i;
-    
-    /** @todo
-        REVIEW: the error checking in this function needs review. the basic
-        idea is to return from this function in a known state - for example
-        there is no point avoiding calling waveInReset just because
-        the thread times out.
-    */
-
-    if( stream->processingThread )
-    {
-        /* callback stream */
-        
-        /* Tell processing thread to abort immediately */
-        stream->abortProcessing = 1;
-        SetEvent( stream->abortEvent );
-    }
-
-
-    if( PA_IS_OUTPUT_STREAM_(stream) )
-    {
-        for( i =0; i < stream->output.deviceCount; ++i )
-        {
-            mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] );
-            if( mmresult != MMSYSERR_NOERROR )
-            {
-                PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
-                return paUnanticipatedHostError;
-            }
-        }
-    }
-
-    if( PA_IS_INPUT_STREAM_(stream) )
-    {
-        for( i=0; i < stream->input.deviceCount; ++i )
-        {
-            mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] );
-            if( mmresult != MMSYSERR_NOERROR )
-            {
-                PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
-                return paUnanticipatedHostError;
-            }
-        }
-    }
-
-
-    if( stream->processingThread )
-    {
-        /* callback stream */
-        
-        PA_DEBUG(("WinMME AbortStream: waiting for background thread.\n"));
-
-        /* Calculate timeOut longer than longest time it could take to return all buffers. */
-        timeout = (int)(stream->allBuffersDurationMs * 1.5);
-        if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )
-            timeout = PA_MME_MIN_TIMEOUT_MSEC_;
-            
-        waitResult = WaitForSingleObject( stream->processingThread, timeout );
-        if( waitResult == WAIT_TIMEOUT )
-        {
-            PA_DEBUG(("WinMME AbortStream: timed out while waiting for background thread to finish.\n"));
-            return paTimedOut;
-        }
-
-        CloseHandle( stream->processingThread );
-        stream->processingThread = NULL;
-    }
-
-    stream->isStopped = 1;
-    stream->isActive = 0;
-
-    return result;
-}
-
-
-static PaError IsStreamStopped( PaStream *s )
-{
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
-    return stream->isStopped;
-}
-
-
-static PaError IsStreamActive( PaStream *s )
-{
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
-    return stream->isActive;
-}
-
-
-static PaTime GetStreamTime( PaStream *s )
-{
-    (void) s; /* unused parameter */
-    
-    return PaUtil_GetTime();
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
-    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-/*
-    As separate stream interfaces are used for blocking and callback
-    streams, the following functions can be guaranteed to only be called
-    for blocking streams.
-*/
-
-static PaError ReadStream( PaStream* s,
-                           void *buffer,
-                           unsigned long frames )
-{
-    PaError result = paNoError;
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-    void *userBuffer;
-    unsigned long framesRead = 0;
-    unsigned long framesProcessed;
-    signed int hostInputBufferIndex;
-    DWORD waitResult;
-    DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);
-    unsigned int channel, i;
-    
-    if( PA_IS_INPUT_STREAM_(stream) )
-    {
-        /* make a local copy of the user buffer pointer(s). this is necessary
-            because PaUtil_CopyInput() advances these pointers every time
-            it is called.
-        */
-        if( stream->bufferProcessor.userInputIsInterleaved )
-        {
-            userBuffer = buffer;
-        }
-        else
-        {
-            userBuffer = alloca( sizeof(void*) * stream->bufferProcessor.inputChannelCount );
-            if( !userBuffer )
-                return paInsufficientMemory;
-            for( i = 0; i<stream->bufferProcessor.inputChannelCount; ++i )
-                ((void**)userBuffer)[i] = ((void**)buffer)[i];
-        }
-        
-        do{
-            if( CurrentInputBuffersAreDone( stream ) )
-            {
-                if( NoBuffersAreQueued( &stream->input ) )
-                {
-                    /** @todo REVIEW: consider what to do if the input overflows.
-                        do we requeue all of the buffers? should we be running
-                        a thread to make sure they are always queued? */
-
-                    result = paInputOverflowed;
-                }
-
-                hostInputBufferIndex = stream->input.currentBufferIndex;
-
-                PaUtil_SetInputFrameCount( &stream->bufferProcessor,
-                        stream->input.framesPerBuffer - stream->input.framesUsedInCurrentBuffer );
-                
-                channel = 0;
-                for( i=0; i<stream->input.deviceCount; ++i )
-                {
-                    /* we have stored the number of channels in the buffer in dwUser */
-                    int channelCount = stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser;
-
-                    PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,
-                            stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData +
-                                stream->input.framesUsedInCurrentBuffer * channelCount *
-                                stream->bufferProcessor.bytesPerHostInputSample,
-                            channelCount );
-
-                    channel += channelCount;
-                }
-                
-                framesProcessed = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, frames - framesRead );
-
-                stream->input.framesUsedInCurrentBuffer += framesProcessed;
-                if( stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer )
-                {
-                    result = AdvanceToNextInputBuffer( stream );
-                    if( result != paNoError )
-                        break;
-                }
-
-                framesRead += framesProcessed;      
-
-            }else{
-                /* wait for MME to signal that a buffer is available */
-                waitResult = WaitForSingleObject( stream->input.bufferEvent, timeout );
-                if( waitResult == WAIT_FAILED )
-                {
-                    result = paUnanticipatedHostError;
-                    break;
-                }
-                else if( waitResult == WAIT_TIMEOUT )
-                {
-                    /* if a timeout is encountered, continue,
-                        perhaps we should give up eventually
-                    */
-                }         
-            }
-        }while( framesRead < frames );
-    }
-    else
-    {
-        result = paCanNotReadFromAnOutputOnlyStream;
-    }
-
-    return result;
-}
-
-
-static PaError WriteStream( PaStream* s,
-                            const void *buffer,
-                            unsigned long frames )
-{
-    PaError result = paNoError;
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-    const void *userBuffer;
-    unsigned long framesWritten = 0;
-    unsigned long framesProcessed;
-    signed int hostOutputBufferIndex;
-    DWORD waitResult;
-    DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);
-    unsigned int channel, i;
-
-        
-    if( PA_IS_OUTPUT_STREAM_(stream) )
-    {
-        /* make a local copy of the user buffer pointer(s). this is necessary
-            because PaUtil_CopyOutput() advances these pointers every time
-            it is called.
-        */
-        if( stream->bufferProcessor.userOutputIsInterleaved )
-        {
-            userBuffer = buffer;
-        }
-        else
-        {
-            userBuffer = alloca( sizeof(void*) * stream->bufferProcessor.outputChannelCount );
-            if( !userBuffer )
-                return paInsufficientMemory;
-            for( i = 0; i<stream->bufferProcessor.outputChannelCount; ++i )
-                ((const void**)userBuffer)[i] = ((const void**)buffer)[i];
-        }
-
-        do{
-            if( CurrentOutputBuffersAreDone( stream ) )
-            {
-                if( NoBuffersAreQueued( &stream->output ) )
-                {
-                    /** @todo REVIEW: consider what to do if the output
-                    underflows. do we requeue all the existing buffers with
-                    zeros? should we run a separate thread to keep the buffers
-                    enqueued at all times? */
-
-                    result = paOutputUnderflowed;
-                }
-
-                hostOutputBufferIndex = stream->output.currentBufferIndex;
-
-                PaUtil_SetOutputFrameCount( &stream->bufferProcessor,
-                        stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
-                
-                channel = 0;
-                for( i=0; i<stream->output.deviceCount; ++i )
-                {
-                    /* we have stored the number of channels in the buffer in dwUser */
-                    int channelCount = stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;
-
-                    PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
-                            stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +
-                                stream->output.framesUsedInCurrentBuffer * channelCount *
-                                stream->bufferProcessor.bytesPerHostOutputSample,
-                            channelCount );
-
-                    channel += channelCount;
-                }
-                
-                framesProcessed = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames - framesWritten );
-
-                stream->output.framesUsedInCurrentBuffer += framesProcessed;
-                if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer )
-                {
-                    result = AdvanceToNextOutputBuffer( stream );
-                    if( result != paNoError )
-                        break;
-                }
-
-                framesWritten += framesProcessed;
-            }
-            else
-            {
-                /* wait for MME to signal that a buffer is available */
-                waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout );
-                if( waitResult == WAIT_FAILED )
-                {
-                    result = paUnanticipatedHostError;
-                    break;
-                }
-                else if( waitResult == WAIT_TIMEOUT )
-                {
-                    /* if a timeout is encountered, continue,
-                        perhaps we should give up eventually
-                    */
-                }             
-            }        
-        }while( framesWritten < frames );
-    }
-    else
-    {
-        result = paCanNotWriteToAnInputOnlyStream;
-    }
-    
-    return result;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-    
-    if( PA_IS_INPUT_STREAM_(stream) )
-        return GetAvailableFrames( &stream->input );
-    else
-        return paCanNotReadFromAnOutputOnlyStream;
-}
-
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
-    PaWinMmeStream *stream = (PaWinMmeStream*)s;
-    
-    if( PA_IS_OUTPUT_STREAM_(stream) )
-        return GetAvailableFrames( &stream->output );
-    else
-        return paCanNotWriteToAnInputOnlyStream;
-}
-
-
-/* NOTE: the following functions are MME-stream specific, and are called directly
-    by client code. We need to check for many more error conditions here because
-    we don't have the benefit of pa_front.c's parameter checking.
-*/
-
-static PaError GetWinMMEStreamPointer( PaWinMmeStream **stream, PaStream *s )
-{
-    PaError result;
-    PaUtilHostApiRepresentation *hostApi;
-    PaWinMmeHostApiRepresentation *winMmeHostApi;
-    
-    result = PaUtil_ValidateStreamPointer( s );
-    if( result != paNoError )
-        return result;
-
-    result = PaUtil_GetHostApiRepresentation( &hostApi, paMME );
-    if( result != paNoError )
-        return result;
-
-    winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
-    
-    /* note, the following would be easier if there was a generic way of testing
-        that a stream belongs to a specific host API */
-    
-    if( PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->callbackStreamInterface
-            || PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->blockingStreamInterface )
-    {
-        /* s is a WinMME stream */
-        *stream = (PaWinMmeStream *)s;
-        return paNoError;
-    }
-    else
-    {
-        return paIncompatibleStreamHostApi;
-    }
-}
-
-
-int PaWinMME_GetStreamInputHandleCount( PaStream* s )
-{
-    PaWinMmeStream *stream;
-    PaError result = GetWinMMEStreamPointer( &stream, s );
-
-    if( result == paNoError )
-        return (PA_IS_INPUT_STREAM_(stream)) ? stream->input.deviceCount : 0;
-    else
-        return result;
-}
-
-
-HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* s, int handleIndex )
-{
-    PaWinMmeStream *stream;
-    PaError result = GetWinMMEStreamPointer( &stream, s );
-
-    if( result == paNoError
-            && PA_IS_INPUT_STREAM_(stream)
-            && handleIndex >= 0
-            && (unsigned int)handleIndex < stream->input.deviceCount )
-        return ((HWAVEIN*)stream->input.waveHandles)[handleIndex];
-    else
-        return 0;
-}
-
-
-int PaWinMME_GetStreamOutputHandleCount( PaStream* s)
-{
-    PaWinMmeStream *stream;
-    PaError result = GetWinMMEStreamPointer( &stream, s );
-
-    if( result == paNoError )
-        return (PA_IS_OUTPUT_STREAM_(stream)) ? stream->output.deviceCount : 0;
-    else
-        return result;
-}
-
-
-HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* s, int handleIndex )
-{
-    PaWinMmeStream *stream;
-    PaError result = GetWinMMEStreamPointer( &stream, s );
-
-    if( result == paNoError
-            && PA_IS_OUTPUT_STREAM_(stream)
-            && handleIndex >= 0
-            && (unsigned int)handleIndex < stream->output.deviceCount )
-        return ((HWAVEOUT*)stream->output.waveHandles)[handleIndex];
-    else
-        return 0;
-}
-
-
-
-
-
+/*

+ * $Id: pa_win_wmme.c,v 1.6.2.86 2004/02/21 11:38:28 rossbencina Exp $

+ * pa_win_wmme.c

+ * Implementation of PortAudio for Windows MultiMedia Extensions (WMME)       

+ *                                                                                         

+ * PortAudio Portable Real-Time Audio Library

+ * Latest Version at: http://www.portaudio.com

+ *

+ * Authors: Ross Bencina and Phil Burk

+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+/* Modification History:

+ PLB = Phil Burk

+ JM = Julien Maillard

+ RDB = Ross Bencina

+ PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer)

+ PLB20010413 - check for excessive numbers of channels

+ PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC

+               including conditional inclusion of memory.h,

+               and explicit typecasting on memory allocation

+ PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory

+ PLB20010816 - pass process instead of thread to SetPriorityClass()

+ PLB20010927 - use number of frames instead of real-time for CPULoad calculation.

+ JM20020118 - prevent hung thread when buffers underflow.

+ PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount

+ RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init

+ RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices

+               refactoring, renaming and fixed a few edge case bugs

+ RDB20020531 - converted to V19 framework

+ ** NOTE  maintanance history is now stored in CVS **

+*/

+

+/** @file

+	

+	@todo Fix buffer catch up code, can sometimes get stuck (perhaps fixed now,

+            needs to be reviewed and tested.)

+

+    @todo implement paInputUnderflow, paOutputOverflow streamCallback statusFlags, paNeverDropInput.

+

+    @todo BUG: PA_MME_SET_LAST_WAVEIN/OUT_ERROR is used in functions which may

+                be called asynchronously from the callback thread. this is bad.

+

+    @todo implement inputBufferAdcTime in callback thread

+

+    @todo review/fix error recovery and cleanup in marked functions

+

+    @todo implement timeInfo for stream priming

+

+    @todo handle the case where the callback returns paAbort or paComplete during stream priming.

+

+    @todo review input overflow and output underflow handling in ReadStream and WriteStream

+

+Non-critical stuff for the future:

+

+    @todo Investigate supporting host buffer formats > 16 bits

+    

+    @todo define UNICODE and _UNICODE in the project settings and see what breaks

+

+*/

+

+/*

+    How it works:

+

+    For both callback and blocking read/write streams we open the MME devices

+    in CALLBACK_EVENT mode. In this mode, MME signals an Event object whenever

+    it has finished with a buffer (either filled it for input, or played it

+    for output). Where necessary we block waiting for Event objects using

+    WaitMultipleObjects().

+

+    When implementing a PA callback stream, we set up a high priority thread

+    which waits on the MME buffer Events and drains/fills the buffers when

+    they are ready.

+

+    When implementing a PA blocking read/write stream, we simply wait on these

+    Events (when necessary) inside the ReadStream() and WriteStream() functions.

+*/

+

+#include <stdio.h>

+#include <stdlib.h>

+#include <math.h>

+#include <windows.h>

+#include <mmsystem.h>

+#include <process.h>

+#include <assert.h>

+/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */

+#ifndef __MWERKS__

+#include <malloc.h>

+#include <memory.h>

+#endif /* __MWERKS__ */

+

+#include "portaudio.h"

+#include "pa_trace.h"

+#include "pa_util.h"

+#include "pa_allocation.h"

+#include "pa_hostapi.h"

+#include "pa_stream.h"

+#include "pa_cpuload.h"

+#include "pa_process.h"

+

+#include "pa_win_wmme.h"

+

+#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */

+#pragma comment(lib, "winmm.lib")

+#endif

+

+/************************************************* Constants ********/

+

+#define PA_MME_USE_HIGH_DEFAULT_LATENCY_    (0)  /* For debugging glitches. */

+

+#if PA_MME_USE_HIGH_DEFAULT_LATENCY_

+ #define PA_MME_WIN_9X_DEFAULT_LATENCY_                     (0.4)

+ #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_               (4)

+ #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_	(4)

+ #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_	(4)

+ #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_	(16)

+ #define PA_MME_MAX_HOST_BUFFER_SECS_				        (0.3)       /* Do not exceed unless user buffer exceeds */

+ #define PA_MME_MAX_HOST_BUFFER_BYTES_				        (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */

+#else

+ #define PA_MME_WIN_9X_DEFAULT_LATENCY_                     (0.2)

+ #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_               (2)

+ #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_	(3)

+ #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_	(2)

+ #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_	(16)

+ #define PA_MME_MAX_HOST_BUFFER_SECS_				        (0.1)       /* Do not exceed unless user buffer exceeds */

+ #define PA_MME_MAX_HOST_BUFFER_BYTES_				        (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */

+#endif

+

+/* Use higher latency for NT because it is even worse at real-time

+   operation than Win9x.

+*/

+#define PA_MME_WIN_NT_DEFAULT_LATENCY_      (PA_MME_WIN_9X_DEFAULT_LATENCY_ * 2)

+#define PA_MME_WIN_WDM_DEFAULT_LATENCY_     (PA_MME_WIN_9X_DEFAULT_LATENCY_)

+

+

+#define PA_MME_MIN_TIMEOUT_MSEC_        (1000)

+

+static const char constInputMapperSuffix_[] = " - Input";

+static const char constOutputMapperSuffix_[] = " - Output";

+

+/********************************************************************/

+

+typedef struct PaWinMmeStream PaWinMmeStream;     /* forward declaration */

+

+/* prototypes for functions declared in this file */

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** stream,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *streamCallback,

+                           void *userData );

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate );

+static PaError CloseStream( PaStream* stream );

+static PaError StartStream( PaStream *stream );

+static PaError StopStream( PaStream *stream );

+static PaError AbortStream( PaStream *stream );

+static PaError IsStreamStopped( PaStream *s );

+static PaError IsStreamActive( PaStream *stream );

+static PaTime GetStreamTime( PaStream *stream );

+static double GetStreamCpuLoad( PaStream* stream );

+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );

+static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );

+static signed long GetStreamReadAvailable( PaStream* stream );

+static signed long GetStreamWriteAvailable( PaStream* stream );

+

+

+/* macros for setting last host error information */

+

+#ifdef UNICODE

+

+#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \

+    {                                                                   \

+        wchar_t mmeErrorTextWide[ MAXERRORLENGTH ];                     \

+        char mmeErrorText[ MAXERRORLENGTH ];                            \

+        waveInGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH );   \

+        WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\

+            mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL );  \

+        PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText );   \

+    }

+

+#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \

+    {                                                                   \

+        wchar_t mmeErrorTextWide[ MAXERRORLENGTH ];                     \

+        char mmeErrorText[ MAXERRORLENGTH ];                            \

+        waveOutGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH );  \

+        WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\

+            mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL );  \

+        PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText );   \

+    }

+    

+#else /* !UNICODE */

+

+#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \

+    {                                                                   \

+        char mmeErrorText[ MAXERRORLENGTH ];                            \

+        waveInGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH );   \

+        PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText );   \

+    }

+

+#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \

+    {                                                                   \

+        char mmeErrorText[ MAXERRORLENGTH ];                            \

+        waveOutGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH );  \

+        PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText );   \

+    }

+

+#endif /* UNICODE */

+

+

+static void PaMme_SetLastSystemError( DWORD errorCode )

+{

+    char *lpMsgBuf;

+    FormatMessage(

+        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,

+        NULL,

+        errorCode,

+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

+        (LPTSTR) &lpMsgBuf,

+        0,

+        NULL

+    );

+    PaUtil_SetLastHostErrorInfo( paMME, errorCode, lpMsgBuf );

+    LocalFree( lpMsgBuf );

+}

+

+#define PA_MME_SET_LAST_SYSTEM_ERROR( errorCode ) \

+    PaMme_SetLastSystemError( errorCode )

+

+

+/* PaError returning wrappers for some commonly used win32 functions

+    note that we allow passing a null ptr to have no effect.

+*/

+

+static PaError CreateEventWithPaError( HANDLE *handle,

+        LPSECURITY_ATTRIBUTES lpEventAttributes,

+        BOOL bManualReset,

+        BOOL bInitialState,

+        LPCTSTR lpName )

+{

+    PaError result = paNoError;

+

+    *handle = NULL;

+    

+    *handle = CreateEvent( lpEventAttributes, bManualReset, bInitialState, lpName );

+    if( *handle == NULL )

+    {

+        result = paUnanticipatedHostError;

+        PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );

+    }

+

+    return result;

+}

+

+

+static PaError ResetEventWithPaError( HANDLE handle )

+{

+    PaError result = paNoError;

+

+    if( handle )

+    {

+        if( ResetEvent( handle ) == 0 )

+        {

+            result = paUnanticipatedHostError;

+            PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );

+        }

+    }

+

+    return result;

+}

+

+

+static PaError CloseHandleWithPaError( HANDLE handle )

+{

+    PaError result = paNoError;

+    

+    if( handle )

+    {

+        if( CloseHandle( handle ) == 0 )

+        {

+            result = paUnanticipatedHostError;

+            PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );

+        }

+    }

+    

+    return result;

+}

+

+

+/* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */

+

+typedef struct

+{

+    PaUtilHostApiRepresentation inheritedHostApiRep;

+    PaUtilStreamInterface callbackStreamInterface;

+    PaUtilStreamInterface blockingStreamInterface;

+

+    PaUtilAllocationGroup *allocations;

+    

+    int inputDeviceCount, outputDeviceCount;

+

+    /** winMmeDeviceIds is an array of WinMme device ids.

+        fields in the range [0, inputDeviceCount) are input device ids,

+        and [inputDeviceCount, inputDeviceCount + outputDeviceCount) are output

+        device ids.

+     */ 

+    UINT *winMmeDeviceIds;

+}

+PaWinMmeHostApiRepresentation;

+

+

+typedef struct

+{

+    PaDeviceInfo inheritedDeviceInfo;

+    DWORD dwFormats; /**<< standard formats bitmask from the WAVEINCAPS and WAVEOUTCAPS structures */

+}

+PaWinMmeDeviceInfo;

+

+

+/*************************************************************************

+ * Returns recommended device ID.

+ * On the PC, the recommended device can be specified by the user by

+ * setting an environment variable. For example, to use device #1.

+ *

+ *    set PA_RECOMMENDED_OUTPUT_DEVICE=1

+ *

+ * The user should first determine the available device ID by using

+ * the supplied application "pa_devs".

+ */

+#define PA_ENV_BUF_SIZE_  (32)

+#define PA_REC_IN_DEV_ENV_NAME_  ("PA_RECOMMENDED_INPUT_DEVICE")

+#define PA_REC_OUT_DEV_ENV_NAME_  ("PA_RECOMMENDED_OUTPUT_DEVICE")

+static PaDeviceIndex GetEnvDefaultDeviceID( char *envName )

+{

+    PaDeviceIndex recommendedIndex = paNoDevice;

+    DWORD   hresult;

+    char    envbuf[PA_ENV_BUF_SIZE_];

+

+#ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */

+

+    /* Let user determine default device by setting environment variable. */

+    hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE_ );

+    if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) )

+    {

+        recommendedIndex = atoi( envbuf );

+    }

+#endif

+

+    return recommendedIndex;

+}

+

+

+static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *hostApi )

+{

+    PaDeviceIndex device;

+

+    /* input */

+    device = GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME_ );

+    if( device != paNoDevice &&

+            ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&

+            hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxInputChannels > 0 )

+    {

+        hostApi->inheritedHostApiRep.info.defaultInputDevice = device;

+    }

+

+    /* output */

+    device = GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME_ );

+    if( device != paNoDevice &&

+            ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&

+            hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxOutputChannels > 0 )

+    {

+        hostApi->inheritedHostApiRep.info.defaultOutputDevice = device;

+    }

+}

+

+

+/** Convert external PA ID to a windows multimedia device ID

+*/

+static UINT LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device )

+{

+    assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount );

+

+	return hostApi->winMmeDeviceIds[ device ];

+}

+

+

+static PaError QueryInputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )

+{

+    MMRESULT mmresult;

+    

+    switch( mmresult = waveInOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )

+    {

+        case MMSYSERR_NOERROR:

+            return paNoError;

+        case MMSYSERR_ALLOCATED:    /* Specified resource is already allocated. */

+            return paDeviceUnavailable;

+        case MMSYSERR_NODRIVER:	    /* No device driver is present. */

+            return paDeviceUnavailable;

+        case MMSYSERR_NOMEM:	    /* Unable to allocate or lock memory. */

+            return paInsufficientMemory;

+        case WAVERR_BADFORMAT:      /* Attempted to open with an unsupported waveform-audio format. */

+            return paSampleFormatNotSupported;

+                    

+        case MMSYSERR_BADDEVICEID:	/* Specified device identifier is out of range. */

+            /* falls through */

+        default:

+            PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+            return paUnanticipatedHostError;

+    }

+}

+

+

+static PaError QueryOutputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )

+{

+    MMRESULT mmresult;

+    

+    switch( mmresult = waveOutOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )

+    {

+        case MMSYSERR_NOERROR:

+            return paNoError;

+        case MMSYSERR_ALLOCATED:    /* Specified resource is already allocated. */

+            return paDeviceUnavailable;

+        case MMSYSERR_NODRIVER:	    /* No device driver is present. */

+            return paDeviceUnavailable;

+        case MMSYSERR_NOMEM:	    /* Unable to allocate or lock memory. */

+            return paInsufficientMemory;

+        case WAVERR_BADFORMAT:      /* Attempted to open with an unsupported waveform-audio format. */

+            return paSampleFormatNotSupported;

+                    

+        case MMSYSERR_BADDEVICEID:	/* Specified device identifier is out of range. */

+            /* falls through */

+        default:

+            PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );

+            return paUnanticipatedHostError;

+    }

+}

+

+

+static PaError QueryFormatSupported( PaDeviceInfo *deviceInfo,

+        PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*),

+        int winMmeDeviceId, int channels, double sampleRate )

+{

+    PaWinMmeDeviceInfo *winMmeDeviceInfo = (PaWinMmeDeviceInfo*)deviceInfo;

+    WAVEFORMATEX waveFormatEx;

+    

+    if( sampleRate == 11025.0

+        && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1M16))

+            || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1S16)) ) ){

+

+        return paNoError;

+    }

+

+    if( sampleRate == 22050.0

+        && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2M16))

+            || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2S16)) ) ){

+

+        return paNoError;

+    }

+

+    if( sampleRate == 44100.0

+        && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4M16))

+            || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4S16)) ) ){

+

+        return paNoError;

+    }

+

+    waveFormatEx.wFormatTag = WAVE_FORMAT_PCM;

+    waveFormatEx.nChannels = (WORD)channels;

+    waveFormatEx.nSamplesPerSec = (DWORD)sampleRate;

+    waveFormatEx.nAvgBytesPerSec = waveFormatEx.nSamplesPerSec * channels * sizeof(short);

+    waveFormatEx.nBlockAlign = (WORD)(channels * sizeof(short));

+    waveFormatEx.wBitsPerSample = 16;

+    waveFormatEx.cbSize = 0;

+

+    return waveFormatExQueryFunction( winMmeDeviceId, &waveFormatEx );

+}

+

+

+#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_  (13) /* must match array length below */

+static double defaultSampleRateSearchOrder_[] =

+    { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0,

+        16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };

+

+static void DetectDefaultSampleRate( PaWinMmeDeviceInfo *winMmeDeviceInfo, int winMmeDeviceId,

+        PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*), int maxChannels )

+{

+    PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;

+    int i;

+    

+    deviceInfo->defaultSampleRate = 0.;

+

+    for( i=0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i )

+    {

+        double sampleRate = defaultSampleRateSearchOrder_[ i ]; 

+        PaError paerror = QueryFormatSupported( deviceInfo, waveFormatExQueryFunction, winMmeDeviceId, maxChannels, sampleRate );

+        if( paerror == paNoError )

+        {

+            deviceInfo->defaultSampleRate = sampleRate;

+            break;

+        }

+    }

+}

+

+

+static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,

+        PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeInputDeviceId, int *success )

+{

+    PaError result = paNoError;

+    char *deviceName; /* non-const ptr */

+    MMRESULT mmresult;

+    WAVEINCAPS wic;

+    PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;

+    

+    *success = 0;

+

+    mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) );

+    if( mmresult == MMSYSERR_NOMEM )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+    else if( mmresult != MMSYSERR_NOERROR )

+    {

+        /* instead of returning paUnanticipatedHostError we return

+            paNoError, but leave success set as 0. This allows

+            Pa_Initialize to just ignore this device, without failing

+            the entire initialisation process.

+        */

+        return paNoError;

+    }           

+

+    if( winMmeInputDeviceId == WAVE_MAPPER )

+    {

+        /* Append I/O suffix to WAVE_MAPPER device. */

+        deviceName = (char *)PaUtil_GroupAllocateMemory(

+                    winMmeHostApi->allocations, strlen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_) );

+        if( !deviceName )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+        strcpy( deviceName, wic.szPname );

+        strcat( deviceName, constInputMapperSuffix_ );

+    }

+    else

+    {

+        deviceName = (char*)PaUtil_GroupAllocateMemory(

+                    winMmeHostApi->allocations, strlen( wic.szPname ) + 1 );

+        if( !deviceName )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+        strcpy( deviceName, wic.szPname  );

+    }

+    deviceInfo->name = deviceName;

+

+    deviceInfo->maxInputChannels = wic.wChannels;

+    /* Sometimes a device can return a rediculously large number of channels.

+     * This happened with an SBLive card on a Windows ME box.

+     * If that happens, then force it to 2 channels.  PLB20010413

+     */

+    if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) )

+    {

+        PA_DEBUG(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxInputChannels ));

+        deviceInfo->maxInputChannels = 2;

+    }

+

+    winMmeDeviceInfo->dwFormats = wic.dwFormats;

+

+    DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId,

+            QueryInputWaveFormatEx, deviceInfo->maxInputChannels );

+

+    *success = 1;

+    

+error:

+    return result;

+}

+

+

+static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,

+        PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeOutputDeviceId, int *success )

+{

+    PaError result = paNoError;

+    char *deviceName; /* non-const ptr */

+    MMRESULT mmresult;

+    WAVEOUTCAPS woc;

+    PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;

+    

+    *success = 0;

+

+    mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) );

+    if( mmresult == MMSYSERR_NOMEM )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+    else if( mmresult != MMSYSERR_NOERROR )

+    {

+        /* instead of returning paUnanticipatedHostError we return

+            paNoError, but leave success set as 0. This allows

+            Pa_Initialize to just ignore this device, without failing

+            the entire initialisation process.

+        */

+        return paNoError;

+    }

+

+    if( winMmeOutputDeviceId == WAVE_MAPPER )

+    {

+        /* Append I/O suffix to WAVE_MAPPER device. */

+        deviceName = (char *)PaUtil_GroupAllocateMemory(

+                    winMmeHostApi->allocations, strlen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_) );

+        if( !deviceName )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+        strcpy( deviceName, woc.szPname );

+        strcat( deviceName, constOutputMapperSuffix_ );

+    }

+    else

+    {

+        deviceName = (char*)PaUtil_GroupAllocateMemory(

+                    winMmeHostApi->allocations, strlen( woc.szPname ) + 1 );

+        if( !deviceName )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+        strcpy( deviceName, woc.szPname  );

+    }

+    deviceInfo->name = deviceName;

+

+    deviceInfo->maxOutputChannels = woc.wChannels;

+    /* Sometimes a device can return a rediculously large number of channels.

+     * This happened with an SBLive card on a Windows ME box.

+     * It also happens on Win XP!

+     */

+    if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) )

+    {

+        PA_DEBUG(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));

+        deviceInfo->maxOutputChannels = 2;

+    }

+

+    winMmeDeviceInfo->dwFormats = woc.dwFormats;

+

+    DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId,

+            QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels );

+

+    *success = 1;

+    

+error:

+    return result;

+}

+

+

+static void GetDefaultLatencies( PaTime *defaultLowLatency, PaTime *defaultHighLatency )

+{

+    OSVERSIONINFO osvi;

+    osvi.dwOSVersionInfoSize = sizeof( osvi );

+	GetVersionEx( &osvi );

+

+    /* Check for NT */

+    if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )

+    {

+        *defaultLowLatency = PA_MME_WIN_NT_DEFAULT_LATENCY_;

+    }

+    else if(osvi.dwMajorVersion >= 5)

+    {

+        *defaultLowLatency  = PA_MME_WIN_WDM_DEFAULT_LATENCY_;

+    }

+    else

+    {

+        *defaultLowLatency  = PA_MME_WIN_9X_DEFAULT_LATENCY_;

+    }     

+

+    *defaultHighLatency = *defaultLowLatency * 2;

+}

+

+

+PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )

+{

+    PaError result = paNoError;

+    int i;

+    PaWinMmeHostApiRepresentation *winMmeHostApi;

+    int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount;

+    PaWinMmeDeviceInfo *deviceInfoArray;

+    int deviceInfoInitializationSucceeded;

+    PaTime defaultLowLatency, defaultHighLatency;

+

+    winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) );

+    if( !winMmeHostApi )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    winMmeHostApi->allocations = PaUtil_CreateAllocationGroup();

+    if( !winMmeHostApi->allocations )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    *hostApi = &winMmeHostApi->inheritedHostApiRep;

+    (*hostApi)->info.structVersion = 1;

+    (*hostApi)->info.type = paMME;

+    (*hostApi)->info.name = "MME";

+

+    

+    /* initialise device counts and default devices under the assumption that

+        there are no devices. These values are incremented below if and when

+        devices are successfully initialized.

+    */

+    (*hostApi)->info.deviceCount = 0;

+    (*hostApi)->info.defaultInputDevice = paNoDevice;

+    (*hostApi)->info.defaultOutputDevice = paNoDevice;

+    winMmeHostApi->inputDeviceCount = 0;

+    winMmeHostApi->outputDeviceCount = 0;

+

+

+    maximumPossibleDeviceCount = 0;

+

+    inputDeviceCount = waveInGetNumDevs();

+    if( inputDeviceCount > 0 )

+    	maximumPossibleDeviceCount += inputDeviceCount + 1;	/* assume there is a WAVE_MAPPER */

+

+    outputDeviceCount = waveOutGetNumDevs();

+    if( outputDeviceCount > 0 )

+	    maximumPossibleDeviceCount += outputDeviceCount + 1;	/* assume there is a WAVE_MAPPER */

+

+

+    if( maximumPossibleDeviceCount > 0 ){

+

+        (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(

+                winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount );

+        if( !(*hostApi)->deviceInfos )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        /* allocate all device info structs in a contiguous block */

+        deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory(

+                winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount );

+        if( !deviceInfoArray )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        winMmeHostApi->winMmeDeviceIds = (UINT*)PaUtil_GroupAllocateMemory(

+                winMmeHostApi->allocations, sizeof(int) * maximumPossibleDeviceCount );

+        if( !winMmeHostApi->winMmeDeviceIds )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency );

+

+        if( inputDeviceCount > 0 ){

+            /* -1 is the WAVE_MAPPER */

+            for( i = -1; i < inputDeviceCount; ++i ){

+                UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);

+                PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];

+                PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;

+                deviceInfo->structVersion = 2;

+                deviceInfo->hostApi = hostApiIndex;

+

+                deviceInfo->maxInputChannels = 0;

+                deviceInfo->maxOutputChannels = 0;

+

+                deviceInfo->defaultLowInputLatency = defaultLowLatency;

+                deviceInfo->defaultLowOutputLatency = defaultLowLatency;

+                deviceInfo->defaultHighInputLatency = defaultHighLatency;

+                deviceInfo->defaultHighOutputLatency = defaultHighLatency;

+

+                result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo,

+                        winMmeDeviceId, &deviceInfoInitializationSucceeded );

+                if( result != paNoError )

+                    goto error;

+

+                if( deviceInfoInitializationSucceeded ){

+                    if( (*hostApi)->info.defaultInputDevice == paNoDevice )

+                        (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;

+

+                    winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId;

+                    (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;

+

+                    winMmeHostApi->inputDeviceCount++;

+                    (*hostApi)->info.deviceCount++;

+                }

+            }

+        }

+

+        if( outputDeviceCount > 0 ){

+            /* -1 is the WAVE_MAPPER */

+            for( i = -1; i < outputDeviceCount; ++i ){

+                UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);

+                PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];

+                PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;

+                deviceInfo->structVersion = 2;

+                deviceInfo->hostApi = hostApiIndex;

+

+                deviceInfo->maxInputChannels = 0;

+                deviceInfo->maxOutputChannels = 0;

+

+                deviceInfo->defaultLowInputLatency = defaultLowLatency;

+                deviceInfo->defaultLowOutputLatency = defaultLowLatency;

+                deviceInfo->defaultHighInputLatency = defaultHighLatency;

+                deviceInfo->defaultHighOutputLatency = defaultHighLatency; 

+

+                result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo,

+                        winMmeDeviceId, &deviceInfoInitializationSucceeded );

+                if( result != paNoError )

+                    goto error;

+

+                if( deviceInfoInitializationSucceeded ){

+                    if( (*hostApi)->info.defaultOutputDevice == paNoDevice )

+                        (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;

+

+                    winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId;

+                    (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;

+

+                    winMmeHostApi->outputDeviceCount++;

+                    (*hostApi)->info.deviceCount++;

+                }

+            }

+        }

+    }

+    

+

+    InitializeDefaultDeviceIdsFromEnv( winMmeHostApi );

+

+    (*hostApi)->Terminate = Terminate;

+    (*hostApi)->OpenStream = OpenStream;

+    (*hostApi)->IsFormatSupported = IsFormatSupported;

+

+    PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream,

+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, GetStreamCpuLoad,

+                                      PaUtil_DummyRead, PaUtil_DummyWrite,

+                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );

+

+    PaUtil_InitializeStreamInterface( &winMmeHostApi->blockingStreamInterface, CloseStream, StartStream,

+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,

+                                      GetStreamTime, PaUtil_DummyGetCpuLoad,

+                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );

+

+    return result;

+

+error:

+    if( winMmeHostApi )

+    {

+        if( winMmeHostApi->allocations )

+        {

+            PaUtil_FreeAllAllocations( winMmeHostApi->allocations );

+            PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );

+        }

+        

+        PaUtil_FreeMemory( winMmeHostApi );

+    }

+

+    return result;

+}

+

+

+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )

+{

+    PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;

+

+    if( winMmeHostApi->allocations )

+    {

+        PaUtil_FreeAllAllocations( winMmeHostApi->allocations );

+        PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );

+    }

+

+    PaUtil_FreeMemory( winMmeHostApi );

+}

+

+

+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,

+                                  const PaStreamParameters *inputParameters,

+                                  const PaStreamParameters *outputParameters,

+                                  double sampleRate )

+{

+    PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;

+    PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo;

+    int inputChannelCount, outputChannelCount;

+    int inputMultipleDeviceChannelCount, outputMultipleDeviceChannelCount;

+    PaSampleFormat inputSampleFormat, outputSampleFormat;

+    PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;

+    UINT winMmeInputDeviceId, winMmeOutputDeviceId;

+    unsigned int i;

+    PaError paerror;

+

+    /* The calls to QueryFormatSupported below are intended to detect invalid

+        sample rates. If we assume that the channel count and format are OK,

+        then the only thing that could fail is the sample rate. This isn't

+        strictly true, but I can't think of a better way to test that the

+        sample rate is valid.

+    */  

+    

+    if( inputParameters )

+    {

+        inputChannelCount = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+        inputStreamInfo = inputParameters->hostApiSpecificStreamInfo;

+        

+        /* all standard sample formats are supported by the buffer adapter,

+             this implementation doesn't support any custom sample formats */

+        if( inputSampleFormat & paCustomFormat )

+            return paSampleFormatNotSupported;

+

+        if( inputParameters->device == paUseHostApiSpecificDeviceSpecification

+                && inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) )

+        {

+            inputMultipleDeviceChannelCount = 0;

+            for( i=0; i< inputStreamInfo->deviceCount; ++i )

+            {

+                inputMultipleDeviceChannelCount += inputStreamInfo->devices[i].channelCount;

+                    

+                inputDeviceInfo = hostApi->deviceInfos[ inputStreamInfo->devices[i].device ];

+

+                /* check that input device can support inputChannelCount */

+                if( inputStreamInfo->devices[i].channelCount <= 0

+                        || inputStreamInfo->devices[i].channelCount > inputDeviceInfo->maxInputChannels )

+                    return paInvalidChannelCount;

+

+                /* test for valid sample rate, see comment above */

+                winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputStreamInfo->devices[i].device );

+                paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, winMmeInputDeviceId, inputStreamInfo->devices[i].channelCount, sampleRate );

+                if( paerror != paNoError )

+                    return paInvalidSampleRate;

+            }

+                

+            if( inputMultipleDeviceChannelCount != inputChannelCount )

+                return paIncompatibleHostApiSpecificStreamInfo;                  

+        }

+        else

+        {

+            if( inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) )

+                return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the input device */

+

+            inputDeviceInfo = hostApi->deviceInfos[ inputParameters->device ];

+

+            /* check that input device can support inputChannelCount */

+            if( inputChannelCount > inputDeviceInfo->maxInputChannels )

+                return paInvalidChannelCount;

+

+            /* test for valid sample rate, see comment above */

+            winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputParameters->device );

+            paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, winMmeInputDeviceId, inputChannelCount, sampleRate );

+            if( paerror != paNoError )

+                return paInvalidSampleRate;

+        }

+    }

+

+    if( outputParameters )

+    {

+        outputChannelCount = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+        outputStreamInfo = outputParameters->hostApiSpecificStreamInfo;

+

+        /* all standard sample formats are supported by the buffer adapter,

+            this implementation doesn't support any custom sample formats */

+        if( outputSampleFormat & paCustomFormat )

+            return paSampleFormatNotSupported;

+

+        if( outputParameters->device == paUseHostApiSpecificDeviceSpecification

+                && outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) )

+        {

+            outputMultipleDeviceChannelCount = 0;

+            for( i=0; i< outputStreamInfo->deviceCount; ++i )

+            {

+                outputMultipleDeviceChannelCount += outputStreamInfo->devices[i].channelCount;

+                    

+                outputDeviceInfo = hostApi->deviceInfos[ outputStreamInfo->devices[i].device ];

+

+                /* check that output device can support outputChannelCount */

+                if( outputStreamInfo->devices[i].channelCount <= 0

+                        || outputStreamInfo->devices[i].channelCount > outputDeviceInfo->maxOutputChannels )

+                    return paInvalidChannelCount;

+

+                /* test for valid sample rate, see comment above */

+                winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputStreamInfo->devices[i].device );

+                paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, winMmeOutputDeviceId, outputStreamInfo->devices[i].channelCount, sampleRate );

+                if( paerror != paNoError )

+                    return paInvalidSampleRate;

+            }

+                

+            if( outputMultipleDeviceChannelCount != outputChannelCount )

+                return paIncompatibleHostApiSpecificStreamInfo;            

+        }

+        else

+        {

+            if( outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) )

+                return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the output device */

+

+            outputDeviceInfo = hostApi->deviceInfos[ outputParameters->device ];

+

+            /* check that output device can support outputChannelCount */

+            if( outputChannelCount > outputDeviceInfo->maxOutputChannels )

+                return paInvalidChannelCount;

+

+            /* test for valid sample rate, see comment above */

+            winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputParameters->device );

+            paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, winMmeOutputDeviceId, outputChannelCount, sampleRate );

+            if( paerror != paNoError )

+                return paInvalidSampleRate;

+        }

+    }

+    

+    /*

+            - if a full duplex stream is requested, check that the combination

+                of input and output parameters is supported

+

+            - check that the device supports sampleRate

+

+            for mme all we can do is test that the input and output devices

+            support the requested sample rate and number of channels. we

+            cannot test for full duplex compatibility.

+    */                                             

+

+    return paFormatIsSupported;

+}

+

+

+

+static void SelectBufferSizeAndCount( unsigned long baseBufferSize,

+    unsigned long requestedLatency,

+    unsigned long baseBufferCount, unsigned long minimumBufferCount,

+    unsigned long maximumBufferSize, unsigned long *hostBufferSize,

+    unsigned long *hostBufferCount )

+{

+    unsigned long sizeMultiplier, bufferCount, latency;

+    unsigned long nextLatency, nextBufferSize;

+    int baseBufferSizeIsPowerOfTwo;

+    

+    sizeMultiplier = 1;

+    bufferCount = baseBufferCount;

+

+    /* count-1 below because latency is always determined by one less

+        than the total number of buffers.

+    */

+    latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);

+

+    if( latency > requestedLatency )

+    {

+

+        /* reduce number of buffers without falling below suggested latency */

+

+        nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2);

+        while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency )

+        {

+            --bufferCount;

+            nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2);

+        }

+

+    }else if( latency < requestedLatency ){

+

+        baseBufferSizeIsPowerOfTwo = (! (baseBufferSize & (baseBufferSize - 1)));

+        if( baseBufferSizeIsPowerOfTwo ){

+

+            /* double size of buffers without exceeding requestedLatency */

+

+            nextBufferSize = (baseBufferSize * (sizeMultiplier*2));

+            nextLatency = nextBufferSize * (bufferCount-1);

+            while( nextBufferSize <= maximumBufferSize

+                    && nextLatency < requestedLatency )

+            {

+                sizeMultiplier *= 2;

+                nextBufferSize = (baseBufferSize * (sizeMultiplier*2));

+                nextLatency = nextBufferSize * (bufferCount-1);

+            }   

+

+        }else{

+

+            /* increase size of buffers upto first excess of requestedLatency */

+

+            nextBufferSize = (baseBufferSize * (sizeMultiplier+1));

+            nextLatency = nextBufferSize * (bufferCount-1);

+            while( nextBufferSize <= maximumBufferSize

+                    && nextLatency < requestedLatency )

+            {

+                ++sizeMultiplier;

+                nextBufferSize = (baseBufferSize * (sizeMultiplier+1));

+                nextLatency = nextBufferSize * (bufferCount-1);

+            }

+

+            if( nextLatency < requestedLatency )

+                ++sizeMultiplier;            

+        }

+

+        /* increase number of buffers until requestedLatency is reached */

+

+        latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);

+        while( latency < requestedLatency )

+        {

+            ++bufferCount;

+            latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);

+        }

+    }

+

+    *hostBufferSize = baseBufferSize * sizeMultiplier;

+    *hostBufferCount = bufferCount;

+}

+

+

+static void ReselectBufferCount( unsigned long bufferSize,

+    unsigned long requestedLatency,

+    unsigned long baseBufferCount, unsigned long minimumBufferCount,

+    unsigned long *hostBufferCount )

+{

+    unsigned long bufferCount, latency;

+    unsigned long nextLatency;

+

+    bufferCount = baseBufferCount;

+

+    /* count-1 below because latency is always determined by one less

+        than the total number of buffers.

+    */

+    latency = bufferSize * (bufferCount-1);

+

+    if( latency > requestedLatency )

+    {

+        /* reduce number of buffers without falling below suggested latency */

+

+        nextLatency = bufferSize * (bufferCount-2);

+        while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency )

+        {

+            --bufferCount;

+            nextLatency = bufferSize * (bufferCount-2);

+        }

+

+    }else if( latency < requestedLatency ){

+

+        /* increase number of buffers until requestedLatency is reached */

+

+        latency = bufferSize * (bufferCount-1);

+        while( latency < requestedLatency )

+        {

+            ++bufferCount;

+            latency = bufferSize * (bufferCount-1);

+        }                                                         

+    }

+

+    *hostBufferCount = bufferCount;

+}

+

+

+/* CalculateBufferSettings() fills the framesPerHostInputBuffer, hostInputBufferCount,

+   framesPerHostOutputBuffer and hostOutputBufferCount parameters based on the values

+   of the other parameters.

+*/

+

+static PaError CalculateBufferSettings(

+        unsigned long *framesPerHostInputBuffer, unsigned long *hostInputBufferCount,

+        unsigned long *framesPerHostOutputBuffer, unsigned long *hostOutputBufferCount,

+        int inputChannelCount, PaSampleFormat hostInputSampleFormat,

+        PaTime suggestedInputLatency, PaWinMmeStreamInfo *inputStreamInfo,

+        int outputChannelCount, PaSampleFormat hostOutputSampleFormat,

+        PaTime suggestedOutputLatency, PaWinMmeStreamInfo *outputStreamInfo,

+        double sampleRate, unsigned long framesPerBuffer )

+{

+    PaError result = paNoError;

+    int effectiveInputChannelCount, effectiveOutputChannelCount;

+    int hostInputFrameSize = 0;

+    unsigned int i;

+    

+    if( inputChannelCount > 0 )

+    {

+        int hostInputSampleSize = Pa_GetSampleSize( hostInputSampleFormat );

+        if( hostInputSampleSize < 0 )

+        {

+            result = hostInputSampleSize;

+            goto error;

+        }

+

+        if( inputStreamInfo

+                && ( inputStreamInfo->flags & paWinMmeUseMultipleDevices ) )

+        {

+            /* set effectiveInputChannelCount to the largest number of

+                channels on any one device.

+            */

+            effectiveInputChannelCount = 0;

+            for( i=0; i< inputStreamInfo->deviceCount; ++i )

+            {

+                if( inputStreamInfo->devices[i].channelCount > effectiveInputChannelCount )

+                    effectiveInputChannelCount = inputStreamInfo->devices[i].channelCount;

+            }

+        }

+        else

+        {

+            effectiveInputChannelCount = inputChannelCount;

+        }

+

+        hostInputFrameSize = hostInputSampleSize * effectiveInputChannelCount;

+

+        if( inputStreamInfo

+                && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )

+        {

+            if( inputStreamInfo->bufferCount <= 0

+                    || inputStreamInfo->framesPerBuffer <= 0 )

+            {

+                result = paIncompatibleHostApiSpecificStreamInfo;

+                goto error;

+            }

+

+            *framesPerHostInputBuffer = inputStreamInfo->framesPerBuffer;

+            *hostInputBufferCount = inputStreamInfo->bufferCount;

+        }

+        else

+        {

+            unsigned long hostBufferSizeBytes, hostBufferCount;

+            unsigned long minimumBufferCount = (outputChannelCount > 0)

+                    ? PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_

+                    : PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_;

+

+            unsigned long maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostInputFrameSize);

+            if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )

+                maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;

+

+            /* compute the following in bytes, then convert back to frames */

+

+            SelectBufferSizeAndCount(

+                ((framesPerBuffer == paFramesPerBufferUnspecified)

+                    ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_

+                    : framesPerBuffer ) * hostInputFrameSize, /* baseBufferSize */

+                ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */

+                4, /* baseBufferCount */

+                minimumBufferCount, maximumBufferSize,

+                &hostBufferSizeBytes, &hostBufferCount );

+

+            *framesPerHostInputBuffer = hostBufferSizeBytes / hostInputFrameSize;

+            *hostInputBufferCount = hostBufferCount;

+        }

+    }

+    else

+    {

+        *framesPerHostInputBuffer = 0;

+        *hostInputBufferCount = 0;

+    }

+

+    if( outputChannelCount > 0 )

+    {

+        if( outputStreamInfo

+                && ( outputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )

+        {

+            if( outputStreamInfo->bufferCount <= 0

+                    || outputStreamInfo->framesPerBuffer <= 0 )

+            {

+                result = paIncompatibleHostApiSpecificStreamInfo;

+                goto error;

+            }

+

+            *framesPerHostOutputBuffer = outputStreamInfo->framesPerBuffer;

+            *hostOutputBufferCount = outputStreamInfo->bufferCount;

+

+            

+            if( inputChannelCount > 0 ) /* full duplex */

+            {

+                if( *framesPerHostInputBuffer != *framesPerHostOutputBuffer )

+                {

+                    if( inputStreamInfo

+                            && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )

+                    { 

+                        /* a custom StreamInfo was used for specifying both input

+                            and output buffer sizes, the larger buffer size

+                            must be a multiple of the smaller buffer size */

+

+                        if( *framesPerHostInputBuffer < *framesPerHostOutputBuffer )

+                        {

+                            if( *framesPerHostOutputBuffer % *framesPerHostInputBuffer != 0 )

+                            {

+                                result = paIncompatibleHostApiSpecificStreamInfo;

+                                goto error;

+                            }

+                        }

+                        else

+                        {

+                            assert( *framesPerHostInputBuffer > *framesPerHostOutputBuffer );

+                            if( *framesPerHostInputBuffer % *framesPerHostOutputBuffer != 0 )

+                            {

+                                result = paIncompatibleHostApiSpecificStreamInfo;

+                                goto error;

+                            }

+                        }                        

+                    }

+                    else

+                    {

+                        /* a custom StreamInfo was not used for specifying the input buffer size,

+                            so use the output buffer size, and approximately the same latency. */

+

+                        *framesPerHostInputBuffer = *framesPerHostOutputBuffer;

+                        *hostInputBufferCount = (((unsigned long)(suggestedInputLatency * sampleRate)) / *framesPerHostInputBuffer) + 1;

+

+                        if( *hostInputBufferCount < PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ )

+                            *hostInputBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;

+                    }

+                }

+            }

+        }

+        else

+        {

+            unsigned long hostBufferSizeBytes, hostBufferCount;

+            unsigned long minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;

+            unsigned long maximumBufferSize;

+            int hostOutputFrameSize;

+            int hostOutputSampleSize;

+

+            hostOutputSampleSize = Pa_GetSampleSize( hostOutputSampleFormat );

+            if( hostOutputSampleSize < 0 )

+            {

+                result = hostOutputSampleSize;

+                goto error;

+            }

+

+            if( outputStreamInfo

+                && ( outputStreamInfo->flags & paWinMmeUseMultipleDevices ) )

+            {

+                /* set effectiveOutputChannelCount to the largest number of

+                    channels on any one device.

+                */

+                effectiveOutputChannelCount = 0;

+                for( i=0; i< outputStreamInfo->deviceCount; ++i )

+                {

+                    if( outputStreamInfo->devices[i].channelCount > effectiveOutputChannelCount )

+                        effectiveOutputChannelCount = outputStreamInfo->devices[i].channelCount;

+                }

+            }

+            else

+            {

+                effectiveOutputChannelCount = outputChannelCount;

+            }

+

+            hostOutputFrameSize = hostOutputSampleSize * effectiveOutputChannelCount;

+            

+            maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostOutputFrameSize);

+            if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )

+                maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;

+

+

+            /* compute the following in bytes, then convert back to frames */

+

+            SelectBufferSizeAndCount(

+                ((framesPerBuffer == paFramesPerBufferUnspecified)

+                    ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_

+                    : framesPerBuffer ) * hostOutputFrameSize, /* baseBufferSize */

+                ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */

+                4, /* baseBufferCount */

+                minimumBufferCount,

+                maximumBufferSize,

+                &hostBufferSizeBytes, &hostBufferCount );

+

+            *framesPerHostOutputBuffer = hostBufferSizeBytes / hostOutputFrameSize;

+            *hostOutputBufferCount = hostBufferCount;

+

+

+            if( inputChannelCount > 0 )

+            {

+                /* ensure that both input and output buffer sizes are the same.

+                    if they don't match at this stage, choose the smallest one

+                    and use that for input and output

+                */

+

+                if( *framesPerHostOutputBuffer != *framesPerHostInputBuffer )

+                {

+                    if( framesPerHostInputBuffer < framesPerHostOutputBuffer )

+                    {

+                        unsigned long framesPerHostBuffer = *framesPerHostInputBuffer;

+                        

+                        minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;

+                        ReselectBufferCount(

+                            framesPerHostBuffer * hostOutputFrameSize, /* bufferSize */

+                            ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */

+                            4, /* baseBufferCount */

+                            minimumBufferCount,

+                            &hostBufferCount );

+

+                        *framesPerHostOutputBuffer = framesPerHostBuffer;

+                        *hostOutputBufferCount = hostBufferCount;

+                    }

+                    else

+                    {

+                        unsigned long framesPerHostBuffer = *framesPerHostOutputBuffer;

+                        

+                        minimumBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;

+                        ReselectBufferCount(

+                            framesPerHostBuffer * hostInputFrameSize, /* bufferSize */

+                            ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */

+                            4, /* baseBufferCount */

+                            minimumBufferCount,

+                            &hostBufferCount );

+

+                        *framesPerHostInputBuffer = framesPerHostBuffer;

+                        *hostInputBufferCount = hostBufferCount;

+                    }

+                }   

+            }

+        }

+    }

+    else

+    {

+        *framesPerHostOutputBuffer = 0;

+        *hostOutputBufferCount = 0;

+    }

+

+error:

+    return result;

+}

+

+

+typedef struct

+{

+    HANDLE bufferEvent;

+    void *waveHandles;

+    unsigned int deviceCount;

+    /* unsigned int channelCount; */

+    WAVEHDR **waveHeaders;                  /* waveHeaders[device][buffer] */

+    unsigned int bufferCount;

+    unsigned int currentBufferIndex;

+    unsigned int framesPerBuffer;

+    unsigned int framesUsedInCurrentBuffer;

+}PaWinMmeSingleDirectionHandlesAndBuffers;

+

+/* prototypes for functions operating on PaWinMmeSingleDirectionHandlesAndBuffers */

+

+static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers );

+static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,

+        PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,

+        unsigned long bytesPerHostSample,

+        double sampleRate, PaWinMmeDeviceAndChannelCount *devices,

+        unsigned int deviceCount, int isInput );

+static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError );

+static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,

+        unsigned long hostBufferCount,

+        PaSampleFormat hostSampleFormat,

+        unsigned long framesPerHostBuffer,

+        PaWinMmeDeviceAndChannelCount *devices,

+        int isInput );

+static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput );

+

+

+static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )

+{

+    handlesAndBuffers->bufferEvent = 0;

+    handlesAndBuffers->waveHandles = 0;

+    handlesAndBuffers->deviceCount = 0;

+    handlesAndBuffers->waveHeaders = 0;

+    handlesAndBuffers->bufferCount = 0;

+}    

+

+static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,

+        PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,

+        unsigned long bytesPerHostSample,

+        double sampleRate, PaWinMmeDeviceAndChannelCount *devices,

+        unsigned int deviceCount, int isInput )

+{

+    PaError result;

+    MMRESULT mmresult;

+    unsigned long bytesPerFrame;

+    WAVEFORMATEX wfx;

+    signed int i;

+

+    /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()

+        has already been called to zero some fields */       

+

+    result = CreateEventWithPaError( &handlesAndBuffers->bufferEvent, NULL, FALSE, FALSE, NULL );

+    if( result != paNoError ) goto error;

+

+    if( isInput )

+        handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * deviceCount );

+    else

+        handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * deviceCount );

+    if( !handlesAndBuffers->waveHandles )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    handlesAndBuffers->deviceCount = deviceCount;

+

+    for( i = 0; i < (signed int)deviceCount; ++i )

+    {

+        if( isInput )

+            ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] = 0;

+        else

+            ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0;

+    }

+

+    wfx.wFormatTag = WAVE_FORMAT_PCM;

+    wfx.nSamplesPerSec = (DWORD) sampleRate;

+    wfx.cbSize = 0;

+    

+    for( i = 0; i < (signed int)deviceCount; ++i )

+    {

+        UINT winMmeDeviceId;

+

+        winMmeDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, devices[i].device );

+        wfx.nChannels = (WORD)devices[i].channelCount;

+

+        bytesPerFrame = wfx.nChannels * bytesPerHostSample;

+

+        wfx.nAvgBytesPerSec = (DWORD)(bytesPerFrame * sampleRate);

+        wfx.nBlockAlign = (WORD)bytesPerFrame;

+        wfx.wBitsPerSample = (WORD)((bytesPerFrame/wfx.nChannels) * 8);

+

+        /* REVIEW: consider not firing an event for input when a full duplex

+            stream is being used. this would probably depend on the

+            neverDropInput flag. */

+

+        if( isInput )

+            mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,

+                               (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );

+        else

+            mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,

+                                (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );

+

+        if( mmresult != MMSYSERR_NOERROR )

+        {

+            switch( mmresult )

+            {

+                case MMSYSERR_ALLOCATED:    /* Specified resource is already allocated. */

+                    result = paDeviceUnavailable;

+                    break;

+                case MMSYSERR_NODRIVER:	    /* No device driver is present. */

+                    result = paDeviceUnavailable;

+                    break;

+                case MMSYSERR_NOMEM:	    /* Unable to allocate or lock memory. */

+                    result = paInsufficientMemory;

+                    break;

+

+                case MMSYSERR_BADDEVICEID:	/* Specified device identifier is out of range. */

+                    /* falls through */

+                case WAVERR_BADFORMAT:      /* Attempted to open with an unsupported waveform-audio format. */

+                    /* falls through */

+                default:

+                    result = paUnanticipatedHostError;

+                    if( isInput )

+                    {

+                        PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+                    }

+                    else

+                    {

+                        PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );

+                    }

+            }

+            goto error;

+        }

+    }

+

+    return result;

+

+error:

+    TerminateWaveHandles( handlesAndBuffers, isInput, 1 /* currentlyProcessingAnError */ );

+

+    return result;

+}

+

+

+static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError )

+{

+    PaError result = paNoError;

+    MMRESULT mmresult;

+    signed int i;

+    

+    if( handlesAndBuffers->waveHandles )

+    {

+        for( i = handlesAndBuffers->deviceCount-1; i >= 0; --i )

+        {

+            if( isInput )

+            {

+                if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] )

+                    mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] );

+            }

+            else

+            {

+                if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] )

+                    mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] );

+            }

+

+            if( mmresult != MMSYSERR_NOERROR &&

+                !currentlyProcessingAnError ) /* don't update the error state if we're already processing an error */

+            {

+                result = paUnanticipatedHostError;

+                if( isInput )

+                {

+                    PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+                }

+                else

+                {

+                    PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );

+                }

+                /* note that we don't break here, we try to continue closing devices */

+            }

+        }

+

+        PaUtil_FreeMemory( handlesAndBuffers->waveHandles );

+        handlesAndBuffers->waveHandles = 0;

+    }

+

+    if( handlesAndBuffers->bufferEvent )

+    {

+        result = CloseHandleWithPaError( handlesAndBuffers->bufferEvent );

+        handlesAndBuffers->bufferEvent = 0;

+    }

+    

+    return result;

+}

+

+

+static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,

+        unsigned long hostBufferCount,

+        PaSampleFormat hostSampleFormat,

+        unsigned long framesPerHostBuffer,

+        PaWinMmeDeviceAndChannelCount *devices,

+        int isInput )

+{

+    PaError result = paNoError;

+    MMRESULT mmresult;

+    WAVEHDR *deviceWaveHeaders;

+    signed int i, j;

+

+    /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()

+        has already been called to zero some fields */

+        

+

+    /* allocate an array of pointers to arrays of wave headers, one array of

+        wave headers per device */

+    handlesAndBuffers->waveHeaders = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * handlesAndBuffers->deviceCount );

+    if( !handlesAndBuffers->waveHeaders )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+    

+    for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i )

+        handlesAndBuffers->waveHeaders[i] = 0;

+

+    handlesAndBuffers->bufferCount = hostBufferCount;

+

+    for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i )

+    {

+        int bufferBytes = Pa_GetSampleSize( hostSampleFormat ) *

+                framesPerHostBuffer * devices[i].channelCount;

+        if( bufferBytes < 0 )

+        {

+            result = paInternalError;

+            goto error;

+        }

+

+        /* Allocate an array of wave headers for device i */

+        deviceWaveHeaders = (WAVEHDR *) PaUtil_AllocateMemory( sizeof(WAVEHDR)*hostBufferCount );

+        if( !deviceWaveHeaders )

+        {

+            result = paInsufficientMemory;

+            goto error;

+        }

+

+        for( j=0; j < (signed int)hostBufferCount; ++j )

+            deviceWaveHeaders[j].lpData = 0;

+

+        handlesAndBuffers->waveHeaders[i] = deviceWaveHeaders;

+

+        /* Allocate a buffer for each wave header */

+        for( j=0; j < (signed int)hostBufferCount; ++j )

+        {

+            deviceWaveHeaders[j].lpData = (char *)PaUtil_AllocateMemory( bufferBytes );

+            if( !deviceWaveHeaders[j].lpData )

+            {

+                result = paInsufficientMemory;

+                goto error;

+            }

+            deviceWaveHeaders[j].dwBufferLength = bufferBytes;

+            deviceWaveHeaders[j].dwUser = 0xFFFFFFFF; /* indicates that *PrepareHeader() has not yet been called, for error clean up code */

+

+            if( isInput )

+            {

+                mmresult = waveInPrepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );

+                if( mmresult != MMSYSERR_NOERROR )

+                {

+                    result = paUnanticipatedHostError;

+                    PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+                    goto error;

+                }

+            }

+            else /* output */

+            {

+                mmresult = waveOutPrepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );

+                if( mmresult != MMSYSERR_NOERROR )

+                {

+                    result = paUnanticipatedHostError;

+                    PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+                    goto error;

+                }

+            }

+            deviceWaveHeaders[j].dwUser = devices[i].channelCount;

+        }

+    }

+

+    return result;

+

+error:

+    TerminateWaveHeaders( handlesAndBuffers, isInput );

+    

+    return result;

+}

+

+

+static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput )

+{

+    signed int i, j;

+    WAVEHDR *deviceWaveHeaders;

+    

+    if( handlesAndBuffers->waveHeaders )

+    {

+        for( i = handlesAndBuffers->deviceCount-1; i >= 0 ; --i )

+        {

+            deviceWaveHeaders = handlesAndBuffers->waveHeaders[i];  /* wave headers for device i */

+            if( deviceWaveHeaders )

+            {

+                for( j = handlesAndBuffers->bufferCount-1; j >= 0; --j )

+                {

+                    if( deviceWaveHeaders[j].lpData )

+                    {

+                        if( deviceWaveHeaders[j].dwUser != 0xFFFFFFFF )

+                        {

+                            if( isInput )

+                                waveInUnprepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );

+                            else

+                                waveOutUnprepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );

+                        }

+

+                        PaUtil_FreeMemory( deviceWaveHeaders[j].lpData );

+                    }

+                }

+

+                PaUtil_FreeMemory( deviceWaveHeaders );

+            }

+        }

+

+        PaUtil_FreeMemory( handlesAndBuffers->waveHeaders );

+        handlesAndBuffers->waveHeaders = 0;

+    }

+}

+

+

+

+/* PaWinMmeStream - a stream data structure specifically for this implementation */

+/* note that struct PaWinMmeStream is typedeffed to PaWinMmeStream above. */

+struct PaWinMmeStream

+{

+    PaUtilStreamRepresentation streamRepresentation;

+    PaUtilCpuLoadMeasurer cpuLoadMeasurer;

+    PaUtilBufferProcessor bufferProcessor;

+

+    int primeStreamUsingCallback;

+

+    PaWinMmeSingleDirectionHandlesAndBuffers input;

+    PaWinMmeSingleDirectionHandlesAndBuffers output;

+

+    /* Processing thread management -------------- */

+    HANDLE abortEvent;

+    HANDLE processingThread;

+    DWORD processingThreadId;

+

+    char throttleProcessingThreadOnOverload; /* 0 -> don't throtte, non-0 -> throttle */

+    int processingThreadPriority;

+    int highThreadPriority;

+    int throttledThreadPriority;

+    unsigned long throttledSleepMsecs;

+

+    int isStopped;

+    volatile int isActive;

+    volatile int stopProcessing; /* stop thread once existing buffers have been returned */

+    volatile int abortProcessing; /* stop thread immediately */

+

+    DWORD allBuffersDurationMs; /* used to calculate timeouts */

+};

+

+/* updates deviceCount if PaWinMmeUseMultipleDevices is used */

+

+static PaError ValidateWinMmeSpecificStreamInfo(

+        const PaStreamParameters *streamParameters,

+        const PaWinMmeStreamInfo *streamInfo,

+        char *throttleProcessingThreadOnOverload,

+        unsigned long *deviceCount )

+{

+	if( streamInfo )

+	{

+	    if( streamInfo->size != sizeof( PaWinMmeStreamInfo )

+	            || streamInfo->version != 1 )

+	    {

+	        return paIncompatibleHostApiSpecificStreamInfo;

+	    }

+

+	    if( streamInfo->flags & paWinMmeDontThrottleOverloadedProcessingThread )

+	        *throttleProcessingThreadOnOverload = 0;

+            

+	    if( streamInfo->flags & paWinMmeUseMultipleDevices )

+	    {

+	        if( streamParameters->device != paUseHostApiSpecificDeviceSpecification )

+	            return paInvalidDevice;

+	

+			*deviceCount = streamInfo->deviceCount;

+		}	

+	}

+

+	return paNoError;

+}

+

+static PaError RetrieveDevicesFromStreamParameters(

+        struct PaUtilHostApiRepresentation *hostApi,

+        const PaStreamParameters *streamParameters,

+        const PaWinMmeStreamInfo *streamInfo,

+        PaWinMmeDeviceAndChannelCount *devices,

+        unsigned long deviceCount )

+{

+    PaError result = paNoError;

+    unsigned int i;

+    int totalChannelCount;

+    PaDeviceIndex hostApiDevice;

+    

+	if( streamInfo && streamInfo->flags & paWinMmeUseMultipleDevices )

+	{

+		totalChannelCount = 0;

+	    for( i=0; i < deviceCount; ++i )

+	    {

+	        /* validate that the device number is within range */

+	        result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,

+	                        streamInfo->devices[i].device, hostApi );

+	        if( result != paNoError )

+	            return result;

+	        

+	        devices[i].device = hostApiDevice;

+	        devices[i].channelCount = streamInfo->devices[i].channelCount;

+	

+	        totalChannelCount += devices[i].channelCount;

+	    }

+	

+	    if( totalChannelCount != streamParameters->channelCount )

+	    {

+	        /* channelCount must match total channels specified by multiple devices */

+	        return paInvalidChannelCount; /* REVIEW use of this error code */

+	    }

+	}	

+	else

+	{		

+	    devices[0].device = streamParameters->device;

+	    devices[0].channelCount = streamParameters->channelCount;

+	}

+

+    return result;

+}

+

+static PaError ValidateInputChannelCounts(

+        struct PaUtilHostApiRepresentation *hostApi,

+        PaWinMmeDeviceAndChannelCount *devices,

+        unsigned long deviceCount )

+{

+    unsigned int i;

+

+	for( i=0; i < deviceCount; ++i )

+	{

+		if( devices[i].channelCount < 1 || devices[i].channelCount

+					> hostApi->deviceInfos[ devices[i].device ]->maxInputChannels )

+        	return paInvalidChannelCount;

+	}

+

+    return paNoError;

+}

+

+static PaError ValidateOutputChannelCounts(

+        struct PaUtilHostApiRepresentation *hostApi,

+        PaWinMmeDeviceAndChannelCount *devices,

+        unsigned long deviceCount )

+{

+    unsigned int i;

+

+	for( i=0; i < deviceCount; ++i )

+	{

+		if( devices[i].channelCount < 1 || devices[i].channelCount

+					> hostApi->deviceInfos[ devices[i].device ]->maxOutputChannels )

+        	return paInvalidChannelCount;

+	}

+

+    return paNoError;

+}

+

+

+/* the following macros are intended to improve the readability of the following code */

+#define PA_IS_INPUT_STREAM_( stream ) ( stream ->input.waveHandles )

+#define PA_IS_OUTPUT_STREAM_( stream ) ( stream ->output.waveHandles )

+#define PA_IS_FULL_DUPLEX_STREAM_( stream ) ( stream ->input.waveHandles && stream ->output.waveHandles )

+#define PA_IS_HALF_DUPLEX_STREAM_( stream ) ( !(stream ->input.waveHandles && stream ->output.waveHandles) )

+

+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,

+                           PaStream** s,

+                           const PaStreamParameters *inputParameters,

+                           const PaStreamParameters *outputParameters,

+                           double sampleRate,

+                           unsigned long framesPerBuffer,

+                           PaStreamFlags streamFlags,

+                           PaStreamCallback *streamCallback,

+                           void *userData )

+{

+    PaError result;

+    PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;

+    PaWinMmeStream *stream = 0;

+    int bufferProcessorIsInitialized = 0;

+    int streamRepresentationIsInitialized = 0;

+    PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;

+    int inputChannelCount, outputChannelCount;

+    PaSampleFormat inputSampleFormat, outputSampleFormat;

+    double suggestedInputLatency, suggestedOutputLatency;

+    PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;

+    unsigned long framesPerHostInputBuffer;

+    unsigned long hostInputBufferCount;

+    unsigned long framesPerHostOutputBuffer;

+    unsigned long hostOutputBufferCount;

+    unsigned long framesPerBufferProcessorCall;

+    PaWinMmeDeviceAndChannelCount *inputDevices = 0;  /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */

+    unsigned long inputDeviceCount = 0;            

+    PaWinMmeDeviceAndChannelCount *outputDevices = 0;

+    unsigned long outputDeviceCount = 0;                /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */

+    char throttleProcessingThreadOnOverload = 1;

+

+    

+    if( inputParameters )

+    {

+		inputChannelCount = inputParameters->channelCount;

+        inputSampleFormat = inputParameters->sampleFormat;

+        suggestedInputLatency = inputParameters->suggestedLatency;

+

+      	inputDeviceCount = 1;

+

+		/* validate input hostApiSpecificStreamInfo */

+        inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo;

+		result = ValidateWinMmeSpecificStreamInfo( inputParameters, inputStreamInfo,

+				&throttleProcessingThreadOnOverload,

+				&inputDeviceCount );

+		if( result != paNoError ) return result;

+

+		inputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * inputDeviceCount );

+        if( !inputDevices ) return paInsufficientMemory;

+

+		result = RetrieveDevicesFromStreamParameters( hostApi, inputParameters, inputStreamInfo, inputDevices, inputDeviceCount );

+		if( result != paNoError ) return result;

+

+		result = ValidateInputChannelCounts( hostApi, inputDevices, inputDeviceCount );

+		if( result != paNoError ) return result;

+

+        hostInputSampleFormat =

+            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );

+	}

+    else

+    {

+        inputChannelCount = 0;

+        inputSampleFormat = 0;

+        suggestedInputLatency = 0.;

+        inputStreamInfo = 0;

+        hostInputSampleFormat = 0;

+    }

+

+

+    if( outputParameters )

+    {

+        outputChannelCount = outputParameters->channelCount;

+        outputSampleFormat = outputParameters->sampleFormat;

+        suggestedOutputLatency = outputParameters->suggestedLatency;

+

+        outputDeviceCount = 1;

+

+		/* validate output hostApiSpecificStreamInfo */

+        outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo;

+		result = ValidateWinMmeSpecificStreamInfo( outputParameters, outputStreamInfo,

+				&throttleProcessingThreadOnOverload,

+				&outputDeviceCount );

+		if( result != paNoError ) return result;

+

+		outputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * outputDeviceCount );

+        if( !outputDevices ) return paInsufficientMemory;

+

+		result = RetrieveDevicesFromStreamParameters( hostApi, outputParameters, outputStreamInfo, outputDevices, outputDeviceCount );

+		if( result != paNoError ) return result;

+

+		result = ValidateOutputChannelCounts( hostApi, outputDevices, outputDeviceCount );

+		if( result != paNoError ) return result;

+

+        hostOutputSampleFormat =

+            PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );

+    }

+    else

+    {

+        outputChannelCount = 0;

+        outputSampleFormat = 0;

+        outputStreamInfo = 0;

+        hostOutputSampleFormat = 0;

+        suggestedOutputLatency = 0.;

+    }

+

+

+    /*

+        IMPLEMENT ME:

+            - alter sampleRate to a close allowable rate if possible / necessary

+    */

+

+

+    /* validate platform specific flags */

+    if( (streamFlags & paPlatformSpecificFlags) != 0 )

+        return paInvalidFlag; /* unexpected platform specific flag */

+

+

+    result = CalculateBufferSettings( &framesPerHostInputBuffer, &hostInputBufferCount,

+                &framesPerHostOutputBuffer, &hostOutputBufferCount,

+                inputChannelCount, hostInputSampleFormat, suggestedInputLatency, inputStreamInfo,

+                outputChannelCount, hostOutputSampleFormat, suggestedOutputLatency, outputStreamInfo,

+                sampleRate, framesPerBuffer );

+    if( result != paNoError ) goto error;

+

+

+    stream = (PaWinMmeStream*)PaUtil_AllocateMemory( sizeof(PaWinMmeStream) );

+    if( !stream )

+    {

+        result = paInsufficientMemory;

+        goto error;

+    }

+

+    InitializeSingleDirectionHandlesAndBuffers( &stream->input );

+    InitializeSingleDirectionHandlesAndBuffers( &stream->output );

+

+    stream->abortEvent = 0;

+    stream->processingThread = 0;

+

+    stream->throttleProcessingThreadOnOverload = throttleProcessingThreadOnOverload;

+

+    PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,

+                                           ( (streamCallback)

+                                            ? &winMmeHostApi->callbackStreamInterface

+                                            : &winMmeHostApi->blockingStreamInterface ),

+                                           streamCallback, userData );

+    streamRepresentationIsInitialized = 1;

+

+    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );

+

+

+    if( inputParameters && outputParameters ) /* full duplex */

+    {

+        if( framesPerHostInputBuffer < framesPerHostOutputBuffer )

+        {

+            assert( (framesPerHostOutputBuffer % framesPerHostInputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */

+

+            framesPerBufferProcessorCall = framesPerHostInputBuffer;

+        }

+        else

+        {

+            assert( (framesPerHostInputBuffer % framesPerHostOutputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */

+            

+            framesPerBufferProcessorCall = framesPerHostOutputBuffer;

+        }

+    }

+    else if( inputParameters )

+    {

+        framesPerBufferProcessorCall = framesPerHostInputBuffer;

+    }

+    else if( outputParameters )

+    {

+        framesPerBufferProcessorCall = framesPerHostOutputBuffer;

+    }

+

+    stream->input.framesPerBuffer = framesPerHostInputBuffer;

+    stream->output.framesPerBuffer = framesPerHostOutputBuffer;

+

+    result =  PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,

+                    inputChannelCount, inputSampleFormat, hostInputSampleFormat,

+                    outputChannelCount, outputSampleFormat, hostOutputSampleFormat,

+                    sampleRate, streamFlags, framesPerBuffer,

+                    framesPerBufferProcessorCall, paUtilFixedHostBufferSize,

+                    streamCallback, userData );

+    if( result != paNoError ) goto error;

+    

+    bufferProcessorIsInitialized = 1;

+

+    stream->streamRepresentation.streamInfo.inputLatency =

+            (double)(PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)

+                +(framesPerHostInputBuffer * (hostInputBufferCount-1))) / sampleRate;

+    stream->streamRepresentation.streamInfo.outputLatency =

+            (double)(PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)

+                +(framesPerHostOutputBuffer * (hostOutputBufferCount-1))) / sampleRate;

+    stream->streamRepresentation.streamInfo.sampleRate = sampleRate;

+

+    stream->primeStreamUsingCallback = ( (streamFlags&paPrimeOutputBuffersUsingStreamCallback) && streamCallback ) ? 1 : 0;

+

+    /* time to sleep when throttling due to >100% cpu usage.

+        -a quater of a buffer's duration */

+    stream->throttledSleepMsecs =

+            (unsigned long)(stream->bufferProcessor.framesPerHostBuffer *

+             stream->bufferProcessor.samplePeriod * .25 * 1000);

+

+    stream->isStopped = 1;

+    stream->isActive = 0;

+

+

+    /* for maximum compatibility with multi-device multichannel drivers,

+        we first open all devices, then we prepare all buffers, finally

+        we start all devices ( in StartStream() ). teardown in reverse order.

+    */

+

+    if( inputParameters )

+    {

+        result = InitializeWaveHandles( winMmeHostApi, &stream->input,

+                stream->bufferProcessor.bytesPerHostInputSample, sampleRate,

+                inputDevices, inputDeviceCount, 1 /* isInput */ );

+        if( result != paNoError ) goto error;

+    }

+    

+    if( outputParameters )

+    {

+        result = InitializeWaveHandles( winMmeHostApi, &stream->output,

+                stream->bufferProcessor.bytesPerHostOutputSample, sampleRate,

+                outputDevices, outputDeviceCount, 0 /* isInput */ );

+        if( result != paNoError ) goto error;

+    }

+

+    if( inputParameters )

+    {

+        result = InitializeWaveHeaders( &stream->input, hostInputBufferCount,

+                hostInputSampleFormat, framesPerHostInputBuffer, inputDevices, 1 /* isInput */ );

+        if( result != paNoError ) goto error;

+    }

+

+    if( outputParameters )

+    {

+        result = InitializeWaveHeaders( &stream->output, hostOutputBufferCount,

+                hostOutputSampleFormat, framesPerHostOutputBuffer, outputDevices, 0 /* not isInput */ );

+        if( result != paNoError ) goto error;

+

+        stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostOutputBuffer * stream->output.bufferCount) / sampleRate);

+    }

+    else

+    {

+        stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostInputBuffer * stream->input.bufferCount) / sampleRate);

+    }

+

+    

+    if( streamCallback )

+    {

+        /* abort event is only needed for callback streams */

+        result = CreateEventWithPaError( &stream->abortEvent, NULL, TRUE, FALSE, NULL );

+        if( result != paNoError ) goto error;

+    }

+

+    *s = (PaStream*)stream;

+

+    return result;

+

+error:

+

+    if( stream )

+    {

+        if( stream->abortEvent )

+            CloseHandle( stream->abortEvent );

+            

+        TerminateWaveHeaders( &stream->output, 0 /* not isInput */ );

+        TerminateWaveHeaders( &stream->input, 1 /* isInput */ );

+

+        TerminateWaveHandles( &stream->output, 0 /* not isInput */, 1 /* currentlyProcessingAnError */ );

+        TerminateWaveHandles( &stream->input, 1 /* isInput */, 1 /* currentlyProcessingAnError */ );

+

+        if( bufferProcessorIsInitialized )

+            PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );

+

+        if( streamRepresentationIsInitialized )

+            PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );

+

+        PaUtil_FreeMemory( stream );

+    }

+

+    return result;

+}

+

+

+/* return non-zero if all current buffers are done */

+static int BuffersAreDone( WAVEHDR **waveHeaders, unsigned int deviceCount, int bufferIndex )

+{

+    unsigned int i;

+    

+    for( i=0; i < deviceCount; ++i )

+    {

+        if( !(waveHeaders[i][ bufferIndex ].dwFlags & WHDR_DONE) )

+        {

+            return 0;

+        }         

+    }

+

+    return 1;

+}

+

+static int CurrentInputBuffersAreDone( PaWinMmeStream *stream )

+{

+    return BuffersAreDone( stream->input.waveHeaders, stream->input.deviceCount, stream->input.currentBufferIndex );

+}

+

+static int CurrentOutputBuffersAreDone( PaWinMmeStream *stream )

+{

+    return BuffersAreDone( stream->output.waveHeaders, stream->output.deviceCount, stream->output.currentBufferIndex );

+}

+

+

+/* return non-zero if any buffers are queued */

+static int NoBuffersAreQueued( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )

+{

+    unsigned int i, j;

+

+    if( handlesAndBuffers->waveHandles )

+    {

+        for( i=0; i < handlesAndBuffers->bufferCount; ++i )

+        {

+            for( j=0; j < handlesAndBuffers->deviceCount; ++j )

+            {

+                if( !( handlesAndBuffers->waveHeaders[ j ][ i ].dwFlags & WHDR_DONE) )

+                {

+                    return 0;

+                }

+            }

+        }

+    }

+

+    return 1;

+}

+

+

+#define PA_CIRCULAR_INCREMENT_( current, max )\

+    ( (((current) + 1) >= (max)) ? (0) : (current+1) )

+

+#define PA_CIRCULAR_DECREMENT_( current, max )\

+    ( ((current) == 0) ? ((max)-1) : (current-1) )

+    

+

+static signed long GetAvailableFrames( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )

+{

+    signed long result = 0;

+    unsigned int i;

+    

+    if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, handlesAndBuffers->currentBufferIndex ) )

+    {

+        /* we could calculate the following in O(1) if we kept track of the

+            last done buffer */

+        result = handlesAndBuffers->framesPerBuffer - handlesAndBuffers->framesUsedInCurrentBuffer;

+

+        i = PA_CIRCULAR_INCREMENT_( handlesAndBuffers->currentBufferIndex, handlesAndBuffers->bufferCount );

+        while( i != handlesAndBuffers->currentBufferIndex )

+        {

+            if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, i ) )

+            {

+                result += handlesAndBuffers->framesPerBuffer;

+                i = PA_CIRCULAR_INCREMENT_( i, handlesAndBuffers->bufferCount );

+            }

+            else

+                break;

+        }

+    }

+

+    return result;

+}

+

+

+static PaError AdvanceToNextInputBuffer( PaWinMmeStream *stream )

+{

+    PaError result = paNoError;

+    MMRESULT mmresult;

+    unsigned int i;

+

+    for( i=0; i < stream->input.deviceCount; ++i )

+    {

+        mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[i],

+                                    &stream->input.waveHeaders[i][ stream->input.currentBufferIndex ],

+                                    sizeof(WAVEHDR) );

+        if( mmresult != MMSYSERR_NOERROR )

+        {

+            result = paUnanticipatedHostError;

+            PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+        }

+    }

+

+    stream->input.currentBufferIndex =

+            PA_CIRCULAR_INCREMENT_( stream->input.currentBufferIndex, stream->input.bufferCount );

+

+    stream->input.framesUsedInCurrentBuffer = 0;

+

+    return result;

+}

+

+

+static PaError AdvanceToNextOutputBuffer( PaWinMmeStream *stream )

+{

+    PaError result = paNoError;

+    MMRESULT mmresult;

+    unsigned int i;

+

+    for( i=0; i < stream->output.deviceCount; ++i )

+    {

+        mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[i],

+                                 &stream->output.waveHeaders[i][ stream->output.currentBufferIndex ],

+                                 sizeof(WAVEHDR) );

+        if( mmresult != MMSYSERR_NOERROR )

+        {

+            result = paUnanticipatedHostError;

+            PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );

+        }

+    }

+

+    stream->output.currentBufferIndex =

+            PA_CIRCULAR_INCREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount );

+

+    stream->output.framesUsedInCurrentBuffer = 0;

+    

+    return result;

+}

+

+

+/* requeue all but the most recent input with the driver. Used for catching

+    up after a total input buffer underrun */

+static PaError CatchUpInputBuffers( PaWinMmeStream *stream )

+{

+    PaError result = paNoError;

+    unsigned int i;

+    

+    for( i=0; i < stream->input.bufferCount - 1; ++i )

+    {

+        result = AdvanceToNextInputBuffer( stream );

+        if( result != paNoError )

+            break;

+    }

+

+    return result;

+}

+

+

+/* take the most recent output and duplicate it to all other output buffers

+    and requeue them. Used for catching up after a total output buffer underrun.

+*/

+static PaError CatchUpOutputBuffers( PaWinMmeStream *stream )

+{

+    PaError result = paNoError;

+    unsigned int i, j;

+    unsigned int previousBufferIndex =

+            PA_CIRCULAR_DECREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount );

+

+    for( i=0; i < stream->output.bufferCount - 1; ++i )

+    {

+        for( j=0; j < stream->output.deviceCount; ++j )

+        {

+            if( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData

+                    != stream->output.waveHeaders[j][ previousBufferIndex ].lpData )

+            {

+                CopyMemory( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData,

+                            stream->output.waveHeaders[j][ previousBufferIndex ].lpData,

+                            stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].dwBufferLength );

+            }

+        }

+

+        result = AdvanceToNextOutputBuffer( stream );

+        if( result != paNoError )

+            break;

+    }

+

+    return result;

+}

+

+

+static DWORD WINAPI ProcessingThreadProc( void *pArg )

+{

+    PaWinMmeStream *stream = (PaWinMmeStream *)pArg;

+    HANDLE events[3];

+    int eventCount = 0;

+    DWORD result = paNoError;

+    DWORD waitResult;

+    DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);

+    int hostBuffersAvailable;

+    signed int hostInputBufferIndex, hostOutputBufferIndex;

+    PaStreamCallbackFlags statusFlags;

+    int callbackResult;

+    int done = 0;

+    unsigned int channel, i;

+    unsigned long framesProcessed;

+    

+    /* prepare event array for call to WaitForMultipleObjects() */

+    if( stream->input.bufferEvent )

+        events[eventCount++] = stream->input.bufferEvent;

+    if( stream->output.bufferEvent )

+        events[eventCount++] = stream->output.bufferEvent;

+    events[eventCount++] = stream->abortEvent;

+

+    statusFlags = 0; /** @todo support paInputUnderflow, paOutputOverflow and paNeverDropInput */

+    

+    /* loop until something causes us to stop */

+    do{

+        /* wait for MME to signal that a buffer is available, or for

+            the PA abort event to be signaled.

+

+          When this indicates that one or more buffers are available

+          NoBuffersAreQueued() and Current*BuffersAreDone are used below to

+          poll for additional done buffers. NoBuffersAreQueued() will fail

+          to identify an underrun/overflow if the driver doesn't mark all done

+          buffers prior to signalling the event. Some drivers do this

+          (eg RME Digi96, and others don't eg VIA PC 97 input). This isn't a

+          huge problem, it just means that we won't always be able to detect

+          underflow/overflow.

+        */

+        waitResult = WaitForMultipleObjects( eventCount, events, FALSE /* wait all = FALSE */, timeout );

+        if( waitResult == WAIT_FAILED )

+        {

+            result = paUnanticipatedHostError;

+            /** @todo FIXME/REVIEW: can't return host error info from an asyncronous thread */

+            done = 1;

+        }

+        else if( waitResult == WAIT_TIMEOUT )

+        {

+            /* if a timeout is encountered, continue */

+        }

+

+        if( stream->abortProcessing )

+        {

+            /* Pa_AbortStream() has been called, stop processing immediately */

+            done = 1;

+        }

+        else if( stream->stopProcessing )

+        {

+            /* Pa_StopStream() has been called or the user callback returned

+                non-zero, processing will continue until all output buffers

+                are marked as done. The stream will stop immediately if it

+                is input-only.

+            */

+

+            if( PA_IS_OUTPUT_STREAM_(stream) )

+            {

+                if( NoBuffersAreQueued( &stream->output ) )

+                    done = 1; /* Will cause thread to return. */

+            }

+            else

+            {

+                /* input only stream */

+                done = 1; /* Will cause thread to return. */

+            }

+        }

+        else

+        {

+            hostBuffersAvailable = 1;

+

+            /* process all available host buffers */

+            do

+            {

+                hostInputBufferIndex = -1;

+                hostOutputBufferIndex = -1;

+                

+                if( PA_IS_INPUT_STREAM_(stream) )

+                {

+                    if( CurrentInputBuffersAreDone( stream ) )

+                    {

+                        if( NoBuffersAreQueued( &stream->input ) )

+                        {

+                            /** @todo

+                               if all of the other buffers are also ready then

+                               we discard all but the most recent. This is an

+                               input buffer overflow. FIXME: these buffers should

+                               be passed to the callback in a paNeverDropInput

+                               stream.

+

+                               note that it is also possible for an input overflow

+                               to happen while the callback is processing a buffer.

+                               that is handled further down.

+                            */

+                            result = CatchUpInputBuffers( stream );

+                            if( result != paNoError )

+                                done = 1;

+

+                            statusFlags |= paInputOverflow;

+                        }

+

+                        hostInputBufferIndex = stream->input.currentBufferIndex;

+                    }

+                }

+

+                if( PA_IS_OUTPUT_STREAM_(stream) )

+                {

+                    if( CurrentOutputBuffersAreDone( stream ) )

+                    {

+                        /* ok, we have an output buffer */

+                        

+                        if( NoBuffersAreQueued( &stream->output ) )

+                        {

+                            /*

+                            if all of the other buffers are also ready, catch up by copying

+                            the most recently generated buffer into all but one of the output

+                            buffers.

+

+                            note that this catch up code only handles the case where all

+                            buffers have been played out due to this thread not having

+                            woken up at all. a more common case occurs when this thread

+                            is woken up, processes one buffer, but takes too long, and as

+                            a result all the other buffers have become un-queued. that

+                            case is handled further down.

+                            */

+

+                            result = CatchUpOutputBuffers( stream );

+                            if( result != paNoError )

+                                done = 1;

+

+                            statusFlags |= paOutputUnderflow;

+                        }

+

+                        hostOutputBufferIndex = stream->output.currentBufferIndex;

+                    }

+                }

+

+               

+                if( (PA_IS_FULL_DUPLEX_STREAM_(stream) && hostInputBufferIndex != -1 && hostOutputBufferIndex != -1) ||

+                        (PA_IS_HALF_DUPLEX_STREAM_(stream) && ( hostInputBufferIndex != -1 || hostOutputBufferIndex != -1 ) ) )

+                {

+                    PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */

+

+

+                    if( PA_IS_OUTPUT_STREAM_(stream) )

+                    {

+                        /* set timeInfo.currentTime and calculate timeInfo.outputBufferDacTime

+                            from the current wave out position */

+                        MMTIME mmtime;

+                        double timeBeforeGetPosition, timeAfterGetPosition;

+                        double time;

+                        long framesInBufferRing; 		

+                        long writePosition;

+                        long playbackPosition;

+                        HWAVEOUT firstWaveOutDevice = ((HWAVEOUT*)stream->output.waveHandles)[0];

+                        

+                        mmtime.wType = TIME_SAMPLES;

+                        timeBeforeGetPosition = PaUtil_GetTime();

+                        waveOutGetPosition( firstWaveOutDevice, &mmtime, sizeof(MMTIME) );

+                        timeAfterGetPosition = PaUtil_GetTime();

+

+                        timeInfo.currentTime = timeAfterGetPosition;

+

+                        /* approximate time at which wave out position was measured

+                            as half way between timeBeforeGetPosition and timeAfterGetPosition */

+                        time = timeBeforeGetPosition + (timeAfterGetPosition - timeBeforeGetPosition) * .5;

+                        

+                        framesInBufferRing = stream->output.bufferCount * stream->bufferProcessor.framesPerHostBuffer;

+                        playbackPosition = mmtime.u.sample % framesInBufferRing;

+

+                        writePosition = stream->output.currentBufferIndex * stream->bufferProcessor.framesPerHostBuffer

+                                + stream->output.framesUsedInCurrentBuffer;

+                       

+                        if( playbackPosition >= writePosition ){

+                            timeInfo.outputBufferDacTime =

+                                    time + ((double)( writePosition + (framesInBufferRing - playbackPosition) ) * stream->bufferProcessor.samplePeriod );

+                        }else{

+                            timeInfo.outputBufferDacTime =

+                                    time + ((double)( writePosition - playbackPosition ) * stream->bufferProcessor.samplePeriod );

+                        }

+                    }

+

+

+                    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

+

+                    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, statusFlags  );

+

+                    /* reset status flags once they have been passed to the buffer processor */

+                    statusFlags = 0;

+

+                    if( PA_IS_INPUT_STREAM_(stream) )

+                    {

+                        PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );

+

+                        channel = 0;

+                        for( i=0; i<stream->input.deviceCount; ++i )

+                        {

+                             /* we have stored the number of channels in the buffer in dwUser */

+                            int channelCount = stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser;

+                            

+                            PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,

+                                    stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData +

+                                        stream->input.framesUsedInCurrentBuffer * channelCount *

+                                        stream->bufferProcessor.bytesPerHostInputSample,

+                                    channelCount );

+                                    

+

+                            channel += channelCount;

+                        }

+                    }

+

+                    if( PA_IS_OUTPUT_STREAM_(stream) )

+                    {

+                        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );

+                        

+                        channel = 0;

+                        for( i=0; i<stream->output.deviceCount; ++i )

+                        {

+                            /* we have stored the number of channels in the buffer in dwUser */

+                            int channelCount = stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;

+

+                            PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,

+                                    stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +

+                                        stream->output.framesUsedInCurrentBuffer * channelCount *

+                                        stream->bufferProcessor.bytesPerHostOutputSample,

+                                    channelCount );

+

+                            channel += channelCount;

+                        }

+                    }

+

+                    callbackResult = paContinue;

+                    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );

+

+                    stream->input.framesUsedInCurrentBuffer += framesProcessed;

+                    stream->output.framesUsedInCurrentBuffer += framesProcessed;

+

+                    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );

+

+                    if( callbackResult == paContinue )

+                    {

+                        /* nothing special to do */

+                    }

+                    else if( callbackResult == paAbort )

+                    {

+                        stream->abortProcessing = 1;

+                        done = 1;

+                        /** @todo FIXME: should probably reset the output device immediately once the callback returns paAbort */

+                        result = paNoError;

+                    }

+                    else

+                    {

+                        /* User callback has asked us to stop with paComplete or other non-zero value */

+                        stream->stopProcessing = 1; /* stop once currently queued audio has finished */

+                        result = paNoError;

+                    }

+

+

+                    if( PA_IS_INPUT_STREAM_(stream)

+                            && stream->stopProcessing == 0 && stream->abortProcessing == 0

+                            && stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer )

+                    {

+                        if( NoBuffersAreQueued( &stream->input ) )

+                        {

+                            /** @todo need to handle PaNeverDropInput here where necessary */

+                            result = CatchUpInputBuffers( stream );

+                            if( result != paNoError )

+                                done = 1;

+

+                            statusFlags |= paInputOverflow;

+                        }

+

+                        result = AdvanceToNextInputBuffer( stream );

+                        if( result != paNoError )

+                            done = 1;

+                    }

+

+                    

+                    if( PA_IS_OUTPUT_STREAM_(stream) && !stream->abortProcessing )

+                    {

+                        if( stream->stopProcessing &&

+                                stream->output.framesUsedInCurrentBuffer < stream->output.framesPerBuffer )

+                        {

+                            /* zero remaining samples in output output buffer and flush */

+

+                            stream->output.framesUsedInCurrentBuffer += PaUtil_ZeroOutput( &stream->bufferProcessor,

+                                    stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );

+

+                            /* we send the entire buffer to the output devices, but we could

+                                just send a partial buffer, rather than zeroing the unused

+                                samples.

+                            */

+                        }

+

+                        if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer )

+                        {

+                            /* check for underflow before enquing the just-generated buffer,

+                                but recover from underflow after enquing it. This ensures

+                                that the most recent audio segment is repeated */

+                            int outputUnderflow = NoBuffersAreQueued( &stream->output );

+

+                            result = AdvanceToNextOutputBuffer( stream );

+                            if( result != paNoError )

+                                done = 1;

+

+                            if( outputUnderflow && !done && !stream->stopProcessing )

+                            {

+                                /* Recover from underflow in the case where the

+                                    underflow occured while processing the buffer

+                                    we just finished */

+

+                                result = CatchUpOutputBuffers( stream );

+                                if( result != paNoError )

+                                    done = 1;

+

+                                statusFlags |= paOutputUnderflow;

+                            }

+                        }

+                    }

+                    

+                    if( stream->throttleProcessingThreadOnOverload != 0 )

+                    {

+                        if( stream->stopProcessing || stream->abortProcessing )

+                        {

+                            if( stream->processingThreadPriority != stream->highThreadPriority )

+                            {

+                                SetThreadPriority( stream->processingThread, stream->highThreadPriority );

+                                stream->processingThreadPriority = stream->highThreadPriority;

+                            }

+                        }

+                        else if( PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) > 1. )

+                        {

+                            if( stream->processingThreadPriority != stream->throttledThreadPriority )

+                            {

+                                SetThreadPriority( stream->processingThread, stream->throttledThreadPriority );

+                                stream->processingThreadPriority = stream->throttledThreadPriority;

+                            }

+

+                            /* sleep to give other processes a go */

+                            Sleep( stream->throttledSleepMsecs );

+                        }

+                        else

+                        {

+                            if( stream->processingThreadPriority != stream->highThreadPriority )

+                            {

+                                SetThreadPriority( stream->processingThread, stream->highThreadPriority );

+                                stream->processingThreadPriority = stream->highThreadPriority;

+                            }

+                        }

+                    }

+                }

+                else

+                {

+                    hostBuffersAvailable = 0;

+                }

+            }

+            while( hostBuffersAvailable &&

+                    stream->stopProcessing == 0 &&

+                    stream->abortProcessing == 0 &&

+                    !done );

+        }

+    }

+    while( !done );

+

+    stream->isActive = 0;

+

+    if( stream->streamRepresentation.streamFinishedCallback != 0 )

+        stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );

+

+    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );

+    

+    return result;

+}

+

+

+/*

+    When CloseStream() is called, the multi-api layer ensures that

+    the stream has already been stopped or aborted.

+*/

+static PaError CloseStream( PaStream* s )

+{

+    PaError result;

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+

+    result = CloseHandleWithPaError( stream->abortEvent );

+    if( result != paNoError ) goto error;

+    

+    TerminateWaveHeaders( &stream->output, 0 /* not isInput */ );

+    TerminateWaveHeaders( &stream->input, 1 /* isInput */ );

+

+    TerminateWaveHandles( &stream->output, 0 /* not isInput */, 0 /* not currentlyProcessingAnError */ );

+    TerminateWaveHandles( &stream->input, 1 /* isInput */, 0 /* not currentlyProcessingAnError */ );

+    

+    PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );

+    PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );

+    PaUtil_FreeMemory( stream );

+

+error:

+    /** @todo REVIEW: what is the best way to clean up a stream if an error is detected? */

+    return result;

+}

+

+

+static PaError StartStream( PaStream *s )

+{

+    PaError result;

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+    MMRESULT mmresult;

+    unsigned int i, j;

+    int callbackResult;

+	unsigned int channel;

+ 	unsigned long framesProcessed;

+	PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement this for stream priming */

+    

+    PaUtil_ResetBufferProcessor( &stream->bufferProcessor );

+    

+    if( PA_IS_INPUT_STREAM_(stream) )

+    {

+        for( i=0; i<stream->input.bufferCount; ++i )

+        {

+            for( j=0; j<stream->input.deviceCount; ++j )

+            {

+                mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[j], &stream->input.waveHeaders[j][i], sizeof(WAVEHDR) );

+                if( mmresult != MMSYSERR_NOERROR )

+                {

+                    result = paUnanticipatedHostError;

+                    PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+                    goto error;

+                }

+            }

+        }

+        stream->input.currentBufferIndex = 0;

+        stream->input.framesUsedInCurrentBuffer = 0;

+    }

+

+    if( PA_IS_OUTPUT_STREAM_(stream) )

+    {

+        for( i=0; i<stream->output.deviceCount; ++i )

+        {

+            if( (mmresult = waveOutPause( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR )

+            {

+                result = paUnanticipatedHostError;

+                PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );

+                goto error;

+            }

+        }

+

+        for( i=0; i<stream->output.bufferCount; ++i )

+        {

+            if( stream->primeStreamUsingCallback )

+            {

+

+                stream->output.framesUsedInCurrentBuffer = 0;

+                do{

+

+                    PaUtil_BeginBufferProcessing( &stream->bufferProcessor,

+                            &timeInfo,

+                            paPrimingOutput | ((stream->input.bufferCount > 0 ) ? paInputUnderflow : 0));

+

+                    if( stream->input.bufferCount > 0 )

+                        PaUtil_SetNoInput( &stream->bufferProcessor );

+

+                    PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );

+

+                    channel = 0;

+                    for( j=0; j<stream->output.deviceCount; ++j )

+                    {

+                        /* we have stored the number of channels in the buffer in dwUser */

+                        int channelCount = stream->output.waveHeaders[j][i].dwUser;

+

+                        PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,

+                                stream->output.waveHeaders[j][i].lpData +

+                                stream->output.framesUsedInCurrentBuffer * channelCount *

+                                stream->bufferProcessor.bytesPerHostOutputSample,

+                                channelCount );

+

+                        /* we have stored the number of channels in the buffer in dwUser */

+                        channel += channelCount;

+                    }

+

+                    callbackResult = paContinue;

+                    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );

+                    stream->output.framesUsedInCurrentBuffer += framesProcessed;

+

+                    if( callbackResult != paContinue )

+                    {

+                        /** @todo fix this, what do we do if callback result is non-zero during stream

+                            priming?

+

+                            for complete: play out primed waveHeaders as usual

+                            for abort: clean up immediately.

+                       */

+                    }

+

+                }while( stream->output.framesUsedInCurrentBuffer != stream->output.framesPerBuffer );

+

+            }

+            else

+            {

+                for( j=0; j<stream->output.deviceCount; ++j )

+                {

+                    ZeroMemory( stream->output.waveHeaders[j][i].lpData, stream->output.waveHeaders[j][i].dwBufferLength );

+                }

+            }   

+

+            /* we queue all channels of a single buffer frame (accross all

+                devices, because some multidevice multichannel drivers work

+                better this way */

+            for( j=0; j<stream->output.deviceCount; ++j )

+            {

+                mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[j], &stream->output.waveHeaders[j][i], sizeof(WAVEHDR) );

+                if( mmresult != MMSYSERR_NOERROR )

+                {

+                    result = paUnanticipatedHostError;

+                    PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );

+                    goto error;

+                }

+            }

+        }

+        stream->output.currentBufferIndex = 0;

+        stream->output.framesUsedInCurrentBuffer = 0;

+    }

+

+

+    stream->isStopped = 0;

+    stream->isActive = 1;

+    stream->stopProcessing = 0;

+    stream->abortProcessing = 0;

+

+    result = ResetEventWithPaError( stream->input.bufferEvent );

+    if( result != paNoError ) goto error;

+

+    result = ResetEventWithPaError( stream->output.bufferEvent );

+    if( result != paNoError ) goto error;

+    

+    

+    if( stream->streamRepresentation.streamCallback )

+    {

+        /* callback stream */

+

+        result = ResetEventWithPaError( stream->abortEvent );

+        if( result != paNoError ) goto error;

+

+        /* Create thread that waits for audio buffers to be ready for processing. */

+        stream->processingThread = CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId );

+        if( !stream->processingThread )

+        {

+            result = paUnanticipatedHostError;

+            PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );

+            goto error;

+        }

+

+        /** @todo could have mme specific stream parameters to allow the user

+            to set the callback thread priorities */

+        stream->highThreadPriority = THREAD_PRIORITY_TIME_CRITICAL;

+        stream->throttledThreadPriority = THREAD_PRIORITY_NORMAL;

+

+        if( !SetThreadPriority( stream->processingThread, stream->highThreadPriority ) )

+        {

+            result = paUnanticipatedHostError;

+            PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );

+            goto error;

+        }

+        stream->processingThreadPriority = stream->highThreadPriority;

+    }

+    else

+    {

+        /* blocking read/write stream */

+

+    }

+

+    if( PA_IS_INPUT_STREAM_(stream) )

+    {

+        for( i=0; i < stream->input.deviceCount; ++i )

+        {

+            mmresult = waveInStart( ((HWAVEIN*)stream->input.waveHandles)[i] );

+            PA_DEBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult));

+            if( mmresult != MMSYSERR_NOERROR )

+            {

+                result = paUnanticipatedHostError;

+                PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+                goto error;

+            }

+        }

+    }

+

+    if( PA_IS_OUTPUT_STREAM_(stream) )

+    {

+        for( i=0; i < stream->output.deviceCount; ++i )

+        {

+            if( (mmresult = waveOutRestart( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR )

+            {

+                result = paUnanticipatedHostError;

+                PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );

+                goto error;

+            }

+        }

+    }

+

+    return result;

+

+error:

+    /** @todo FIXME: implement recovery as best we can

+    This should involve rolling back to a state as-if this function had never been called

+    */

+    return result;

+}

+

+

+static PaError StopStream( PaStream *s )

+{

+    PaError result = paNoError;

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+    int timeout;

+    DWORD waitResult;

+    MMRESULT mmresult;

+    signed int hostOutputBufferIndex;

+    unsigned int channel, waitCount, i;                  

+    

+    /** @todo

+        REVIEW: the error checking in this function needs review. the basic

+        idea is to return from this function in a known state - for example

+        there is no point avoiding calling waveInReset just because

+        the thread times out.

+    */

+

+    if( stream->processingThread )

+    {

+        /* callback stream */

+

+        /* Tell processing thread to stop generating more data and to let current data play out. */

+        stream->stopProcessing = 1;

+

+        /* Calculate timeOut longer than longest time it could take to return all buffers. */

+        timeout = (int)(stream->allBuffersDurationMs * 1.5);

+        if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )

+            timeout = PA_MME_MIN_TIMEOUT_MSEC_;

+

+        PA_DEBUG(("WinMME StopStream: waiting for background thread.\n"));

+

+        waitResult = WaitForSingleObject( stream->processingThread, timeout );

+        if( waitResult == WAIT_TIMEOUT )

+        {

+            /* try to abort */

+            stream->abortProcessing = 1;

+            SetEvent( stream->abortEvent );

+            waitResult = WaitForSingleObject( stream->processingThread, timeout );

+            if( waitResult == WAIT_TIMEOUT )

+            {

+                PA_DEBUG(("WinMME StopStream: timed out while waiting for background thread to finish.\n"));

+                result = paTimedOut;

+            }

+        }

+

+        CloseHandle( stream->processingThread );

+        stream->processingThread = NULL;

+    }

+    else

+    {

+        /* blocking read / write stream */

+

+        if( PA_IS_OUTPUT_STREAM_(stream) )

+        {

+            if( stream->output.framesUsedInCurrentBuffer > 0 )

+            {

+                /* there are still unqueued frames in the current buffer, so flush them */

+

+                hostOutputBufferIndex = stream->output.currentBufferIndex;

+

+                PaUtil_SetOutputFrameCount( &stream->bufferProcessor,

+                        stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );

+                

+                channel = 0;

+                for( i=0; i<stream->output.deviceCount; ++i )

+                {

+                    /* we have stored the number of channels in the buffer in dwUser */

+                    int channelCount = stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;

+

+                    PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,

+                            stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +

+                                stream->output.framesUsedInCurrentBuffer * channelCount *

+                                stream->bufferProcessor.bytesPerHostOutputSample,

+                            channelCount );

+

+                    channel += channelCount;

+                }

+

+                PaUtil_ZeroOutput( &stream->bufferProcessor,

+                        stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );

+

+                /* we send the entire buffer to the output devices, but we could

+                    just send a partial buffer, rather than zeroing the unused

+                    samples.

+                */

+                AdvanceToNextOutputBuffer( stream );

+            }

+            

+

+            timeout = (stream->allBuffersDurationMs / stream->output.bufferCount) + 1;

+            if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )

+                timeout = PA_MME_MIN_TIMEOUT_MSEC_;

+

+            waitCount = 0;

+            while( !NoBuffersAreQueued( &stream->output ) && waitCount <= stream->output.bufferCount )

+            {

+                /* wait for MME to signal that a buffer is available */

+                waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout );

+                if( waitResult == WAIT_FAILED )

+                {

+                    break;

+                }

+                else if( waitResult == WAIT_TIMEOUT )

+                {

+                    /* keep waiting */

+                }

+

+                ++waitCount;

+            }

+        }

+    }

+

+    if( PA_IS_OUTPUT_STREAM_(stream) )

+    {

+        for( i =0; i < stream->output.deviceCount; ++i )

+        {

+            mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] );

+            if( mmresult != MMSYSERR_NOERROR )

+            {

+                result = paUnanticipatedHostError;

+                PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );

+            }

+        }

+    }

+

+    if( PA_IS_INPUT_STREAM_(stream) )

+    {

+        for( i=0; i < stream->input.deviceCount; ++i )

+        {

+            mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] );

+            if( mmresult != MMSYSERR_NOERROR )

+            {

+                result = paUnanticipatedHostError;

+                PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+            }

+        }

+    }

+

+    stream->isStopped = 1;

+    stream->isActive = 0;

+

+    return result;

+}

+

+

+static PaError AbortStream( PaStream *s )

+{

+    PaError result = paNoError;

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+    int timeout;

+    DWORD waitResult;

+    MMRESULT mmresult;

+    unsigned int i;

+    

+    /** @todo

+        REVIEW: the error checking in this function needs review. the basic

+        idea is to return from this function in a known state - for example

+        there is no point avoiding calling waveInReset just because

+        the thread times out.

+    */

+

+    if( stream->processingThread )

+    {

+        /* callback stream */

+        

+        /* Tell processing thread to abort immediately */

+        stream->abortProcessing = 1;

+        SetEvent( stream->abortEvent );

+    }

+

+

+    if( PA_IS_OUTPUT_STREAM_(stream) )

+    {

+        for( i =0; i < stream->output.deviceCount; ++i )

+        {

+            mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] );

+            if( mmresult != MMSYSERR_NOERROR )

+            {

+                PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );

+                return paUnanticipatedHostError;

+            }

+        }

+    }

+

+    if( PA_IS_INPUT_STREAM_(stream) )

+    {

+        for( i=0; i < stream->input.deviceCount; ++i )

+        {

+            mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] );

+            if( mmresult != MMSYSERR_NOERROR )

+            {

+                PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );

+                return paUnanticipatedHostError;

+            }

+        }

+    }

+

+

+    if( stream->processingThread )

+    {

+        /* callback stream */

+        

+        PA_DEBUG(("WinMME AbortStream: waiting for background thread.\n"));

+

+        /* Calculate timeOut longer than longest time it could take to return all buffers. */

+        timeout = (int)(stream->allBuffersDurationMs * 1.5);

+        if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )

+            timeout = PA_MME_MIN_TIMEOUT_MSEC_;

+            

+        waitResult = WaitForSingleObject( stream->processingThread, timeout );

+        if( waitResult == WAIT_TIMEOUT )

+        {

+            PA_DEBUG(("WinMME AbortStream: timed out while waiting for background thread to finish.\n"));

+            return paTimedOut;

+        }

+

+        CloseHandle( stream->processingThread );

+        stream->processingThread = NULL;

+    }

+

+    stream->isStopped = 1;

+    stream->isActive = 0;

+

+    return result;

+}

+

+

+static PaError IsStreamStopped( PaStream *s )

+{

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+

+    return stream->isStopped;

+}

+

+

+static PaError IsStreamActive( PaStream *s )

+{

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+

+    return stream->isActive;

+}

+

+

+static PaTime GetStreamTime( PaStream *s )

+{

+    (void) s; /* unused parameter */

+    

+    return PaUtil_GetTime();

+}

+

+

+static double GetStreamCpuLoad( PaStream* s )

+{

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+

+    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );

+}

+

+

+/*

+    As separate stream interfaces are used for blocking and callback

+    streams, the following functions can be guaranteed to only be called

+    for blocking streams.

+*/

+

+static PaError ReadStream( PaStream* s,

+                           void *buffer,

+                           unsigned long frames )

+{

+    PaError result = paNoError;

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+    void *userBuffer;

+    unsigned long framesRead = 0;

+    unsigned long framesProcessed;

+    signed int hostInputBufferIndex;

+    DWORD waitResult;

+    DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);

+    unsigned int channel, i;

+    

+    if( PA_IS_INPUT_STREAM_(stream) )

+    {

+        /* make a local copy of the user buffer pointer(s). this is necessary

+            because PaUtil_CopyInput() advances these pointers every time

+            it is called.

+        */

+        if( stream->bufferProcessor.userInputIsInterleaved )

+        {

+            userBuffer = buffer;

+        }

+        else

+        {

+            userBuffer = alloca( sizeof(void*) * stream->bufferProcessor.inputChannelCount );

+            if( !userBuffer )

+                return paInsufficientMemory;

+            for( i = 0; i<stream->bufferProcessor.inputChannelCount; ++i )

+                ((void**)userBuffer)[i] = ((void**)buffer)[i];

+        }

+        

+        do{

+            if( CurrentInputBuffersAreDone( stream ) )

+            {

+                if( NoBuffersAreQueued( &stream->input ) )

+                {

+                    /** @todo REVIEW: consider what to do if the input overflows.

+                        do we requeue all of the buffers? should we be running

+                        a thread to make sure they are always queued? */

+

+                    result = paInputOverflowed;

+                }

+

+                hostInputBufferIndex = stream->input.currentBufferIndex;

+

+                PaUtil_SetInputFrameCount( &stream->bufferProcessor,

+                        stream->input.framesPerBuffer - stream->input.framesUsedInCurrentBuffer );

+                

+                channel = 0;

+                for( i=0; i<stream->input.deviceCount; ++i )

+                {

+                    /* we have stored the number of channels in the buffer in dwUser */

+                    int channelCount = stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser;

+

+                    PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,

+                            stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData +

+                                stream->input.framesUsedInCurrentBuffer * channelCount *

+                                stream->bufferProcessor.bytesPerHostInputSample,

+                            channelCount );

+

+                    channel += channelCount;

+                }

+                

+                framesProcessed = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, frames - framesRead );

+

+                stream->input.framesUsedInCurrentBuffer += framesProcessed;

+                if( stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer )

+                {

+                    result = AdvanceToNextInputBuffer( stream );

+                    if( result != paNoError )

+                        break;

+                }

+

+                framesRead += framesProcessed;      

+

+            }else{

+                /* wait for MME to signal that a buffer is available */

+                waitResult = WaitForSingleObject( stream->input.bufferEvent, timeout );

+                if( waitResult == WAIT_FAILED )

+                {

+                    result = paUnanticipatedHostError;

+                    break;

+                }

+                else if( waitResult == WAIT_TIMEOUT )

+                {

+                    /* if a timeout is encountered, continue,

+                        perhaps we should give up eventually

+                    */

+                }         

+            }

+        }while( framesRead < frames );

+    }

+    else

+    {

+        result = paCanNotReadFromAnOutputOnlyStream;

+    }

+

+    return result;

+}

+

+

+static PaError WriteStream( PaStream* s,

+                            const void *buffer,

+                            unsigned long frames )

+{

+    PaError result = paNoError;

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+    const void *userBuffer;

+    unsigned long framesWritten = 0;

+    unsigned long framesProcessed;

+    signed int hostOutputBufferIndex;

+    DWORD waitResult;

+    DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);

+    unsigned int channel, i;

+

+        

+    if( PA_IS_OUTPUT_STREAM_(stream) )

+    {

+        /* make a local copy of the user buffer pointer(s). this is necessary

+            because PaUtil_CopyOutput() advances these pointers every time

+            it is called.

+        */

+        if( stream->bufferProcessor.userOutputIsInterleaved )

+        {

+            userBuffer = buffer;

+        }

+        else

+        {

+            userBuffer = alloca( sizeof(void*) * stream->bufferProcessor.outputChannelCount );

+            if( !userBuffer )

+                return paInsufficientMemory;

+            for( i = 0; i<stream->bufferProcessor.outputChannelCount; ++i )

+                ((const void**)userBuffer)[i] = ((const void**)buffer)[i];

+        }

+

+        do{

+            if( CurrentOutputBuffersAreDone( stream ) )

+            {

+                if( NoBuffersAreQueued( &stream->output ) )

+                {

+                    /** @todo REVIEW: consider what to do if the output

+                    underflows. do we requeue all the existing buffers with

+                    zeros? should we run a separate thread to keep the buffers

+                    enqueued at all times? */

+

+                    result = paOutputUnderflowed;

+                }

+

+                hostOutputBufferIndex = stream->output.currentBufferIndex;

+

+                PaUtil_SetOutputFrameCount( &stream->bufferProcessor,

+                        stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );

+                

+                channel = 0;

+                for( i=0; i<stream->output.deviceCount; ++i )

+                {

+                    /* we have stored the number of channels in the buffer in dwUser */

+                    int channelCount = stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;

+

+                    PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,

+                            stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +

+                                stream->output.framesUsedInCurrentBuffer * channelCount *

+                                stream->bufferProcessor.bytesPerHostOutputSample,

+                            channelCount );

+

+                    channel += channelCount;

+                }

+                

+                framesProcessed = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames - framesWritten );

+

+                stream->output.framesUsedInCurrentBuffer += framesProcessed;

+                if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer )

+                {

+                    result = AdvanceToNextOutputBuffer( stream );

+                    if( result != paNoError )

+                        break;

+                }

+

+                framesWritten += framesProcessed;

+            }

+            else

+            {

+                /* wait for MME to signal that a buffer is available */

+                waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout );

+                if( waitResult == WAIT_FAILED )

+                {

+                    result = paUnanticipatedHostError;

+                    break;

+                }

+                else if( waitResult == WAIT_TIMEOUT )

+                {

+                    /* if a timeout is encountered, continue,

+                        perhaps we should give up eventually

+                    */

+                }             

+            }        

+        }while( framesWritten < frames );

+    }

+    else

+    {

+        result = paCanNotWriteToAnInputOnlyStream;

+    }

+    

+    return result;

+}

+

+

+static signed long GetStreamReadAvailable( PaStream* s )

+{

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+    

+    if( PA_IS_INPUT_STREAM_(stream) )

+        return GetAvailableFrames( &stream->input );

+    else

+        return paCanNotReadFromAnOutputOnlyStream;

+}

+

+

+static signed long GetStreamWriteAvailable( PaStream* s )

+{

+    PaWinMmeStream *stream = (PaWinMmeStream*)s;

+    

+    if( PA_IS_OUTPUT_STREAM_(stream) )

+        return GetAvailableFrames( &stream->output );

+    else

+        return paCanNotWriteToAnInputOnlyStream;

+}

+

+

+/* NOTE: the following functions are MME-stream specific, and are called directly

+    by client code. We need to check for many more error conditions here because

+    we don't have the benefit of pa_front.c's parameter checking.

+*/

+

+static PaError GetWinMMEStreamPointer( PaWinMmeStream **stream, PaStream *s )

+{

+    PaError result;

+    PaUtilHostApiRepresentation *hostApi;

+    PaWinMmeHostApiRepresentation *winMmeHostApi;

+    

+    result = PaUtil_ValidateStreamPointer( s );

+    if( result != paNoError )

+        return result;

+

+    result = PaUtil_GetHostApiRepresentation( &hostApi, paMME );

+    if( result != paNoError )

+        return result;

+

+    winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;

+    

+    /* note, the following would be easier if there was a generic way of testing

+        that a stream belongs to a specific host API */

+    

+    if( PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->callbackStreamInterface

+            || PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->blockingStreamInterface )

+    {

+        /* s is a WinMME stream */

+        *stream = (PaWinMmeStream *)s;

+        return paNoError;

+    }

+    else

+    {

+        return paIncompatibleStreamHostApi;

+    }

+}

+

+

+int PaWinMME_GetStreamInputHandleCount( PaStream* s )

+{

+    PaWinMmeStream *stream;

+    PaError result = GetWinMMEStreamPointer( &stream, s );

+

+    if( result == paNoError )

+        return (PA_IS_INPUT_STREAM_(stream)) ? stream->input.deviceCount : 0;

+    else

+        return result;

+}

+

+

+HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* s, int handleIndex )

+{

+    PaWinMmeStream *stream;

+    PaError result = GetWinMMEStreamPointer( &stream, s );

+

+    if( result == paNoError

+            && PA_IS_INPUT_STREAM_(stream)

+            && handleIndex >= 0

+            && (unsigned int)handleIndex < stream->input.deviceCount )

+        return ((HWAVEIN*)stream->input.waveHandles)[handleIndex];

+    else

+        return 0;

+}

+

+

+int PaWinMME_GetStreamOutputHandleCount( PaStream* s)

+{

+    PaWinMmeStream *stream;

+    PaError result = GetWinMMEStreamPointer( &stream, s );

+

+    if( result == paNoError )

+        return (PA_IS_OUTPUT_STREAM_(stream)) ? stream->output.deviceCount : 0;

+    else

+        return result;

+}

+

+

+HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* s, int handleIndex )

+{

+    PaWinMmeStream *stream;

+    PaError result = GetWinMMEStreamPointer( &stream, s );

+

+    if( result == paNoError

+            && PA_IS_OUTPUT_STREAM_(stream)

+            && handleIndex >= 0

+            && (unsigned int)handleIndex < stream->output.deviceCount )

+        return ((HWAVEOUT*)stream->output.waveHandles)[handleIndex];

+    else

+        return 0;

+}

+

+

+

+

+

diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_wmme.h b/pjmedia/src/pjmedia/portaudio/pa_win_wmme.h
index 1a71633..ae807e6 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_win_wmme.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_win_wmme.h
@@ -1,160 +1,181 @@
-#ifndef PA_WIN_WMME_H
-#define PA_WIN_WMME_H
-/*
- * $Id: pa_win_wmme.h,v 1.1.2.14 2004/02/20 14:16:53 rossbencina Exp $
- * PortAudio Portable Real-Time Audio Library
- * MME specific extensions
- *
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-/** @file
- @brief WMME-specific PortAudio API extension header file.
-*/
-
-
-#include "portaudio.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-#define paWinMmeUseLowLevelLatencyParameters            (0x01)
-#define paWinMmeUseMultipleDevices                      (0x02)  /* use mme specific multiple device feature */
-
-
-/* By default, the mme implementation drops the processing thread's priority
-    to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100%
-    This flag disables any priority throttling. The processing thread will always
-    run at THREAD_PRIORITY_TIME_CRITICAL.
-*/
-#define paWinMmeDontThrottleOverloadedProcessingThread  (0x08)
-
-
-typedef struct PaWinMmeDeviceAndChannelCount{
-    PaDeviceIndex device;
-    int channelCount;
-}PaWinMmeDeviceAndChannelCount;
-
-
-typedef struct PaWinMmeStreamInfo{
-    unsigned long size;             /**< sizeof(PaWinMmeStreamInfo) */
-    PaHostApiTypeId hostApiType;    /**< paMME */
-    unsigned long version;          /**< 1 */
-
-    unsigned long flags;
-
-    /* low-level latency setting support
-        These settings control the number and size of host buffers in order
-        to set latency. They will be used instead of the generic parameters
-        to Pa_OpenStream() if flags contains the PaWinMmeUseLowLevelLatencyParameters
-        flag.
-
-        If PaWinMmeStreamInfo structures with PaWinMmeUseLowLevelLatencyParameters
-        are supplied for both input and output in a full duplex stream, then the
-        input and output framesPerBuffer must be the same, or the larger of the
-        two must be a multiple of the smaller, otherwise a
-        paIncompatibleHostApiSpecificStreamInfo error will be returned from
-        Pa_OpenStream().
-    */
-    unsigned long framesPerBuffer;
-    unsigned long bufferCount;  /* formerly numBuffers */ 
-
-    /* multiple devices per direction support
-        If flags contains the PaWinMmeUseMultipleDevices flag,
-        this functionality will be used, otherwise the device parameter to
-        Pa_OpenStream() will be used instead.
-        If devices are specified here, the corresponding device parameter
-        to Pa_OpenStream() should be set to paUseHostApiSpecificDeviceSpecification,
-        otherwise an paInvalidDevice error will result.
-        The total number of channels accross all specified devices
-        must agree with the corresponding channelCount parameter to
-        Pa_OpenStream() otherwise a paInvalidChannelCount error will result.
-    */
-    PaWinMmeDeviceAndChannelCount *devices;
-    unsigned long deviceCount;
-
-}PaWinMmeStreamInfo;
-
-
-/** Retrieve the number of wave in handles used by a PortAudio WinMME stream.
- Returns zero if the stream is output only.
-
- @return A non-negative value indicating the number of wave in handles
- or, a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-
- @see PaWinMME_GetStreamInputHandle
-*/
-int PaWinMME_GetStreamInputHandleCount( PaStream* stream );
-
-
-/** Retrieve a wave in handle used by a PortAudio WinMME stream.
-
- @param stream The stream to query.
- @param handleIndex The zero based index of the wave in handle to retrieve. This
-    should be in the range [0, PaWinMME_GetStreamInputHandle(stream)-1].
-
- @return A valid wave in handle, or NULL if an error occurred.
-
- @see PaWinMME_GetStreamInputHandle
-*/
-HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* stream, int handleIndex );
-
-
-/** Retrieve the number of wave out handles used by a PortAudio WinMME stream.
- Returns zero if the stream is input only.
- 
- @return A non-negative value indicating the number of wave out handles
- or, a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-
- @see PaWinMME_GetStreamOutputHandle
-*/
-int PaWinMME_GetStreamOutputHandleCount( PaStream* stream );
-
-
-/** Retrieve a wave out handle used by a PortAudio WinMME stream.
-
- @param stream The stream to query.
- @param handleIndex The zero based index of the wave out handle to retrieve.
-    This should be in the range [0, PaWinMME_GetStreamOutputHandleCount(stream)-1].
-
- @return A valid wave out handle, or NULL if an error occurred.
-
- @see PaWinMME_GetStreamOutputHandleCount
-*/
-HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* stream, int handleIndex );
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* PA_WIN_WMME_H */                                  
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_WIN_WMME_H

+#define PA_WIN_WMME_H

+/*

+ * $Id: pa_win_wmme.h,v 1.1.2.14 2004/02/20 14:16:53 rossbencina Exp $

+ * PortAudio Portable Real-Time Audio Library

+ * MME specific extensions

+ *

+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ *

+ */

+

+/** @file

+ @brief WMME-specific PortAudio API extension header file.

+*/

+

+

+#include "portaudio.h"

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+#define paWinMmeUseLowLevelLatencyParameters            (0x01)

+#define paWinMmeUseMultipleDevices                      (0x02)  /* use mme specific multiple device feature */

+

+

+/* By default, the mme implementation drops the processing thread's priority

+    to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100%

+    This flag disables any priority throttling. The processing thread will always

+    run at THREAD_PRIORITY_TIME_CRITICAL.

+*/

+#define paWinMmeDontThrottleOverloadedProcessingThread  (0x08)

+

+

+typedef struct PaWinMmeDeviceAndChannelCount{

+    PaDeviceIndex device;

+    int channelCount;

+}PaWinMmeDeviceAndChannelCount;

+

+

+typedef struct PaWinMmeStreamInfo{

+    unsigned long size;             /**< sizeof(PaWinMmeStreamInfo) */

+    PaHostApiTypeId hostApiType;    /**< paMME */

+    unsigned long version;          /**< 1 */

+

+    unsigned long flags;

+

+    /* low-level latency setting support

+        These settings control the number and size of host buffers in order

+        to set latency. They will be used instead of the generic parameters

+        to Pa_OpenStream() if flags contains the PaWinMmeUseLowLevelLatencyParameters

+        flag.

+

+        If PaWinMmeStreamInfo structures with PaWinMmeUseLowLevelLatencyParameters

+        are supplied for both input and output in a full duplex stream, then the

+        input and output framesPerBuffer must be the same, or the larger of the

+        two must be a multiple of the smaller, otherwise a

+        paIncompatibleHostApiSpecificStreamInfo error will be returned from

+        Pa_OpenStream().

+    */

+    unsigned long framesPerBuffer;

+    unsigned long bufferCount;  /* formerly numBuffers */ 

+

+    /* multiple devices per direction support

+        If flags contains the PaWinMmeUseMultipleDevices flag,

+        this functionality will be used, otherwise the device parameter to

+        Pa_OpenStream() will be used instead.

+        If devices are specified here, the corresponding device parameter

+        to Pa_OpenStream() should be set to paUseHostApiSpecificDeviceSpecification,

+        otherwise an paInvalidDevice error will result.

+        The total number of channels accross all specified devices

+        must agree with the corresponding channelCount parameter to

+        Pa_OpenStream() otherwise a paInvalidChannelCount error will result.

+    */

+    PaWinMmeDeviceAndChannelCount *devices;

+    unsigned long deviceCount;

+

+}PaWinMmeStreamInfo;

+

+

+/** Retrieve the number of wave in handles used by a PortAudio WinMME stream.

+ Returns zero if the stream is output only.

+

+ @return A non-negative value indicating the number of wave in handles

+ or, a PaErrorCode (which are always negative) if PortAudio is not initialized

+ or an error is encountered.

+

+ @see PaWinMME_GetStreamInputHandle

+*/

+int PaWinMME_GetStreamInputHandleCount( PaStream* stream );

+

+

+/** Retrieve a wave in handle used by a PortAudio WinMME stream.

+

+ @param stream The stream to query.

+ @param handleIndex The zero based index of the wave in handle to retrieve. This

+    should be in the range [0, PaWinMME_GetStreamInputHandle(stream)-1].

+

+ @return A valid wave in handle, or NULL if an error occurred.

+

+ @see PaWinMME_GetStreamInputHandle

+*/

+HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* stream, int handleIndex );

+

+

+/** Retrieve the number of wave out handles used by a PortAudio WinMME stream.

+ Returns zero if the stream is input only.

+ 

+ @return A non-negative value indicating the number of wave out handles

+ or, a PaErrorCode (which are always negative) if PortAudio is not initialized

+ or an error is encountered.

+

+ @see PaWinMME_GetStreamOutputHandle

+*/

+int PaWinMME_GetStreamOutputHandleCount( PaStream* stream );

+

+

+/** Retrieve a wave out handle used by a PortAudio WinMME stream.

+

+ @param stream The stream to query.

+ @param handleIndex The zero based index of the wave out handle to retrieve.

+    This should be in the range [0, PaWinMME_GetStreamOutputHandleCount(stream)-1].

+

+ @return A valid wave out handle, or NULL if an error occurred.

+

+ @see PaWinMME_GetStreamOutputHandleCount

+*/

+HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* stream, int handleIndex );

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+

+#endif /* PA_WIN_WMME_H */                                  

diff --git a/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.c b/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.c
index 3a33540..cbd441f 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.c
+++ b/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.c
@@ -1,1167 +1,1188 @@
-#include "pa_x86_plain_converters.h"
-
-#include "pa_converters.h"
-#include "pa_dither.h"
-
-/*
-    plain intel assemby versions of standard pa converter functions.
-
-    the main reason these versions are faster than the equivalent C versions
-    is that float -> int casting is expensive in C on x86 because the rounding
-    mode needs to be changed for every cast. these versions only set
-    the rounding mode once outside the loop.
-
-    small additional speed gains are made by the way that clamping is
-    implemented.
-
-TODO:
-    o- inline dither code
-    o- implement Dither only (no-clip) versions
-    o- implement int8 and uint8 versions
-    o- test thouroughly
-
-    o- the packed 24 bit functions could benefit from unrolling and avoiding
-        byte and word sized register access.
-*/
-
-/* -------------------------------------------------------------------------- */
-
-/*
-#define PA_CLIP_( val, min, max )\
-    { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
-*/
-
-/*
-    the following notes were used to determine whether a floating point
-    value should be saturated (ie >1 or <-1) by loading it into an integer
-    register. these should be rewritten so that they make sense.
-
-    an ieee floating point value
-
-    1.xxxxxxxxxxxxxxxxxxxx?
-
-
-    is less than  or equal to 1 and greater than or equal to -1 either:
-
-        if the mantissa is 0 and the unbiased exponent is 0
-
-        OR
-
-        if the unbiased exponent < 0
-
-    this translates to:
-
-        if the mantissa is 0 and the biased exponent is 7F
-
-        or
-
-        if the biased exponent is less than 7F
-
-
-    therefore the value is greater than 1 or less than -1 if
-
-        the mantissa is not 0 and the biased exponent is 7F
-
-        or
-
-        if the biased exponent is greater than 7F
-
-
-    in other words, if we mask out the sign bit, the value is
-    greater than 1 or less than -1 if its integer representation is greater than:
-
-    0 01111111 0000 0000 0000 0000 0000 000
-
-    0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000
-*/
-
-/* -------------------------------------------------------------------------- */
-
-static const short fpuControlWord_ = 0x033F; /*round to nearest, 64 bit precision, all exceptions masked*/
-static const double int32Scaler_ = 0x7FFFFFFF;
-static const double ditheredInt32Scaler_ = 0x7FFFFFFE;
-static const double int24Scaler_ = 0x7FFFFF;
-static const double ditheredInt24Scaler_ = 0x7FFFFE;
-static const double int16Scaler_ = 0x7FFF;
-static const double ditheredInt16Scaler_ = 0x7FFE;
-
-#define PA_DITHER_BITS_   (15)
-/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */
-#define PA_FLOAT_DITHER_SCALE_  (1.0 / ((1<<PA_DITHER_BITS_)-1))
-static const float const_float_dither_scale_ = (float) PA_FLOAT_DITHER_SCALE_;
-#define PA_DITHER_SHIFT_  ((32 - PA_DITHER_BITS_) + 1)
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
-    float *src = (float*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-    (void)ditherGenerator; // unused parameter
-
-    while( count-- )
-    {
-        // REVIEW
-        double scaled = *src * 0x7FFFFFFF;
-        *dest = (signed long) scaled;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-*/
-
-    short savedFpuControlWord;
-
-    (void) ditherGenerator; /* unused parameter */
-
-
-    __asm{
-        // esi -> source ptr
-        // eax -> source byte stride
-        // edi -> destination ptr
-        // ebx -> destination byte stride
-        // ecx -> source end ptr
-        // edx -> temp
-
-        mov     esi, sourceBuffer
-
-        mov     edx, 4                  // sizeof float32 and int32
-        mov     eax, sourceStride
-        imul    eax, edx
-
-        mov     ecx, count
-        imul    ecx, eax
-        add     ecx, esi
-    
-        mov     edi, destinationBuffer
-        
-        mov     ebx, destinationStride
-        imul    ebx, edx
-
-        fwait
-        fstcw   savedFpuControlWord
-        fldcw   fpuControlWord_
-
-        fld     int32Scaler_             // stack:  (int)0x7FFFFFFF
-
-    Float32_To_Int32_loop:
-
-        // load unscaled value into st(0)
-        fld     dword ptr [esi]         // stack:  value, (int)0x7FFFFFFF
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFFFFFF, (int)0x7FFFFFFF
-        /*
-            note: we could store to a temporary qword here which would cause
-            wraparound distortion instead of int indefinite 0x10. that would
-            be more work, and given that not enabling clipping is only advisable
-            when you know that your signal isn't going to clip it isn't worth it.
-        */
-        fistp   dword ptr [edi]         // pop st(0) into dest, stack:  (int)0x7FFFFFFF
-
-        add     edi, ebx                // increment destination ptr
-        //lea     edi, [edi+ebx]
-
-        cmp     esi, ecx                // has src ptr reached end?
-        jne     Float32_To_Int32_loop
-
-        ffree   st(0)
-        fincstp
-
-        fwait
-        fnclex
-        fldcw   savedFpuControlWord
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_Clip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
-    float *src = (float*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-    (void) ditherGenerator; // unused parameter
-
-    while( count-- )
-    {
-        // REVIEW
-        double scaled = *src * 0x7FFFFFFF;
-        PA_CLIP_( scaled, -2147483648., 2147483647.  );
-        *dest = (signed long) scaled;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-*/
-
-    short savedFpuControlWord;
-
-    (void) ditherGenerator; /* unused parameter */
-
-    __asm{
-        // esi -> source ptr
-        // eax -> source byte stride
-        // edi -> destination ptr
-        // ebx -> destination byte stride
-        // ecx -> source end ptr
-        // edx -> temp
-
-        mov     esi, sourceBuffer
-
-        mov     edx, 4                  // sizeof float32 and int32
-        mov     eax, sourceStride
-        imul    eax, edx
-
-        mov     ecx, count
-        imul    ecx, eax
-        add     ecx, esi
-    
-        mov     edi, destinationBuffer
-        
-        mov     ebx, destinationStride
-        imul    ebx, edx
-
-        fwait
-        fstcw   savedFpuControlWord
-        fldcw   fpuControlWord_
-
-        fld     int32Scaler_             // stack:  (int)0x7FFFFFFF
-
-    Float32_To_Int32_Clip_loop:
-
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-
-        and     edx, 0x7FFFFFFF         // mask off sign
-        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0
-
-        jg      Float32_To_Int32_Clip_clamp
-
-        // load unscaled value into st(0)
-        fld     dword ptr [esi]         // stack:  value, (int)0x7FFFFFFF
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFFFFFF, (int)0x7FFFFFFF
-        fistp   dword ptr [edi]         // pop st(0) into dest, stack:  (int)0x7FFFFFFF
-        jmp     Float32_To_Int32_Clip_stored
-    
-    Float32_To_Int32_Clip_clamp:
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-        shr     edx, 31                 // move sign bit into bit 0
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        add     edx, 0x7FFFFFFF         // convert to maximum range integers
-        mov     dword ptr [edi], edx
-
-    Float32_To_Int32_Clip_stored:
-
-        //add     edi, ebx                // increment destination ptr
-        lea     edi, [edi+ebx]
-
-        cmp     esi, ecx                // has src ptr reached end?
-        jne     Float32_To_Int32_Clip_loop
-
-        ffree   st(0)
-        fincstp
-
-        fwait
-        fnclex
-        fldcw   savedFpuControlWord
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_DitherClip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-    /*
-    float *src = (float*)sourceBuffer;
-    signed long *dest =  (signed long*)destinationBuffer;
-
-    while( count-- )
-    {
-        // REVIEW
-        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        // use smaller scaler to prevent overflow when we add the dither
-        double dithered = ((double)*src * (2147483646.0)) + dither;
-        PA_CLIP_( dithered, -2147483648., 2147483647.  );
-        *dest = (signed long) dithered;
-
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-    */
-
-    short savedFpuControlWord;
-
-    // spill storage:
-    signed long sourceByteStride;
-    signed long highpassedDither;
-
-    // dither state:
-    unsigned long ditherPrevious = ditherGenerator->previous;
-    unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
-    unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
-                    
-    __asm{
-        // esi -> source ptr
-        // eax -> source byte stride
-        // edi -> destination ptr
-        // ebx -> destination byte stride
-        // ecx -> source end ptr
-        // edx -> temp
-
-        mov     esi, sourceBuffer
-
-        mov     edx, 4                  // sizeof float32 and int32
-        mov     eax, sourceStride
-        imul    eax, edx
-
-        mov     ecx, count
-        imul    ecx, eax
-        add     ecx, esi
-    
-        mov     edi, destinationBuffer
-        
-        mov     ebx, destinationStride
-        imul    ebx, edx
-
-        fwait
-        fstcw   savedFpuControlWord
-        fldcw   fpuControlWord_
-
-        fld     ditheredInt32Scaler_    // stack:  int scaler
-
-    Float32_To_Int32_DitherClip_loop:
-
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-
-        and     edx, 0x7FFFFFFF         // mask off sign
-        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0
-
-        jg      Float32_To_Int32_DitherClip_clamp
-
-        // load unscaled value into st(0)
-        fld     dword ptr [esi]         // stack:  value, int scaler
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*(int scaler), int scaler
-
-        /*
-        // call PaUtil_GenerateFloatTriangularDither with C calling convention
-        mov     sourceByteStride, eax   // save eax
-        mov     sourceEnd, ecx          // save ecx
-        push    ditherGenerator         // pass ditherGenerator parameter on stack
-	    call    PaUtil_GenerateFloatTriangularDither  // stack:  dither, value*(int scaler), int scaler
-	    pop     edx                     // clear parameter off stack
-        mov     ecx, sourceEnd          // restore ecx
-        mov     eax, sourceByteStride   // restore eax
-        */
-
-    // generate dither
-        mov     sourceByteStride, eax   // save eax
-        mov     edx, 196314165
-        mov     eax, ditherRandSeed1
-        mul     edx                     // eax:edx = eax * 196314165
-        //add     eax, 907633515
-        lea     eax, [eax+907633515]
-        mov     ditherRandSeed1, eax
-        mov     edx, 196314165
-        mov     eax, ditherRandSeed2
-        mul     edx                     // eax:edx = eax * 196314165
-        //add     eax, 907633515
-        lea     eax, [eax+907633515]
-        mov     edx, ditherRandSeed1
-        shr     edx, PA_DITHER_SHIFT_
-        mov     ditherRandSeed2, eax
-        shr     eax, PA_DITHER_SHIFT_
-        //add     eax, edx                // eax -> current
-        lea     eax, [eax+edx]
-        mov     edx, ditherPrevious
-        neg     edx
-        lea     edx, [eax+edx]          // highpass = current - previous
-        mov     highpassedDither, edx
-        mov     ditherPrevious, eax     // previous = current
-        mov     eax, sourceByteStride   // restore eax
-        fild    highpassedDither
-        fmul    const_float_dither_scale_
-    // end generate dither, dither signal in st(0)
-    
-        faddp   st(1), st(0)            // stack: dither + value*(int scaler), int scaler
-        fistp   dword ptr [edi]         // pop st(0) into dest, stack:  int scaler
-        jmp     Float32_To_Int32_DitherClip_stored
-    
-    Float32_To_Int32_DitherClip_clamp:
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-        shr     edx, 31                 // move sign bit into bit 0
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        add     edx, 0x7FFFFFFF         // convert to maximum range integers
-        mov     dword ptr [edi], edx
-
-    Float32_To_Int32_DitherClip_stored:
-
-        //add     edi, ebx              // increment destination ptr
-        lea     edi, [edi+ebx]
-
-        cmp     esi, ecx                // has src ptr reached end?
-        jne     Float32_To_Int32_DitherClip_loop
-
-        ffree   st(0)
-        fincstp
-
-        fwait
-        fnclex
-        fldcw   savedFpuControlWord
-    }
-
-    ditherGenerator->previous = ditherPrevious;
-    ditherGenerator->randSeed1 = ditherRandSeed1;
-    ditherGenerator->randSeed2 = ditherRandSeed2;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    signed long temp;
-
-    (void) ditherGenerator; // unused parameter
-    
-    while( count-- )
-    {
-        // convert to 32 bit and drop the low 8 bits
-        double scaled = *src * 0x7FFFFFFF;
-        temp = (signed long) scaled;
-
-        dest[0] = (unsigned char)(temp >> 8);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 24);
-
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-*/
-
-    short savedFpuControlWord;
-    
-    signed long tempInt32;
-
-    (void) ditherGenerator; /* unused parameter */
-                 
-    __asm{
-        // esi -> source ptr
-        // eax -> source byte stride
-        // edi -> destination ptr
-        // ebx -> destination byte stride
-        // ecx -> source end ptr
-        // edx -> temp
-
-        mov     esi, sourceBuffer
-
-        mov     edx, 4                  // sizeof float32
-        mov     eax, sourceStride
-        imul    eax, edx
-
-        mov     ecx, count
-        imul    ecx, eax
-        add     ecx, esi
-
-        mov     edi, destinationBuffer
-
-        mov     edx, 3                  // sizeof int24
-        mov     ebx, destinationStride
-        imul    ebx, edx
-
-        fwait
-        fstcw   savedFpuControlWord
-        fldcw   fpuControlWord_
-
-        fld     int24Scaler_             // stack:  (int)0x7FFFFF
-
-    Float32_To_Int24_loop:
-
-        // load unscaled value into st(0)
-        fld     dword ptr [esi]         // stack:  value, (int)0x7FFFFF
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFFFF, (int)0x7FFFFF
-        fistp   tempInt32               // pop st(0) into tempInt32, stack:  (int)0x7FFFFF
-        mov     edx, tempInt32
-
-        mov     byte ptr [edi], DL
-        shr     edx, 8
-        //mov     byte ptr [edi+1], DL
-        //mov     byte ptr [edi+2], DH
-        mov     word ptr [edi+1], DX
-
-        //add     edi, ebx                // increment destination ptr
-        lea     edi, [edi+ebx]
-
-        cmp     esi, ecx                // has src ptr reached end?
-        jne     Float32_To_Int24_loop
-
-        ffree   st(0)
-        fincstp
-
-        fwait
-        fnclex
-        fldcw   savedFpuControlWord
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_Clip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    signed long temp;
-
-    (void) ditherGenerator; // unused parameter
-    
-    while( count-- )
-    {
-        // convert to 32 bit and drop the low 8 bits
-        double scaled = *src * 0x7FFFFFFF;
-        PA_CLIP_( scaled, -2147483648., 2147483647.  );
-        temp = (signed long) scaled;
-
-        dest[0] = (unsigned char)(temp >> 8);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 24);
-
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-*/
-
-    short savedFpuControlWord;
-    
-    signed long tempInt32;
-
-    (void) ditherGenerator; /* unused parameter */
-                 
-    __asm{
-        // esi -> source ptr
-        // eax -> source byte stride
-        // edi -> destination ptr
-        // ebx -> destination byte stride
-        // ecx -> source end ptr
-        // edx -> temp
-
-        mov     esi, sourceBuffer
-
-        mov     edx, 4                  // sizeof float32
-        mov     eax, sourceStride
-        imul    eax, edx
-
-        mov     ecx, count
-        imul    ecx, eax
-        add     ecx, esi
-
-        mov     edi, destinationBuffer
-
-        mov     edx, 3                  // sizeof int24
-        mov     ebx, destinationStride
-        imul    ebx, edx
-
-        fwait
-        fstcw   savedFpuControlWord
-        fldcw   fpuControlWord_
-
-        fld     int24Scaler_             // stack:  (int)0x7FFFFF
-
-    Float32_To_Int24_Clip_loop:
-
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-
-        and     edx, 0x7FFFFFFF         // mask off sign
-        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0
-
-        jg      Float32_To_Int24_Clip_clamp
-
-        // load unscaled value into st(0)
-        fld     dword ptr [esi]         // stack:  value, (int)0x7FFFFF
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFFFF, (int)0x7FFFFF
-        fistp   tempInt32               // pop st(0) into tempInt32, stack:  (int)0x7FFFFF
-        mov     edx, tempInt32
-        jmp     Float32_To_Int24_Clip_store
-    
-    Float32_To_Int24_Clip_clamp:
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-        shr     edx, 31                 // move sign bit into bit 0
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        add     edx, 0x7FFFFF           // convert to maximum range integers
-
-    Float32_To_Int24_Clip_store:
-
-        mov     byte ptr [edi], DL
-        shr     edx, 8
-        //mov     byte ptr [edi+1], DL
-        //mov     byte ptr [edi+2], DH
-        mov     word ptr [edi+1], DX
-
-        //add     edi, ebx                // increment destination ptr
-        lea     edi, [edi+ebx]
-
-        cmp     esi, ecx                // has src ptr reached end?
-        jne     Float32_To_Int24_Clip_loop
-
-        ffree   st(0)
-        fincstp
-
-        fwait
-        fnclex
-        fldcw   savedFpuControlWord
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_DitherClip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
-    float *src = (float*)sourceBuffer;
-    unsigned char *dest = (unsigned char*)destinationBuffer;
-    signed long temp;
-    
-    while( count-- )
-    {
-        // convert to 32 bit and drop the low 8 bits
-
-        // FIXME: the dither amplitude here appears to be too small by 8 bits
-        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        // use smaller scaler to prevent overflow when we add the dither
-        double dithered = ((double)*src * (2147483646.0)) + dither;
-        PA_CLIP_( dithered, -2147483648., 2147483647.  );
-        
-        temp = (signed long) dithered;
-
-        dest[0] = (unsigned char)(temp >> 8);
-        dest[1] = (unsigned char)(temp >> 16);
-        dest[2] = (unsigned char)(temp >> 24);
-
-        src += sourceStride;
-        dest += destinationStride * 3;
-    }
-*/
-
-    short savedFpuControlWord;
-
-    // spill storage:
-    signed long sourceByteStride;
-    signed long highpassedDither;
-
-    // dither state:
-    unsigned long ditherPrevious = ditherGenerator->previous;
-    unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
-    unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
-    
-    signed long tempInt32;
-                 
-    __asm{
-        // esi -> source ptr
-        // eax -> source byte stride
-        // edi -> destination ptr
-        // ebx -> destination byte stride
-        // ecx -> source end ptr
-        // edx -> temp
-
-        mov     esi, sourceBuffer
-
-        mov     edx, 4                  // sizeof float32
-        mov     eax, sourceStride
-        imul    eax, edx
-
-        mov     ecx, count
-        imul    ecx, eax
-        add     ecx, esi
-
-        mov     edi, destinationBuffer
-
-        mov     edx, 3                  // sizeof int24
-        mov     ebx, destinationStride
-        imul    ebx, edx
-
-        fwait
-        fstcw   savedFpuControlWord
-        fldcw   fpuControlWord_
-
-        fld     ditheredInt24Scaler_    // stack:  int scaler
-
-    Float32_To_Int24_DitherClip_loop:
-
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-
-        and     edx, 0x7FFFFFFF         // mask off sign
-        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0
-
-        jg      Float32_To_Int24_DitherClip_clamp
-
-        // load unscaled value into st(0)
-        fld     dword ptr [esi]         // stack:  value, int scaler
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*(int scaler), int scaler
-
-    /*
-        // call PaUtil_GenerateFloatTriangularDither with C calling convention
-        mov     sourceByteStride, eax   // save eax
-        mov     sourceEnd, ecx          // save ecx
-        push    ditherGenerator         // pass ditherGenerator parameter on stack
-	    call    PaUtil_GenerateFloatTriangularDither  // stack:  dither, value*(int scaler), int scaler
-	    pop     edx                     // clear parameter off stack
-        mov     ecx, sourceEnd          // restore ecx
-        mov     eax, sourceByteStride   // restore eax
-    */
-    
-    // generate dither
-        mov     sourceByteStride, eax   // save eax
-        mov     edx, 196314165
-        mov     eax, ditherRandSeed1
-        mul     edx                     // eax:edx = eax * 196314165
-        //add     eax, 907633515
-        lea     eax, [eax+907633515]
-        mov     ditherRandSeed1, eax
-        mov     edx, 196314165
-        mov     eax, ditherRandSeed2
-        mul     edx                     // eax:edx = eax * 196314165
-        //add     eax, 907633515
-        lea     eax, [eax+907633515]
-        mov     edx, ditherRandSeed1
-        shr     edx, PA_DITHER_SHIFT_
-        mov     ditherRandSeed2, eax
-        shr     eax, PA_DITHER_SHIFT_
-        //add     eax, edx                // eax -> current
-        lea     eax, [eax+edx]
-        mov     edx, ditherPrevious
-        neg     edx
-        lea     edx, [eax+edx]          // highpass = current - previous
-        mov     highpassedDither, edx
-        mov     ditherPrevious, eax     // previous = current
-        mov     eax, sourceByteStride   // restore eax
-        fild    highpassedDither
-        fmul    const_float_dither_scale_
-    // end generate dither, dither signal in st(0)
-
-        faddp   st(1), st(0)            // stack: dither * value*(int scaler), int scaler
-        fistp   tempInt32               // pop st(0) into tempInt32, stack:  int scaler
-        mov     edx, tempInt32
-        jmp     Float32_To_Int24_DitherClip_store
-    
-    Float32_To_Int24_DitherClip_clamp:
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-        shr     edx, 31                 // move sign bit into bit 0
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        add     edx, 0x7FFFFF           // convert to maximum range integers
-
-    Float32_To_Int24_DitherClip_store:
-
-        mov     byte ptr [edi], DL
-        shr     edx, 8
-        //mov     byte ptr [edi+1], DL
-        //mov     byte ptr [edi+2], DH
-        mov     word ptr [edi+1], DX
-
-        //add     edi, ebx                // increment destination ptr
-        lea     edi, [edi+ebx]
-
-        cmp     esi, ecx                // has src ptr reached end?
-        jne     Float32_To_Int24_DitherClip_loop
-
-        ffree   st(0)
-        fincstp
-
-        fwait
-        fnclex
-        fldcw   savedFpuControlWord
-    }
-
-    ditherGenerator->previous = ditherPrevious;
-    ditherGenerator->randSeed1 = ditherRandSeed1;
-    ditherGenerator->randSeed2 = ditherRandSeed2;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
-    float *src = (float*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    (void)ditherGenerator; // unused parameter
-
-    while( count-- )
-    {
-
-        short samp = (short) (*src * (32767.0f));
-        *dest = samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-*/
-
-    short savedFpuControlWord;
-   
-    (void) ditherGenerator; /* unused parameter */
-
-    __asm{
-        // esi -> source ptr
-        // eax -> source byte stride
-        // edi -> destination ptr
-        // ebx -> destination byte stride
-        // ecx -> source end ptr
-        // edx -> temp
-
-        mov     esi, sourceBuffer
-
-        mov     edx, 4                  // sizeof float32
-        mov     eax, sourceStride
-        imul    eax, edx                // source byte stride
-
-        mov     ecx, count
-        imul    ecx, eax
-        add     ecx, esi                // source end ptr = count * source byte stride + source ptr
-
-        mov     edi, destinationBuffer
-
-        mov     edx, 2                  // sizeof int16
-        mov     ebx, destinationStride
-        imul    ebx, edx                // destination byte stride
-
-        fwait
-        fstcw   savedFpuControlWord
-        fldcw   fpuControlWord_
-
-        fld     int16Scaler_            // stack:  (int)0x7FFF
-
-    Float32_To_Int16_loop:
-
-        // load unscaled value into st(0)
-        fld     dword ptr [esi]         // stack:  value, (int)0x7FFF
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFF, (int)0x7FFF
-        fistp   word ptr [edi]          // store scaled int into dest, stack:  (int)0x7FFF
-
-        add     edi, ebx                // increment destination ptr
-        //lea     edi, [edi+ebx]
-        
-        cmp     esi, ecx                // has src ptr reached end?
-        jne     Float32_To_Int16_loop
-
-        ffree   st(0)
-        fincstp
-
-        fwait
-        fnclex
-        fldcw   savedFpuControlWord
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_Clip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
-    float *src = (float*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    (void)ditherGenerator; // unused parameter
-
-    while( count-- )
-    {
-        long samp = (signed long) (*src * (32767.0f));
-        PA_CLIP_( samp, -0x8000, 0x7FFF );
-        *dest = (signed short) samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-*/
-
-    short savedFpuControlWord;
-   
-    (void) ditherGenerator; /* unused parameter */
-
-    __asm{
-        // esi -> source ptr
-        // eax -> source byte stride
-        // edi -> destination ptr
-        // ebx -> destination byte stride
-        // ecx -> source end ptr
-        // edx -> temp
-
-        mov     esi, sourceBuffer
-
-        mov     edx, 4                  // sizeof float32
-        mov     eax, sourceStride
-        imul    eax, edx                // source byte stride
-
-        mov     ecx, count
-        imul    ecx, eax
-        add     ecx, esi                // source end ptr = count * source byte stride + source ptr
-
-        mov     edi, destinationBuffer
-
-        mov     edx, 2                  // sizeof int16
-        mov     ebx, destinationStride
-        imul    ebx, edx                // destination byte stride
-
-        fwait
-        fstcw   savedFpuControlWord
-        fldcw   fpuControlWord_
-
-        fld     int16Scaler_            // stack:  (int)0x7FFF
-
-    Float32_To_Int16_Clip_loop:
-
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-
-        and     edx, 0x7FFFFFFF         // mask off sign
-        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0
-
-        jg      Float32_To_Int16_Clip_clamp
-
-        // load unscaled value into st(0)
-        fld     dword ptr [esi]         // stack:  value, (int)0x7FFF
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFF, (int)0x7FFF
-        fistp   word ptr [edi]          // store scaled int into dest, stack:  (int)0x7FFF
-        jmp     Float32_To_Int16_Clip_stored
-    
-    Float32_To_Int16_Clip_clamp:
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-        shr     edx, 31                 // move sign bit into bit 0
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        add     dx, 0x7FFF              // convert to maximum range integers
-        mov     word ptr [edi], dx      // store clamped into into dest
-
-    Float32_To_Int16_Clip_stored:
-
-        add     edi, ebx                // increment destination ptr
-        //lea     edi, [edi+ebx]
-        
-        cmp     esi, ecx                // has src ptr reached end?
-        jne     Float32_To_Int16_Clip_loop
-
-        ffree   st(0)
-        fincstp
-
-        fwait
-        fnclex
-        fldcw   savedFpuControlWord
-    }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_DitherClip(
-    void *destinationBuffer, signed int destinationStride,
-    void *sourceBuffer, signed int sourceStride,
-    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
-    float *src = (float*)sourceBuffer;
-    signed short *dest =  (signed short*)destinationBuffer;
-    (void)ditherGenerator; // unused parameter
-
-    while( count-- )
-    {
-
-        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
-        // use smaller scaler to prevent overflow when we add the dither 
-        float dithered = (*src * (32766.0f)) + dither;
-        signed long samp = (signed long) dithered;
-        PA_CLIP_( samp, -0x8000, 0x7FFF );
-        *dest = (signed short) samp;
-
-        src += sourceStride;
-        dest += destinationStride;
-    }
-*/
-
-    short savedFpuControlWord;
-
-    // spill storage:
-    signed long sourceByteStride;
-    signed long highpassedDither;
-
-    // dither state:
-    unsigned long ditherPrevious = ditherGenerator->previous;
-    unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
-    unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
-
-    __asm{
-        // esi -> source ptr
-        // eax -> source byte stride
-        // edi -> destination ptr
-        // ebx -> destination byte stride
-        // ecx -> source end ptr
-        // edx -> temp
-
-        mov     esi, sourceBuffer
-
-        mov     edx, 4                  // sizeof float32
-        mov     eax, sourceStride
-        imul    eax, edx                // source byte stride
-
-        mov     ecx, count
-        imul    ecx, eax
-        add     ecx, esi                // source end ptr = count * source byte stride + source ptr
-
-        mov     edi, destinationBuffer
-
-        mov     edx, 2                  // sizeof int16
-        mov     ebx, destinationStride
-        imul    ebx, edx                // destination byte stride
-
-        fwait
-        fstcw   savedFpuControlWord
-        fldcw   fpuControlWord_
-
-        fld     ditheredInt16Scaler_    // stack:  int scaler
-
-    Float32_To_Int16_DitherClip_loop:
-
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-
-        and     edx, 0x7FFFFFFF         // mask off sign
-        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0
-
-        jg      Float32_To_Int16_DitherClip_clamp
-
-        // load unscaled value into st(0)
-        fld     dword ptr [esi]         // stack:  value, int scaler
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*(int scaler), int scaler
-
-        /*
-        // call PaUtil_GenerateFloatTriangularDither with C calling convention
-        mov     sourceByteStride, eax   // save eax
-        mov     sourceEnd, ecx          // save ecx
-        push    ditherGenerator         // pass ditherGenerator parameter on stack
-	    call    PaUtil_GenerateFloatTriangularDither  // stack:  dither, value*(int scaler), int scaler
-	    pop     edx                     // clear parameter off stack
-        mov     ecx, sourceEnd          // restore ecx
-        mov     eax, sourceByteStride   // restore eax
-        */
-
-    // generate dither
-        mov     sourceByteStride, eax   // save eax
-        mov     edx, 196314165
-        mov     eax, ditherRandSeed1
-        mul     edx                     // eax:edx = eax * 196314165
-        //add     eax, 907633515
-        lea     eax, [eax+907633515]
-        mov     ditherRandSeed1, eax
-        mov     edx, 196314165
-        mov     eax, ditherRandSeed2
-        mul     edx                     // eax:edx = eax * 196314165
-        //add     eax, 907633515
-        lea     eax, [eax+907633515]
-        mov     edx, ditherRandSeed1
-        shr     edx, PA_DITHER_SHIFT_
-        mov     ditherRandSeed2, eax
-        shr     eax, PA_DITHER_SHIFT_
-        //add     eax, edx                // eax -> current
-        lea     eax, [eax+edx]            // current = randSeed1>>x + randSeed2>>x
-        mov     edx, ditherPrevious
-        neg     edx
-        lea     edx, [eax+edx]          // highpass = current - previous
-        mov     highpassedDither, edx
-        mov     ditherPrevious, eax     // previous = current
-        mov     eax, sourceByteStride   // restore eax
-        fild    highpassedDither
-        fmul    const_float_dither_scale_
-    // end generate dither, dither signal in st(0)
-        
-        faddp   st(1), st(0)            // stack: dither * value*(int scaler), int scaler
-        fistp   word ptr [edi]          // store scaled int into dest, stack:  int scaler
-        jmp     Float32_To_Int16_DitherClip_stored
-    
-    Float32_To_Int16_DitherClip_clamp:
-        mov     edx, dword ptr [esi]    // load floating point value into integer register
-        shr     edx, 31                 // move sign bit into bit 0
-        add     esi, eax                // increment source ptr
-        //lea     esi, [esi+eax]
-        add     dx, 0x7FFF              // convert to maximum range integers
-        mov     word ptr [edi], dx      // store clamped into into dest
-
-    Float32_To_Int16_DitherClip_stored:
-
-        add     edi, ebx                // increment destination ptr
-        //lea     edi, [edi+ebx]
-        
-        cmp     esi, ecx                // has src ptr reached end?
-        jne     Float32_To_Int16_DitherClip_loop
-
-        ffree   st(0)
-        fincstp
-
-        fwait
-        fnclex
-        fldcw   savedFpuControlWord
-    }
-
-    ditherGenerator->previous = ditherPrevious;
-    ditherGenerator->randSeed1 = ditherRandSeed1;
-    ditherGenerator->randSeed2 = ditherRandSeed2;
-}
-
-/* -------------------------------------------------------------------------- */
-
-void PaUtil_InitializeX86PlainConverters( void )
-{
-    paConverters.Float32_To_Int32 = Float32_To_Int32;
-    paConverters.Float32_To_Int32_Clip = Float32_To_Int32_Clip;
-    paConverters.Float32_To_Int32_DitherClip = Float32_To_Int32_DitherClip;
-
-    paConverters.Float32_To_Int24 = Float32_To_Int24;
-    paConverters.Float32_To_Int24_Clip = Float32_To_Int24_Clip;
-    paConverters.Float32_To_Int24_DitherClip = Float32_To_Int24_DitherClip;
-    
-    paConverters.Float32_To_Int16 = Float32_To_Int16;
-    paConverters.Float32_To_Int16_Clip = Float32_To_Int16_Clip;
-    paConverters.Float32_To_Int16_DitherClip = Float32_To_Int16_DitherClip;
-}
-
-/* -------------------------------------------------------------------------- */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include "pa_x86_plain_converters.h"

+

+#include "pa_converters.h"

+#include "pa_dither.h"

+

+/*

+    plain intel assemby versions of standard pa converter functions.

+

+    the main reason these versions are faster than the equivalent C versions

+    is that float -> int casting is expensive in C on x86 because the rounding

+    mode needs to be changed for every cast. these versions only set

+    the rounding mode once outside the loop.

+

+    small additional speed gains are made by the way that clamping is

+    implemented.

+

+TODO:

+    o- inline dither code

+    o- implement Dither only (no-clip) versions

+    o- implement int8 and uint8 versions

+    o- test thouroughly

+

+    o- the packed 24 bit functions could benefit from unrolling and avoiding

+        byte and word sized register access.

+*/

+

+/* -------------------------------------------------------------------------- */

+

+/*

+#define PA_CLIP_( val, min, max )\

+    { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }

+*/

+

+/*

+    the following notes were used to determine whether a floating point

+    value should be saturated (ie >1 or <-1) by loading it into an integer

+    register. these should be rewritten so that they make sense.

+

+    an ieee floating point value

+

+    1.xxxxxxxxxxxxxxxxxxxx?

+

+

+    is less than  or equal to 1 and greater than or equal to -1 either:

+

+        if the mantissa is 0 and the unbiased exponent is 0

+

+        OR

+

+        if the unbiased exponent < 0

+

+    this translates to:

+

+        if the mantissa is 0 and the biased exponent is 7F

+

+        or

+

+        if the biased exponent is less than 7F

+

+

+    therefore the value is greater than 1 or less than -1 if

+

+        the mantissa is not 0 and the biased exponent is 7F

+

+        or

+

+        if the biased exponent is greater than 7F

+

+

+    in other words, if we mask out the sign bit, the value is

+    greater than 1 or less than -1 if its integer representation is greater than:

+

+    0 01111111 0000 0000 0000 0000 0000 000

+

+    0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000

+*/

+

+/* -------------------------------------------------------------------------- */

+

+static const short fpuControlWord_ = 0x033F; /*round to nearest, 64 bit precision, all exceptions masked*/

+static const double int32Scaler_ = 0x7FFFFFFF;

+static const double ditheredInt32Scaler_ = 0x7FFFFFFE;

+static const double int24Scaler_ = 0x7FFFFF;

+static const double ditheredInt24Scaler_ = 0x7FFFFE;

+static const double int16Scaler_ = 0x7FFF;

+static const double ditheredInt16Scaler_ = 0x7FFE;

+

+#define PA_DITHER_BITS_   (15)

+/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */

+#define PA_FLOAT_DITHER_SCALE_  (1.0 / ((1<<PA_DITHER_BITS_)-1))

+static const float const_float_dither_scale_ = (float) PA_FLOAT_DITHER_SCALE_;

+#define PA_DITHER_SHIFT_  ((32 - PA_DITHER_BITS_) + 1)

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int32(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+/*

+    float *src = (float*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+    (void)ditherGenerator; // unused parameter

+

+    while( count-- )

+    {

+        // REVIEW

+        double scaled = *src * 0x7FFFFFFF;

+        *dest = (signed long) scaled;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+*/

+

+    short savedFpuControlWord;

+

+    (void) ditherGenerator; /* unused parameter */

+

+

+    __asm{

+        // esi -> source ptr

+        // eax -> source byte stride

+        // edi -> destination ptr

+        // ebx -> destination byte stride

+        // ecx -> source end ptr

+        // edx -> temp

+

+        mov     esi, sourceBuffer

+

+        mov     edx, 4                  // sizeof float32 and int32

+        mov     eax, sourceStride

+        imul    eax, edx

+

+        mov     ecx, count

+        imul    ecx, eax

+        add     ecx, esi

+    

+        mov     edi, destinationBuffer

+        

+        mov     ebx, destinationStride

+        imul    ebx, edx

+

+        fwait

+        fstcw   savedFpuControlWord

+        fldcw   fpuControlWord_

+

+        fld     int32Scaler_             // stack:  (int)0x7FFFFFFF

+

+    Float32_To_Int32_loop:

+

+        // load unscaled value into st(0)

+        fld     dword ptr [esi]         // stack:  value, (int)0x7FFFFFFF

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFFFFFF, (int)0x7FFFFFFF

+        /*

+            note: we could store to a temporary qword here which would cause

+            wraparound distortion instead of int indefinite 0x10. that would

+            be more work, and given that not enabling clipping is only advisable

+            when you know that your signal isn't going to clip it isn't worth it.

+        */

+        fistp   dword ptr [edi]         // pop st(0) into dest, stack:  (int)0x7FFFFFFF

+

+        add     edi, ebx                // increment destination ptr

+        //lea     edi, [edi+ebx]

+

+        cmp     esi, ecx                // has src ptr reached end?

+        jne     Float32_To_Int32_loop

+

+        ffree   st(0)

+        fincstp

+

+        fwait

+        fnclex

+        fldcw   savedFpuControlWord

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int32_Clip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+/*

+    float *src = (float*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+    (void) ditherGenerator; // unused parameter

+

+    while( count-- )

+    {

+        // REVIEW

+        double scaled = *src * 0x7FFFFFFF;

+        PA_CLIP_( scaled, -2147483648., 2147483647.  );

+        *dest = (signed long) scaled;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+*/

+

+    short savedFpuControlWord;

+

+    (void) ditherGenerator; /* unused parameter */

+

+    __asm{

+        // esi -> source ptr

+        // eax -> source byte stride

+        // edi -> destination ptr

+        // ebx -> destination byte stride

+        // ecx -> source end ptr

+        // edx -> temp

+

+        mov     esi, sourceBuffer

+

+        mov     edx, 4                  // sizeof float32 and int32

+        mov     eax, sourceStride

+        imul    eax, edx

+

+        mov     ecx, count

+        imul    ecx, eax

+        add     ecx, esi

+    

+        mov     edi, destinationBuffer

+        

+        mov     ebx, destinationStride

+        imul    ebx, edx

+

+        fwait

+        fstcw   savedFpuControlWord

+        fldcw   fpuControlWord_

+

+        fld     int32Scaler_             // stack:  (int)0x7FFFFFFF

+

+    Float32_To_Int32_Clip_loop:

+

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+

+        and     edx, 0x7FFFFFFF         // mask off sign

+        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0

+

+        jg      Float32_To_Int32_Clip_clamp

+

+        // load unscaled value into st(0)

+        fld     dword ptr [esi]         // stack:  value, (int)0x7FFFFFFF

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFFFFFF, (int)0x7FFFFFFF

+        fistp   dword ptr [edi]         // pop st(0) into dest, stack:  (int)0x7FFFFFFF

+        jmp     Float32_To_Int32_Clip_stored

+    

+    Float32_To_Int32_Clip_clamp:

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+        shr     edx, 31                 // move sign bit into bit 0

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        add     edx, 0x7FFFFFFF         // convert to maximum range integers

+        mov     dword ptr [edi], edx

+

+    Float32_To_Int32_Clip_stored:

+

+        //add     edi, ebx                // increment destination ptr

+        lea     edi, [edi+ebx]

+

+        cmp     esi, ecx                // has src ptr reached end?

+        jne     Float32_To_Int32_Clip_loop

+

+        ffree   st(0)

+        fincstp

+

+        fwait

+        fnclex

+        fldcw   savedFpuControlWord

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int32_DitherClip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+    /*

+    float *src = (float*)sourceBuffer;

+    signed long *dest =  (signed long*)destinationBuffer;

+

+    while( count-- )

+    {

+        // REVIEW

+        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        // use smaller scaler to prevent overflow when we add the dither

+        double dithered = ((double)*src * (2147483646.0)) + dither;

+        PA_CLIP_( dithered, -2147483648., 2147483647.  );

+        *dest = (signed long) dithered;

+

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+    */

+

+    short savedFpuControlWord;

+

+    // spill storage:

+    signed long sourceByteStride;

+    signed long highpassedDither;

+

+    // dither state:

+    unsigned long ditherPrevious = ditherGenerator->previous;

+    unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;

+    unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;

+                    

+    __asm{

+        // esi -> source ptr

+        // eax -> source byte stride

+        // edi -> destination ptr

+        // ebx -> destination byte stride

+        // ecx -> source end ptr

+        // edx -> temp

+

+        mov     esi, sourceBuffer

+

+        mov     edx, 4                  // sizeof float32 and int32

+        mov     eax, sourceStride

+        imul    eax, edx

+

+        mov     ecx, count

+        imul    ecx, eax

+        add     ecx, esi

+    

+        mov     edi, destinationBuffer

+        

+        mov     ebx, destinationStride

+        imul    ebx, edx

+

+        fwait

+        fstcw   savedFpuControlWord

+        fldcw   fpuControlWord_

+

+        fld     ditheredInt32Scaler_    // stack:  int scaler

+

+    Float32_To_Int32_DitherClip_loop:

+

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+

+        and     edx, 0x7FFFFFFF         // mask off sign

+        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0

+

+        jg      Float32_To_Int32_DitherClip_clamp

+

+        // load unscaled value into st(0)

+        fld     dword ptr [esi]         // stack:  value, int scaler

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*(int scaler), int scaler

+

+        /*

+        // call PaUtil_GenerateFloatTriangularDither with C calling convention

+        mov     sourceByteStride, eax   // save eax

+        mov     sourceEnd, ecx          // save ecx

+        push    ditherGenerator         // pass ditherGenerator parameter on stack

+	    call    PaUtil_GenerateFloatTriangularDither  // stack:  dither, value*(int scaler), int scaler

+	    pop     edx                     // clear parameter off stack

+        mov     ecx, sourceEnd          // restore ecx

+        mov     eax, sourceByteStride   // restore eax

+        */

+

+    // generate dither

+        mov     sourceByteStride, eax   // save eax

+        mov     edx, 196314165

+        mov     eax, ditherRandSeed1

+        mul     edx                     // eax:edx = eax * 196314165

+        //add     eax, 907633515

+        lea     eax, [eax+907633515]

+        mov     ditherRandSeed1, eax

+        mov     edx, 196314165

+        mov     eax, ditherRandSeed2

+        mul     edx                     // eax:edx = eax * 196314165

+        //add     eax, 907633515

+        lea     eax, [eax+907633515]

+        mov     edx, ditherRandSeed1

+        shr     edx, PA_DITHER_SHIFT_

+        mov     ditherRandSeed2, eax

+        shr     eax, PA_DITHER_SHIFT_

+        //add     eax, edx                // eax -> current

+        lea     eax, [eax+edx]

+        mov     edx, ditherPrevious

+        neg     edx

+        lea     edx, [eax+edx]          // highpass = current - previous

+        mov     highpassedDither, edx

+        mov     ditherPrevious, eax     // previous = current

+        mov     eax, sourceByteStride   // restore eax

+        fild    highpassedDither

+        fmul    const_float_dither_scale_

+    // end generate dither, dither signal in st(0)

+    

+        faddp   st(1), st(0)            // stack: dither + value*(int scaler), int scaler

+        fistp   dword ptr [edi]         // pop st(0) into dest, stack:  int scaler

+        jmp     Float32_To_Int32_DitherClip_stored

+    

+    Float32_To_Int32_DitherClip_clamp:

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+        shr     edx, 31                 // move sign bit into bit 0

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        add     edx, 0x7FFFFFFF         // convert to maximum range integers

+        mov     dword ptr [edi], edx

+

+    Float32_To_Int32_DitherClip_stored:

+

+        //add     edi, ebx              // increment destination ptr

+        lea     edi, [edi+ebx]

+

+        cmp     esi, ecx                // has src ptr reached end?

+        jne     Float32_To_Int32_DitherClip_loop

+

+        ffree   st(0)

+        fincstp

+

+        fwait

+        fnclex

+        fldcw   savedFpuControlWord

+    }

+

+    ditherGenerator->previous = ditherPrevious;

+    ditherGenerator->randSeed1 = ditherRandSeed1;

+    ditherGenerator->randSeed2 = ditherRandSeed2;

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int24(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+/*

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    signed long temp;

+

+    (void) ditherGenerator; // unused parameter

+    

+    while( count-- )

+    {

+        // convert to 32 bit and drop the low 8 bits

+        double scaled = *src * 0x7FFFFFFF;

+        temp = (signed long) scaled;

+

+        dest[0] = (unsigned char)(temp >> 8);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 24);

+

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+*/

+

+    short savedFpuControlWord;

+    

+    signed long tempInt32;

+

+    (void) ditherGenerator; /* unused parameter */

+                 

+    __asm{

+        // esi -> source ptr

+        // eax -> source byte stride

+        // edi -> destination ptr

+        // ebx -> destination byte stride

+        // ecx -> source end ptr

+        // edx -> temp

+

+        mov     esi, sourceBuffer

+

+        mov     edx, 4                  // sizeof float32

+        mov     eax, sourceStride

+        imul    eax, edx

+

+        mov     ecx, count

+        imul    ecx, eax

+        add     ecx, esi

+

+        mov     edi, destinationBuffer

+

+        mov     edx, 3                  // sizeof int24

+        mov     ebx, destinationStride

+        imul    ebx, edx

+

+        fwait

+        fstcw   savedFpuControlWord

+        fldcw   fpuControlWord_

+

+        fld     int24Scaler_             // stack:  (int)0x7FFFFF

+

+    Float32_To_Int24_loop:

+

+        // load unscaled value into st(0)

+        fld     dword ptr [esi]         // stack:  value, (int)0x7FFFFF

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFFFF, (int)0x7FFFFF

+        fistp   tempInt32               // pop st(0) into tempInt32, stack:  (int)0x7FFFFF

+        mov     edx, tempInt32

+

+        mov     byte ptr [edi], DL

+        shr     edx, 8

+        //mov     byte ptr [edi+1], DL

+        //mov     byte ptr [edi+2], DH

+        mov     word ptr [edi+1], DX

+

+        //add     edi, ebx                // increment destination ptr

+        lea     edi, [edi+ebx]

+

+        cmp     esi, ecx                // has src ptr reached end?

+        jne     Float32_To_Int24_loop

+

+        ffree   st(0)

+        fincstp

+

+        fwait

+        fnclex

+        fldcw   savedFpuControlWord

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int24_Clip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+/*

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    signed long temp;

+

+    (void) ditherGenerator; // unused parameter

+    

+    while( count-- )

+    {

+        // convert to 32 bit and drop the low 8 bits

+        double scaled = *src * 0x7FFFFFFF;

+        PA_CLIP_( scaled, -2147483648., 2147483647.  );

+        temp = (signed long) scaled;

+

+        dest[0] = (unsigned char)(temp >> 8);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 24);

+

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+*/

+

+    short savedFpuControlWord;

+    

+    signed long tempInt32;

+

+    (void) ditherGenerator; /* unused parameter */

+                 

+    __asm{

+        // esi -> source ptr

+        // eax -> source byte stride

+        // edi -> destination ptr

+        // ebx -> destination byte stride

+        // ecx -> source end ptr

+        // edx -> temp

+

+        mov     esi, sourceBuffer

+

+        mov     edx, 4                  // sizeof float32

+        mov     eax, sourceStride

+        imul    eax, edx

+

+        mov     ecx, count

+        imul    ecx, eax

+        add     ecx, esi

+

+        mov     edi, destinationBuffer

+

+        mov     edx, 3                  // sizeof int24

+        mov     ebx, destinationStride

+        imul    ebx, edx

+

+        fwait

+        fstcw   savedFpuControlWord

+        fldcw   fpuControlWord_

+

+        fld     int24Scaler_             // stack:  (int)0x7FFFFF

+

+    Float32_To_Int24_Clip_loop:

+

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+

+        and     edx, 0x7FFFFFFF         // mask off sign

+        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0

+

+        jg      Float32_To_Int24_Clip_clamp

+

+        // load unscaled value into st(0)

+        fld     dword ptr [esi]         // stack:  value, (int)0x7FFFFF

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFFFF, (int)0x7FFFFF

+        fistp   tempInt32               // pop st(0) into tempInt32, stack:  (int)0x7FFFFF

+        mov     edx, tempInt32

+        jmp     Float32_To_Int24_Clip_store

+    

+    Float32_To_Int24_Clip_clamp:

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+        shr     edx, 31                 // move sign bit into bit 0

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        add     edx, 0x7FFFFF           // convert to maximum range integers

+

+    Float32_To_Int24_Clip_store:

+

+        mov     byte ptr [edi], DL

+        shr     edx, 8

+        //mov     byte ptr [edi+1], DL

+        //mov     byte ptr [edi+2], DH

+        mov     word ptr [edi+1], DX

+

+        //add     edi, ebx                // increment destination ptr

+        lea     edi, [edi+ebx]

+

+        cmp     esi, ecx                // has src ptr reached end?

+        jne     Float32_To_Int24_Clip_loop

+

+        ffree   st(0)

+        fincstp

+

+        fwait

+        fnclex

+        fldcw   savedFpuControlWord

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int24_DitherClip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+/*

+    float *src = (float*)sourceBuffer;

+    unsigned char *dest = (unsigned char*)destinationBuffer;

+    signed long temp;

+    

+    while( count-- )

+    {

+        // convert to 32 bit and drop the low 8 bits

+

+        // FIXME: the dither amplitude here appears to be too small by 8 bits

+        double dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        // use smaller scaler to prevent overflow when we add the dither

+        double dithered = ((double)*src * (2147483646.0)) + dither;

+        PA_CLIP_( dithered, -2147483648., 2147483647.  );

+        

+        temp = (signed long) dithered;

+

+        dest[0] = (unsigned char)(temp >> 8);

+        dest[1] = (unsigned char)(temp >> 16);

+        dest[2] = (unsigned char)(temp >> 24);

+

+        src += sourceStride;

+        dest += destinationStride * 3;

+    }

+*/

+

+    short savedFpuControlWord;

+

+    // spill storage:

+    signed long sourceByteStride;

+    signed long highpassedDither;

+

+    // dither state:

+    unsigned long ditherPrevious = ditherGenerator->previous;

+    unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;

+    unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;

+    

+    signed long tempInt32;

+                 

+    __asm{

+        // esi -> source ptr

+        // eax -> source byte stride

+        // edi -> destination ptr

+        // ebx -> destination byte stride

+        // ecx -> source end ptr

+        // edx -> temp

+

+        mov     esi, sourceBuffer

+

+        mov     edx, 4                  // sizeof float32

+        mov     eax, sourceStride

+        imul    eax, edx

+

+        mov     ecx, count

+        imul    ecx, eax

+        add     ecx, esi

+

+        mov     edi, destinationBuffer

+

+        mov     edx, 3                  // sizeof int24

+        mov     ebx, destinationStride

+        imul    ebx, edx

+

+        fwait

+        fstcw   savedFpuControlWord

+        fldcw   fpuControlWord_

+

+        fld     ditheredInt24Scaler_    // stack:  int scaler

+

+    Float32_To_Int24_DitherClip_loop:

+

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+

+        and     edx, 0x7FFFFFFF         // mask off sign

+        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0

+

+        jg      Float32_To_Int24_DitherClip_clamp

+

+        // load unscaled value into st(0)

+        fld     dword ptr [esi]         // stack:  value, int scaler

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*(int scaler), int scaler

+

+    /*

+        // call PaUtil_GenerateFloatTriangularDither with C calling convention

+        mov     sourceByteStride, eax   // save eax

+        mov     sourceEnd, ecx          // save ecx

+        push    ditherGenerator         // pass ditherGenerator parameter on stack

+	    call    PaUtil_GenerateFloatTriangularDither  // stack:  dither, value*(int scaler), int scaler

+	    pop     edx                     // clear parameter off stack

+        mov     ecx, sourceEnd          // restore ecx

+        mov     eax, sourceByteStride   // restore eax

+    */

+    

+    // generate dither

+        mov     sourceByteStride, eax   // save eax

+        mov     edx, 196314165

+        mov     eax, ditherRandSeed1

+        mul     edx                     // eax:edx = eax * 196314165

+        //add     eax, 907633515

+        lea     eax, [eax+907633515]

+        mov     ditherRandSeed1, eax

+        mov     edx, 196314165

+        mov     eax, ditherRandSeed2

+        mul     edx                     // eax:edx = eax * 196314165

+        //add     eax, 907633515

+        lea     eax, [eax+907633515]

+        mov     edx, ditherRandSeed1

+        shr     edx, PA_DITHER_SHIFT_

+        mov     ditherRandSeed2, eax

+        shr     eax, PA_DITHER_SHIFT_

+        //add     eax, edx                // eax -> current

+        lea     eax, [eax+edx]

+        mov     edx, ditherPrevious

+        neg     edx

+        lea     edx, [eax+edx]          // highpass = current - previous

+        mov     highpassedDither, edx

+        mov     ditherPrevious, eax     // previous = current

+        mov     eax, sourceByteStride   // restore eax

+        fild    highpassedDither

+        fmul    const_float_dither_scale_

+    // end generate dither, dither signal in st(0)

+

+        faddp   st(1), st(0)            // stack: dither * value*(int scaler), int scaler

+        fistp   tempInt32               // pop st(0) into tempInt32, stack:  int scaler

+        mov     edx, tempInt32

+        jmp     Float32_To_Int24_DitherClip_store

+    

+    Float32_To_Int24_DitherClip_clamp:

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+        shr     edx, 31                 // move sign bit into bit 0

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        add     edx, 0x7FFFFF           // convert to maximum range integers

+

+    Float32_To_Int24_DitherClip_store:

+

+        mov     byte ptr [edi], DL

+        shr     edx, 8

+        //mov     byte ptr [edi+1], DL

+        //mov     byte ptr [edi+2], DH

+        mov     word ptr [edi+1], DX

+

+        //add     edi, ebx                // increment destination ptr

+        lea     edi, [edi+ebx]

+

+        cmp     esi, ecx                // has src ptr reached end?

+        jne     Float32_To_Int24_DitherClip_loop

+

+        ffree   st(0)

+        fincstp

+

+        fwait

+        fnclex

+        fldcw   savedFpuControlWord

+    }

+

+    ditherGenerator->previous = ditherPrevious;

+    ditherGenerator->randSeed1 = ditherRandSeed1;

+    ditherGenerator->randSeed2 = ditherRandSeed2;

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int16(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+/*

+    float *src = (float*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    (void)ditherGenerator; // unused parameter

+

+    while( count-- )

+    {

+

+        short samp = (short) (*src * (32767.0f));

+        *dest = samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+*/

+

+    short savedFpuControlWord;

+   

+    (void) ditherGenerator; /* unused parameter */

+

+    __asm{

+        // esi -> source ptr

+        // eax -> source byte stride

+        // edi -> destination ptr

+        // ebx -> destination byte stride

+        // ecx -> source end ptr

+        // edx -> temp

+

+        mov     esi, sourceBuffer

+

+        mov     edx, 4                  // sizeof float32

+        mov     eax, sourceStride

+        imul    eax, edx                // source byte stride

+

+        mov     ecx, count

+        imul    ecx, eax

+        add     ecx, esi                // source end ptr = count * source byte stride + source ptr

+

+        mov     edi, destinationBuffer

+

+        mov     edx, 2                  // sizeof int16

+        mov     ebx, destinationStride

+        imul    ebx, edx                // destination byte stride

+

+        fwait

+        fstcw   savedFpuControlWord

+        fldcw   fpuControlWord_

+

+        fld     int16Scaler_            // stack:  (int)0x7FFF

+

+    Float32_To_Int16_loop:

+

+        // load unscaled value into st(0)

+        fld     dword ptr [esi]         // stack:  value, (int)0x7FFF

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFF, (int)0x7FFF

+        fistp   word ptr [edi]          // store scaled int into dest, stack:  (int)0x7FFF

+

+        add     edi, ebx                // increment destination ptr

+        //lea     edi, [edi+ebx]

+        

+        cmp     esi, ecx                // has src ptr reached end?

+        jne     Float32_To_Int16_loop

+

+        ffree   st(0)

+        fincstp

+

+        fwait

+        fnclex

+        fldcw   savedFpuControlWord

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int16_Clip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+/*

+    float *src = (float*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    (void)ditherGenerator; // unused parameter

+

+    while( count-- )

+    {

+        long samp = (signed long) (*src * (32767.0f));

+        PA_CLIP_( samp, -0x8000, 0x7FFF );

+        *dest = (signed short) samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+*/

+

+    short savedFpuControlWord;

+   

+    (void) ditherGenerator; /* unused parameter */

+

+    __asm{

+        // esi -> source ptr

+        // eax -> source byte stride

+        // edi -> destination ptr

+        // ebx -> destination byte stride

+        // ecx -> source end ptr

+        // edx -> temp

+

+        mov     esi, sourceBuffer

+

+        mov     edx, 4                  // sizeof float32

+        mov     eax, sourceStride

+        imul    eax, edx                // source byte stride

+

+        mov     ecx, count

+        imul    ecx, eax

+        add     ecx, esi                // source end ptr = count * source byte stride + source ptr

+

+        mov     edi, destinationBuffer

+

+        mov     edx, 2                  // sizeof int16

+        mov     ebx, destinationStride

+        imul    ebx, edx                // destination byte stride

+

+        fwait

+        fstcw   savedFpuControlWord

+        fldcw   fpuControlWord_

+

+        fld     int16Scaler_            // stack:  (int)0x7FFF

+

+    Float32_To_Int16_Clip_loop:

+

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+

+        and     edx, 0x7FFFFFFF         // mask off sign

+        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0

+

+        jg      Float32_To_Int16_Clip_clamp

+

+        // load unscaled value into st(0)

+        fld     dword ptr [esi]         // stack:  value, (int)0x7FFF

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*0x7FFF, (int)0x7FFF

+        fistp   word ptr [edi]          // store scaled int into dest, stack:  (int)0x7FFF

+        jmp     Float32_To_Int16_Clip_stored

+    

+    Float32_To_Int16_Clip_clamp:

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+        shr     edx, 31                 // move sign bit into bit 0

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        add     dx, 0x7FFF              // convert to maximum range integers

+        mov     word ptr [edi], dx      // store clamped into into dest

+

+    Float32_To_Int16_Clip_stored:

+

+        add     edi, ebx                // increment destination ptr

+        //lea     edi, [edi+ebx]

+        

+        cmp     esi, ecx                // has src ptr reached end?

+        jne     Float32_To_Int16_Clip_loop

+

+        ffree   st(0)

+        fincstp

+

+        fwait

+        fnclex

+        fldcw   savedFpuControlWord

+    }

+}

+

+/* -------------------------------------------------------------------------- */

+

+static void Float32_To_Int16_DitherClip(

+    void *destinationBuffer, signed int destinationStride,

+    void *sourceBuffer, signed int sourceStride,

+    unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )

+{

+/*

+    float *src = (float*)sourceBuffer;

+    signed short *dest =  (signed short*)destinationBuffer;

+    (void)ditherGenerator; // unused parameter

+

+    while( count-- )

+    {

+

+        float dither  = PaUtil_GenerateFloatTriangularDither( ditherGenerator );

+        // use smaller scaler to prevent overflow when we add the dither 

+        float dithered = (*src * (32766.0f)) + dither;

+        signed long samp = (signed long) dithered;

+        PA_CLIP_( samp, -0x8000, 0x7FFF );

+        *dest = (signed short) samp;

+

+        src += sourceStride;

+        dest += destinationStride;

+    }

+*/

+

+    short savedFpuControlWord;

+

+    // spill storage:

+    signed long sourceByteStride;

+    signed long highpassedDither;

+

+    // dither state:

+    unsigned long ditherPrevious = ditherGenerator->previous;

+    unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;

+    unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;

+

+    __asm{

+        // esi -> source ptr

+        // eax -> source byte stride

+        // edi -> destination ptr

+        // ebx -> destination byte stride

+        // ecx -> source end ptr

+        // edx -> temp

+

+        mov     esi, sourceBuffer

+

+        mov     edx, 4                  // sizeof float32

+        mov     eax, sourceStride

+        imul    eax, edx                // source byte stride

+

+        mov     ecx, count

+        imul    ecx, eax

+        add     ecx, esi                // source end ptr = count * source byte stride + source ptr

+

+        mov     edi, destinationBuffer

+

+        mov     edx, 2                  // sizeof int16

+        mov     ebx, destinationStride

+        imul    ebx, edx                // destination byte stride

+

+        fwait

+        fstcw   savedFpuControlWord

+        fldcw   fpuControlWord_

+

+        fld     ditheredInt16Scaler_    // stack:  int scaler

+

+    Float32_To_Int16_DitherClip_loop:

+

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+

+        and     edx, 0x7FFFFFFF         // mask off sign

+        cmp     edx, 0x3F800000         // greater than 1.0 or less than -1.0

+

+        jg      Float32_To_Int16_DitherClip_clamp

+

+        // load unscaled value into st(0)

+        fld     dword ptr [esi]         // stack:  value, int scaler

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        fmul    st(0), st(1)            // st(0) *= st(1), stack:  value*(int scaler), int scaler

+

+        /*

+        // call PaUtil_GenerateFloatTriangularDither with C calling convention

+        mov     sourceByteStride, eax   // save eax

+        mov     sourceEnd, ecx          // save ecx

+        push    ditherGenerator         // pass ditherGenerator parameter on stack

+	    call    PaUtil_GenerateFloatTriangularDither  // stack:  dither, value*(int scaler), int scaler

+	    pop     edx                     // clear parameter off stack

+        mov     ecx, sourceEnd          // restore ecx

+        mov     eax, sourceByteStride   // restore eax

+        */

+

+    // generate dither

+        mov     sourceByteStride, eax   // save eax

+        mov     edx, 196314165

+        mov     eax, ditherRandSeed1

+        mul     edx                     // eax:edx = eax * 196314165

+        //add     eax, 907633515

+        lea     eax, [eax+907633515]

+        mov     ditherRandSeed1, eax

+        mov     edx, 196314165

+        mov     eax, ditherRandSeed2

+        mul     edx                     // eax:edx = eax * 196314165

+        //add     eax, 907633515

+        lea     eax, [eax+907633515]

+        mov     edx, ditherRandSeed1

+        shr     edx, PA_DITHER_SHIFT_

+        mov     ditherRandSeed2, eax

+        shr     eax, PA_DITHER_SHIFT_

+        //add     eax, edx                // eax -> current

+        lea     eax, [eax+edx]            // current = randSeed1>>x + randSeed2>>x

+        mov     edx, ditherPrevious

+        neg     edx

+        lea     edx, [eax+edx]          // highpass = current - previous

+        mov     highpassedDither, edx

+        mov     ditherPrevious, eax     // previous = current

+        mov     eax, sourceByteStride   // restore eax

+        fild    highpassedDither

+        fmul    const_float_dither_scale_

+    // end generate dither, dither signal in st(0)

+        

+        faddp   st(1), st(0)            // stack: dither * value*(int scaler), int scaler

+        fistp   word ptr [edi]          // store scaled int into dest, stack:  int scaler

+        jmp     Float32_To_Int16_DitherClip_stored

+    

+    Float32_To_Int16_DitherClip_clamp:

+        mov     edx, dword ptr [esi]    // load floating point value into integer register

+        shr     edx, 31                 // move sign bit into bit 0

+        add     esi, eax                // increment source ptr

+        //lea     esi, [esi+eax]

+        add     dx, 0x7FFF              // convert to maximum range integers

+        mov     word ptr [edi], dx      // store clamped into into dest

+

+    Float32_To_Int16_DitherClip_stored:

+

+        add     edi, ebx                // increment destination ptr

+        //lea     edi, [edi+ebx]

+        

+        cmp     esi, ecx                // has src ptr reached end?

+        jne     Float32_To_Int16_DitherClip_loop

+

+        ffree   st(0)

+        fincstp

+

+        fwait

+        fnclex

+        fldcw   savedFpuControlWord

+    }

+

+    ditherGenerator->previous = ditherPrevious;

+    ditherGenerator->randSeed1 = ditherRandSeed1;

+    ditherGenerator->randSeed2 = ditherRandSeed2;

+}

+

+/* -------------------------------------------------------------------------- */

+

+void PaUtil_InitializeX86PlainConverters( void )

+{

+    paConverters.Float32_To_Int32 = Float32_To_Int32;

+    paConverters.Float32_To_Int32_Clip = Float32_To_Int32_Clip;

+    paConverters.Float32_To_Int32_DitherClip = Float32_To_Int32_DitherClip;

+

+    paConverters.Float32_To_Int24 = Float32_To_Int24;

+    paConverters.Float32_To_Int24_Clip = Float32_To_Int24_Clip;

+    paConverters.Float32_To_Int24_DitherClip = Float32_To_Int24_DitherClip;

+    

+    paConverters.Float32_To_Int16 = Float32_To_Int16;

+    paConverters.Float32_To_Int16_Clip = Float32_To_Int16_Clip;

+    paConverters.Float32_To_Int16_DitherClip = Float32_To_Int16_DitherClip;

+}

+

+/* -------------------------------------------------------------------------- */

diff --git a/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.h b/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.h
index f56c710..5aedc51 100644
--- a/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.h
+++ b/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.h
@@ -1,19 +1,40 @@
-#ifndef PA_X86_PLAIN_CONVERTERS_H
-#define PA_X86_PLAIN_CONVERTERS_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/**
- @brief Install optimised converter functions suitable for all IA32 processors
-*/
-void PaUtil_InitializeX86PlainConverters( void );
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_X86_PLAIN_CONVERTERS_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#ifndef PA_X86_PLAIN_CONVERTERS_H

+#define PA_X86_PLAIN_CONVERTERS_H

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+

+/**

+ @brief Install optimised converter functions suitable for all IA32 processors

+*/

+void PaUtil_InitializeX86PlainConverters( void );

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PA_X86_PLAIN_CONVERTERS_H */

diff --git a/pjmedia/src/pjmedia/portaudio/portaudio.h b/pjmedia/src/pjmedia/portaudio/portaudio.h
index 341d92c..aaf5c80 100644
--- a/pjmedia/src/pjmedia/portaudio/portaudio.h
+++ b/pjmedia/src/pjmedia/portaudio/portaudio.h
@@ -1,1123 +1,1144 @@
-
-#ifndef PORTAUDIO_H
-#define PORTAUDIO_H
-/*
- * $Id: portaudio.h,v 1.5.2.50 2004/12/13 11:50:40 rossbencina Exp $
- * PortAudio Portable Real-Time Audio Library
- * PortAudio API Header File
- * Latest version available at: http://www.portaudio.com/
- *
- * Copyright (c) 1999-2002 Ross Bencina and Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/** @file
- @brief The PortAudio API.
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
- 
-/** Retrieve the release number of the currently running PortAudio build,
- eg 1900.
-*/
-int Pa_GetVersion( void );
-
-
-/** Retrieve a textual description of the current PortAudio build,
- eg "PortAudio V19-devel 13 October 2002".
-*/
-const char* Pa_GetVersionText( void );
-
-
-/** Error codes returned by PortAudio functions.
- Note that with the exception of paNoError, all PaErrorCodes are negative.
-*/
-
-typedef int PaError;
-typedef enum PaErrorCode
-{
-    paNoError = 0,
-
-    paNotInitialized = -10000,
-    paUnanticipatedHostError,
-    paInvalidChannelCount,
-    paInvalidSampleRate,
-    paInvalidDevice,
-    paInvalidFlag,
-    paSampleFormatNotSupported,
-    paBadIODeviceCombination,
-    paInsufficientMemory,
-    paBufferTooBig,
-    paBufferTooSmall,
-    paNullCallback,
-    paBadStreamPtr,
-    paTimedOut,
-    paInternalError,
-    paDeviceUnavailable,
-    paIncompatibleHostApiSpecificStreamInfo,
-    paStreamIsStopped,
-    paStreamIsNotStopped,
-    paInputOverflowed,
-    paOutputUnderflowed,
-    paHostApiNotFound,
-    paInvalidHostApi,
-    paCanNotReadFromACallbackStream,      /**< @todo review error code name */
-    paCanNotWriteToACallbackStream,       /**< @todo review error code name */
-    paCanNotReadFromAnOutputOnlyStream,   /**< @todo review error code name */
-    paCanNotWriteToAnInputOnlyStream,     /**< @todo review error code name */
-    paIncompatibleStreamHostApi
-} PaErrorCode;
-
-
-/** Translate the supplied PortAudio error code into a human readable
- message.
-*/
-const char *Pa_GetErrorText( PaError errorCode );
-
-
-/** Library initialization function - call this before using PortAudio.
- This function initialises internal data structures and prepares underlying
- host APIs for use. This function MUST be called before using any other
- PortAudio API functions.
-
- If Pa_Initialize() is called multiple times, each successful 
- call must be matched with a corresponding call to Pa_Terminate(). 
- Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not 
- required to be fully nested.
-
- Note that if Pa_Initialize() returns an error code, Pa_Terminate() should
- NOT be called.
-
- @return paNoError if successful, otherwise an error code indicating the cause
- of failure.
-
- @see Pa_Terminate
-*/
-PaError Pa_Initialize( void );
-
-
-/** Library termination function - call this when finished using PortAudio.
- This function deallocates all resources allocated by PortAudio since it was
- initializied by a call to Pa_Initialize(). In cases where Pa_Initialise() has
- been called multiple times, each call must be matched with a corresponding call
- to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically
- close any PortAudio streams that are still open.
-
- Pa_Terminate() MUST be called before exiting a program which uses PortAudio.
- Failure to do so may result in serious resource leaks, such as audio devices
- not being available until the next reboot.
-
- @return paNoError if successful, otherwise an error code indicating the cause
- of failure.
- 
- @see Pa_Initialize
-*/
-PaError Pa_Terminate( void );
-
-
-
-/** The type used to refer to audio devices. Values of this type usually
- range from 0 to (Pa_DeviceCount-1), and may also take on the PaNoDevice
- and paUseHostApiSpecificDeviceSpecification values.
-
- @see Pa_DeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification
-*/
-typedef int PaDeviceIndex;
-
-
-/** A special PaDeviceIndex value indicating that no device is available,
- or should be used.
-
- @see PaDeviceIndex
-*/
-#define paNoDevice ((PaDeviceIndex)-1)
-
-
-/** A special PaDeviceIndex value indicating that the device(s) to be used
- are specified in the host api specific stream info structure.
-
- @see PaDeviceIndex
-*/
-#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2)
-
-
-/* Host API enumeration mechanism */
-
-/** The type used to enumerate to host APIs at runtime. Values of this type
- range from 0 to (Pa_GetHostApiCount()-1).
-
- @see Pa_GetHostApiCount
-*/
-typedef int PaHostApiIndex;
-
-
-/** Retrieve the number of available host APIs. Even if a host API is
- available it may have no devices available.
-
- @return A non-negative value indicating the number of available host APIs
- or, a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-
- @see PaHostApiIndex
-*/
-PaHostApiIndex Pa_GetHostApiCount( void );
-
-
-/** Retrieve the index of the default host API. The default host API will be
- the lowest common denominator host API on the current platform and is
- unlikely to provide the best performance.
-
- @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1)
- indicating the default host API index or, a PaErrorCode (which are always
- negative) if PortAudio is not initialized or an error is encountered.
-*/
-PaHostApiIndex Pa_GetDefaultHostApi( void );
-
-
-/** Unchanging unique identifiers for each supported host API. This type
- is used in the PaHostApiInfo structure. The values are guaranteed to be
- unique and to never change, thus allowing code to be written that
- conditionally uses host API specific extensions.
-
- New type ids will be allocated when support for a host API reaches
- "public alpha" status, prior to that developers should use the
- paInDevelopment type id.
-
- @see PaHostApiInfo
-*/
-typedef enum PaHostApiTypeId
-{
-    paInDevelopment=0, /* use while developing support for a new host API */
-    paDirectSound=1,
-    paMME=2,
-    paASIO=3,
-    paSoundManager=4,
-    paCoreAudio=5,
-    paOSS=7,
-    paALSA=8,
-    paAL=9,
-    paBeOS=10,
-    paWDMKS=11,
-    paJACK=12
-} PaHostApiTypeId;
-
-
-/** A structure containing information about a particular host API. */
-
-typedef struct PaHostApiInfo
-{
-    /** this is struct version 1 */
-    int structVersion;
-    /** The well known unique identifier of this host API @see PaHostApiTypeId */
-    PaHostApiTypeId type;
-    /** A textual description of the host API for display on user interfaces. */
-    const char *name;
-
-    /**  The number of devices belonging to this host API. This field may be
-     used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate
-     all devices for this host API.
-     @see Pa_HostApiDeviceIndexToDeviceIndex
-    */
-    int deviceCount;
-
-    /** The the default input device for this host API. The value will be a
-     device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice
-     if no default input device is available.
-    */
-    PaDeviceIndex defaultInputDevice;
-
-    /** The the default output device for this host API. The value will be a
-     device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice
-     if no default output device is available.
-    */
-    PaDeviceIndex defaultOutputDevice;
-    
-} PaHostApiInfo;
-
-
-/** Retrieve a pointer to a structure containing information about a specific
- host Api.
-
- @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1)
-
- @return A pointer to an immutable PaHostApiInfo structure describing
- a specific host API. If the hostApi parameter is out of range or an error
- is encountered, the function returns NULL.
-
- The returned structure is owned by the PortAudio implementation and must not
- be manipulated or freed. The pointer is only guaranteed to be valid between
- calls to Pa_Initialize() and Pa_Terminate().
-*/
-const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi );
-
-
-/** Convert a static host API unique identifier, into a runtime
- host API index.
-
- @param type A unique host API identifier belonging to the PaHostApiTypeId
- enumeration.
-
- @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or,
- a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
- 
- The paHostApiNotFound error code indicates that the host API specified by the
- type parameter is not available.
-
- @see PaHostApiTypeId
-*/
-PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type );
-
-
-/** Convert a host-API-specific device index to standard PortAudio device index.
- This function may be used in conjunction with the deviceCount field of
- PaHostApiInfo to enumerate all devices for the specified host API.
-
- @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1)
-
- @param hostApiDeviceIndex A valid per-host device index in the range
- 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1)
-
- @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1)
- or, a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-
- A paInvalidHostApi error code indicates that the host API index specified by
- the hostApi parameter is out of range.
-
- A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter
- is out of range.
- 
- @see PaHostApiInfo
-*/
-PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi,
-        int hostApiDeviceIndex );
-
-
-
-/** Structure used to return information about a host error condition.
-*/
-typedef struct PaHostErrorInfo{
-    PaHostApiTypeId hostApiType;    /**< the host API which returned the error code */
-    long errorCode;                 /**< the error code returned */
-    const char *errorText;          /**< a textual description of the error if available, otherwise a zero-length string */
-}PaHostErrorInfo;
-
-
-/** Return information about the last host error encountered. The error
- information returned by Pa_GetLastHostErrorInfo() will never be modified
- asyncronously by errors occurring in other PortAudio owned threads
- (such as the thread that manages the stream callback.)
-
- This function is provided as a last resort, primarily to enhance debugging
- by providing clients with access to all available error information.
-
- @return A pointer to an immutable structure constaining information about
- the host error. The values in this structure will only be valid if a
- PortAudio function has previously returned the paUnanticipatedHostError
- error code.
-*/
-const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void );
-
-
-
-/* Device enumeration and capabilities */
-
-/** Retrieve the number of available devices. The number of available devices
- may be zero.
-
- @return A non-negative value indicating the number of available devices or,
- a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-*/
-PaDeviceIndex Pa_GetDeviceCount( void );
-
-
-/** Retrieve the index of the default input device. The result can be
- used in the inputDevice parameter to Pa_OpenStream().
-
- @return The default input device index for the default host API, or paNoDevice
- if no default input device is available or an error was encountered.
-*/
-PaDeviceIndex Pa_GetDefaultInputDevice( void );
-
-
-/** Retrieve the index of the default output device. The result can be
- used in the outputDevice parameter to Pa_OpenStream().
-
- @return The default output device index for the defualt host API, or paNoDevice
- if no default output device is available or an error was encountered.
-
- @note
- On the PC, the user can specify a default device by
- setting an environment variable. For example, to use device #1.
-<pre>
- set PA_RECOMMENDED_OUTPUT_DEVICE=1
-</pre>
- The user should first determine the available device ids by using
- the supplied application "pa_devs".
-*/
-PaDeviceIndex Pa_GetDefaultOutputDevice( void );
-
-
-/** The type used to represent monotonic time in seconds that can be used
- for syncronisation. The type is used for the outTime argument to the
- PaStreamCallback and as the result of Pa_GetStreamTime().
-     
- @see PaStreamCallback, Pa_GetStreamTime
-*/
-typedef double PaTime;
-
-
-/** A type used to specify one or more sample formats. Each value indicates
- a possible format for sound data passed to and from the stream callback,
- Pa_ReadStream and Pa_WriteStream.
-
- The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8
- and aUInt8 are usually implemented by all implementations.
-
- The floating point representation (paFloat32) uses +1.0 and -1.0 as the
- maximum and minimum respectively.
-
- paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
-
- The paNonInterleaved flag indicates that a multichannel buffer is passed
- as a set of non-interleaved pointers.
-
- @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo
- @see paFloat32, paInt16, paInt32, paInt24, paInt8
- @see paUInt8, paCustomFormat, paNonInterleaved
-*/
-typedef unsigned long PaSampleFormat;
-
-
-#define paFloat32        ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */
-#define paInt32          ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */
-#define paInt24          ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */
-#define paInt16          ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */
-#define paInt8           ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */
-#define paUInt8          ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */
-#define paCustomFormat   ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */
-
-#define paNonInterleaved ((PaSampleFormat) 0x80000000)
-
-/** A structure providing information and capabilities of PortAudio devices.
- Devices may support input, output or both input and output.
-*/
-typedef struct PaDeviceInfo
-{
-    int structVersion;  /* this is struct version 2 */
-    const char *name;
-    PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/
-    
-    int maxInputChannels;
-    int maxOutputChannels;
-
-    /* Default latency values for interactive performance. */
-    PaTime defaultLowInputLatency;
-    PaTime defaultLowOutputLatency;
-    /* Default latency values for robust non-interactive applications (eg. playing sound files). */
-    PaTime defaultHighInputLatency;
-    PaTime defaultHighOutputLatency;
-
-    double defaultSampleRate;
-} PaDeviceInfo;
-
-
-/** Retrieve a pointer to a PaDeviceInfo structure containing information
- about the specified device.
- @return A pointer to an immutable PaDeviceInfo structure. If the device
- parameter is out of range the function returns NULL.
-
- @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1)
-
- @note PortAudio manages the memory referenced by the returned pointer,
- the client must not manipulate or free the memory. The pointer is only
- guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate().
-
- @see PaDeviceInfo, PaDeviceIndex
-*/
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device );
-
-
-/** Parameters for one direction (input or output) of a stream.
-*/
-typedef struct PaStreamParameters
-{
-    /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1)
-     specifying the device to be used or the special constant
-     paUseHostApiSpecificDeviceSpecification which indicates that the actual
-     device(s) to use are specified in hostApiSpecificStreamInfo.
-     This field must not be set to paNoDevice.
-    */
-    PaDeviceIndex device;
-    
-    /** The number of channels of sound to be delivered to the
-     stream callback or accessed by Pa_ReadStream() or Pa_WriteStream().
-     It can range from 1 to the value of maxInputChannels in the
-     PaDeviceInfo record for the device specified by the device parameter.
-    */
-    int channelCount;
-
-    /** The sample format of the buffer provided to the stream callback,
-     a_ReadStream() or Pa_WriteStream(). It may be any of the formats described
-     by the PaSampleFormat enumeration.
-    */
-    PaSampleFormat sampleFormat;
-
-    /** The desired latency in seconds. Where practical, implementations should
-     configure their latency based on these parameters, otherwise they may
-     choose the closest viable latency instead. Unless the suggested latency
-     is greater than the absolute upper limit for the device implementations
-     shouldround the suggestedLatency up to the next practial value - ie to
-     provide an equal or higher latency than suggestedLatency whereever possibe.
-     Actual latency values for an open stream may be retrieved using the
-     inputLatency and outputLatency fields of the PaStreamInfo structure
-     returned by Pa_GetStreamInfo().
-     @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo
-    */
-    PaTime suggestedLatency;
-
-    /** An optional pointer to a host api specific data structure
-     containing additional information for device setup and/or stream processing.
-     hostApiSpecificStreamInfo is never required for correct operation,
-     if not used it should be set to NULL.
-    */
-    void *hostApiSpecificStreamInfo;
-
-} PaStreamParameters;
-
-
-/** Return code for Pa_IsFormatSupported indicating success. */
-#define paFormatIsSupported (0)
-
-/** Determine whether it would be possible to open a stream with the specified
- parameters.
-
- @param inputParameters A structure that describes the input parameters used to
- open a stream. The suggestedLatency field is ignored. See PaStreamParameters
- for a description of these parameters. inputParameters must be NULL for
- output-only streams.
-
- @param outputParameters A structure that describes the output parameters used
- to open a stream. The suggestedLatency field is ignored. See PaStreamParameters
- for a description of these parameters. outputParameters must be NULL for
- input-only streams.
-
- @param sampleRate The required sampleRate. For full-duplex streams it is the
- sample rate for both input and output
-
- @return Returns 0 if the format is supported, and an error code indicating why
- the format is not supported otherwise. The constant paFormatIsSupported is
- provided to compare with the return value for success.
-
- @see paFormatIsSupported, PaStreamParameters
-*/
-PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
-                              const PaStreamParameters *outputParameters,
-                              double sampleRate );
-
-
-
-/* Streaming types and functions */
-
-
-/**
- A single PaStream can provide multiple channels of real-time
- streaming audio input and output to a client application. A stream
- provides access to audio hardware represented by one or more
- PaDevices. Depending on the underlying Host API, it may be possible 
- to open multiple streams using the same device, however this behavior 
- is implementation defined. Portable applications should assume that 
- a PaDevice may be simultaneously used by at most one PaStream.
-
- Pointers to PaStream objects are passed between PortAudio functions that
- operate on streams.
-
- @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream,
- Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive,
- Pa_GetStreamTime, Pa_GetStreamCpuLoad
-
-*/
-typedef void PaStream;
-
-
-/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream()
- or Pa_OpenDefaultStream() to indicate that the stream callback will
- accept buffers of any size.
-*/
-#define paFramesPerBufferUnspecified  (0)
-
-
-/** Flags used to control the behavior of a stream. They are passed as
- parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be
- ORed together.
-
- @see Pa_OpenStream, Pa_OpenDefaultStream
- @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput,
-  paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags
-*/
-typedef unsigned long PaStreamFlags;
-
-/** @see PaStreamFlags */
-#define   paNoFlag          ((PaStreamFlags) 0)
-
-/** Disable default clipping of out of range samples.
- @see PaStreamFlags
-*/
-#define   paClipOff         ((PaStreamFlags) 0x00000001)
-
-/** Disable default dithering.
- @see PaStreamFlags
-*/
-#define   paDitherOff       ((PaStreamFlags) 0x00000002)
-
-/** Flag requests that where possible a full duplex stream will not discard
- overflowed input samples without calling the stream callback. This flag is
- only valid for full duplex callback streams and only when used in combination
- with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using
- this flag incorrectly results in a paInvalidFlag error being returned from
- Pa_OpenStream and Pa_OpenDefaultStream.
-
- @see PaStreamFlags, paFramesPerBufferUnspecified
-*/
-#define   paNeverDropInput  ((PaStreamFlags) 0x00000004)
-
-/** Call the stream callback to fill initial output buffers, rather than the
- default behavior of priming the buffers with zeros (silence). This flag has
- no effect for input-only and blocking read/write streams.
- 
- @see PaStreamFlags
-*/
-#define   paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008)
-
-/** A mask specifying the platform specific bits.
- @see PaStreamFlags
-*/
-#define   paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000)
-
-/**
- Timing information for the buffers passed to the stream callback.
-*/
-typedef struct PaStreamCallbackTimeInfo{
-    PaTime inputBufferAdcTime;
-    PaTime currentTime;
-    PaTime outputBufferDacTime;
-} PaStreamCallbackTimeInfo;
-
-
-/**
- Flag bit constants for the statusFlags to PaStreamCallback.
-
- @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow,
- paPrimingOutput
-*/
-typedef unsigned long PaStreamCallbackFlags;
-
-/** In a stream opened with paFramesPerBufferUnspecified, indicates that
- input data is all silence (zeros) because no real data is available. In a
- stream opened without paFramesPerBufferUnspecified, it indicates that one or
- more zero samples have been inserted into the input buffer to compensate
- for an input underflow.
- @see PaStreamCallbackFlags
-*/
-#define paInputUnderflow   ((PaStreamCallbackFlags) 0x00000001)
-
-/** In a stream opened with paFramesPerBufferUnspecified, indicates that data
- prior to the first sample of the input buffer was discarded due to an
- overflow, possibly because the stream callback is using too much CPU time.
- Otherwise indicates that data prior to one or more samples in the
- input buffer was discarded.
- @see PaStreamCallbackFlags
-*/
-#define paInputOverflow    ((PaStreamCallbackFlags) 0x00000002)
-
-/** Indicates that output data (or a gap) was inserted, possibly because the
- stream callback is using too much CPU time.
- @see PaStreamCallbackFlags
-*/
-#define paOutputUnderflow  ((PaStreamCallbackFlags) 0x00000004)
-
-/** Indicates that output data will be discarded because no room is available.
- @see PaStreamCallbackFlags
-*/
-#define paOutputOverflow   ((PaStreamCallbackFlags) 0x00000008)
-
-/** Some of all of the output data will be used to prime the stream, input
- data may be zero.
- @see PaStreamCallbackFlags
-*/
-#define paPrimingOutput    ((PaStreamCallbackFlags) 0x00000010)
-
-/**
- Allowable return values for the PaStreamCallback.
- @see PaStreamCallback
-*/
-typedef enum PaStreamCallbackResult
-{
-    paContinue=0,
-    paComplete=1,
-    paAbort=2
-} PaStreamCallbackResult;
-
-
-/**
- Functions of type PaStreamCallback are implemented by PortAudio clients.
- They consume, process or generate audio in response to requests from an
- active PortAudio stream.
-     
- @param input and @param output are arrays of interleaved samples,
- the format, packing and number of channels used by the buffers are
- determined by parameters to Pa_OpenStream().
-     
- @param frameCount The number of sample frames to be processed by
- the stream callback.
-
- @param timeInfo The time in seconds when the first sample of the input
- buffer was received at the audio input, the time in seconds when the first
- sample of the output buffer will begin being played at the audio output, and
- the time in seconds when the stream callback was called.
- See also Pa_GetStreamTime()
-
- @param statusFlags Flags indicating whether input and/or output buffers
- have been inserted or will be dropped to overcome underflow or overflow
- conditions.
-
- @param userData The value of a user supplied pointer passed to
- Pa_OpenStream() intended for storing synthesis data etc.
-
- @return
- The stream callback should return one of the values in the
- PaStreamCallbackResult enumeration. To ensure that the callback continues
- to be called, it should return paContinue (0). Either paComplete or paAbort
- can be returned to finish stream processing, after either of these values is
- returned the callback will not be called again. If paAbort is returned the
- stream will finish as soon as possible. If paComplete is returned, the stream
- will continue until all buffers generated by the callback have been played.
- This may be useful in applications such as soundfile players where a specific
- duration of output is required. However, it is not necessary to utilise this
- mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also
- be used to stop the stream. The callback must always fill the entire output
- buffer irrespective of its return value.
-
- @see Pa_OpenStream, Pa_OpenDefaultStream
-
- @note With the exception of Pa_GetStreamCpuLoad() it is not permissable to call
- PortAudio API functions from within the stream callback.
-*/
-typedef int PaStreamCallback(
-    const void *input, void *output,
-    unsigned long frameCount,
-    const PaStreamCallbackTimeInfo* timeInfo,
-    PaStreamCallbackFlags statusFlags,
-    void *userData );
-
-
-/** Opens a stream for either input, output or both.
-     
- @param stream The address of a PaStream pointer which will receive
- a pointer to the newly opened stream.
-     
- @param inputParameters A structure that describes the input parameters used by
- the opened stream. See PaStreamParameters for a description of these parameters.
- inputParameters must be NULL for output-only streams.
-
- @param outputParameters A structure that describes the output parameters used by
- the opened stream. See PaStreamParameters for a description of these parameters.
- outputParameters must be NULL for input-only streams.
- 
- @param sampleRate The desired sampleRate. For full-duplex streams it is the
- sample rate for both input and output
-     
- @param framesPerBuffer The number of frames passed to the stream callback
- function, or the preferred block granularity for a blocking read/write stream.
- The special value paFramesPerBufferUnspecified (0) may be used to request that
- the stream callback will recieve an optimal (and possibly varying) number of
- frames based on host requirements and the requested latency settings.
- Note: With some host APIs, the use of non-zero framesPerBuffer for a callback
- stream may introduce an additional layer of buffering which could introduce
- additional latency. PortAudio guarantees that the additional latency
- will be kept to the theoretical minimum however, it is strongly recommended
- that a non-zero framesPerBuffer value only be used when your algorithm
- requires a fixed number of frames per stream callback.
- 
- @param streamFlags Flags which modify the behaviour of the streaming process.
- This parameter may contain a combination of flags ORed together. Some flags may
- only be relevant to certain buffer formats.
-     
- @param streamCallback A pointer to a client supplied function that is responsible
- for processing and filling input and output buffers. If this parameter is NULL
- the stream will be opened in 'blocking read/write' mode. In blocking mode,
- the client can receive sample data using Pa_ReadStream and write sample data
- using Pa_WriteStream, the number of samples that may be read or written
- without blocking is returned by Pa_GetStreamReadAvailable and
- Pa_GetStreamWriteAvailable respectively.
-
- @param userData A client supplied pointer which is passed to the stream callback
- function. It could for example, contain a pointer to instance data necessary
- for processing the audio buffers. This parameter is ignored if streamCallback
- is NULL.
-     
- @return
- Upon success Pa_OpenStream() returns paNoError and places a pointer to a
- valid PaStream in the stream argument. The stream is inactive (stopped).
- If a call to Pa_OpenStream() fails, a non-zero error code is returned (see
- PaError for possible error codes) and the value of stream is invalid.
-
- @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream,
- Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable
-*/
-PaError Pa_OpenStream( PaStream** stream,
-                       const PaStreamParameters *inputParameters,
-                       const PaStreamParameters *outputParameters,
-                       double sampleRate,
-                       unsigned long framesPerBuffer,
-                       PaStreamFlags streamFlags,
-                       PaStreamCallback *streamCallback,
-                       void *userData );
-
-
-/** A simplified version of Pa_OpenStream() that opens the default input
- and/or output devices.
-
- @param stream The address of a PaStream pointer which will receive
- a pointer to the newly opened stream.
- 
- @param numInputChannels  The number of channels of sound that will be supplied
- to the stream callback or returned by Pa_ReadStream. It can range from 1 to
- the value of maxInputChannels in the PaDeviceInfo record for the default input
- device. If 0 the stream is opened as an output-only stream.
-
- @param numOutputChannels The number of channels of sound to be delivered to the
- stream callback or passed to Pa_WriteStream. It can range from 1 to the value
- of maxOutputChannels in the PaDeviceInfo record for the default output dvice.
- If 0 the stream is opened as an output-only stream.
-
- @param sampleFormat The sample format of both the input and output buffers
- provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream.
- sampleFormat may be any of the formats described by the PaSampleFormat
- enumeration.
- 
- @param sampleRate Same as Pa_OpenStream parameter of the same name.
- @param framesPerBuffer Same as Pa_OpenStream parameter of the same name.
- @param streamCallback Same as Pa_OpenStream parameter of the same name.
- @param userData Same as Pa_OpenStream parameter of the same name.
-
- @return As for Pa_OpenStream
-
- @see Pa_OpenStream, PaStreamCallback
-*/
-PaError Pa_OpenDefaultStream( PaStream** stream,
-                              int numInputChannels,
-                              int numOutputChannels,
-                              PaSampleFormat sampleFormat,
-                              double sampleRate,
-                              unsigned long framesPerBuffer,
-                              PaStreamCallback *streamCallback,
-                              void *userData );
-
-
-/** Closes an audio stream. If the audio stream is active it
- discards any pending buffers as if Pa_AbortStream() had been called.
-*/
-PaError Pa_CloseStream( PaStream *stream );
-
-
-/** Functions of type PaStreamFinishedCallback are implemented by PortAudio 
- clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback
- function. Once registered they are called when the stream becomes inactive
- (ie once a call to Pa_StopStream() will not block).
- A stream will become inactive after the stream callback returns non-zero,
- or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio
- output, if the stream callback returns paComplete, or Pa_StopStream is called,
- the stream finished callback will not be called until all generated sample data
- has been played.
- 
- @param userData The userData parameter supplied to Pa_OpenStream()
-
- @see Pa_SetStreamFinishedCallback
-*/
-typedef void PaStreamFinishedCallback( void *userData );
-
-
-/** Register a stream finished callback function which will be called when the 
- stream becomes inactive. See the description of PaStreamFinishedCallback for 
- further details about when the callback will be called.
-
- @param stream a pointer to a PaStream that is in the stopped state - if the
- stream is not stopped, the stream's finished callback will remain unchanged 
- and an error code will be returned.
-
- @param streamFinishedCallback a pointer to a function with the same signature
- as PaStreamFinishedCallback, that will be called when the stream becomes
- inactive. Passing NULL for this parameter will un-register a previously
- registered stream finished callback function.
-
- @return on success returns paNoError, otherwise an error code indicating the cause
- of the error.
-
- @see PaStreamFinishedCallback
-*/
-PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); 
-
-
-/** Commences audio processing.
-*/
-PaError Pa_StartStream( PaStream *stream );
-
-
-/** Terminates audio processing. It waits until all pending
- audio buffers have been played before it returns.
-*/
-PaError Pa_StopStream( PaStream *stream );
-
-
-/** Terminates audio processing immediately without waiting for pending
- buffers to complete.
-*/
-PaError Pa_AbortStream( PaStream *stream );
-
-
-/** Determine whether the stream is stopped.
- A stream is considered to be stopped prior to a successful call to
- Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream.
- If a stream callback returns a value other than paContinue the stream is NOT
- considered to be stopped.
-
- @return Returns one (1) when the stream is stopped, zero (0) when
- the stream is running or, a PaErrorCode (which are always negative) if
- PortAudio is not initialized or an error is encountered.
-
- @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive
-*/
-PaError Pa_IsStreamStopped( PaStream *stream );
-
-
-/** Determine whether the stream is active.
- A stream is active after a successful call to Pa_StartStream(), until it
- becomes inactive either as a result of a call to Pa_StopStream() or
- Pa_AbortStream(), or as a result of a return value other than paContinue from
- the stream callback. In the latter case, the stream is considered inactive
- after the last buffer has finished playing.
-
- @return Returns one (1) when the stream is active (ie playing or recording
- audio), zero (0) when not playing or, a PaErrorCode (which are always negative)
- if PortAudio is not initialized or an error is encountered.
-
- @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped
-*/
-PaError Pa_IsStreamActive( PaStream *stream );
-
-
-
-/** A structure containing unchanging information about an open stream.
- @see Pa_GetStreamInfo
-*/
-
-typedef struct PaStreamInfo
-{
-    /** this is struct version 1 */
-    int structVersion;
-
-    /** The input latency of the stream in seconds. This value provides the most
-     accurate estimate of input latency available to the implementation. It may
-     differ significantly from the suggestedLatency value passed to Pa_OpenStream().
-     The value of this field will be zero (0.) for output-only streams.
-     @see PaTime
-    */
-    PaTime inputLatency;
-
-    /** The output latency of the stream in seconds. This value provides the most
-     accurate estimate of output latency available to the implementation. It may
-     differ significantly from the suggestedLatency value passed to Pa_OpenStream().
-     The value of this field will be zero (0.) for input-only streams.
-     @see PaTime
-    */
-    PaTime outputLatency;
-
-    /** The sample rate of the stream in Hertz (samples per second). In cases
-     where the hardware sample rate is inaccurate and PortAudio is aware of it,
-     the value of this field may be different from the sampleRate parameter
-     passed to Pa_OpenStream(). If information about the actual hardware sample
-     rate is not available, this field will have the same value as the sampleRate
-     parameter passed to Pa_OpenStream().
-    */
-    double sampleRate;
-    
-} PaStreamInfo;
-
-
-/** Retrieve a pointer to a PaStreamInfo structure containing information
- about the specified stream.
- @return A pointer to an immutable PaStreamInfo structure. If the stream
- parameter invalid, or an error is encountered, the function returns NULL.
-
- @param stream A pointer to an open stream previously created with Pa_OpenStream.
-
- @note PortAudio manages the memory referenced by the returned pointer,
- the client must not manipulate or free the memory. The pointer is only
- guaranteed to be valid until the specified stream is closed.
-
- @see PaStreamInfo
-*/
-const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream );
-
-
-/** Determine the current time for the stream according to the same clock used
- to generate buffer timestamps. This time may be used for syncronising other
- events to the audio stream, for example synchronizing audio to MIDI.
-                                        
- @return The stream's current time in seconds, or 0 if an error occurred.
-
- @see PaTime, PaStreamCallback
-*/
-PaTime Pa_GetStreamTime( PaStream *stream );
-
-
-/** Retrieve CPU usage information for the specified stream.
- The "CPU Load" is a fraction of total CPU time consumed by a callback stream's
- audio processing routines including, but not limited to the client supplied
- stream callback. This function does not work with blocking read/write streams.
-
- This function may be called from the stream callback function or the
- application.
-     
- @return
- A floating point value, typically between 0.0 and 1.0, where 1.0 indicates
- that the stream callback is consuming the maximum number of CPU cycles possible
- to maintain real-time operation. A value of 0.5 would imply that PortAudio and
- the stream callback was consuming roughly 50% of the available CPU time. The
- return value may exceed 1.0. A value of 0.0 will always be returned for a
- blocking read/write stream, or if an error occurrs.
-*/
-double Pa_GetStreamCpuLoad( PaStream* stream );
-
-
-/** Read samples from an input stream. The function doesn't return until
- the entire buffer has been filled - this may involve waiting for the operating
- system to supply the data.
-
- @param stream A pointer to an open stream previously created with Pa_OpenStream.
- 
- @param buffer A pointer to a buffer of sample frames. The buffer contains
- samples in the format specified by the inputParameters->sampleFormat field
- used to open the stream, and the number of channels specified by
- inputParameters->numChannels. If non-interleaved samples were requested,
- buffer is a pointer to the first element of an array of non-interleaved
- buffer pointers, one for each channel.
-
- @param frames The number of frames to be read into buffer. This parameter
- is not constrained to a specific range, however high performance applications
- will want to match this parameter to the framesPerBuffer parameter used
- when opening the stream.
-
- @return On success PaNoError will be returned, or PaInputOverflowed if input
- data was discarded by PortAudio after the previous call and before this call.
-*/
-PaError Pa_ReadStream( PaStream* stream,
-                       void *buffer,
-                       unsigned long frames );
-
-
-/** Write samples to an output stream. This function doesn't return until the
- entire buffer has been consumed - this may involve waiting for the operating
- system to consume the data.
-
- @param stream A pointer to an open stream previously created with Pa_OpenStream.
-
- @param buffer A pointer to a buffer of sample frames. The buffer contains
- samples in the format specified by the outputParameters->sampleFormat field
- used to open the stream, and the number of channels specified by
- outputParameters->numChannels. If non-interleaved samples were requested,
- buffer is a pointer to the first element of an array of non-interleaved
- buffer pointers, one for each channel.
-
- @param frames The number of frames to be written from buffer. This parameter
- is not constrained to a specific range, however high performance applications
- will want to match this parameter to the framesPerBuffer parameter used
- when opening the stream.
-
- @return On success PaNoError will be returned, or paOutputUnderflowed if
- additional output data was inserted after the previous call and before this
- call.
-*/
-PaError Pa_WriteStream( PaStream* stream,
-                        const void *buffer,
-                        unsigned long frames );
-
-
-/** Retrieve the number of frames that can be read from the stream without
- waiting.
-
- @return Returns a non-negative value representing the maximum number of frames
- that can be read from the stream without blocking or busy waiting or, a
- PaErrorCode (which are always negative) if PortAudio is not initialized or an
- error is encountered.
-*/
-signed long Pa_GetStreamReadAvailable( PaStream* stream );
-
-
-/** Retrieve the number of frames that can be written to the stream without
- waiting.
-
- @return Returns a non-negative value representing the maximum number of frames
- that can be written to the stream without blocking or busy waiting or, a
- PaErrorCode (which are always negative) if PortAudio is not initialized or an
- error is encountered.
-*/
-signed long Pa_GetStreamWriteAvailable( PaStream* stream );
-
-
-/* Miscellaneous utilities */
-
-
-/** Retrieve the size of a given sample format in bytes.
-
- @return The size in bytes of a single sample in the specified format,
- or paSampleFormatNotSupported if the format is not supported.
-*/
-PaError Pa_GetSampleSize( PaSampleFormat format );
-
-
-/** Put the caller to sleep for at least 'msec' milliseconds. This function is
- provided only as a convenience for authors of portable code (such as the tests
- and examples in the PortAudio distribution.)
-
- The function may sleep longer than requested so don't rely on this for accurate
- musical timing.
-*/
-void Pa_Sleep( long msec );
-
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PORTAUDIO_H */
+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef PORTAUDIO_H

+#define PORTAUDIO_H

+/*

+ * $Id: portaudio.h,v 1.5.2.50 2004/12/13 11:50:40 rossbencina Exp $

+ * PortAudio Portable Real-Time Audio Library

+ * PortAudio API Header File

+ * Latest version available at: http://www.portaudio.com/

+ *

+ * Copyright (c) 1999-2002 Ross Bencina and Phil Burk

+ *

+ * Permission is hereby granted, free of charge, to any person obtaining

+ * a copy of this software and associated documentation files

+ * (the "Software"), to deal in the Software without restriction,

+ * including without limitation the rights to use, copy, modify, merge,

+ * publish, distribute, sublicense, and/or sell copies of the Software,

+ * and to permit persons to whom the Software is furnished to do so,

+ * subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be

+ * included in all copies or substantial portions of the Software.

+ *

+ * Any person wishing to distribute modifications to the Software is

+ * requested to send the modifications to the original developer so that

+ * they can be incorporated into the canonical version.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR

+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF

+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ */

+

+/** @file

+ @brief The PortAudio API.

+*/

+

+

+#ifdef __cplusplus

+extern "C"

+{

+#endif /* __cplusplus */

+

+ 

+/** Retrieve the release number of the currently running PortAudio build,

+ eg 1900.

+*/

+int Pa_GetVersion( void );

+

+

+/** Retrieve a textual description of the current PortAudio build,

+ eg "PortAudio V19-devel 13 October 2002".

+*/

+const char* Pa_GetVersionText( void );

+

+

+/** Error codes returned by PortAudio functions.

+ Note that with the exception of paNoError, all PaErrorCodes are negative.

+*/

+

+typedef int PaError;

+typedef enum PaErrorCode

+{

+    paNoError = 0,

+

+    paNotInitialized = -10000,

+    paUnanticipatedHostError,

+    paInvalidChannelCount,

+    paInvalidSampleRate,

+    paInvalidDevice,

+    paInvalidFlag,

+    paSampleFormatNotSupported,

+    paBadIODeviceCombination,

+    paInsufficientMemory,

+    paBufferTooBig,

+    paBufferTooSmall,

+    paNullCallback,

+    paBadStreamPtr,

+    paTimedOut,

+    paInternalError,

+    paDeviceUnavailable,

+    paIncompatibleHostApiSpecificStreamInfo,

+    paStreamIsStopped,

+    paStreamIsNotStopped,

+    paInputOverflowed,

+    paOutputUnderflowed,

+    paHostApiNotFound,

+    paInvalidHostApi,

+    paCanNotReadFromACallbackStream,      /**< @todo review error code name */

+    paCanNotWriteToACallbackStream,       /**< @todo review error code name */

+    paCanNotReadFromAnOutputOnlyStream,   /**< @todo review error code name */

+    paCanNotWriteToAnInputOnlyStream,     /**< @todo review error code name */

+    paIncompatibleStreamHostApi

+} PaErrorCode;

+

+

+/** Translate the supplied PortAudio error code into a human readable

+ message.

+*/

+const char *Pa_GetErrorText( PaError errorCode );

+

+

+/** Library initialization function - call this before using PortAudio.

+ This function initialises internal data structures and prepares underlying

+ host APIs for use. This function MUST be called before using any other

+ PortAudio API functions.

+

+ If Pa_Initialize() is called multiple times, each successful 

+ call must be matched with a corresponding call to Pa_Terminate(). 

+ Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not 

+ required to be fully nested.

+

+ Note that if Pa_Initialize() returns an error code, Pa_Terminate() should

+ NOT be called.

+

+ @return paNoError if successful, otherwise an error code indicating the cause

+ of failure.

+

+ @see Pa_Terminate

+*/

+PaError Pa_Initialize( void );

+

+

+/** Library termination function - call this when finished using PortAudio.

+ This function deallocates all resources allocated by PortAudio since it was

+ initializied by a call to Pa_Initialize(). In cases where Pa_Initialise() has

+ been called multiple times, each call must be matched with a corresponding call

+ to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically

+ close any PortAudio streams that are still open.

+

+ Pa_Terminate() MUST be called before exiting a program which uses PortAudio.

+ Failure to do so may result in serious resource leaks, such as audio devices

+ not being available until the next reboot.

+

+ @return paNoError if successful, otherwise an error code indicating the cause

+ of failure.

+ 

+ @see Pa_Initialize

+*/

+PaError Pa_Terminate( void );

+

+

+

+/** The type used to refer to audio devices. Values of this type usually

+ range from 0 to (Pa_DeviceCount-1), and may also take on the PaNoDevice

+ and paUseHostApiSpecificDeviceSpecification values.

+

+ @see Pa_DeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification

+*/

+typedef int PaDeviceIndex;

+

+

+/** A special PaDeviceIndex value indicating that no device is available,

+ or should be used.

+

+ @see PaDeviceIndex

+*/

+#define paNoDevice ((PaDeviceIndex)-1)

+

+

+/** A special PaDeviceIndex value indicating that the device(s) to be used

+ are specified in the host api specific stream info structure.

+

+ @see PaDeviceIndex

+*/

+#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2)

+

+

+/* Host API enumeration mechanism */

+

+/** The type used to enumerate to host APIs at runtime. Values of this type

+ range from 0 to (Pa_GetHostApiCount()-1).

+

+ @see Pa_GetHostApiCount

+*/

+typedef int PaHostApiIndex;

+

+

+/** Retrieve the number of available host APIs. Even if a host API is

+ available it may have no devices available.

+

+ @return A non-negative value indicating the number of available host APIs

+ or, a PaErrorCode (which are always negative) if PortAudio is not initialized

+ or an error is encountered.

+

+ @see PaHostApiIndex

+*/

+PaHostApiIndex Pa_GetHostApiCount( void );

+

+

+/** Retrieve the index of the default host API. The default host API will be

+ the lowest common denominator host API on the current platform and is

+ unlikely to provide the best performance.

+

+ @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1)

+ indicating the default host API index or, a PaErrorCode (which are always

+ negative) if PortAudio is not initialized or an error is encountered.

+*/

+PaHostApiIndex Pa_GetDefaultHostApi( void );

+

+

+/** Unchanging unique identifiers for each supported host API. This type

+ is used in the PaHostApiInfo structure. The values are guaranteed to be

+ unique and to never change, thus allowing code to be written that

+ conditionally uses host API specific extensions.

+

+ New type ids will be allocated when support for a host API reaches

+ "public alpha" status, prior to that developers should use the

+ paInDevelopment type id.

+

+ @see PaHostApiInfo

+*/

+typedef enum PaHostApiTypeId

+{

+    paInDevelopment=0, /* use while developing support for a new host API */

+    paDirectSound=1,

+    paMME=2,

+    paASIO=3,

+    paSoundManager=4,

+    paCoreAudio=5,

+    paOSS=7,

+    paALSA=8,

+    paAL=9,

+    paBeOS=10,

+    paWDMKS=11,

+    paJACK=12

+} PaHostApiTypeId;

+

+

+/** A structure containing information about a particular host API. */

+

+typedef struct PaHostApiInfo

+{

+    /** this is struct version 1 */

+    int structVersion;

+    /** The well known unique identifier of this host API @see PaHostApiTypeId */

+    PaHostApiTypeId type;

+    /** A textual description of the host API for display on user interfaces. */

+    const char *name;

+

+    /**  The number of devices belonging to this host API. This field may be

+     used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate

+     all devices for this host API.

+     @see Pa_HostApiDeviceIndexToDeviceIndex

+    */

+    int deviceCount;

+

+    /** The the default input device for this host API. The value will be a

+     device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice

+     if no default input device is available.

+    */

+    PaDeviceIndex defaultInputDevice;

+

+    /** The the default output device for this host API. The value will be a

+     device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice

+     if no default output device is available.

+    */

+    PaDeviceIndex defaultOutputDevice;

+    

+} PaHostApiInfo;

+

+

+/** Retrieve a pointer to a structure containing information about a specific

+ host Api.

+

+ @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1)

+

+ @return A pointer to an immutable PaHostApiInfo structure describing

+ a specific host API. If the hostApi parameter is out of range or an error

+ is encountered, the function returns NULL.

+

+ The returned structure is owned by the PortAudio implementation and must not

+ be manipulated or freed. The pointer is only guaranteed to be valid between

+ calls to Pa_Initialize() and Pa_Terminate().

+*/

+const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi );

+

+

+/** Convert a static host API unique identifier, into a runtime

+ host API index.

+

+ @param type A unique host API identifier belonging to the PaHostApiTypeId

+ enumeration.

+

+ @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or,

+ a PaErrorCode (which are always negative) if PortAudio is not initialized

+ or an error is encountered.

+ 

+ The paHostApiNotFound error code indicates that the host API specified by the

+ type parameter is not available.

+

+ @see PaHostApiTypeId

+*/

+PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type );

+

+

+/** Convert a host-API-specific device index to standard PortAudio device index.

+ This function may be used in conjunction with the deviceCount field of

+ PaHostApiInfo to enumerate all devices for the specified host API.

+

+ @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1)

+

+ @param hostApiDeviceIndex A valid per-host device index in the range

+ 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1)

+

+ @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1)

+ or, a PaErrorCode (which are always negative) if PortAudio is not initialized

+ or an error is encountered.

+

+ A paInvalidHostApi error code indicates that the host API index specified by

+ the hostApi parameter is out of range.

+

+ A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter

+ is out of range.

+ 

+ @see PaHostApiInfo

+*/

+PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi,

+        int hostApiDeviceIndex );

+

+

+

+/** Structure used to return information about a host error condition.

+*/

+typedef struct PaHostErrorInfo{

+    PaHostApiTypeId hostApiType;    /**< the host API which returned the error code */

+    long errorCode;                 /**< the error code returned */

+    const char *errorText;          /**< a textual description of the error if available, otherwise a zero-length string */

+}PaHostErrorInfo;

+

+

+/** Return information about the last host error encountered. The error

+ information returned by Pa_GetLastHostErrorInfo() will never be modified

+ asyncronously by errors occurring in other PortAudio owned threads

+ (such as the thread that manages the stream callback.)

+

+ This function is provided as a last resort, primarily to enhance debugging

+ by providing clients with access to all available error information.

+

+ @return A pointer to an immutable structure constaining information about

+ the host error. The values in this structure will only be valid if a

+ PortAudio function has previously returned the paUnanticipatedHostError

+ error code.

+*/

+const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void );

+

+

+

+/* Device enumeration and capabilities */

+

+/** Retrieve the number of available devices. The number of available devices

+ may be zero.

+

+ @return A non-negative value indicating the number of available devices or,

+ a PaErrorCode (which are always negative) if PortAudio is not initialized

+ or an error is encountered.

+*/

+PaDeviceIndex Pa_GetDeviceCount( void );

+

+

+/** Retrieve the index of the default input device. The result can be

+ used in the inputDevice parameter to Pa_OpenStream().

+

+ @return The default input device index for the default host API, or paNoDevice

+ if no default input device is available or an error was encountered.

+*/

+PaDeviceIndex Pa_GetDefaultInputDevice( void );

+

+

+/** Retrieve the index of the default output device. The result can be

+ used in the outputDevice parameter to Pa_OpenStream().

+

+ @return The default output device index for the defualt host API, or paNoDevice

+ if no default output device is available or an error was encountered.

+

+ @note

+ On the PC, the user can specify a default device by

+ setting an environment variable. For example, to use device #1.

+<pre>

+ set PA_RECOMMENDED_OUTPUT_DEVICE=1

+</pre>

+ The user should first determine the available device ids by using

+ the supplied application "pa_devs".

+*/

+PaDeviceIndex Pa_GetDefaultOutputDevice( void );

+

+

+/** The type used to represent monotonic time in seconds that can be used

+ for syncronisation. The type is used for the outTime argument to the

+ PaStreamCallback and as the result of Pa_GetStreamTime().

+     

+ @see PaStreamCallback, Pa_GetStreamTime

+*/

+typedef double PaTime;

+

+

+/** A type used to specify one or more sample formats. Each value indicates

+ a possible format for sound data passed to and from the stream callback,

+ Pa_ReadStream and Pa_WriteStream.

+

+ The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8

+ and aUInt8 are usually implemented by all implementations.

+

+ The floating point representation (paFloat32) uses +1.0 and -1.0 as the

+ maximum and minimum respectively.

+

+ paUInt8 is an unsigned 8 bit format where 128 is considered "ground"

+

+ The paNonInterleaved flag indicates that a multichannel buffer is passed

+ as a set of non-interleaved pointers.

+

+ @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo

+ @see paFloat32, paInt16, paInt32, paInt24, paInt8

+ @see paUInt8, paCustomFormat, paNonInterleaved

+*/

+typedef unsigned long PaSampleFormat;

+

+

+#define paFloat32        ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */

+#define paInt32          ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */

+#define paInt24          ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */

+#define paInt16          ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */

+#define paInt8           ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */

+#define paUInt8          ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */

+#define paCustomFormat   ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */

+

+#define paNonInterleaved ((PaSampleFormat) 0x80000000)

+

+/** A structure providing information and capabilities of PortAudio devices.

+ Devices may support input, output or both input and output.

+*/

+typedef struct PaDeviceInfo

+{

+    int structVersion;  /* this is struct version 2 */

+    const char *name;

+    PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/

+    

+    int maxInputChannels;

+    int maxOutputChannels;

+

+    /* Default latency values for interactive performance. */

+    PaTime defaultLowInputLatency;

+    PaTime defaultLowOutputLatency;

+    /* Default latency values for robust non-interactive applications (eg. playing sound files). */

+    PaTime defaultHighInputLatency;

+    PaTime defaultHighOutputLatency;

+

+    double defaultSampleRate;

+} PaDeviceInfo;

+

+

+/** Retrieve a pointer to a PaDeviceInfo structure containing information

+ about the specified device.

+ @return A pointer to an immutable PaDeviceInfo structure. If the device

+ parameter is out of range the function returns NULL.

+

+ @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1)

+

+ @note PortAudio manages the memory referenced by the returned pointer,

+ the client must not manipulate or free the memory. The pointer is only

+ guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate().

+

+ @see PaDeviceInfo, PaDeviceIndex

+*/

+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device );

+

+

+/** Parameters for one direction (input or output) of a stream.

+*/

+typedef struct PaStreamParameters

+{

+    /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1)

+     specifying the device to be used or the special constant

+     paUseHostApiSpecificDeviceSpecification which indicates that the actual

+     device(s) to use are specified in hostApiSpecificStreamInfo.

+     This field must not be set to paNoDevice.

+    */

+    PaDeviceIndex device;

+    

+    /** The number of channels of sound to be delivered to the

+     stream callback or accessed by Pa_ReadStream() or Pa_WriteStream().

+     It can range from 1 to the value of maxInputChannels in the

+     PaDeviceInfo record for the device specified by the device parameter.

+    */

+    int channelCount;

+

+    /** The sample format of the buffer provided to the stream callback,

+     a_ReadStream() or Pa_WriteStream(). It may be any of the formats described

+     by the PaSampleFormat enumeration.

+    */

+    PaSampleFormat sampleFormat;

+

+    /** The desired latency in seconds. Where practical, implementations should

+     configure their latency based on these parameters, otherwise they may

+     choose the closest viable latency instead. Unless the suggested latency

+     is greater than the absolute upper limit for the device implementations

+     shouldround the suggestedLatency up to the next practial value - ie to

+     provide an equal or higher latency than suggestedLatency whereever possibe.

+     Actual latency values for an open stream may be retrieved using the

+     inputLatency and outputLatency fields of the PaStreamInfo structure

+     returned by Pa_GetStreamInfo().

+     @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo

+    */

+    PaTime suggestedLatency;

+

+    /** An optional pointer to a host api specific data structure

+     containing additional information for device setup and/or stream processing.

+     hostApiSpecificStreamInfo is never required for correct operation,

+     if not used it should be set to NULL.

+    */

+    void *hostApiSpecificStreamInfo;

+

+} PaStreamParameters;

+

+

+/** Return code for Pa_IsFormatSupported indicating success. */

+#define paFormatIsSupported (0)

+

+/** Determine whether it would be possible to open a stream with the specified

+ parameters.

+

+ @param inputParameters A structure that describes the input parameters used to

+ open a stream. The suggestedLatency field is ignored. See PaStreamParameters

+ for a description of these parameters. inputParameters must be NULL for

+ output-only streams.

+

+ @param outputParameters A structure that describes the output parameters used

+ to open a stream. The suggestedLatency field is ignored. See PaStreamParameters

+ for a description of these parameters. outputParameters must be NULL for

+ input-only streams.

+

+ @param sampleRate The required sampleRate. For full-duplex streams it is the

+ sample rate for both input and output

+

+ @return Returns 0 if the format is supported, and an error code indicating why

+ the format is not supported otherwise. The constant paFormatIsSupported is

+ provided to compare with the return value for success.

+

+ @see paFormatIsSupported, PaStreamParameters

+*/

+PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,

+                              const PaStreamParameters *outputParameters,

+                              double sampleRate );

+

+

+

+/* Streaming types and functions */

+

+

+/**

+ A single PaStream can provide multiple channels of real-time

+ streaming audio input and output to a client application. A stream

+ provides access to audio hardware represented by one or more

+ PaDevices. Depending on the underlying Host API, it may be possible 

+ to open multiple streams using the same device, however this behavior 

+ is implementation defined. Portable applications should assume that 

+ a PaDevice may be simultaneously used by at most one PaStream.

+

+ Pointers to PaStream objects are passed between PortAudio functions that

+ operate on streams.

+

+ @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream,

+ Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive,

+ Pa_GetStreamTime, Pa_GetStreamCpuLoad

+

+*/

+typedef void PaStream;

+

+

+/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream()

+ or Pa_OpenDefaultStream() to indicate that the stream callback will

+ accept buffers of any size.

+*/

+#define paFramesPerBufferUnspecified  (0)

+

+

+/** Flags used to control the behavior of a stream. They are passed as

+ parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be

+ ORed together.

+

+ @see Pa_OpenStream, Pa_OpenDefaultStream

+ @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput,

+  paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags

+*/

+typedef unsigned long PaStreamFlags;

+

+/** @see PaStreamFlags */

+#define   paNoFlag          ((PaStreamFlags) 0)

+

+/** Disable default clipping of out of range samples.

+ @see PaStreamFlags

+*/

+#define   paClipOff         ((PaStreamFlags) 0x00000001)

+

+/** Disable default dithering.

+ @see PaStreamFlags

+*/

+#define   paDitherOff       ((PaStreamFlags) 0x00000002)

+

+/** Flag requests that where possible a full duplex stream will not discard

+ overflowed input samples without calling the stream callback. This flag is

+ only valid for full duplex callback streams and only when used in combination

+ with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using

+ this flag incorrectly results in a paInvalidFlag error being returned from

+ Pa_OpenStream and Pa_OpenDefaultStream.

+

+ @see PaStreamFlags, paFramesPerBufferUnspecified

+*/

+#define   paNeverDropInput  ((PaStreamFlags) 0x00000004)

+

+/** Call the stream callback to fill initial output buffers, rather than the

+ default behavior of priming the buffers with zeros (silence). This flag has

+ no effect for input-only and blocking read/write streams.

+ 

+ @see PaStreamFlags

+*/

+#define   paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008)

+

+/** A mask specifying the platform specific bits.

+ @see PaStreamFlags

+*/

+#define   paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000)

+

+/**

+ Timing information for the buffers passed to the stream callback.

+*/

+typedef struct PaStreamCallbackTimeInfo{

+    PaTime inputBufferAdcTime;

+    PaTime currentTime;

+    PaTime outputBufferDacTime;

+} PaStreamCallbackTimeInfo;

+

+

+/**

+ Flag bit constants for the statusFlags to PaStreamCallback.

+

+ @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow,

+ paPrimingOutput

+*/

+typedef unsigned long PaStreamCallbackFlags;

+

+/** In a stream opened with paFramesPerBufferUnspecified, indicates that

+ input data is all silence (zeros) because no real data is available. In a

+ stream opened without paFramesPerBufferUnspecified, it indicates that one or

+ more zero samples have been inserted into the input buffer to compensate

+ for an input underflow.

+ @see PaStreamCallbackFlags

+*/

+#define paInputUnderflow   ((PaStreamCallbackFlags) 0x00000001)

+

+/** In a stream opened with paFramesPerBufferUnspecified, indicates that data

+ prior to the first sample of the input buffer was discarded due to an

+ overflow, possibly because the stream callback is using too much CPU time.

+ Otherwise indicates that data prior to one or more samples in the

+ input buffer was discarded.

+ @see PaStreamCallbackFlags

+*/

+#define paInputOverflow    ((PaStreamCallbackFlags) 0x00000002)

+

+/** Indicates that output data (or a gap) was inserted, possibly because the

+ stream callback is using too much CPU time.

+ @see PaStreamCallbackFlags

+*/

+#define paOutputUnderflow  ((PaStreamCallbackFlags) 0x00000004)

+

+/** Indicates that output data will be discarded because no room is available.

+ @see PaStreamCallbackFlags

+*/

+#define paOutputOverflow   ((PaStreamCallbackFlags) 0x00000008)

+

+/** Some of all of the output data will be used to prime the stream, input

+ data may be zero.

+ @see PaStreamCallbackFlags

+*/

+#define paPrimingOutput    ((PaStreamCallbackFlags) 0x00000010)

+

+/**

+ Allowable return values for the PaStreamCallback.

+ @see PaStreamCallback

+*/

+typedef enum PaStreamCallbackResult

+{

+    paContinue=0,

+    paComplete=1,

+    paAbort=2

+} PaStreamCallbackResult;

+

+

+/**

+ Functions of type PaStreamCallback are implemented by PortAudio clients.

+ They consume, process or generate audio in response to requests from an

+ active PortAudio stream.

+     

+ @param input and @param output are arrays of interleaved samples,

+ the format, packing and number of channels used by the buffers are

+ determined by parameters to Pa_OpenStream().

+     

+ @param frameCount The number of sample frames to be processed by

+ the stream callback.

+

+ @param timeInfo The time in seconds when the first sample of the input

+ buffer was received at the audio input, the time in seconds when the first

+ sample of the output buffer will begin being played at the audio output, and

+ the time in seconds when the stream callback was called.

+ See also Pa_GetStreamTime()

+

+ @param statusFlags Flags indicating whether input and/or output buffers

+ have been inserted or will be dropped to overcome underflow or overflow

+ conditions.

+

+ @param userData The value of a user supplied pointer passed to

+ Pa_OpenStream() intended for storing synthesis data etc.

+

+ @return

+ The stream callback should return one of the values in the

+ PaStreamCallbackResult enumeration. To ensure that the callback continues

+ to be called, it should return paContinue (0). Either paComplete or paAbort

+ can be returned to finish stream processing, after either of these values is

+ returned the callback will not be called again. If paAbort is returned the

+ stream will finish as soon as possible. If paComplete is returned, the stream

+ will continue until all buffers generated by the callback have been played.

+ This may be useful in applications such as soundfile players where a specific

+ duration of output is required. However, it is not necessary to utilise this

+ mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also

+ be used to stop the stream. The callback must always fill the entire output

+ buffer irrespective of its return value.

+

+ @see Pa_OpenStream, Pa_OpenDefaultStream

+

+ @note With the exception of Pa_GetStreamCpuLoad() it is not permissable to call

+ PortAudio API functions from within the stream callback.

+*/

+typedef int PaStreamCallback(

+    const void *input, void *output,

+    unsigned long frameCount,

+    const PaStreamCallbackTimeInfo* timeInfo,

+    PaStreamCallbackFlags statusFlags,

+    void *userData );

+

+

+/** Opens a stream for either input, output or both.

+     

+ @param stream The address of a PaStream pointer which will receive

+ a pointer to the newly opened stream.

+     

+ @param inputParameters A structure that describes the input parameters used by

+ the opened stream. See PaStreamParameters for a description of these parameters.

+ inputParameters must be NULL for output-only streams.

+

+ @param outputParameters A structure that describes the output parameters used by

+ the opened stream. See PaStreamParameters for a description of these parameters.

+ outputParameters must be NULL for input-only streams.

+ 

+ @param sampleRate The desired sampleRate. For full-duplex streams it is the

+ sample rate for both input and output

+     

+ @param framesPerBuffer The number of frames passed to the stream callback

+ function, or the preferred block granularity for a blocking read/write stream.

+ The special value paFramesPerBufferUnspecified (0) may be used to request that

+ the stream callback will recieve an optimal (and possibly varying) number of

+ frames based on host requirements and the requested latency settings.

+ Note: With some host APIs, the use of non-zero framesPerBuffer for a callback

+ stream may introduce an additional layer of buffering which could introduce

+ additional latency. PortAudio guarantees that the additional latency

+ will be kept to the theoretical minimum however, it is strongly recommended

+ that a non-zero framesPerBuffer value only be used when your algorithm

+ requires a fixed number of frames per stream callback.

+ 

+ @param streamFlags Flags which modify the behaviour of the streaming process.

+ This parameter may contain a combination of flags ORed together. Some flags may

+ only be relevant to certain buffer formats.

+     

+ @param streamCallback A pointer to a client supplied function that is responsible

+ for processing and filling input and output buffers. If this parameter is NULL

+ the stream will be opened in 'blocking read/write' mode. In blocking mode,

+ the client can receive sample data using Pa_ReadStream and write sample data

+ using Pa_WriteStream, the number of samples that may be read or written

+ without blocking is returned by Pa_GetStreamReadAvailable and

+ Pa_GetStreamWriteAvailable respectively.

+

+ @param userData A client supplied pointer which is passed to the stream callback

+ function. It could for example, contain a pointer to instance data necessary

+ for processing the audio buffers. This parameter is ignored if streamCallback

+ is NULL.

+     

+ @return

+ Upon success Pa_OpenStream() returns paNoError and places a pointer to a

+ valid PaStream in the stream argument. The stream is inactive (stopped).

+ If a call to Pa_OpenStream() fails, a non-zero error code is returned (see

+ PaError for possible error codes) and the value of stream is invalid.

+

+ @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream,

+ Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable

+*/

+PaError Pa_OpenStream( PaStream** stream,

+                       const PaStreamParameters *inputParameters,

+                       const PaStreamParameters *outputParameters,

+                       double sampleRate,

+                       unsigned long framesPerBuffer,

+                       PaStreamFlags streamFlags,

+                       PaStreamCallback *streamCallback,

+                       void *userData );

+

+

+/** A simplified version of Pa_OpenStream() that opens the default input

+ and/or output devices.

+

+ @param stream The address of a PaStream pointer which will receive

+ a pointer to the newly opened stream.

+ 

+ @param numInputChannels  The number of channels of sound that will be supplied

+ to the stream callback or returned by Pa_ReadStream. It can range from 1 to

+ the value of maxInputChannels in the PaDeviceInfo record for the default input

+ device. If 0 the stream is opened as an output-only stream.

+

+ @param numOutputChannels The number of channels of sound to be delivered to the

+ stream callback or passed to Pa_WriteStream. It can range from 1 to the value

+ of maxOutputChannels in the PaDeviceInfo record for the default output dvice.

+ If 0 the stream is opened as an output-only stream.

+

+ @param sampleFormat The sample format of both the input and output buffers

+ provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream.

+ sampleFormat may be any of the formats described by the PaSampleFormat

+ enumeration.

+ 

+ @param sampleRate Same as Pa_OpenStream parameter of the same name.

+ @param framesPerBuffer Same as Pa_OpenStream parameter of the same name.

+ @param streamCallback Same as Pa_OpenStream parameter of the same name.

+ @param userData Same as Pa_OpenStream parameter of the same name.

+

+ @return As for Pa_OpenStream

+

+ @see Pa_OpenStream, PaStreamCallback

+*/

+PaError Pa_OpenDefaultStream( PaStream** stream,

+                              int numInputChannels,

+                              int numOutputChannels,

+                              PaSampleFormat sampleFormat,

+                              double sampleRate,

+                              unsigned long framesPerBuffer,

+                              PaStreamCallback *streamCallback,

+                              void *userData );

+

+

+/** Closes an audio stream. If the audio stream is active it

+ discards any pending buffers as if Pa_AbortStream() had been called.

+*/

+PaError Pa_CloseStream( PaStream *stream );

+

+

+/** Functions of type PaStreamFinishedCallback are implemented by PortAudio 

+ clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback

+ function. Once registered they are called when the stream becomes inactive

+ (ie once a call to Pa_StopStream() will not block).

+ A stream will become inactive after the stream callback returns non-zero,

+ or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio

+ output, if the stream callback returns paComplete, or Pa_StopStream is called,

+ the stream finished callback will not be called until all generated sample data

+ has been played.

+ 

+ @param userData The userData parameter supplied to Pa_OpenStream()

+

+ @see Pa_SetStreamFinishedCallback

+*/

+typedef void PaStreamFinishedCallback( void *userData );

+

+

+/** Register a stream finished callback function which will be called when the 

+ stream becomes inactive. See the description of PaStreamFinishedCallback for 

+ further details about when the callback will be called.

+

+ @param stream a pointer to a PaStream that is in the stopped state - if the

+ stream is not stopped, the stream's finished callback will remain unchanged 

+ and an error code will be returned.

+

+ @param streamFinishedCallback a pointer to a function with the same signature

+ as PaStreamFinishedCallback, that will be called when the stream becomes

+ inactive. Passing NULL for this parameter will un-register a previously

+ registered stream finished callback function.

+

+ @return on success returns paNoError, otherwise an error code indicating the cause

+ of the error.

+

+ @see PaStreamFinishedCallback

+*/

+PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); 

+

+

+/** Commences audio processing.

+*/

+PaError Pa_StartStream( PaStream *stream );

+

+

+/** Terminates audio processing. It waits until all pending

+ audio buffers have been played before it returns.

+*/

+PaError Pa_StopStream( PaStream *stream );

+

+

+/** Terminates audio processing immediately without waiting for pending

+ buffers to complete.

+*/

+PaError Pa_AbortStream( PaStream *stream );

+

+

+/** Determine whether the stream is stopped.

+ A stream is considered to be stopped prior to a successful call to

+ Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream.

+ If a stream callback returns a value other than paContinue the stream is NOT

+ considered to be stopped.

+

+ @return Returns one (1) when the stream is stopped, zero (0) when

+ the stream is running or, a PaErrorCode (which are always negative) if

+ PortAudio is not initialized or an error is encountered.

+

+ @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive

+*/

+PaError Pa_IsStreamStopped( PaStream *stream );

+

+

+/** Determine whether the stream is active.

+ A stream is active after a successful call to Pa_StartStream(), until it

+ becomes inactive either as a result of a call to Pa_StopStream() or

+ Pa_AbortStream(), or as a result of a return value other than paContinue from

+ the stream callback. In the latter case, the stream is considered inactive

+ after the last buffer has finished playing.

+

+ @return Returns one (1) when the stream is active (ie playing or recording

+ audio), zero (0) when not playing or, a PaErrorCode (which are always negative)

+ if PortAudio is not initialized or an error is encountered.

+

+ @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped

+*/

+PaError Pa_IsStreamActive( PaStream *stream );

+

+

+

+/** A structure containing unchanging information about an open stream.

+ @see Pa_GetStreamInfo

+*/

+

+typedef struct PaStreamInfo

+{

+    /** this is struct version 1 */

+    int structVersion;

+

+    /** The input latency of the stream in seconds. This value provides the most

+     accurate estimate of input latency available to the implementation. It may

+     differ significantly from the suggestedLatency value passed to Pa_OpenStream().

+     The value of this field will be zero (0.) for output-only streams.

+     @see PaTime

+    */

+    PaTime inputLatency;

+

+    /** The output latency of the stream in seconds. This value provides the most

+     accurate estimate of output latency available to the implementation. It may

+     differ significantly from the suggestedLatency value passed to Pa_OpenStream().

+     The value of this field will be zero (0.) for input-only streams.

+     @see PaTime

+    */

+    PaTime outputLatency;

+

+    /** The sample rate of the stream in Hertz (samples per second). In cases

+     where the hardware sample rate is inaccurate and PortAudio is aware of it,

+     the value of this field may be different from the sampleRate parameter

+     passed to Pa_OpenStream(). If information about the actual hardware sample

+     rate is not available, this field will have the same value as the sampleRate

+     parameter passed to Pa_OpenStream().

+    */

+    double sampleRate;

+    

+} PaStreamInfo;

+

+

+/** Retrieve a pointer to a PaStreamInfo structure containing information

+ about the specified stream.

+ @return A pointer to an immutable PaStreamInfo structure. If the stream

+ parameter invalid, or an error is encountered, the function returns NULL.

+

+ @param stream A pointer to an open stream previously created with Pa_OpenStream.

+

+ @note PortAudio manages the memory referenced by the returned pointer,

+ the client must not manipulate or free the memory. The pointer is only

+ guaranteed to be valid until the specified stream is closed.

+

+ @see PaStreamInfo

+*/

+const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream );

+

+

+/** Determine the current time for the stream according to the same clock used

+ to generate buffer timestamps. This time may be used for syncronising other

+ events to the audio stream, for example synchronizing audio to MIDI.

+                                        

+ @return The stream's current time in seconds, or 0 if an error occurred.

+

+ @see PaTime, PaStreamCallback

+*/

+PaTime Pa_GetStreamTime( PaStream *stream );

+

+

+/** Retrieve CPU usage information for the specified stream.

+ The "CPU Load" is a fraction of total CPU time consumed by a callback stream's

+ audio processing routines including, but not limited to the client supplied

+ stream callback. This function does not work with blocking read/write streams.

+

+ This function may be called from the stream callback function or the

+ application.

+     

+ @return

+ A floating point value, typically between 0.0 and 1.0, where 1.0 indicates

+ that the stream callback is consuming the maximum number of CPU cycles possible

+ to maintain real-time operation. A value of 0.5 would imply that PortAudio and

+ the stream callback was consuming roughly 50% of the available CPU time. The

+ return value may exceed 1.0. A value of 0.0 will always be returned for a

+ blocking read/write stream, or if an error occurrs.

+*/

+double Pa_GetStreamCpuLoad( PaStream* stream );

+

+

+/** Read samples from an input stream. The function doesn't return until

+ the entire buffer has been filled - this may involve waiting for the operating

+ system to supply the data.

+

+ @param stream A pointer to an open stream previously created with Pa_OpenStream.

+ 

+ @param buffer A pointer to a buffer of sample frames. The buffer contains

+ samples in the format specified by the inputParameters->sampleFormat field

+ used to open the stream, and the number of channels specified by

+ inputParameters->numChannels. If non-interleaved samples were requested,

+ buffer is a pointer to the first element of an array of non-interleaved

+ buffer pointers, one for each channel.

+

+ @param frames The number of frames to be read into buffer. This parameter

+ is not constrained to a specific range, however high performance applications

+ will want to match this parameter to the framesPerBuffer parameter used

+ when opening the stream.

+

+ @return On success PaNoError will be returned, or PaInputOverflowed if input

+ data was discarded by PortAudio after the previous call and before this call.

+*/

+PaError Pa_ReadStream( PaStream* stream,

+                       void *buffer,

+                       unsigned long frames );

+

+

+/** Write samples to an output stream. This function doesn't return until the

+ entire buffer has been consumed - this may involve waiting for the operating

+ system to consume the data.

+

+ @param stream A pointer to an open stream previously created with Pa_OpenStream.

+

+ @param buffer A pointer to a buffer of sample frames. The buffer contains

+ samples in the format specified by the outputParameters->sampleFormat field

+ used to open the stream, and the number of channels specified by

+ outputParameters->numChannels. If non-interleaved samples were requested,

+ buffer is a pointer to the first element of an array of non-interleaved

+ buffer pointers, one for each channel.

+

+ @param frames The number of frames to be written from buffer. This parameter

+ is not constrained to a specific range, however high performance applications

+ will want to match this parameter to the framesPerBuffer parameter used

+ when opening the stream.

+

+ @return On success PaNoError will be returned, or paOutputUnderflowed if

+ additional output data was inserted after the previous call and before this

+ call.

+*/

+PaError Pa_WriteStream( PaStream* stream,

+                        const void *buffer,

+                        unsigned long frames );

+

+

+/** Retrieve the number of frames that can be read from the stream without

+ waiting.

+

+ @return Returns a non-negative value representing the maximum number of frames

+ that can be read from the stream without blocking or busy waiting or, a

+ PaErrorCode (which are always negative) if PortAudio is not initialized or an

+ error is encountered.

+*/

+signed long Pa_GetStreamReadAvailable( PaStream* stream );

+

+

+/** Retrieve the number of frames that can be written to the stream without

+ waiting.

+

+ @return Returns a non-negative value representing the maximum number of frames

+ that can be written to the stream without blocking or busy waiting or, a

+ PaErrorCode (which are always negative) if PortAudio is not initialized or an

+ error is encountered.

+*/

+signed long Pa_GetStreamWriteAvailable( PaStream* stream );

+

+

+/* Miscellaneous utilities */

+

+

+/** Retrieve the size of a given sample format in bytes.

+

+ @return The size in bytes of a single sample in the specified format,

+ or paSampleFormatNotSupported if the format is not supported.

+*/

+PaError Pa_GetSampleSize( PaSampleFormat format );

+

+

+/** Put the caller to sleep for at least 'msec' milliseconds. This function is

+ provided only as a convenience for authors of portable code (such as the tests

+ and examples in the PortAudio distribution.)

+

+ The function may sleep longer than requested so don't rely on this for accurate

+ musical timing.

+*/

+void Pa_Sleep( long msec );

+

+

+

+#ifdef __cplusplus

+}

+#endif /* __cplusplus */

+#endif /* PORTAUDIO_H */

diff --git a/pjmedia/src/pjmedia/rtcp.c b/pjmedia/src/pjmedia/rtcp.c
index 04a4de5..baa05be 100644
--- a/pjmedia/src/pjmedia/rtcp.c
+++ b/pjmedia/src/pjmedia/rtcp.c
@@ -1,202 +1,223 @@
-/* $Id$
- *
- */
-
-#include <pjmedia/rtcp.h>
-#include <pj/os.h>	/* pj_gettimeofday */
-#include <pj/sock.h>	/* pj_htonx, pj_ntohx */
-#include <string.h>	/* memset */
-
-#define RTCP_SR   200
-#define RTCP_RR   201
-
-
-
-/*
- * Get NTP time.
- */
-static void rtcp_get_ntp_time(struct pj_rtcp_ntp_rec *ntp)
-{
-    pj_time_val tv;
-
-    pj_gettimeofday(&tv);
-    
-    ntp->hi = tv.sec;
-    tv.msec = tv.msec % 1000;
-    ntp->lo = tv.msec * 0xFFFF / 1000;
-    ntp->lo <<= 16;
-}
-
-
-PJ_DEF(void) pj_rtcp_init(pj_rtcp_session *s, pj_uint32_t ssrc)
-{
-    pj_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt;
-    
-    memset(rtcp_pkt, 0, sizeof(pj_rtcp_pkt));
-    
-    /* Init time */
-    s->rtcp_lsr.hi = s->rtcp_lsr.lo = 0;
-    s->rtcp_lsr_time = 0;
-    
-    /* Init common RTCP header */
-    rtcp_pkt->common.version = 2;
-    rtcp_pkt->common.count = 1;
-    rtcp_pkt->common.pt = RTCP_SR;
-    rtcp_pkt->common.length = pj_htons(12);
-    
-    /* Init SR */
-    rtcp_pkt->sr.ssrc = pj_htonl(ssrc);
-    
-    /* RR will be initialized on receipt of the first RTP packet. */
-}
-
-PJ_DEF(void) pj_rtcp_fini(pj_rtcp_session *session)
-{
-    /* Nothing to do. */
-    PJ_UNUSED_ARG(session)
-}
-
-static void rtcp_init_seq(pj_rtcp_session *s, pj_uint16_t  seq)
-{
-    s->received = 0;
-    s->expected_prior = 0;
-    s->received_prior = 0;
-    s->transit = 0;
-    s->jitter = 0;
-
-    pj_rtp_seq_restart(&s->seq_ctrl, seq);
-}
-
-PJ_DEF(void) pj_rtcp_rx_rtp(pj_rtcp_session *s, pj_uint16_t seq, pj_uint32_t rtp_ts)
-{   
-    pj_uint32_t arrival;
-    pj_int32_t transit;
-    unsigned long timer_tick;
-    pj_time_val tv;
-    int status;
-
-    /* Update sequence numbers (received, lost, etc). */
-    status = pj_rtp_seq_update(&s->seq_ctrl, seq);
-    if (status == PJ_RTP_ERR_SESSION_RESTARTED) {
-	rtcp_init_seq(s, seq);
-	status = 0;
-    }
-    
-    if (status != 0)
-	return;
-
-    ++s->received;
-
-    pj_gettimeofday(&tv);
-    timer_tick = tv.sec * 1000 + tv.msec;
-    
-    /*
-     * Calculate jitter (s->jitter is in timer tick unit)
-     */
-    PJ_TODO(SUPPORT_JITTER_CALCULATION_FOR_NON_8KHZ_SAMPLE_RATE)
-
-    arrival = timer_tick << 3;	// 8 samples per ms.
-    transit = arrival - rtp_ts;
-    
-    if (s->transit == 0) {
-	s->transit = transit;
-    } else {
-	pj_int32_t d, jitter = s->jitter;
-	
-	d = transit - s->transit;
-	s->transit = transit;
-	if (d < 0) 
-	    d = -d;
-	
-	jitter += d - ((jitter + 8) >> 4);
-	s->jitter = jitter;
-    }
-}
-
-PJ_DEF(void) pj_rtcp_tx_rtp(pj_rtcp_session *s, pj_uint16_t  bytes_payload_size)
-{
-    pj_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt;
-    rtcp_pkt->sr.sender_pcount = pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_pcount) + 1);
-    rtcp_pkt->sr.sender_bcount = pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_bcount) + bytes_payload_size );
-}
-
-static void rtcp_build_rtcp(pj_rtcp_session *s, pj_uint32_t receiver_ssrc)
-{   
-    pj_uint32_t expected;
-    pj_uint32_t u32;
-    pj_uint32_t expected_interval, received_interval, lost_interval;
-    pj_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt;
-    
-    /* SSRC and last_seq */
-    rtcp_pkt->rr.ssrc = pj_htonl(receiver_ssrc);
-    rtcp_pkt->rr.last_seq = (s->seq_ctrl.cycles & 0xFFFF0000L);
-    rtcp_pkt->rr.last_seq += s->seq_ctrl.max_seq;
-    rtcp_pkt->rr.last_seq = pj_htonl(rtcp_pkt->rr.last_seq);
-
-    /* Jitter */
-    rtcp_pkt->rr.jitter = pj_htonl(s->jitter >> 4);
-    
-    /* Total lost. */
-    expected = pj_ntohl(rtcp_pkt->rr.last_seq) - s->seq_ctrl.base_seq + 1;
-    u32 = expected - s->received;
-    rtcp_pkt->rr.total_lost_2 = (u32 >> 16) & 0x00FF;
-    rtcp_pkt->rr.total_lost_1 = (u32 >> 8) & 0x00FF;
-    rtcp_pkt->rr.total_lost_0 = u32 & 0x00FF;
-
-    /* Fraction lost calculation */
-    expected_interval = expected - s->expected_prior;
-    s->expected_prior = expected;
-    
-    received_interval = s->received - s->received_prior;
-    s->received_prior = s->received;
-    
-    lost_interval = expected_interval - received_interval;
-    
-    if (expected_interval==0 || lost_interval == 0) {
-	rtcp_pkt->rr.fract_lost = 0;
-    } else {
-	rtcp_pkt->rr.fract_lost = (lost_interval << 8) / expected_interval;
-    }
-}
-
-PJ_DEF(void) pj_rtcp_build_rtcp(pj_rtcp_session *session, pj_rtcp_pkt **ret_p_pkt, int *len)
-{
-    pj_rtcp_pkt *rtcp_pkt = &session->rtcp_pkt;
-    pj_rtcp_ntp_rec ntp;
-    pj_time_val now;
-    
-    rtcp_build_rtcp(session, session->peer_ssrc);
-    
-    /* Get current NTP time. */
-    rtcp_get_ntp_time(&ntp);
-    
-    /* Fill in NTP timestamp in SR. */
-    rtcp_pkt->sr.ntp_sec = pj_htonl(ntp.hi);
-    rtcp_pkt->sr.ntp_frac = pj_htonl(ntp.lo);
-    
-    if (session->rtcp_lsr_time == 0 || session->rtcp_lsr.lo == 0) {
-	rtcp_pkt->rr.lsr = 0;
-	rtcp_pkt->rr.dlsr = 0;
-    } else {
-	unsigned msec_elapsed;
-	
-	/* Fill in LSR.
-	   LSR is the middle 32bit of the last SR NTP time received.
-	 */
-	rtcp_pkt->rr.lsr = ((session->rtcp_lsr.hi & 0x0000FFFF) << 16) | 
-			   ((session->rtcp_lsr.lo >> 16) & 0xFFFF);
-	rtcp_pkt->rr.lsr = pj_htonl(rtcp_pkt->rr.lsr);
-	
-	/* Fill in DLSR.
-	   DLSR is Delay since Last SR, in 1/65536 seconds.
-	 */
-	pj_gettimeofday(&now);
-	msec_elapsed = (now.msec - session->rtcp_lsr_time);
-	rtcp_pkt->rr.dlsr = pj_htonl((msec_elapsed * 65536) / 1000);
-    }
-    
-    /* Return pointer. */
-    *ret_p_pkt = rtcp_pkt;
-    *len = sizeof(pj_rtcp_pkt);
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#include <pjmedia/rtcp.h>

+#include <pj/os.h>	/* pj_gettimeofday */

+#include <pj/sock.h>	/* pj_htonx, pj_ntohx */

+#include <string.h>	/* memset */

+

+#define RTCP_SR   200

+#define RTCP_RR   201

+

+

+

+/*

+ * Get NTP time.

+ */

+static void rtcp_get_ntp_time(struct pj_rtcp_ntp_rec *ntp)

+{

+    pj_time_val tv;

+

+    pj_gettimeofday(&tv);

+    

+    ntp->hi = tv.sec;

+    tv.msec = tv.msec % 1000;

+    ntp->lo = tv.msec * 0xFFFF / 1000;

+    ntp->lo <<= 16;

+}

+

+

+PJ_DEF(void) pj_rtcp_init(pj_rtcp_session *s, pj_uint32_t ssrc)

+{

+    pj_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt;

+    

+    memset(rtcp_pkt, 0, sizeof(pj_rtcp_pkt));

+    

+    /* Init time */

+    s->rtcp_lsr.hi = s->rtcp_lsr.lo = 0;

+    s->rtcp_lsr_time = 0;

+    

+    /* Init common RTCP header */

+    rtcp_pkt->common.version = 2;

+    rtcp_pkt->common.count = 1;

+    rtcp_pkt->common.pt = RTCP_SR;

+    rtcp_pkt->common.length = pj_htons(12);

+    

+    /* Init SR */

+    rtcp_pkt->sr.ssrc = pj_htonl(ssrc);

+    

+    /* RR will be initialized on receipt of the first RTP packet. */

+}

+

+PJ_DEF(void) pj_rtcp_fini(pj_rtcp_session *session)

+{

+    /* Nothing to do. */

+    PJ_UNUSED_ARG(session)

+}

+

+static void rtcp_init_seq(pj_rtcp_session *s, pj_uint16_t  seq)

+{

+    s->received = 0;

+    s->expected_prior = 0;

+    s->received_prior = 0;

+    s->transit = 0;

+    s->jitter = 0;

+

+    pj_rtp_seq_restart(&s->seq_ctrl, seq);

+}

+

+PJ_DEF(void) pj_rtcp_rx_rtp(pj_rtcp_session *s, pj_uint16_t seq, pj_uint32_t rtp_ts)

+{   

+    pj_uint32_t arrival;

+    pj_int32_t transit;

+    unsigned long timer_tick;

+    pj_time_val tv;

+    int status;

+

+    /* Update sequence numbers (received, lost, etc). */

+    status = pj_rtp_seq_update(&s->seq_ctrl, seq);

+    if (status == PJ_RTP_ERR_SESSION_RESTARTED) {

+	rtcp_init_seq(s, seq);

+	status = 0;

+    }

+    

+    if (status != 0)

+	return;

+

+    ++s->received;

+

+    pj_gettimeofday(&tv);

+    timer_tick = tv.sec * 1000 + tv.msec;

+    

+    /*

+     * Calculate jitter (s->jitter is in timer tick unit)

+     */

+    PJ_TODO(SUPPORT_JITTER_CALCULATION_FOR_NON_8KHZ_SAMPLE_RATE)

+

+    arrival = timer_tick << 3;	// 8 samples per ms.

+    transit = arrival - rtp_ts;

+    

+    if (s->transit == 0) {

+	s->transit = transit;

+    } else {

+	pj_int32_t d, jitter = s->jitter;

+	

+	d = transit - s->transit;

+	s->transit = transit;

+	if (d < 0) 

+	    d = -d;

+	

+	jitter += d - ((jitter + 8) >> 4);

+	s->jitter = jitter;

+    }

+}

+

+PJ_DEF(void) pj_rtcp_tx_rtp(pj_rtcp_session *s, pj_uint16_t  bytes_payload_size)

+{

+    pj_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt;

+    rtcp_pkt->sr.sender_pcount = pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_pcount) + 1);

+    rtcp_pkt->sr.sender_bcount = pj_htonl( pj_ntohl(rtcp_pkt->sr.sender_bcount) + bytes_payload_size );

+}

+

+static void rtcp_build_rtcp(pj_rtcp_session *s, pj_uint32_t receiver_ssrc)

+{   

+    pj_uint32_t expected;

+    pj_uint32_t u32;

+    pj_uint32_t expected_interval, received_interval, lost_interval;

+    pj_rtcp_pkt *rtcp_pkt = &s->rtcp_pkt;

+    

+    /* SSRC and last_seq */

+    rtcp_pkt->rr.ssrc = pj_htonl(receiver_ssrc);

+    rtcp_pkt->rr.last_seq = (s->seq_ctrl.cycles & 0xFFFF0000L);

+    rtcp_pkt->rr.last_seq += s->seq_ctrl.max_seq;

+    rtcp_pkt->rr.last_seq = pj_htonl(rtcp_pkt->rr.last_seq);

+

+    /* Jitter */

+    rtcp_pkt->rr.jitter = pj_htonl(s->jitter >> 4);

+    

+    /* Total lost. */

+    expected = pj_ntohl(rtcp_pkt->rr.last_seq) - s->seq_ctrl.base_seq + 1;

+    u32 = expected - s->received;

+    rtcp_pkt->rr.total_lost_2 = (u32 >> 16) & 0x00FF;

+    rtcp_pkt->rr.total_lost_1 = (u32 >> 8) & 0x00FF;

+    rtcp_pkt->rr.total_lost_0 = u32 & 0x00FF;

+

+    /* Fraction lost calculation */

+    expected_interval = expected - s->expected_prior;

+    s->expected_prior = expected;

+    

+    received_interval = s->received - s->received_prior;

+    s->received_prior = s->received;

+    

+    lost_interval = expected_interval - received_interval;

+    

+    if (expected_interval==0 || lost_interval == 0) {

+	rtcp_pkt->rr.fract_lost = 0;

+    } else {

+	rtcp_pkt->rr.fract_lost = (lost_interval << 8) / expected_interval;

+    }

+}

+

+PJ_DEF(void) pj_rtcp_build_rtcp(pj_rtcp_session *session, pj_rtcp_pkt **ret_p_pkt, int *len)

+{

+    pj_rtcp_pkt *rtcp_pkt = &session->rtcp_pkt;

+    pj_rtcp_ntp_rec ntp;

+    pj_time_val now;

+    

+    rtcp_build_rtcp(session, session->peer_ssrc);

+    

+    /* Get current NTP time. */

+    rtcp_get_ntp_time(&ntp);

+    

+    /* Fill in NTP timestamp in SR. */

+    rtcp_pkt->sr.ntp_sec = pj_htonl(ntp.hi);

+    rtcp_pkt->sr.ntp_frac = pj_htonl(ntp.lo);

+    

+    if (session->rtcp_lsr_time == 0 || session->rtcp_lsr.lo == 0) {

+	rtcp_pkt->rr.lsr = 0;

+	rtcp_pkt->rr.dlsr = 0;

+    } else {

+	unsigned msec_elapsed;

+	

+	/* Fill in LSR.

+	   LSR is the middle 32bit of the last SR NTP time received.

+	 */

+	rtcp_pkt->rr.lsr = ((session->rtcp_lsr.hi & 0x0000FFFF) << 16) | 

+			   ((session->rtcp_lsr.lo >> 16) & 0xFFFF);

+	rtcp_pkt->rr.lsr = pj_htonl(rtcp_pkt->rr.lsr);

+	

+	/* Fill in DLSR.

+	   DLSR is Delay since Last SR, in 1/65536 seconds.

+	 */

+	pj_gettimeofday(&now);

+	msec_elapsed = (now.msec - session->rtcp_lsr_time);

+	rtcp_pkt->rr.dlsr = pj_htonl((msec_elapsed * 65536) / 1000);

+    }

+    

+    /* Return pointer. */

+    *ret_p_pkt = rtcp_pkt;

+    *len = sizeof(pj_rtcp_pkt);

+}

+

diff --git a/pjmedia/src/pjmedia/rtcp.h b/pjmedia/src/pjmedia/rtcp.h
index d3d2baa..fbe42d9 100644
--- a/pjmedia/src/pjmedia/rtcp.h
+++ b/pjmedia/src/pjmedia/rtcp.h
@@ -1,178 +1,199 @@
-/* $Id$
- *
- */
-
-#ifndef __PJMEDIA_RTCP_H__
-#define __PJMEDIA_RTCP_H__
-
-/**
- * @file rtcp.h
- * @brief RTCP implementation.
- */
-
-#include <pj/types.h>
-#include <pjmedia/rtp.h>
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJMED_RTCP RTCP
- * @ingroup PJMEDIA
- * @{
- */
-
-/**
- * RTCP sender report.
- */
-struct pj_rtcp_sr
-{
-    pj_uint32_t	    ssrc;
-    pj_uint32_t	    ntp_sec;
-    pj_uint32_t	    ntp_frac;
-    pj_uint32_t	    rtp_ts;
-    pj_uint32_t	    sender_pcount;
-    pj_uint32_t	    sender_bcount;
-};
-
-typedef struct pj_rtcp_sr pj_rtcp_sr;
-
-/**
- * RTCP receiver report.
- */
-struct pj_rtcp_rr
-{
-    pj_uint32_t	    ssrc;
-#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
-    pj_uint32_t	    fract_lost:8;
-    pj_uint32_t	    total_lost_2:8;
-    pj_uint32_t	    total_lost_1:8;
-    pj_uint32_t	    total_lost_0:8;
-#else
-    pj_uint32_t	    fract_lost:8;
-    pj_uint32_t	    total_lost_0:8;
-    pj_uint32_t	    total_lost_1:8;
-    pj_uint32_t	    total_lost_2:8;
-#endif	
-    pj_uint32_t	    last_seq;
-    pj_uint32_t	    jitter;
-    pj_uint32_t	    lsr;
-    pj_uint32_t	    dlsr;
-};
-
-typedef struct pj_rtcp_rr pj_rtcp_rr;
-
-/**
- * RTCP common header.
- */
-struct pj_rtcp_common
-{
-#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
-    unsigned	    version:2;	/* packet type            */
-    unsigned	    p:1;	/* padding flag           */
-    unsigned	    count:5;	/* varies by payload type */
-    unsigned	    pt:8;	/* payload type           */
-#else
-    unsigned	    count:5;	/* varies by payload type */
-    unsigned	    p:1;	/* padding flag           */
-    unsigned	    version:2;	/* packet type            */
-    unsigned	    pt:8;	/* payload type           */
-#endif
-    pj_uint16_t	    length;	/* packet length          */
-};
-
-typedef struct pj_rtcp_common pj_rtcp_common;
-
-/**
- * RTCP packet.
- */
-struct pj_rtcp_pkt
-{
-    pj_rtcp_common  common;	
-    pj_rtcp_sr	    sr;
-    pj_rtcp_rr	    rr;		/* variable-length list */
-};
-
-typedef struct pj_rtcp_pkt pj_rtcp_pkt;
-
-/**
- * NTP time representation.
- */
-struct pj_rtcp_ntp_rec
-{
-    pj_uint32_t	    hi;
-    pj_uint32_t	    lo;
-};
-
-typedef struct pj_rtcp_ntp_rec pj_rtcp_ntp_rec;
-
-/**
- * RTCP session.
- */
-struct pj_rtcp_session
-{
-    pj_rtcp_pkt		rtcp_pkt;
-    
-    pj_rtp_seq_session	seq_ctrl;
-
-    pj_uint32_t		received;       /* packets received */
-    pj_uint32_t		expected_prior; /* packet expected at last interval */
-    pj_uint32_t		received_prior; /* packet received at last interval */
-    pj_int32_t		transit;        /* relative trans time for prev pkt */
-    pj_uint32_t		jitter;		/* estimated jitter */
-    
-    pj_rtcp_ntp_rec	rtcp_lsr;	/* NTP timestamp in last sender report received */
-    unsigned 		rtcp_lsr_time;  /* Time when last RTCP SR is received. */
-    unsigned 		peer_ssrc;	/* Peer SSRC */
-    
-};
-
-typedef struct pj_rtcp_session pj_rtcp_session;
-
-/**
- * Init RTCP session.
- * @param session The session
- * @param ssrc The SSRC used in to identify the session.
- */
-PJ_DECL(void) pj_rtcp_init( pj_rtcp_session *session, pj_uint32_t ssrc );
-
-/**
- * Deinit RTCP session.
- * @param session The session.
- */
-PJ_DECL(void) pj_rtcp_fini( pj_rtcp_session *session);
-
-/**
- * Call this function everytime an RTP packet is received to let the RTCP
- * session do its internal calculations.
- * @param session The session.
- * @param seq The RTP packet sequence number, in host byte order.
- * @param ts The RTP packet timestamp, in host byte order.
- */
-PJ_DECL(void) pj_rtcp_rx_rtp( pj_rtcp_session *session, pj_uint16_t seq, pj_uint32_t ts );
-
-/**
- * Call this function everytime an RTP packet is sent to let the RTCP session
- * do its internal calculations.
- * @param session The session.
- * @param bytes_payload_size The payload size of the RTP packet (ie packet minus
- *             RTP header).
- */
-PJ_DECL(void) pj_rtcp_tx_rtp( pj_rtcp_session *session, pj_uint16_t bytes_payload_size );
-
-/**
- * Build a RTCP SR/RR packet to be transmitted to remote RTP peer.
- * @param session The session.
- * @param rtcp_pkt [output] Upon return, it will contain pointer to the RTCP packet.
- * @param len [output] Upon return, it will indicate the size of the RTCP packet.
- */
-PJ_DECL(void) pj_rtcp_build_rtcp( pj_rtcp_session *session, pj_rtcp_pkt **rtcp_pkt, int *len );
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-
-#endif	/* __PJMEDIA_RTCP_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJMEDIA_RTCP_H__

+#define __PJMEDIA_RTCP_H__

+

+/**

+ * @file rtcp.h

+ * @brief RTCP implementation.

+ */

+

+#include <pj/types.h>

+#include <pjmedia/rtp.h>

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJMED_RTCP RTCP

+ * @ingroup PJMEDIA

+ * @{

+ */

+

+/**

+ * RTCP sender report.

+ */

+struct pj_rtcp_sr

+{

+    pj_uint32_t	    ssrc;

+    pj_uint32_t	    ntp_sec;

+    pj_uint32_t	    ntp_frac;

+    pj_uint32_t	    rtp_ts;

+    pj_uint32_t	    sender_pcount;

+    pj_uint32_t	    sender_bcount;

+};

+

+typedef struct pj_rtcp_sr pj_rtcp_sr;

+

+/**

+ * RTCP receiver report.

+ */

+struct pj_rtcp_rr

+{

+    pj_uint32_t	    ssrc;

+#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0

+    pj_uint32_t	    fract_lost:8;

+    pj_uint32_t	    total_lost_2:8;

+    pj_uint32_t	    total_lost_1:8;

+    pj_uint32_t	    total_lost_0:8;

+#else

+    pj_uint32_t	    fract_lost:8;

+    pj_uint32_t	    total_lost_0:8;

+    pj_uint32_t	    total_lost_1:8;

+    pj_uint32_t	    total_lost_2:8;

+#endif	

+    pj_uint32_t	    last_seq;

+    pj_uint32_t	    jitter;

+    pj_uint32_t	    lsr;

+    pj_uint32_t	    dlsr;

+};

+

+typedef struct pj_rtcp_rr pj_rtcp_rr;

+

+/**

+ * RTCP common header.

+ */

+struct pj_rtcp_common

+{

+#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0

+    unsigned	    version:2;	/* packet type            */

+    unsigned	    p:1;	/* padding flag           */

+    unsigned	    count:5;	/* varies by payload type */

+    unsigned	    pt:8;	/* payload type           */

+#else

+    unsigned	    count:5;	/* varies by payload type */

+    unsigned	    p:1;	/* padding flag           */

+    unsigned	    version:2;	/* packet type            */

+    unsigned	    pt:8;	/* payload type           */

+#endif

+    pj_uint16_t	    length;	/* packet length          */

+};

+

+typedef struct pj_rtcp_common pj_rtcp_common;

+

+/**

+ * RTCP packet.

+ */

+struct pj_rtcp_pkt

+{

+    pj_rtcp_common  common;	

+    pj_rtcp_sr	    sr;

+    pj_rtcp_rr	    rr;		/* variable-length list */

+};

+

+typedef struct pj_rtcp_pkt pj_rtcp_pkt;

+

+/**

+ * NTP time representation.

+ */

+struct pj_rtcp_ntp_rec

+{

+    pj_uint32_t	    hi;

+    pj_uint32_t	    lo;

+};

+

+typedef struct pj_rtcp_ntp_rec pj_rtcp_ntp_rec;

+

+/**

+ * RTCP session.

+ */

+struct pj_rtcp_session

+{

+    pj_rtcp_pkt		rtcp_pkt;

+    

+    pj_rtp_seq_session	seq_ctrl;

+

+    pj_uint32_t		received;       /* packets received */

+    pj_uint32_t		expected_prior; /* packet expected at last interval */

+    pj_uint32_t		received_prior; /* packet received at last interval */

+    pj_int32_t		transit;        /* relative trans time for prev pkt */

+    pj_uint32_t		jitter;		/* estimated jitter */

+    

+    pj_rtcp_ntp_rec	rtcp_lsr;	/* NTP timestamp in last sender report received */

+    unsigned 		rtcp_lsr_time;  /* Time when last RTCP SR is received. */

+    unsigned 		peer_ssrc;	/* Peer SSRC */

+    

+};

+

+typedef struct pj_rtcp_session pj_rtcp_session;

+

+/**

+ * Init RTCP session.

+ * @param session The session

+ * @param ssrc The SSRC used in to identify the session.

+ */

+PJ_DECL(void) pj_rtcp_init( pj_rtcp_session *session, pj_uint32_t ssrc );

+

+/**

+ * Deinit RTCP session.

+ * @param session The session.

+ */

+PJ_DECL(void) pj_rtcp_fini( pj_rtcp_session *session);

+

+/**

+ * Call this function everytime an RTP packet is received to let the RTCP

+ * session do its internal calculations.

+ * @param session The session.

+ * @param seq The RTP packet sequence number, in host byte order.

+ * @param ts The RTP packet timestamp, in host byte order.

+ */

+PJ_DECL(void) pj_rtcp_rx_rtp( pj_rtcp_session *session, pj_uint16_t seq, pj_uint32_t ts );

+

+/**

+ * Call this function everytime an RTP packet is sent to let the RTCP session

+ * do its internal calculations.

+ * @param session The session.

+ * @param bytes_payload_size The payload size of the RTP packet (ie packet minus

+ *             RTP header).

+ */

+PJ_DECL(void) pj_rtcp_tx_rtp( pj_rtcp_session *session, pj_uint16_t bytes_payload_size );

+

+/**

+ * Build a RTCP SR/RR packet to be transmitted to remote RTP peer.

+ * @param session The session.

+ * @param rtcp_pkt [output] Upon return, it will contain pointer to the RTCP packet.

+ * @param len [output] Upon return, it will indicate the size of the RTCP packet.

+ */

+PJ_DECL(void) pj_rtcp_build_rtcp( pj_rtcp_session *session, pj_rtcp_pkt **rtcp_pkt, int *len );

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+

+#endif	/* __PJMEDIA_RTCP_H__ */

diff --git a/pjmedia/src/pjmedia/rtp.c b/pjmedia/src/pjmedia/rtp.c
index bbb867b..c1b9286 100644
--- a/pjmedia/src/pjmedia/rtp.c
+++ b/pjmedia/src/pjmedia/rtp.c
@@ -1,247 +1,268 @@
-/* $Id$
- *
- */
-
-#include <pjmedia/rtp.h>
-#include <pj/log.h>
-#include <pj/os.h>	/* pj_gettimeofday() */
-#include <pj/sock.h>	/* pj_htonx, pj_htonx */
-#include <string.h>	/* memset() */
-
-#define THIS_FILE   "rtp.c"
-
-#define RTP_VERSION	2
-
-#define RTP_SEQ_MOD	(1 << 16)
-#define MAX_DROPOUT 	((pj_int16_t)3000)
-#define MAX_MISORDER 	((pj_int16_t)100)
-#define MIN_SEQUENTIAL  ((pj_int16_t)2)
-
-
-PJ_DEF(pj_status_t) pj_rtp_session_init( pj_rtp_session *ses,
-					 int default_pt, pj_uint32_t sender_ssrc )
-{
-    PJ_LOG(4, (THIS_FILE, "pj_rtp_session_init: ses=%p, default_pt=%d, ssrc=0x%x",
-	       ses, default_pt, sender_ssrc));
-
-    /* Check RTP header packing. */
-    if (sizeof(struct pj_rtp_hdr) != 12) {
-	pj_assert(!"Wrong RTP header packing!");
-	return PJ_RTP_ERR_RTP_PACKING;
-    }
-
-    /* If sender_ssrc is not specified, create from time value. */
-    if (sender_ssrc == 0 || sender_ssrc == (pj_uint32_t)-1) {
-	pj_time_val tv;
-
-	pj_gettimeofday(&tv);
-	sender_ssrc  = (pj_uint32_t) pj_htonl(tv.sec);
-    } else {
-	sender_ssrc = pj_htonl(sender_ssrc);
-    }
-
-    /* Initialize session. */
-    ses->out_extseq = 0;
-    ses->peer_ssrc = 0;
-    
-    /* Sequence number will be initialized when the first RTP packet is receieved. */
-
-    /* Build default header for outgoing RTP packet. */
-    memset(ses, 0, sizeof(*ses));
-    ses->out_hdr.v = RTP_VERSION;
-    ses->out_hdr.p = 0;
-    ses->out_hdr.x = 0;
-    ses->out_hdr.cc = 0;
-    ses->out_hdr.m = 0;
-    ses->out_hdr.pt = (pj_uint8_t) default_pt;
-    ses->out_hdr.seq = (pj_uint16_t) pj_htons( (pj_uint16_t)ses->out_extseq );
-    ses->out_hdr.ts = 0;
-    ses->out_hdr.ssrc = sender_ssrc;
-
-    /* Keep some arguments as session defaults. */
-    ses->out_pt = (pj_uint16_t) default_pt;
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pj_rtp_encode_rtp( pj_rtp_session *ses, int pt, int m,
-				       int payload_len, int ts_len,
-				       const void **rtphdr, int *hdrlen )
-{
-    PJ_UNUSED_ARG(payload_len)
-
-    PJ_LOG(6, (THIS_FILE, 
-	      "pj_rtp_encode_rtp: ses=%p, pt=%d, m=%d, pt_len=%d, ts_len=%d",
-	      ses, pt, m, payload_len, ts_len));
-
-    /* Update session. */
-    ses->out_extseq++;
-    ses->out_hdr.ts = pj_htonl(pj_ntohl(ses->out_hdr.ts)+ts_len);
-
-    /* Create outgoing header. */
-    ses->out_hdr.pt = (pj_uint8_t) ((pt == -1) ? ses->out_pt : pt);
-    ses->out_hdr.m = (pj_uint16_t) m;
-    ses->out_hdr.seq = pj_htons( (pj_uint16_t) ses->out_extseq);
-
-    /* Return values */
-    *rtphdr = &ses->out_hdr;
-    *hdrlen = sizeof(pj_rtp_hdr);
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pj_rtp_decode_rtp( pj_rtp_session *ses, 
-				       const void *pkt, int pkt_len,
-				       const pj_rtp_hdr **hdr,
-				       const void **payload,
-				       unsigned *payloadlen)
-{
-    int offset;
-
-    PJ_UNUSED_ARG(ses)
-
-    PJ_LOG(6, (THIS_FILE, 
-	      "pj_rtp_decode_rtp: ses=%p, pkt=%p, pkt_len=%d",
-	      ses, pkt, pkt_len));
-
-    /* Assume RTP header at the start of packet. We'll verify this later. */
-    *hdr = (pj_rtp_hdr*)pkt;
-
-    /* Check RTP header sanity. */
-    if ((*hdr)->v != RTP_VERSION) {
-	PJ_LOG(4, (THIS_FILE, "  invalid RTP version!"));
-	return PJ_RTP_ERR_INVALID_VERSION;
-    }
-
-    /* Payload is located right after header plus CSRC */
-    offset = sizeof(pj_rtp_hdr) + ((*hdr)->cc * sizeof(pj_uint32_t));
-
-    /* Adjust offset if RTP extension is used. */
-    if ((*hdr)->x) {
-	pj_rtp_ext_hdr *ext = (pj_rtp_ext_hdr*) (((pj_uint8_t*)pkt) + offset);
-	offset += (pj_ntohs(ext->length) * sizeof(pj_uint32_t));
-    }
-
-    /* Check that offset is less than packet size */
-    if (offset >= pkt_len)
-	return PJ_RTP_ERR_INVALID_PACKET;
-
-    /* Find and set payload. */
-    *payload = ((pj_uint8_t*)pkt) + offset;
-    *payloadlen = pkt_len - offset;
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pj_rtp_session_update( pj_rtp_session *ses, const pj_rtp_hdr *hdr)
-{
-    int status;
-
-    /* Check SSRC. */
-    if (ses->peer_ssrc == 0) ses->peer_ssrc = pj_ntohl(hdr->ssrc);
-    /*
-    if (pj_ntohl(ses->peer_ssrc) != hdr->ssrc) {
-	PJ_LOG(4, (THIS_FILE, "pj_rtp_session_update: ses=%p, invalid ssrc 0x%p (!=0x%p)",
-		   ses, pj_ntohl(hdr->ssrc), ses->peer_ssrc));
-	return PJ_RTP_ERR_INVALID_SSRC;
-    }
-    */
-
-    /* Check payload type. */
-    if (hdr->pt != ses->out_pt) {
-	PJ_LOG(4, (THIS_FILE, "pj_rtp_session_update: ses=%p, invalid payload type %d (!=%d)",
-		   ses, hdr->pt, ses->out_pt));
-	return PJ_RTP_ERR_INVALID_PT;
-    }
-
-    /* Initialize sequence number on first packet received. */
-    if (ses->received == 0)
-	pj_rtp_seq_init( &ses->seq_ctrl, pj_ntohs(hdr->seq) );
-
-    /* Check sequence number to see if remote session has been restarted. */
-    status = pj_rtp_seq_update( &ses->seq_ctrl, pj_ntohs(hdr->seq));
-    if (status == PJ_RTP_ERR_SESSION_RESTARTED) {
-	pj_rtp_seq_restart( &ses->seq_ctrl, pj_ntohs(hdr->seq));
-	++ses->received;
-    } else if (status == 0 || status == PJ_RTP_ERR_SESSION_PROBATION) {
-	++ses->received;
-    }
-
-
-    return status;
-}
-
-
-void pj_rtp_seq_restart(pj_rtp_seq_session *sctrl, pj_uint16_t seq)
-{
-    sctrl->base_seq = seq;
-    sctrl->max_seq = seq;
-    sctrl->bad_seq = RTP_SEQ_MOD + 1;
-    sctrl->cycles = 0;
-}
-
-
-void pj_rtp_seq_init(pj_rtp_seq_session *sctrl, pj_uint16_t seq)
-{
-    pj_rtp_seq_restart(sctrl, seq);
-
-    sctrl->max_seq = (pj_uint16_t) (seq - 1);
-    sctrl->probation = MIN_SEQUENTIAL;
-}
-
-
-int pj_rtp_seq_update(pj_rtp_seq_session *sctrl, pj_uint16_t seq)
-{
-    pj_uint16_t udelta = (pj_uint16_t) (seq - sctrl->max_seq);
-    
-    /*
-     * Source is not valid until MIN_SEQUENTIAL packets with
-     * sequential sequence numbers have been received.
-     */
-    if (sctrl->probation) {
-	/* packet is in sequence */
-        if (seq == sctrl->max_seq+ 1) {
-	    sctrl->probation--;
-            sctrl->max_seq = seq;
-            if (sctrl->probation == 0) {
-                return PJ_RTP_ERR_SESSION_RESTARTED;
-            }
-	} else {
-	    sctrl->probation = MIN_SEQUENTIAL - 1;
-	    sctrl->max_seq = seq;
-        }
-        return PJ_RTP_ERR_SESSION_PROBATION;
-
-    } else if (udelta < MAX_DROPOUT) {
-	/* in order, with permissible gap */
-	if (seq < sctrl->max_seq) {
-	    /* Sequence number wrapped - count another 64K cycle. */
-	    sctrl->cycles += RTP_SEQ_MOD;
-        }
-        sctrl->max_seq = seq;
-
-    } else if (udelta <= (RTP_SEQ_MOD - MAX_MISORDER)) {
-	/* the sequence number made a very large jump */
-        if (seq == sctrl->bad_seq) {
-	    /*
-	     * Two sequential packets -- assume that the other side
-	     * restarted without telling us so just re-sync
-	     * (i.e., pretend this was the first packet).
-	     */
-	    return PJ_RTP_ERR_SESSION_RESTARTED;
-	}
-        else {
-	    sctrl->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);
-            return PJ_RTP_ERR_BAD_SEQUENCE;
-        }
-    } else {
-	/* duplicate or reordered packet */
-    }
-    
-    return 0;
-}
-
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#include <pjmedia/rtp.h>

+#include <pj/log.h>

+#include <pj/os.h>	/* pj_gettimeofday() */

+#include <pj/sock.h>	/* pj_htonx, pj_htonx */

+#include <string.h>	/* memset() */

+

+#define THIS_FILE   "rtp.c"

+

+#define RTP_VERSION	2

+

+#define RTP_SEQ_MOD	(1 << 16)

+#define MAX_DROPOUT 	((pj_int16_t)3000)

+#define MAX_MISORDER 	((pj_int16_t)100)

+#define MIN_SEQUENTIAL  ((pj_int16_t)2)

+

+

+PJ_DEF(pj_status_t) pj_rtp_session_init( pj_rtp_session *ses,

+					 int default_pt, pj_uint32_t sender_ssrc )

+{

+    PJ_LOG(4, (THIS_FILE, "pj_rtp_session_init: ses=%p, default_pt=%d, ssrc=0x%x",

+	       ses, default_pt, sender_ssrc));

+

+    /* Check RTP header packing. */

+    if (sizeof(struct pj_rtp_hdr) != 12) {

+	pj_assert(!"Wrong RTP header packing!");

+	return PJ_RTP_ERR_RTP_PACKING;

+    }

+

+    /* If sender_ssrc is not specified, create from time value. */

+    if (sender_ssrc == 0 || sender_ssrc == (pj_uint32_t)-1) {

+	pj_time_val tv;

+

+	pj_gettimeofday(&tv);

+	sender_ssrc  = (pj_uint32_t) pj_htonl(tv.sec);

+    } else {

+	sender_ssrc = pj_htonl(sender_ssrc);

+    }

+

+    /* Initialize session. */

+    ses->out_extseq = 0;

+    ses->peer_ssrc = 0;

+    

+    /* Sequence number will be initialized when the first RTP packet is receieved. */

+

+    /* Build default header for outgoing RTP packet. */

+    memset(ses, 0, sizeof(*ses));

+    ses->out_hdr.v = RTP_VERSION;

+    ses->out_hdr.p = 0;

+    ses->out_hdr.x = 0;

+    ses->out_hdr.cc = 0;

+    ses->out_hdr.m = 0;

+    ses->out_hdr.pt = (pj_uint8_t) default_pt;

+    ses->out_hdr.seq = (pj_uint16_t) pj_htons( (pj_uint16_t)ses->out_extseq );

+    ses->out_hdr.ts = 0;

+    ses->out_hdr.ssrc = sender_ssrc;

+

+    /* Keep some arguments as session defaults. */

+    ses->out_pt = (pj_uint16_t) default_pt;

+

+    return PJ_SUCCESS;

+}

+

+

+PJ_DEF(pj_status_t) pj_rtp_encode_rtp( pj_rtp_session *ses, int pt, int m,

+				       int payload_len, int ts_len,

+				       const void **rtphdr, int *hdrlen )

+{

+    PJ_UNUSED_ARG(payload_len)

+

+    PJ_LOG(6, (THIS_FILE, 

+	      "pj_rtp_encode_rtp: ses=%p, pt=%d, m=%d, pt_len=%d, ts_len=%d",

+	      ses, pt, m, payload_len, ts_len));

+

+    /* Update session. */

+    ses->out_extseq++;

+    ses->out_hdr.ts = pj_htonl(pj_ntohl(ses->out_hdr.ts)+ts_len);

+

+    /* Create outgoing header. */

+    ses->out_hdr.pt = (pj_uint8_t) ((pt == -1) ? ses->out_pt : pt);

+    ses->out_hdr.m = (pj_uint16_t) m;

+    ses->out_hdr.seq = pj_htons( (pj_uint16_t) ses->out_extseq);

+

+    /* Return values */

+    *rtphdr = &ses->out_hdr;

+    *hdrlen = sizeof(pj_rtp_hdr);

+

+    return PJ_SUCCESS;

+}

+

+

+PJ_DEF(pj_status_t) pj_rtp_decode_rtp( pj_rtp_session *ses, 

+				       const void *pkt, int pkt_len,

+				       const pj_rtp_hdr **hdr,

+				       const void **payload,

+				       unsigned *payloadlen)

+{

+    int offset;

+

+    PJ_UNUSED_ARG(ses)

+

+    PJ_LOG(6, (THIS_FILE, 

+	      "pj_rtp_decode_rtp: ses=%p, pkt=%p, pkt_len=%d",

+	      ses, pkt, pkt_len));

+

+    /* Assume RTP header at the start of packet. We'll verify this later. */

+    *hdr = (pj_rtp_hdr*)pkt;

+

+    /* Check RTP header sanity. */

+    if ((*hdr)->v != RTP_VERSION) {

+	PJ_LOG(4, (THIS_FILE, "  invalid RTP version!"));

+	return PJ_RTP_ERR_INVALID_VERSION;

+    }

+

+    /* Payload is located right after header plus CSRC */

+    offset = sizeof(pj_rtp_hdr) + ((*hdr)->cc * sizeof(pj_uint32_t));

+

+    /* Adjust offset if RTP extension is used. */

+    if ((*hdr)->x) {

+	pj_rtp_ext_hdr *ext = (pj_rtp_ext_hdr*) (((pj_uint8_t*)pkt) + offset);

+	offset += (pj_ntohs(ext->length) * sizeof(pj_uint32_t));

+    }

+

+    /* Check that offset is less than packet size */

+    if (offset >= pkt_len)

+	return PJ_RTP_ERR_INVALID_PACKET;

+

+    /* Find and set payload. */

+    *payload = ((pj_uint8_t*)pkt) + offset;

+    *payloadlen = pkt_len - offset;

+

+    return PJ_SUCCESS;

+}

+

+

+PJ_DEF(pj_status_t) pj_rtp_session_update( pj_rtp_session *ses, const pj_rtp_hdr *hdr)

+{

+    int status;

+

+    /* Check SSRC. */

+    if (ses->peer_ssrc == 0) ses->peer_ssrc = pj_ntohl(hdr->ssrc);

+    /*

+    if (pj_ntohl(ses->peer_ssrc) != hdr->ssrc) {

+	PJ_LOG(4, (THIS_FILE, "pj_rtp_session_update: ses=%p, invalid ssrc 0x%p (!=0x%p)",

+		   ses, pj_ntohl(hdr->ssrc), ses->peer_ssrc));

+	return PJ_RTP_ERR_INVALID_SSRC;

+    }

+    */

+

+    /* Check payload type. */

+    if (hdr->pt != ses->out_pt) {

+	PJ_LOG(4, (THIS_FILE, "pj_rtp_session_update: ses=%p, invalid payload type %d (!=%d)",

+		   ses, hdr->pt, ses->out_pt));

+	return PJ_RTP_ERR_INVALID_PT;

+    }

+

+    /* Initialize sequence number on first packet received. */

+    if (ses->received == 0)

+	pj_rtp_seq_init( &ses->seq_ctrl, pj_ntohs(hdr->seq) );

+

+    /* Check sequence number to see if remote session has been restarted. */

+    status = pj_rtp_seq_update( &ses->seq_ctrl, pj_ntohs(hdr->seq));

+    if (status == PJ_RTP_ERR_SESSION_RESTARTED) {

+	pj_rtp_seq_restart( &ses->seq_ctrl, pj_ntohs(hdr->seq));

+	++ses->received;

+    } else if (status == 0 || status == PJ_RTP_ERR_SESSION_PROBATION) {

+	++ses->received;

+    }

+

+

+    return status;

+}

+

+

+void pj_rtp_seq_restart(pj_rtp_seq_session *sctrl, pj_uint16_t seq)

+{

+    sctrl->base_seq = seq;

+    sctrl->max_seq = seq;

+    sctrl->bad_seq = RTP_SEQ_MOD + 1;

+    sctrl->cycles = 0;

+}

+

+

+void pj_rtp_seq_init(pj_rtp_seq_session *sctrl, pj_uint16_t seq)

+{

+    pj_rtp_seq_restart(sctrl, seq);

+

+    sctrl->max_seq = (pj_uint16_t) (seq - 1);

+    sctrl->probation = MIN_SEQUENTIAL;

+}

+

+

+int pj_rtp_seq_update(pj_rtp_seq_session *sctrl, pj_uint16_t seq)

+{

+    pj_uint16_t udelta = (pj_uint16_t) (seq - sctrl->max_seq);

+    

+    /*

+     * Source is not valid until MIN_SEQUENTIAL packets with

+     * sequential sequence numbers have been received.

+     */

+    if (sctrl->probation) {

+	/* packet is in sequence */

+        if (seq == sctrl->max_seq+ 1) {

+	    sctrl->probation--;

+            sctrl->max_seq = seq;

+            if (sctrl->probation == 0) {

+                return PJ_RTP_ERR_SESSION_RESTARTED;

+            }

+	} else {

+	    sctrl->probation = MIN_SEQUENTIAL - 1;

+	    sctrl->max_seq = seq;

+        }

+        return PJ_RTP_ERR_SESSION_PROBATION;

+

+    } else if (udelta < MAX_DROPOUT) {

+	/* in order, with permissible gap */

+	if (seq < sctrl->max_seq) {

+	    /* Sequence number wrapped - count another 64K cycle. */

+	    sctrl->cycles += RTP_SEQ_MOD;

+        }

+        sctrl->max_seq = seq;

+

+    } else if (udelta <= (RTP_SEQ_MOD - MAX_MISORDER)) {

+	/* the sequence number made a very large jump */

+        if (seq == sctrl->bad_seq) {

+	    /*

+	     * Two sequential packets -- assume that the other side

+	     * restarted without telling us so just re-sync

+	     * (i.e., pretend this was the first packet).

+	     */

+	    return PJ_RTP_ERR_SESSION_RESTARTED;

+	}

+        else {

+	    sctrl->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);

+            return PJ_RTP_ERR_BAD_SEQUENCE;

+        }

+    } else {

+	/* duplicate or reordered packet */

+    }

+    

+    return 0;

+}

+

+

diff --git a/pjmedia/src/pjmedia/rtp.h b/pjmedia/src/pjmedia/rtp.h
index e705aa415..1615b2d 100644
--- a/pjmedia/src/pjmedia/rtp.h
+++ b/pjmedia/src/pjmedia/rtp.h
@@ -1,242 +1,263 @@
-/* $Id$
- *
- */
-
-#ifndef __PJMEDIA_RTP_H__
-#define __PJMEDIA_RTP_H__
-
-#include <pj/types.h>
-
-/**
- * @file rtp.h
- * @brief RTP implementation.
- */
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJMED_RTP RTP
- * @ingroup PJMEDIA
- * @{
- *
- * The RTP module is designed to be dependent only to PJLIB, it does not depend
- * on any other parts of PJMEDIA library. The RTP module does not even depend
- * on any transports (sockets), to promote even more use.
- *
- * An RTCP implementation is also separated from this module.
- *
- * The functions that are provided by this module:
- *  - creating RTP header for each outgoing packet.
- *  - decoding RTP packet into RTP header and payload.
- *  - provide simple RTP session management (sequence number, etc.)
- *
- * The RTP module does not use any dynamic memory at all.
- *
- * \section P1 How to Use the RTP Module
- * 
- * First application must call #pj_rtp_session_init to initialize the RTP 
- * session.
- *
- * When application wants to send RTP packet, it needs to call 
- * #pj_rtp_encode_rtp to build the RTP header. Note that this WILL NOT build
- * the complete RTP packet, but instead only the header. Application can
- * then either concatenate the header with the payload, or send the two
- * fragments (the header and the payload) using scatter-gather transport API
- * (e.g. \a sendv()).
- *
- * When application receives an RTP packet, first it should call
- * #pj_rtp_decode_rtp to decode RTP header and payload, then it should call
- * #pj_rtp_session_update to check whether we can process the RTP payload,
- * and to let the RTP session updates its internal status. The decode function
- * is guaranteed to point the payload to the correct position regardless of
- * any options present in the RTP packet.
- *
- */
-
-
-#ifdef _MSC_VER
-#  pragma warning ( disable : 4214 )
-#endif
-
-
-/**
- * Error codes.
- */
-enum pj_rtp_error_t
-{
-    PJ_RTP_ERR_RTP_PACKING,	    /**< Invalid RTP packet. */
-    PJ_RTP_ERR_INVALID_VERSION,	    /**< Invalid RTP version. */
-    PJ_RTP_ERR_INVALID_SSRC,	    /**< Invalid SSRC. */
-    PJ_RTP_ERR_INVALID_PT,	    /**< Invalid payload type. */
-    PJ_RTP_ERR_INVALID_PACKET,	    /**< Invalid packet. */
-    PJ_RTP_ERR_SESSION_RESTARTED,   /**< Session has just been restarted. */
-    PJ_RTP_ERR_SESSION_PROBATION,   /**< Session in probation. */
-    PJ_RTP_ERR_BAD_SEQUENCE,	    /**< Bad RTP sequence number. */
-};
-
-#pragma pack(1)
-/**
- * RTP packet header.
- */
-struct pj_rtp_hdr
-{
-#if defined(PJ_IS_BIG_ENDIAN) && (PJ_IS_BIG_ENDIAN!=0)
-    pj_uint16_t v:2;	/**< packet type/version	    */
-    pj_uint16_t p:1;	/**< padding flag		    */
-    pj_uint16_t x:1;	/**< extension flag	    */
-    pj_uint16_t cc:4;	/**< CSRC count		    */
-    pj_uint16_t m:1;	/**< marker bit		    */
-    pj_uint16_t pt:7;	/**< payload type		    */
-#else
-    pj_uint16_t cc:4;	/**< CSRC count		    */
-    pj_uint16_t x:1;	/**< header extension flag    */ 
-    pj_uint16_t p:1;	/**< padding flag		    */
-    pj_uint16_t v:2;	/**< packet type/version	    */
-    pj_uint16_t pt:7;	/**< payload type		    */
-    pj_uint16_t m:1;	/**< marker bit		    */
-#endif
-    pj_uint16_t seq;	/**< sequence number	    */
-    pj_uint32_t ts;	/**< timestamp		    */
-    pj_uint32_t ssrc;	/**< synchronization source   */
-};
-#pragma pack()
-
-typedef struct pj_rtp_hdr pj_rtp_hdr;
-
-/**
- * RTP extendsion header.
- */
-struct pj_rtp_ext_hdr
-{
-    pj_uint16_t	profile_data;
-    pj_uint16_t	length;
-};
-
-typedef struct pj_rtp_ext_hdr pj_rtp_ext_hdr;
-
-/**
- * A generic sequence number management, used by both RTP and RTCP.
- */
-struct pj_rtp_seq_session
-{
-    pj_uint16_t	    max_seq;	    /**< highest sequence number heard */
-    pj_uint32_t	    cycles;	    /**< shifted count of seq. number cycles */
-    pj_uint32_t	    base_seq;	    /**< base seq number */
-    pj_uint32_t	    bad_seq;        /**< last 'bad' seq number + 1 */
-    pj_uint32_t	    probation;      /**< sequ. packets till source is valid */
-};
-
-typedef struct pj_rtp_seq_session pj_rtp_seq_session;
-
-/**
- * RTP session descriptor.
- */
-struct pj_rtp_session
-{
-    pj_rtp_hdr		out_hdr;    /**< Saved header for outgoing packets. */
-    pj_rtp_seq_session	seq_ctrl;   /**< Sequence number management. */
-    pj_uint16_t	        out_pt;	    /**< Default outgoing payload type. */
-    pj_uint32_t	        out_extseq; /**< Outgoing extended sequence number. */
-    pj_uint32_t	        peer_ssrc;  /**< Peer SSRC. */
-    pj_uint32_t	        received;   /**< Number of received packets. */
-};
-
-typedef struct pj_rtp_session pj_rtp_session;
-
-/**
- * \brief Initialize RTP session.
- * This function will initialize the RTP session according to given parameters.
- *
- * @param ses		The session.
- * @param default_pt	Default payload type.
- * @param sender_ssrc	SSRC used for outgoing packets.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_rtp_session_init( pj_rtp_session *ses,
-					  int default_pt, pj_uint32_t sender_ssrc );
-
-/**
- * \brief Encode outgoing RTP packet header.
- * Create the RTP header based on arguments and current state of the RTP
- * session.
- *
- * @param ses		The session.
- * @param pt		Payload type.
- * @param m		Marker flag.
- * @param payload_len	Payload length in bytes.
- * @param ts_len	Timestamp length.
- * @param rtphdr	Upon return will point to RTP packet header.
- * @param hdrlen	Upon return will indicate the size of RTP packet header
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_rtp_encode_rtp( pj_rtp_session *ses, int pt, int m,
-				        int payload_len, int ts_len,
-					const void **rtphdr, int *hdrlen );
-
-/**
- * \brief Decode an incoming RTP packet.
- * This function will decode incoming packet into RTP header and payload.
- * The decode function is guaranteed to point the payload to the correct 
- * position regardless of any options present in the RTP packet.
- *
- * @param ses		The session.
- * @param pkt		The received RTP packet.
- * @param pkt_len	The length of the packet.
- * @param hdr		Upon return will point to the location of the RTP header
- *			inside the packet.
- * @param payload	Upon return will point to the location of the
- *			payload inside the packet.
- * @param payloadlen	Upon return will indicate the size of the payload.
- *
- * @return zero if successfull.
- */
-PJ_DECL(pj_status_t) pj_rtp_decode_rtp( pj_rtp_session *ses, 
-				        const void *pkt, int pkt_len,
-					const pj_rtp_hdr **hdr,
-					const void **payload,
-					unsigned *payloadlen);
-
-/**
- * \brief Update RTP session with an incoming RTP packet. 
- * Call this function everytime
- * an RTP packet is received to check whether the packet can be received and to
- * let the RTP session performs its internal calculations.
- *
- * @param ses	    The session.
- * @param hdr	    The RTP header of the incoming packet.
- *
- * @return zero if the packet is valid and can be processed, otherwise will
- *         return one of the error in #pj_rtp_error_t.
- */
-PJ_DECL(pj_status_t) pj_rtp_session_update( pj_rtp_session *ses, 
-					    const pj_rtp_hdr *hdr);
-
-/** 
-* \brief Internal.
- * Internal function for sequence control, shared by RTCP implementation. 
- */
-void pj_rtp_seq_init(pj_rtp_seq_session *seq_ctrl, pj_uint16_t seq);
-
-/** 
-* \brief Internal.
- * Internal function for sequence control, shared by RTCP implementation. 
- */
-void pj_rtp_seq_restart(pj_rtp_seq_session *seq_ctrl, pj_uint16_t seq);
-
-/** 
-* \brief Internal.
- * Internal function for sequence control, shared by RTCP implementation. 
- */
-int  pj_rtp_seq_update(pj_rtp_seq_session *seq_ctrl, pj_uint16_t seq);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-
-#endif	/* __PJMEDIA_RTP_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJMEDIA_RTP_H__

+#define __PJMEDIA_RTP_H__

+

+#include <pj/types.h>

+

+/**

+ * @file rtp.h

+ * @brief RTP implementation.

+ */

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJMED_RTP RTP

+ * @ingroup PJMEDIA

+ * @{

+ *

+ * The RTP module is designed to be dependent only to PJLIB, it does not depend

+ * on any other parts of PJMEDIA library. The RTP module does not even depend

+ * on any transports (sockets), to promote even more use.

+ *

+ * An RTCP implementation is also separated from this module.

+ *

+ * The functions that are provided by this module:

+ *  - creating RTP header for each outgoing packet.

+ *  - decoding RTP packet into RTP header and payload.

+ *  - provide simple RTP session management (sequence number, etc.)

+ *

+ * The RTP module does not use any dynamic memory at all.

+ *

+ * \section P1 How to Use the RTP Module

+ * 

+ * First application must call #pj_rtp_session_init to initialize the RTP 

+ * session.

+ *

+ * When application wants to send RTP packet, it needs to call 

+ * #pj_rtp_encode_rtp to build the RTP header. Note that this WILL NOT build

+ * the complete RTP packet, but instead only the header. Application can

+ * then either concatenate the header with the payload, or send the two

+ * fragments (the header and the payload) using scatter-gather transport API

+ * (e.g. \a sendv()).

+ *

+ * When application receives an RTP packet, first it should call

+ * #pj_rtp_decode_rtp to decode RTP header and payload, then it should call

+ * #pj_rtp_session_update to check whether we can process the RTP payload,

+ * and to let the RTP session updates its internal status. The decode function

+ * is guaranteed to point the payload to the correct position regardless of

+ * any options present in the RTP packet.

+ *

+ */

+

+

+#ifdef _MSC_VER

+#  pragma warning ( disable : 4214 )

+#endif

+

+

+/**

+ * Error codes.

+ */

+enum pj_rtp_error_t

+{

+    PJ_RTP_ERR_RTP_PACKING,	    /**< Invalid RTP packet. */

+    PJ_RTP_ERR_INVALID_VERSION,	    /**< Invalid RTP version. */

+    PJ_RTP_ERR_INVALID_SSRC,	    /**< Invalid SSRC. */

+    PJ_RTP_ERR_INVALID_PT,	    /**< Invalid payload type. */

+    PJ_RTP_ERR_INVALID_PACKET,	    /**< Invalid packet. */

+    PJ_RTP_ERR_SESSION_RESTARTED,   /**< Session has just been restarted. */

+    PJ_RTP_ERR_SESSION_PROBATION,   /**< Session in probation. */

+    PJ_RTP_ERR_BAD_SEQUENCE,	    /**< Bad RTP sequence number. */

+};

+

+#pragma pack(1)

+/**

+ * RTP packet header.

+ */

+struct pj_rtp_hdr

+{

+#if defined(PJ_IS_BIG_ENDIAN) && (PJ_IS_BIG_ENDIAN!=0)

+    pj_uint16_t v:2;	/**< packet type/version	    */

+    pj_uint16_t p:1;	/**< padding flag		    */

+    pj_uint16_t x:1;	/**< extension flag	    */

+    pj_uint16_t cc:4;	/**< CSRC count		    */

+    pj_uint16_t m:1;	/**< marker bit		    */

+    pj_uint16_t pt:7;	/**< payload type		    */

+#else

+    pj_uint16_t cc:4;	/**< CSRC count		    */

+    pj_uint16_t x:1;	/**< header extension flag    */ 

+    pj_uint16_t p:1;	/**< padding flag		    */

+    pj_uint16_t v:2;	/**< packet type/version	    */

+    pj_uint16_t pt:7;	/**< payload type		    */

+    pj_uint16_t m:1;	/**< marker bit		    */

+#endif

+    pj_uint16_t seq;	/**< sequence number	    */

+    pj_uint32_t ts;	/**< timestamp		    */

+    pj_uint32_t ssrc;	/**< synchronization source   */

+};

+#pragma pack()

+

+typedef struct pj_rtp_hdr pj_rtp_hdr;

+

+/**

+ * RTP extendsion header.

+ */

+struct pj_rtp_ext_hdr

+{

+    pj_uint16_t	profile_data;

+    pj_uint16_t	length;

+};

+

+typedef struct pj_rtp_ext_hdr pj_rtp_ext_hdr;

+

+/**

+ * A generic sequence number management, used by both RTP and RTCP.

+ */

+struct pj_rtp_seq_session

+{

+    pj_uint16_t	    max_seq;	    /**< highest sequence number heard */

+    pj_uint32_t	    cycles;	    /**< shifted count of seq. number cycles */

+    pj_uint32_t	    base_seq;	    /**< base seq number */

+    pj_uint32_t	    bad_seq;        /**< last 'bad' seq number + 1 */

+    pj_uint32_t	    probation;      /**< sequ. packets till source is valid */

+};

+

+typedef struct pj_rtp_seq_session pj_rtp_seq_session;

+

+/**

+ * RTP session descriptor.

+ */

+struct pj_rtp_session

+{

+    pj_rtp_hdr		out_hdr;    /**< Saved header for outgoing packets. */

+    pj_rtp_seq_session	seq_ctrl;   /**< Sequence number management. */

+    pj_uint16_t	        out_pt;	    /**< Default outgoing payload type. */

+    pj_uint32_t	        out_extseq; /**< Outgoing extended sequence number. */

+    pj_uint32_t	        peer_ssrc;  /**< Peer SSRC. */

+    pj_uint32_t	        received;   /**< Number of received packets. */

+};

+

+typedef struct pj_rtp_session pj_rtp_session;

+

+/**

+ * \brief Initialize RTP session.

+ * This function will initialize the RTP session according to given parameters.

+ *

+ * @param ses		The session.

+ * @param default_pt	Default payload type.

+ * @param sender_ssrc	SSRC used for outgoing packets.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_rtp_session_init( pj_rtp_session *ses,

+					  int default_pt, pj_uint32_t sender_ssrc );

+

+/**

+ * \brief Encode outgoing RTP packet header.

+ * Create the RTP header based on arguments and current state of the RTP

+ * session.

+ *

+ * @param ses		The session.

+ * @param pt		Payload type.

+ * @param m		Marker flag.

+ * @param payload_len	Payload length in bytes.

+ * @param ts_len	Timestamp length.

+ * @param rtphdr	Upon return will point to RTP packet header.

+ * @param hdrlen	Upon return will indicate the size of RTP packet header

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_rtp_encode_rtp( pj_rtp_session *ses, int pt, int m,

+				        int payload_len, int ts_len,

+					const void **rtphdr, int *hdrlen );

+

+/**

+ * \brief Decode an incoming RTP packet.

+ * This function will decode incoming packet into RTP header and payload.

+ * The decode function is guaranteed to point the payload to the correct 

+ * position regardless of any options present in the RTP packet.

+ *

+ * @param ses		The session.

+ * @param pkt		The received RTP packet.

+ * @param pkt_len	The length of the packet.

+ * @param hdr		Upon return will point to the location of the RTP header

+ *			inside the packet.

+ * @param payload	Upon return will point to the location of the

+ *			payload inside the packet.

+ * @param payloadlen	Upon return will indicate the size of the payload.

+ *

+ * @return zero if successfull.

+ */

+PJ_DECL(pj_status_t) pj_rtp_decode_rtp( pj_rtp_session *ses, 

+				        const void *pkt, int pkt_len,

+					const pj_rtp_hdr **hdr,

+					const void **payload,

+					unsigned *payloadlen);

+

+/**

+ * \brief Update RTP session with an incoming RTP packet. 

+ * Call this function everytime

+ * an RTP packet is received to check whether the packet can be received and to

+ * let the RTP session performs its internal calculations.

+ *

+ * @param ses	    The session.

+ * @param hdr	    The RTP header of the incoming packet.

+ *

+ * @return zero if the packet is valid and can be processed, otherwise will

+ *         return one of the error in #pj_rtp_error_t.

+ */

+PJ_DECL(pj_status_t) pj_rtp_session_update( pj_rtp_session *ses, 

+					    const pj_rtp_hdr *hdr);

+

+/** 

+* \brief Internal.

+ * Internal function for sequence control, shared by RTCP implementation. 

+ */

+void pj_rtp_seq_init(pj_rtp_seq_session *seq_ctrl, pj_uint16_t seq);

+

+/** 

+* \brief Internal.

+ * Internal function for sequence control, shared by RTCP implementation. 

+ */

+void pj_rtp_seq_restart(pj_rtp_seq_session *seq_ctrl, pj_uint16_t seq);

+

+/** 

+* \brief Internal.

+ * Internal function for sequence control, shared by RTCP implementation. 

+ */

+int  pj_rtp_seq_update(pj_rtp_seq_session *seq_ctrl, pj_uint16_t seq);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+

+#endif	/* __PJMEDIA_RTP_H__ */

diff --git a/pjmedia/src/pjmedia/sdp.c b/pjmedia/src/pjmedia/sdp.c
index aea3a43..c3b20a9 100644
--- a/pjmedia/src/pjmedia/sdp.c
+++ b/pjmedia/src/pjmedia/sdp.c
@@ -1,936 +1,957 @@
-/* $Id$
- *
- */
-
-
-#include <pjmedia/sdp.h>
-#include <pj/scanner.h>
-#include <pj/except.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/string.h>
-#include <pj/pool.h>
-
-enum {
-    SKIP_WS = 0,
-    SYNTAX_ERROR = 1,
-};
-#define TOKEN		"-.!%*_=`'~"
-#define NTP_OFFSET	((pj_uint32_t)2208988800)
-#define LOG_THIS	"sdp"
-
-/*
- * Prototypes for line parser.
- */
-static void parse_version(pj_scanner *scanner);
-static void parse_origin(pj_scanner *scanner, pjsdp_session_desc *ses);
-static void parse_time(pj_scanner *scanner, pjsdp_session_desc *ses);
-static void parse_generic_line(pj_scanner *scanner, pj_str_t *str);
-static void parse_connection_info(pj_scanner *scanner, pjsdp_conn_info *conn);
-static pjsdp_attr *parse_attr(pj_pool_t *pool, pj_scanner *scanner);
-static void parse_media(pj_scanner *scanner, pjsdp_media_desc *med);
-
-/*
- * Prototypes for attribute parsers.
- */
-static pjsdp_rtpmap_attr *  parse_rtpmap_attr( pj_pool_t *pool, pj_scanner *scanner );
-static pjsdp_attr_string *  parse_generic_string_attr( pj_pool_t *pool, pj_scanner *scanner );
-static pjsdp_attr_num *	    parse_generic_num_attr( pj_pool_t *pool, pj_scanner *scanner );
-static pjsdp_attr *	    parse_name_only_attr( pj_pool_t *pool, pj_scanner *scanner );
-static pjsdp_fmtp_attr *    parse_fmtp_attr( pj_pool_t *pool, pj_scanner *scanner );
-
-
-/* 
- * Prototypes for functions to print attribute.
- * All of them returns integer for the length printed, or -1 on error.
- */
-static int print_rtpmap_attr(const pjsdp_rtpmap_attr *attr, 
-			     char *buf, int length);
-static int print_generic_string_attr(const pjsdp_attr_string *attr, 
-				     char *buf, int length);
-static int print_generic_num_attr(const pjsdp_attr_num *attr, 
-				  char *buf, int length);
-static int print_name_only_attr(const pjsdp_attr *attr, 
-				char *buf, int length);
-static int print_fmtp_attr(const pjsdp_fmtp_attr *attr, 
-			   char *buf, int length);
-
-/*
- * Prototypes for cloning attributes.
- */
-static pjsdp_attr* clone_rtpmap_attr (pj_pool_t *pool, const pjsdp_attr *rhs);
-static pjsdp_attr* clone_generic_string_attr (pj_pool_t *pool, const pjsdp_attr *rhs);
-static pjsdp_attr* clone_generic_num_attr (pj_pool_t *pool, const pjsdp_attr *rhs);
-static pjsdp_attr* clone_name_only_attr (pj_pool_t *pool, const pjsdp_attr *rhs);
-static pjsdp_attr* clone_fmtp_attr (pj_pool_t *pool, const pjsdp_attr *rhs);
-
-
-/*
- * Prototypes
- */
-static void init_sdp_parser(void);
-
-
-typedef void *  (*FPARSE)(pj_pool_t *pool, pj_scanner *scanner);
-typedef int (*FPRINT)(const void *attr, char *buf, int length);
-typedef pjsdp_attr*  (*FCLONE)(pj_pool_t *pool, const pjsdp_attr *rhs);
-
-/*
- * Array of functions to print attribute.
- */
-static struct attr_map_rec
-{
-    pj_str_t name;
-    FPARSE   parse_attr;
-    FPRINT   print_attr;
-    FCLONE   clone;
-} attr_map[] = 
-{
-    {{"rtpmap", 6},    (FPARSE)&parse_rtpmap_attr,	   (FPRINT)&print_rtpmap_attr,		(FCLONE)&clone_rtpmap_attr},
-    {{"cat", 3},       (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},
-    {{"keywds", 6},    (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},
-    {{"tool", 4},      (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},
-    {{"ptime", 5},     (FPARSE)&parse_generic_num_attr,    (FPRINT)&print_generic_num_attr,	(FCLONE)&clone_generic_num_attr},
-    {{"recvonly", 8},  (FPARSE)&parse_name_only_attr,	   (FPRINT)&print_name_only_attr,	(FCLONE)&clone_name_only_attr},
-    {{"sendonly", 8},  (FPARSE)&parse_name_only_attr,	   (FPRINT)&print_name_only_attr,	(FCLONE)&clone_name_only_attr},
-    {{"sendrecv", 8},  (FPARSE)&parse_name_only_attr,	   (FPRINT)&print_name_only_attr,	(FCLONE)&clone_name_only_attr},
-    {{"orient", 6},    (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},
-    {{"type", 4},      (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},
-    {{"charset", 7},   (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},
-    {{"sdplang", 7},   (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},
-    {{"lang", 4},      (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},
-    {{"framerate", 9}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},
-    {{"quality", 7},   (FPARSE)&parse_generic_num_attr,    (FPRINT)&print_generic_num_attr,	(FCLONE)&clone_generic_num_attr},
-    {{"fmtp", 4},      (FPARSE)&parse_fmtp_attr,	   (FPRINT)&print_fmtp_attr,		(FCLONE)&clone_fmtp_attr},
-    {{"inactive", 8},  (FPARSE)&parse_name_only_attr,	   (FPRINT)&print_name_only_attr,	(FCLONE)&clone_name_only_attr},
-    {{"", 0},	       NULL, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr}
-};
-
-/*
- * Scanner character specification.
- */
-static int is_initialized;
-static pj_char_spec cs_token;
-
-static void init_sdp_parser(void)
-{
-    if (is_initialized == 0) {
-	is_initialized = 1;
-	if (is_initialized != 1) {
-	    return;
-	}
-    }
-    pj_cs_add_alpha(cs_token);
-    pj_cs_add_num(cs_token);
-    pj_cs_add_str( cs_token, TOKEN);
-}
-
-static int print_rtpmap_attr(const pjsdp_rtpmap_attr *rtpmap, 
-			     char *buf, int len)
-{
-    char *p = buf;
-
-    if (len < 16+rtpmap->encoding_name.slen+rtpmap->parameter.slen) {
-	return -1;
-    }
-    
-    /* colon and payload type. */
-    *p++ = ':';
-    len = pj_utoa(rtpmap->payload_type, p);
-    p += len;
-
-    /* space, encoding name */
-    *p++ = ' ';
-    pj_memcpy(p, rtpmap->encoding_name.ptr, rtpmap->encoding_name.slen);
-    p += rtpmap->encoding_name.slen;
-
-    /* slash, clock-rate. */
-    *p++ = '/';
-    len = pj_utoa(rtpmap->clock_rate, p);
-    p += len;
-
-    /* optionally add encoding parameter. */
-    if (rtpmap->parameter.slen) {
-	*p++ = '/';
-	pj_memcpy(p, rtpmap->parameter.ptr, rtpmap->parameter.slen);
-	p += rtpmap->parameter.slen;
-    }
-
-    return p-buf;
-}
-
-static int print_generic_string_attr(const pjsdp_attr_string *attr, 
-				     char *buf, int len)
-{
-    char *p = buf;
-
-    if (len < attr->value.slen + 4) {
-	return -1;
-    }
-
-    /* colon and attribute value. */
-    *p++ = ':';
-    pj_memcpy(p, attr->value.ptr, attr->value.slen);
-    p += attr->value.slen;
-
-    return p-buf;
-}
-
-static int print_generic_num_attr(const pjsdp_attr_num *attr, char *buf, int len)
-{
-    char *p = buf;
-
-    if (len < 10) {
-	return -1;
-    }
-    *p++ = ':';
-    return pj_utoa(attr->value, p);
-}
-
-static int print_name_only_attr(const pjsdp_attr *attr, char *buf, int len)
-{
-    PJ_UNUSED_ARG(attr)
-    PJ_UNUSED_ARG(buf)
-    PJ_UNUSED_ARG(len)
-    return 0;
-}
-
-static int print_fmtp_attr(const pjsdp_fmtp_attr *fmtp, char *buf, int len)
-{
-    char *p = buf;
-
-    if (len < 4+fmtp->format.slen+fmtp->param.slen) {
-	return -1;
-    }
-
-    /* colon and format. */
-    *p++ = ':';
-    pj_memcpy(p, fmtp->format.ptr, fmtp->format.slen);
-    p += fmtp->format.slen;
-
-    /* space and parameter. */
-    *p++ = ' ';
-    pj_memcpy(p, fmtp->param.ptr, fmtp->param.slen);
-    p += fmtp->param.slen;
-
-    return p-buf;
-}
-
-
-static int print_attr(const pjsdp_attr *attr, char *buf, int len)
-{
-    char *p = buf;
-    struct attr_map_rec *desc = &attr_map[attr->type];
-
-    if (len < 16) {
-	return -1;
-    }
-
-    *p++ = 'a';
-    *p++ = '=';
-    pj_memcpy(p, desc->name.ptr, desc->name.slen);
-    p += desc->name.slen;
-    
-    len = (*desc->print_attr)(attr, p, (buf+len)-p);
-    if (len < 0) {
-	return -1;
-    }
-    p += len;
-    *p++ = '\r';
-    *p++ = '\n';
-    return p-buf;
-}
-
-static pjsdp_attr* clone_rtpmap_attr (pj_pool_t *pool, const pjsdp_attr *p)
-{
-    const pjsdp_rtpmap_attr *rhs = (const pjsdp_rtpmap_attr*)p;
-    pjsdp_rtpmap_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_rtpmap_attr));
-    if (!attr)
-	return NULL;
-
-    attr->type = rhs->type;
-    attr->payload_type = rhs->payload_type;
-    if (!pj_strdup (pool, &attr->encoding_name, &rhs->encoding_name)) return NULL;
-    attr->clock_rate = rhs->clock_rate;
-    if (!pj_strdup (pool, &attr->parameter, &rhs->parameter)) return NULL;
-
-    return (pjsdp_attr*)attr;
-}
-
-static pjsdp_attr* clone_generic_string_attr (pj_pool_t *pool, const pjsdp_attr *p)
-{
-    const pjsdp_attr_string* rhs = (const pjsdp_attr_string*) p;
-    pjsdp_attr_string *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr_string));
-    if (!attr)
-	return NULL;
-
-    attr->type = rhs->type;
-    if (!pj_strdup (pool, &attr->value, &rhs->value)) return NULL;
-
-    return (pjsdp_attr*)attr;
-}
-
-static pjsdp_attr* clone_generic_num_attr (pj_pool_t *pool, const pjsdp_attr *p)
-{
-    const pjsdp_attr_num* rhs = (const pjsdp_attr_num*) p;
-    pjsdp_attr_num *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr_num));
-    if (!attr)
-	return NULL;
-
-    attr->type = rhs->type;
-    attr->value = rhs->value;
-
-    return (pjsdp_attr*)attr;
-}
-
-static pjsdp_attr* clone_name_only_attr (pj_pool_t *pool, const pjsdp_attr *rhs)
-{
-    pjsdp_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr));
-    if (!attr)
-	return NULL;
-
-    attr->type = rhs->type;
-    return attr;
-}
-
-static pjsdp_attr* clone_fmtp_attr (pj_pool_t *pool, const pjsdp_attr *p)
-{
-    const pjsdp_fmtp_attr* rhs = (const pjsdp_fmtp_attr*) p;
-    pjsdp_fmtp_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_fmtp_attr));
-    if (!attr)
-	return NULL;
-
-    attr->type = rhs->type;
-    if (!pj_strdup (pool, &attr->format, &rhs->format)) return NULL;
-    if (!pj_strdup (pool, &attr->param, &rhs->param)) return NULL;
-
-    return (pjsdp_attr*)attr;
-}
-
-PJ_DEF(pjsdp_attr*) pjsdp_attr_clone (pj_pool_t *pool, const pjsdp_attr *rhs)
-{
-    struct attr_map_rec *desc;
-
-    if (rhs->type >= PJSDP_END_OF_ATTR) {
-	pj_assert(0);
-	return NULL;
-    }
-
-    desc = &attr_map[rhs->type];
-    return (*desc->clone) (pool, rhs);
-}
-
-PJ_DEF(const pjsdp_attr*) pjsdp_attr_find (int count, const pjsdp_attr *attr_array[], int type)
-{
-    int i;
-
-    for (i=0; i<count; ++i) {
-	if (attr_array[i]->type == type)
-	    return attr_array[i];
-    }
-    return NULL;
-}
-
-static int print_connection_info( pjsdp_conn_info *c, char *buf, int len)
-{
-    char *p = buf;
-
-    if (len < 8+c->net_type.slen+c->addr_type.slen+c->addr.slen) {
-	return -1;
-    }
-    *p++ = 'c';
-    *p++ = '=';
-    pj_memcpy(p, c->net_type.ptr, c->net_type.slen);
-    p += c->net_type.slen;
-    *p++ = ' ';
-    pj_memcpy(p, c->addr_type.ptr, c->addr_type.slen);
-    p += c->addr_type.slen;
-    *p++ = ' ';
-    pj_memcpy(p, c->addr.ptr, c->addr.slen);
-    p += c->addr.slen;
-    *p++ = '\r';
-    *p++ = '\n';
-
-    return p-buf;
-}
-
-PJ_DEF(pjsdp_conn_info*) pjsdp_conn_info_clone (pj_pool_t *pool, const pjsdp_conn_info *rhs)
-{
-    pjsdp_conn_info *c = pj_pool_alloc (pool, sizeof(pjsdp_conn_info));
-    if (!c) return NULL;
-
-    if (!pj_strdup (pool, &c->net_type, &rhs->net_type)) return NULL;
-    if (!pj_strdup (pool, &c->addr_type, &rhs->addr_type)) return NULL;
-    if (!pj_strdup (pool, &c->addr, &rhs->addr)) return NULL;
-
-    return c;
-}
-
-static int print_media_desc( pjsdp_media_desc *m, char *buf, int len)
-{
-    char *p = buf;
-    char *end = buf+len;
-    unsigned i;
-    int printed;
-
-    /* check length for the "m=" line. */
-    if (len < m->desc.media.slen+m->desc.transport.slen+12+24) {
-	return -1;
-    }
-    *p++ = 'm';	    /* m= */
-    *p++ = '=';
-    pj_memcpy(p, m->desc.media.ptr, m->desc.media.slen);
-    p += m->desc.media.slen;
-    *p++ = ' ';
-    printed = pj_utoa(m->desc.port, p);
-    p += printed;
-    if (m->desc.port_count > 1) {
-	*p++ = '/';
-	printed = pj_utoa(m->desc.port_count, p);
-	p += printed;
-    }
-    *p++ = ' ';
-    pj_memcpy(p, m->desc.transport.ptr, m->desc.transport.slen);
-    p += m->desc.transport.slen;
-    for (i=0; i<m->desc.fmt_count; ++i) {
-	*p++ = ' ';
-	pj_memcpy(p, m->desc.fmt[i].ptr, m->desc.fmt[i].slen);
-	p += m->desc.fmt[i].slen;
-    }
-    *p++ = '\r';
-    *p++ = '\n';
-
-    /* print connection info, if present. */
-    if (m->conn) {
-	printed = print_connection_info(m->conn, p, end-p);
-	if (printed < 0) {
-	    return -1;
-	}
-	p += printed;
-    }
-
-    /* print attributes. */
-    for (i=0; i<m->attr_count; ++i) {
-	printed = print_attr(m->attr[i], p, end-p);
-	if (printed < 0) {
-	    return -1;
-	}
-	p += printed;
-    }
-
-    return p-buf;
-}
-
-PJ_DEF(pjsdp_media_desc*) pjsdp_media_desc_clone (pj_pool_t *pool, 
-						  const pjsdp_media_desc *rhs)
-{
-    unsigned int i;
-    pjsdp_media_desc *m = pj_pool_alloc (pool, sizeof(pjsdp_media_desc));
-    if (!m)
-	return NULL;
-
-    pj_strdup (pool, &m->desc.media, &rhs->desc.media);
-    m->desc.port = rhs->desc.port;
-    m->desc.port_count = rhs->desc.port_count;
-    pj_strdup (pool, &m->desc.transport, &rhs->desc.transport);
-    m->desc.fmt_count = rhs->desc.fmt_count;
-    for (i=0; i<rhs->desc.fmt_count; ++i)
-	m->desc.fmt[i] = rhs->desc.fmt[i];
-
-    if (rhs->conn) {
-	m->conn = pjsdp_conn_info_clone (pool, rhs->conn);
-	if (!m->conn)
-	    return NULL;
-    } else {
-	m->conn = NULL;
-    }
-
-    m->attr_count = rhs->attr_count;
-    for (i=0; i < rhs->attr_count; ++i) {
-	m->attr[i] = pjsdp_attr_clone (pool, rhs->attr[i]);
-	if (!m->attr[i])
-	    return NULL;
-    }
-
-    return m;
-}
-
-/** Check if the media description has the specified attribute. */
-PJ_DEF(pj_bool_t) pjsdp_media_desc_has_attr (const pjsdp_media_desc *m, 
-					     pjsdp_attr_type_e attr_type)
-{
-    unsigned i;
-    for (i=0; i<m->attr_count; ++i) {
-	pjsdp_attr *attr = m->attr[i];
-	if (attr->type == attr_type)
-	    return 1;
-    }
-    return 0;
-}
-
-/** Find rtpmap attribute for the specified payload type. */
-PJ_DEF(const pjsdp_rtpmap_attr*) 
-pjsdp_media_desc_find_rtpmap (const pjsdp_media_desc *m, unsigned pt)
-{
-    unsigned i;
-    for (i=0; i<m->attr_count; ++i) {
-	pjsdp_attr *attr = m->attr[i];
-	if (attr->type == PJSDP_ATTR_RTPMAP) {
-	    const pjsdp_rtpmap_attr* rtpmap = (const pjsdp_rtpmap_attr*)attr;
-	    if (rtpmap->payload_type == pt)
-		return rtpmap;
-	}
-    }
-    return NULL;
-}
-
-
-static int print_session(const pjsdp_session_desc *ses, char *buf, pj_ssize_t len)
-{
-    char *p = buf;
-    char *end = buf+len;
-    unsigned i;
-    int printed;
-
-    /* Check length for v= and o= lines. */
-    if (len < 5+ 
-	      2+ses->origin.user.slen+18+
-	      ses->origin.net_type.slen+ses->origin.addr.slen + 2)
-    {
-	return -1;
-    }
-
-    /* SDP version (v= line) */
-    pj_memcpy(p, "v=0\r\n", 5);
-    p += 5;
-
-    /* Owner (o=) line. */
-    *p++ = 'o';
-    *p++ = '=';
-    pj_memcpy(p, ses->origin.user.ptr, ses->origin.user.slen);
-    p += ses->origin.user.slen;
-    *p++ = ' ';
-    printed = pj_utoa(ses->origin.id, p);
-    p += printed;
-    *p++ = ' ';
-    printed = pj_utoa(ses->origin.version, p);
-    p += printed;
-    *p++ = ' ';
-    pj_memcpy(p, ses->origin.net_type.ptr, ses->origin.net_type.slen);
-    p += ses->origin.net_type.slen;
-    *p++ = ' ';
-    pj_memcpy(p, ses->origin.addr_type.ptr, ses->origin.addr_type.slen);
-    p += ses->origin.addr_type.slen;
-    *p++ = ' ';
-    pj_memcpy(p, ses->origin.addr.ptr, ses->origin.addr.slen);
-    p += ses->origin.addr.slen;
-    *p++ = '\r';
-    *p++ = '\n';
-
-    /* Session name (s=) line. */
-    if ((end-p)  < 8+ses->name.slen) {
-	return -1;
-    }
-    *p++ = 's';
-    *p++ = '=';
-    pj_memcpy(p, ses->name.ptr, ses->name.slen);
-    p += ses->name.slen;
-    *p++ = '\r';
-    *p++ = '\n';
-
-    /* Time */
-    if ((end-p) < 24) {
-	return -1;
-    }
-    *p++ = 't';
-    *p++ = '=';
-    printed = pj_utoa(ses->time.start, p);
-    p += printed;
-    *p++ = ' ';
-    printed = pj_utoa(ses->time.stop, p);
-    p += printed;
-    *p++ = '\r';
-    *p++ = '\n';
-
-    /* Connection line (c=) if exist. */
-    if (ses->conn) {
-	printed = print_connection_info(ses->conn, p, end-p);
-	if (printed < 1) {
-	    return -1;
-	}
-	p += printed;
-    }
-
-    /* Print all attribute (a=) lines. */
-    for (i=0; i<ses->attr_count; ++i) {
-	printed = print_attr(ses->attr[i], p, end-p);
-	if (printed < 0) {
-	    return -1;
-	}
-	p += printed;
-    }
-
-    /* Print media (m=) lines. */
-    for (i=0; i<ses->media_count; ++i) {
-	printed = print_media_desc(ses->media[i], p, end-p);
-	if (printed < 0) {
-	    return -1;
-	}
-	p += printed;
-    }
-
-    return p-buf;
-}
-
-/******************************************************************************
- * PARSERS
- */
-
-static void parse_version(pj_scanner *scanner)
-{
-    pj_scan_advance_n(scanner, 3, SKIP_WS);
-    pj_scan_get_newline(scanner);
-}
-
-static void parse_origin(pj_scanner *scanner, pjsdp_session_desc *ses)
-{
-    pj_str_t str;
-
-    /* o= */
-    pj_scan_advance_n(scanner, 2, SKIP_WS);
-
-    /* username. */
-    pj_scan_get_until_ch(scanner, ' ', &ses->origin.user);
-    pj_scan_get_char(scanner);
-
-    /* id */
-    pj_scan_get_until_ch(scanner, ' ', &str);
-    ses->origin.id = pj_strtoul(&str);
-    pj_scan_get_char(scanner);
-
-    /* version */
-    pj_scan_get_until_ch(scanner, ' ', &str);
-    ses->origin.version = pj_strtoul(&str);
-    pj_scan_get_char(scanner);
-
-    /* network-type */
-    pj_scan_get_until_ch(scanner, ' ', &ses->origin.net_type);
-    pj_scan_get_char(scanner);
-
-    /* addr-type */
-    pj_scan_get_until_ch(scanner, ' ', &ses->origin.addr_type);
-    pj_scan_get_char(scanner);
-
-    /* address */
-    pj_scan_get_until_ch(scanner, '\r', &ses->origin.addr);
-
-    /* newline */
-    pj_scan_get_newline(scanner);
-}
-
-static void parse_time(pj_scanner *scanner, pjsdp_session_desc *ses)
-{
-    pj_str_t str;
-
-    /* t= */
-    pj_scan_advance_n(scanner, 2, SKIP_WS);
-
-    /* start time */
-    pj_scan_get_until_ch(scanner, ' ', &str);
-    ses->time.start = pj_strtoul(&str);
-
-    pj_scan_get_char(scanner);
-
-    /* stop time */
-    pj_scan_get_until_ch(scanner, '\r', &str);
-    ses->time.stop = pj_strtoul(&str);
-
-    /* newline */
-    pj_scan_get_newline(scanner);
-}
-
-static void parse_generic_line(pj_scanner *scanner, pj_str_t *str)
-{
-    /* x= */
-    pj_scan_advance_n(scanner, 2, SKIP_WS);
-
-    /* get anything until newline. */
-    pj_scan_get_until_ch(scanner, '\r', str);
-
-    /* newline. */
-    pj_scan_get_newline(scanner);
-}
-
-static void parse_connection_info(pj_scanner *scanner, pjsdp_conn_info *conn)
-{
-    /* c= */
-    pj_scan_advance_n(scanner, 2, SKIP_WS);
-
-    /* network-type */
-    pj_scan_get_until_ch(scanner, ' ', &conn->net_type);
-    pj_scan_get_char(scanner);
-
-    /* addr-type */
-    pj_scan_get_until_ch(scanner, ' ', &conn->addr_type);
-    pj_scan_get_char(scanner);
-
-    /* address. */
-    pj_scan_get_until_ch(scanner, '\r', &conn->addr);
-
-    /* newline */
-    pj_scan_get_newline(scanner);
-}
-
-static void parse_media(pj_scanner *scanner, pjsdp_media_desc *med)
-{
-    pj_str_t str;
-
-    /* m= */
-    pj_scan_advance_n(scanner, 2, SKIP_WS);
-
-    /* type */
-    pj_scan_get_until_ch(scanner, ' ', &med->desc.media);
-    pj_scan_get_char(scanner);
-
-    /* port */
-    pj_scan_get(scanner, cs_token, &str);
-    med->desc.port = (unsigned short)pj_strtoul(&str);
-    if (*scanner->current == '/') {
-	/* port count */
-	pj_scan_get_char(scanner);
-	pj_scan_get(scanner, cs_token, &str);
-	med->desc.port_count = pj_strtoul(&str);
-
-    } else {
-	med->desc.port_count = 0;
-    }
-
-    if (pj_scan_get_char(scanner) != ' ') {
-	PJ_THROW(SYNTAX_ERROR);
-    }
-
-    /* transport */
-    pj_scan_get_until_ch(scanner, ' ', &med->desc.transport);
-
-    /* format list */
-    med->desc.fmt_count = 0;
-    while (*scanner->current == ' ') {
-	pj_scan_get_char(scanner);
-	pj_scan_get(scanner, cs_token, &med->desc.fmt[med->desc.fmt_count++]);
-    }
-
-    /* newline */
-    pj_scan_get_newline(scanner);
-}
-
-static pjsdp_rtpmap_attr * parse_rtpmap_attr( pj_pool_t *pool, pj_scanner *scanner )
-{
-    pjsdp_rtpmap_attr *rtpmap;
-    pj_str_t str;
-
-    rtpmap = pj_pool_calloc(pool, 1, sizeof(*rtpmap));
-    if (pj_scan_get_char(scanner) != ':') {
-	PJ_THROW(SYNTAX_ERROR);
-    }
-    pj_scan_get_until_ch(scanner, ' ', &str);
-    rtpmap->payload_type = pj_strtoul(&str);
-    pj_scan_get_char(scanner);
-
-    pj_scan_get_until_ch(scanner, '/', &rtpmap->encoding_name);
-    pj_scan_get_char(scanner);
-    pj_scan_get(scanner, cs_token, &str);
-    rtpmap->clock_rate = pj_strtoul(&str);
-
-    if (*scanner->current == '/') {
-	pj_scan_get_char(scanner);
-	pj_scan_get_until_ch(scanner, '\r', &rtpmap->parameter);
-    }
-
-    return rtpmap;
-}
-
-static pjsdp_attr_string * parse_generic_string_attr( pj_pool_t *pool, pj_scanner *scanner )
-{
-    pjsdp_attr_string *attr;
-    attr = pj_pool_calloc(pool, 1, sizeof(*attr));
-
-    if (pj_scan_get_char(scanner) != ':') {
-	PJ_THROW(SYNTAX_ERROR);
-    }
-    pj_scan_get_until_ch(scanner, '\r', &attr->value);
-    return attr;
-}
-
-static pjsdp_attr_num *	parse_generic_num_attr( pj_pool_t *pool, pj_scanner *scanner )
-{
-    pjsdp_attr_num *attr;
-    pj_str_t str;
-
-    attr = pj_pool_calloc(pool, 1, sizeof(*attr));
-
-    if (pj_scan_get_char(scanner) != ':') {
-	PJ_THROW(SYNTAX_ERROR);
-    }
-    pj_scan_get_until_ch(scanner, '\r', &str);
-    attr->value = pj_strtoul(&str);
-    return attr;
-}
-
-static pjsdp_attr * parse_name_only_attr( pj_pool_t *pool, pj_scanner *scanner )
-{
-    pjsdp_attr *attr;
-
-    PJ_UNUSED_ARG(scanner)
-    attr = pj_pool_calloc(pool, 1, sizeof(*attr));
-    return attr;
-}
-
-static pjsdp_fmtp_attr * parse_fmtp_attr( pj_pool_t *pool, pj_scanner *scanner )
-{
-    pjsdp_fmtp_attr *fmtp;
-
-    fmtp = pj_pool_calloc(pool, 1, sizeof(*fmtp));
-
-    if (pj_scan_get_char(scanner) != ':') {
-	PJ_THROW(SYNTAX_ERROR);
-    }
-    pj_scan_get_until_ch(scanner, ' ', &fmtp->format);
-    pj_scan_get_char(scanner);
-    pj_scan_get_until_ch(scanner, '\r', &fmtp->param);
-    return fmtp;
-}
-
-static pjsdp_attr *parse_attr( pj_pool_t *pool, pj_scanner *scanner)
-{
-    void * (*parse_func)(pj_pool_t *pool, pj_scanner *scanner) = NULL;
-    pj_str_t attrname;
-    unsigned i;
-    pjsdp_attr *attr;
-
-    /* skip a= */
-    pj_scan_advance_n(scanner, 2, SKIP_WS);
-    
-    /* get attr name. */
-    pj_scan_get(scanner, cs_token, &attrname);
-
-    /* find entry to handle attrname */
-    for (i=0; i<PJ_ARRAY_SIZE(attr_map); ++i) {
-	struct attr_map_rec *p = &attr_map[i];
-	if (pj_strcmp(&attrname, &p->name) == 0) {
-	    parse_func = p->parse_attr;
-	    break;
-	}
-    }
-
-    /* fallback to generic string parser. */
-    if (parse_func == NULL) {
-	parse_func = &parse_generic_string_attr;
-    }
-
-    attr = (*parse_func)(pool, scanner);
-    attr->type = i;
-	
-    /* newline */
-    pj_scan_get_newline(scanner);
-
-    return attr;
-}
-
-static void on_scanner_error(pj_scanner *scanner)
-{
-    PJ_UNUSED_ARG(scanner)
-
-    PJ_THROW(SYNTAX_ERROR);
-}
-
-/*
- * Parse SDP message.
- */
-PJ_DEF(pjsdp_session_desc*) pjsdp_parse( char *buf, pj_size_t len, 
-					 pj_pool_t *pool)
-{
-    pj_scanner scanner;
-    pjsdp_session_desc *session;
-    pjsdp_media_desc *media = NULL;
-    void *attr;
-    pjsdp_conn_info *conn;
-    pj_str_t dummy;
-    int cur_name = 254;
-    PJ_USE_EXCEPTION;
-
-    init_sdp_parser();
-
-    pj_scan_init(&scanner, buf, len, 0, &on_scanner_error);
-    session = pj_pool_calloc(pool, 1, sizeof(*session));
-
-    PJ_TRY {
-	while (!pj_scan_is_eof(&scanner)) {
-		cur_name = *scanner.current;
-		switch (cur_name) {
-		case 'a':
-		    attr = parse_attr(pool, &scanner);
-		    if (attr) {
-			if (media) {
-			    media->attr[media->attr_count++] = attr;
-			} else {
-			    session->attr[session->attr_count++] = attr;
-			}
-		    }
-		    break;
-		case 'o':
-		    parse_origin(&scanner, session);
-		    break;
-		case 's':
-		    parse_generic_line(&scanner, &session->name);
-		    break;
-		case 'c':
-		    conn = pj_pool_calloc(pool, 1, sizeof(*conn));
-		    parse_connection_info(&scanner, conn);
-		    if (media) {
-			media->conn = conn;
-		    } else {
-			session->conn = conn;
-		    }
-		    break;
-		case 't':
-		    parse_time(&scanner, session);
-		    break;
-		case 'm':
-		    media = pj_pool_calloc(pool, 1, sizeof(*media));
-		    parse_media(&scanner, media);
-		    session->media[ session->media_count++ ] = media;
-		    break;
-		case 'v':
-		    parse_version(&scanner);
-		    break;
-		default:
-		    parse_generic_line(&scanner, &dummy);
-		    break;
-		}
-	}
-    }
-    PJ_CATCH(SYNTAX_ERROR) {
-	PJ_LOG(2, (LOG_THIS, "Syntax error in SDP parser '%c' line %d col %d",
-		cur_name, scanner.line, scanner.col));
-	if (!pj_scan_is_eof(&scanner)) {
-	    if (*scanner.current != '\r') {
-		pj_scan_get_until_ch(&scanner, '\r', &dummy);
-	    }
-	    pj_scan_get_newline(&scanner);
-	}
-    }
-    PJ_END;
-
-    pj_scan_fini(&scanner);
-    return session;
-}
-
-/*
- * Print SDP description.
- */
-PJ_DEF(int) pjsdp_print( const pjsdp_session_desc *desc, char *buf, pj_size_t size)
-{
-    return print_session(desc, buf, size);
-}
-
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+

+#include <pjmedia/sdp.h>

+#include <pj/scanner.h>

+#include <pj/except.h>

+#include <pj/log.h>

+#include <pj/os.h>

+#include <pj/string.h>

+#include <pj/pool.h>

+

+enum {

+    SKIP_WS = 0,

+    SYNTAX_ERROR = 1,

+};

+#define TOKEN		"-.!%*_=`'~"

+#define NTP_OFFSET	((pj_uint32_t)2208988800)

+#define LOG_THIS	"sdp"

+

+/*

+ * Prototypes for line parser.

+ */

+static void parse_version(pj_scanner *scanner);

+static void parse_origin(pj_scanner *scanner, pjsdp_session_desc *ses);

+static void parse_time(pj_scanner *scanner, pjsdp_session_desc *ses);

+static void parse_generic_line(pj_scanner *scanner, pj_str_t *str);

+static void parse_connection_info(pj_scanner *scanner, pjsdp_conn_info *conn);

+static pjsdp_attr *parse_attr(pj_pool_t *pool, pj_scanner *scanner);

+static void parse_media(pj_scanner *scanner, pjsdp_media_desc *med);

+

+/*

+ * Prototypes for attribute parsers.

+ */

+static pjsdp_rtpmap_attr *  parse_rtpmap_attr( pj_pool_t *pool, pj_scanner *scanner );

+static pjsdp_attr_string *  parse_generic_string_attr( pj_pool_t *pool, pj_scanner *scanner );

+static pjsdp_attr_num *	    parse_generic_num_attr( pj_pool_t *pool, pj_scanner *scanner );

+static pjsdp_attr *	    parse_name_only_attr( pj_pool_t *pool, pj_scanner *scanner );

+static pjsdp_fmtp_attr *    parse_fmtp_attr( pj_pool_t *pool, pj_scanner *scanner );

+

+

+/* 

+ * Prototypes for functions to print attribute.

+ * All of them returns integer for the length printed, or -1 on error.

+ */

+static int print_rtpmap_attr(const pjsdp_rtpmap_attr *attr, 

+			     char *buf, int length);

+static int print_generic_string_attr(const pjsdp_attr_string *attr, 

+				     char *buf, int length);

+static int print_generic_num_attr(const pjsdp_attr_num *attr, 

+				  char *buf, int length);

+static int print_name_only_attr(const pjsdp_attr *attr, 

+				char *buf, int length);

+static int print_fmtp_attr(const pjsdp_fmtp_attr *attr, 

+			   char *buf, int length);

+

+/*

+ * Prototypes for cloning attributes.

+ */

+static pjsdp_attr* clone_rtpmap_attr (pj_pool_t *pool, const pjsdp_attr *rhs);

+static pjsdp_attr* clone_generic_string_attr (pj_pool_t *pool, const pjsdp_attr *rhs);

+static pjsdp_attr* clone_generic_num_attr (pj_pool_t *pool, const pjsdp_attr *rhs);

+static pjsdp_attr* clone_name_only_attr (pj_pool_t *pool, const pjsdp_attr *rhs);

+static pjsdp_attr* clone_fmtp_attr (pj_pool_t *pool, const pjsdp_attr *rhs);

+

+

+/*

+ * Prototypes

+ */

+static void init_sdp_parser(void);

+

+

+typedef void *  (*FPARSE)(pj_pool_t *pool, pj_scanner *scanner);

+typedef int (*FPRINT)(const void *attr, char *buf, int length);

+typedef pjsdp_attr*  (*FCLONE)(pj_pool_t *pool, const pjsdp_attr *rhs);

+

+/*

+ * Array of functions to print attribute.

+ */

+static struct attr_map_rec

+{

+    pj_str_t name;

+    FPARSE   parse_attr;

+    FPRINT   print_attr;

+    FCLONE   clone;

+} attr_map[] = 

+{

+    {{"rtpmap", 6},    (FPARSE)&parse_rtpmap_attr,	   (FPRINT)&print_rtpmap_attr,		(FCLONE)&clone_rtpmap_attr},

+    {{"cat", 3},       (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},

+    {{"keywds", 6},    (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},

+    {{"tool", 4},      (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},

+    {{"ptime", 5},     (FPARSE)&parse_generic_num_attr,    (FPRINT)&print_generic_num_attr,	(FCLONE)&clone_generic_num_attr},

+    {{"recvonly", 8},  (FPARSE)&parse_name_only_attr,	   (FPRINT)&print_name_only_attr,	(FCLONE)&clone_name_only_attr},

+    {{"sendonly", 8},  (FPARSE)&parse_name_only_attr,	   (FPRINT)&print_name_only_attr,	(FCLONE)&clone_name_only_attr},

+    {{"sendrecv", 8},  (FPARSE)&parse_name_only_attr,	   (FPRINT)&print_name_only_attr,	(FCLONE)&clone_name_only_attr},

+    {{"orient", 6},    (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},

+    {{"type", 4},      (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},

+    {{"charset", 7},   (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},

+    {{"sdplang", 7},   (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},

+    {{"lang", 4},      (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},

+    {{"framerate", 9}, (FPARSE)&parse_generic_string_attr, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr},

+    {{"quality", 7},   (FPARSE)&parse_generic_num_attr,    (FPRINT)&print_generic_num_attr,	(FCLONE)&clone_generic_num_attr},

+    {{"fmtp", 4},      (FPARSE)&parse_fmtp_attr,	   (FPRINT)&print_fmtp_attr,		(FCLONE)&clone_fmtp_attr},

+    {{"inactive", 8},  (FPARSE)&parse_name_only_attr,	   (FPRINT)&print_name_only_attr,	(FCLONE)&clone_name_only_attr},

+    {{"", 0},	       NULL, (FPRINT)&print_generic_string_attr,	(FCLONE)&clone_generic_string_attr}

+};

+

+/*

+ * Scanner character specification.

+ */

+static int is_initialized;

+static pj_char_spec cs_token;

+

+static void init_sdp_parser(void)

+{

+    if (is_initialized == 0) {

+	is_initialized = 1;

+	if (is_initialized != 1) {

+	    return;

+	}

+    }

+    pj_cs_add_alpha(cs_token);

+    pj_cs_add_num(cs_token);

+    pj_cs_add_str( cs_token, TOKEN);

+}

+

+static int print_rtpmap_attr(const pjsdp_rtpmap_attr *rtpmap, 

+			     char *buf, int len)

+{

+    char *p = buf;

+

+    if (len < 16+rtpmap->encoding_name.slen+rtpmap->parameter.slen) {

+	return -1;

+    }

+    

+    /* colon and payload type. */

+    *p++ = ':';

+    len = pj_utoa(rtpmap->payload_type, p);

+    p += len;

+

+    /* space, encoding name */

+    *p++ = ' ';

+    pj_memcpy(p, rtpmap->encoding_name.ptr, rtpmap->encoding_name.slen);

+    p += rtpmap->encoding_name.slen;

+

+    /* slash, clock-rate. */

+    *p++ = '/';

+    len = pj_utoa(rtpmap->clock_rate, p);

+    p += len;

+

+    /* optionally add encoding parameter. */

+    if (rtpmap->parameter.slen) {

+	*p++ = '/';

+	pj_memcpy(p, rtpmap->parameter.ptr, rtpmap->parameter.slen);

+	p += rtpmap->parameter.slen;

+    }

+

+    return p-buf;

+}

+

+static int print_generic_string_attr(const pjsdp_attr_string *attr, 

+				     char *buf, int len)

+{

+    char *p = buf;

+

+    if (len < attr->value.slen + 4) {

+	return -1;

+    }

+

+    /* colon and attribute value. */

+    *p++ = ':';

+    pj_memcpy(p, attr->value.ptr, attr->value.slen);

+    p += attr->value.slen;

+

+    return p-buf;

+}

+

+static int print_generic_num_attr(const pjsdp_attr_num *attr, char *buf, int len)

+{

+    char *p = buf;

+

+    if (len < 10) {

+	return -1;

+    }

+    *p++ = ':';

+    return pj_utoa(attr->value, p);

+}

+

+static int print_name_only_attr(const pjsdp_attr *attr, char *buf, int len)

+{

+    PJ_UNUSED_ARG(attr)

+    PJ_UNUSED_ARG(buf)

+    PJ_UNUSED_ARG(len)

+    return 0;

+}

+

+static int print_fmtp_attr(const pjsdp_fmtp_attr *fmtp, char *buf, int len)

+{

+    char *p = buf;

+

+    if (len < 4+fmtp->format.slen+fmtp->param.slen) {

+	return -1;

+    }

+

+    /* colon and format. */

+    *p++ = ':';

+    pj_memcpy(p, fmtp->format.ptr, fmtp->format.slen);

+    p += fmtp->format.slen;

+

+    /* space and parameter. */

+    *p++ = ' ';

+    pj_memcpy(p, fmtp->param.ptr, fmtp->param.slen);

+    p += fmtp->param.slen;

+

+    return p-buf;

+}

+

+

+static int print_attr(const pjsdp_attr *attr, char *buf, int len)

+{

+    char *p = buf;

+    struct attr_map_rec *desc = &attr_map[attr->type];

+

+    if (len < 16) {

+	return -1;

+    }

+

+    *p++ = 'a';

+    *p++ = '=';

+    pj_memcpy(p, desc->name.ptr, desc->name.slen);

+    p += desc->name.slen;

+    

+    len = (*desc->print_attr)(attr, p, (buf+len)-p);

+    if (len < 0) {

+	return -1;

+    }

+    p += len;

+    *p++ = '\r';

+    *p++ = '\n';

+    return p-buf;

+}

+

+static pjsdp_attr* clone_rtpmap_attr (pj_pool_t *pool, const pjsdp_attr *p)

+{

+    const pjsdp_rtpmap_attr *rhs = (const pjsdp_rtpmap_attr*)p;

+    pjsdp_rtpmap_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_rtpmap_attr));

+    if (!attr)

+	return NULL;

+

+    attr->type = rhs->type;

+    attr->payload_type = rhs->payload_type;

+    if (!pj_strdup (pool, &attr->encoding_name, &rhs->encoding_name)) return NULL;

+    attr->clock_rate = rhs->clock_rate;

+    if (!pj_strdup (pool, &attr->parameter, &rhs->parameter)) return NULL;

+

+    return (pjsdp_attr*)attr;

+}

+

+static pjsdp_attr* clone_generic_string_attr (pj_pool_t *pool, const pjsdp_attr *p)

+{

+    const pjsdp_attr_string* rhs = (const pjsdp_attr_string*) p;

+    pjsdp_attr_string *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr_string));

+    if (!attr)

+	return NULL;

+

+    attr->type = rhs->type;

+    if (!pj_strdup (pool, &attr->value, &rhs->value)) return NULL;

+

+    return (pjsdp_attr*)attr;

+}

+

+static pjsdp_attr* clone_generic_num_attr (pj_pool_t *pool, const pjsdp_attr *p)

+{

+    const pjsdp_attr_num* rhs = (const pjsdp_attr_num*) p;

+    pjsdp_attr_num *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr_num));

+    if (!attr)

+	return NULL;

+

+    attr->type = rhs->type;

+    attr->value = rhs->value;

+

+    return (pjsdp_attr*)attr;

+}

+

+static pjsdp_attr* clone_name_only_attr (pj_pool_t *pool, const pjsdp_attr *rhs)

+{

+    pjsdp_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_attr));

+    if (!attr)

+	return NULL;

+

+    attr->type = rhs->type;

+    return attr;

+}

+

+static pjsdp_attr* clone_fmtp_attr (pj_pool_t *pool, const pjsdp_attr *p)

+{

+    const pjsdp_fmtp_attr* rhs = (const pjsdp_fmtp_attr*) p;

+    pjsdp_fmtp_attr *attr = pj_pool_alloc (pool, sizeof(pjsdp_fmtp_attr));

+    if (!attr)

+	return NULL;

+

+    attr->type = rhs->type;

+    if (!pj_strdup (pool, &attr->format, &rhs->format)) return NULL;

+    if (!pj_strdup (pool, &attr->param, &rhs->param)) return NULL;

+

+    return (pjsdp_attr*)attr;

+}

+

+PJ_DEF(pjsdp_attr*) pjsdp_attr_clone (pj_pool_t *pool, const pjsdp_attr *rhs)

+{

+    struct attr_map_rec *desc;

+

+    if (rhs->type >= PJSDP_END_OF_ATTR) {

+	pj_assert(0);

+	return NULL;

+    }

+

+    desc = &attr_map[rhs->type];

+    return (*desc->clone) (pool, rhs);

+}

+

+PJ_DEF(const pjsdp_attr*) pjsdp_attr_find (int count, const pjsdp_attr *attr_array[], int type)

+{

+    int i;

+

+    for (i=0; i<count; ++i) {

+	if (attr_array[i]->type == type)

+	    return attr_array[i];

+    }

+    return NULL;

+}

+

+static int print_connection_info( pjsdp_conn_info *c, char *buf, int len)

+{

+    char *p = buf;

+

+    if (len < 8+c->net_type.slen+c->addr_type.slen+c->addr.slen) {

+	return -1;

+    }

+    *p++ = 'c';

+    *p++ = '=';

+    pj_memcpy(p, c->net_type.ptr, c->net_type.slen);

+    p += c->net_type.slen;

+    *p++ = ' ';

+    pj_memcpy(p, c->addr_type.ptr, c->addr_type.slen);

+    p += c->addr_type.slen;

+    *p++ = ' ';

+    pj_memcpy(p, c->addr.ptr, c->addr.slen);

+    p += c->addr.slen;

+    *p++ = '\r';

+    *p++ = '\n';

+

+    return p-buf;

+}

+

+PJ_DEF(pjsdp_conn_info*) pjsdp_conn_info_clone (pj_pool_t *pool, const pjsdp_conn_info *rhs)

+{

+    pjsdp_conn_info *c = pj_pool_alloc (pool, sizeof(pjsdp_conn_info));

+    if (!c) return NULL;

+

+    if (!pj_strdup (pool, &c->net_type, &rhs->net_type)) return NULL;

+    if (!pj_strdup (pool, &c->addr_type, &rhs->addr_type)) return NULL;

+    if (!pj_strdup (pool, &c->addr, &rhs->addr)) return NULL;

+

+    return c;

+}

+

+static int print_media_desc( pjsdp_media_desc *m, char *buf, int len)

+{

+    char *p = buf;

+    char *end = buf+len;

+    unsigned i;

+    int printed;

+

+    /* check length for the "m=" line. */

+    if (len < m->desc.media.slen+m->desc.transport.slen+12+24) {

+	return -1;

+    }

+    *p++ = 'm';	    /* m= */

+    *p++ = '=';

+    pj_memcpy(p, m->desc.media.ptr, m->desc.media.slen);

+    p += m->desc.media.slen;

+    *p++ = ' ';

+    printed = pj_utoa(m->desc.port, p);

+    p += printed;

+    if (m->desc.port_count > 1) {

+	*p++ = '/';

+	printed = pj_utoa(m->desc.port_count, p);

+	p += printed;

+    }

+    *p++ = ' ';

+    pj_memcpy(p, m->desc.transport.ptr, m->desc.transport.slen);

+    p += m->desc.transport.slen;

+    for (i=0; i<m->desc.fmt_count; ++i) {

+	*p++ = ' ';

+	pj_memcpy(p, m->desc.fmt[i].ptr, m->desc.fmt[i].slen);

+	p += m->desc.fmt[i].slen;

+    }

+    *p++ = '\r';

+    *p++ = '\n';

+

+    /* print connection info, if present. */

+    if (m->conn) {

+	printed = print_connection_info(m->conn, p, end-p);

+	if (printed < 0) {

+	    return -1;

+	}

+	p += printed;

+    }

+

+    /* print attributes. */

+    for (i=0; i<m->attr_count; ++i) {

+	printed = print_attr(m->attr[i], p, end-p);

+	if (printed < 0) {

+	    return -1;

+	}

+	p += printed;

+    }

+

+    return p-buf;

+}

+

+PJ_DEF(pjsdp_media_desc*) pjsdp_media_desc_clone (pj_pool_t *pool, 

+						  const pjsdp_media_desc *rhs)

+{

+    unsigned int i;

+    pjsdp_media_desc *m = pj_pool_alloc (pool, sizeof(pjsdp_media_desc));

+    if (!m)

+	return NULL;

+

+    pj_strdup (pool, &m->desc.media, &rhs->desc.media);

+    m->desc.port = rhs->desc.port;

+    m->desc.port_count = rhs->desc.port_count;

+    pj_strdup (pool, &m->desc.transport, &rhs->desc.transport);

+    m->desc.fmt_count = rhs->desc.fmt_count;

+    for (i=0; i<rhs->desc.fmt_count; ++i)

+	m->desc.fmt[i] = rhs->desc.fmt[i];

+

+    if (rhs->conn) {

+	m->conn = pjsdp_conn_info_clone (pool, rhs->conn);

+	if (!m->conn)

+	    return NULL;

+    } else {

+	m->conn = NULL;

+    }

+

+    m->attr_count = rhs->attr_count;

+    for (i=0; i < rhs->attr_count; ++i) {

+	m->attr[i] = pjsdp_attr_clone (pool, rhs->attr[i]);

+	if (!m->attr[i])

+	    return NULL;

+    }

+

+    return m;

+}

+

+/** Check if the media description has the specified attribute. */

+PJ_DEF(pj_bool_t) pjsdp_media_desc_has_attr (const pjsdp_media_desc *m, 

+					     pjsdp_attr_type_e attr_type)

+{

+    unsigned i;

+    for (i=0; i<m->attr_count; ++i) {

+	pjsdp_attr *attr = m->attr[i];

+	if (attr->type == attr_type)

+	    return 1;

+    }

+    return 0;

+}

+

+/** Find rtpmap attribute for the specified payload type. */

+PJ_DEF(const pjsdp_rtpmap_attr*) 

+pjsdp_media_desc_find_rtpmap (const pjsdp_media_desc *m, unsigned pt)

+{

+    unsigned i;

+    for (i=0; i<m->attr_count; ++i) {

+	pjsdp_attr *attr = m->attr[i];

+	if (attr->type == PJSDP_ATTR_RTPMAP) {

+	    const pjsdp_rtpmap_attr* rtpmap = (const pjsdp_rtpmap_attr*)attr;

+	    if (rtpmap->payload_type == pt)

+		return rtpmap;

+	}

+    }

+    return NULL;

+}

+

+

+static int print_session(const pjsdp_session_desc *ses, char *buf, pj_ssize_t len)

+{

+    char *p = buf;

+    char *end = buf+len;

+    unsigned i;

+    int printed;

+

+    /* Check length for v= and o= lines. */

+    if (len < 5+ 

+	      2+ses->origin.user.slen+18+

+	      ses->origin.net_type.slen+ses->origin.addr.slen + 2)

+    {

+	return -1;

+    }

+

+    /* SDP version (v= line) */

+    pj_memcpy(p, "v=0\r\n", 5);

+    p += 5;

+

+    /* Owner (o=) line. */

+    *p++ = 'o';

+    *p++ = '=';

+    pj_memcpy(p, ses->origin.user.ptr, ses->origin.user.slen);

+    p += ses->origin.user.slen;

+    *p++ = ' ';

+    printed = pj_utoa(ses->origin.id, p);

+    p += printed;

+    *p++ = ' ';

+    printed = pj_utoa(ses->origin.version, p);

+    p += printed;

+    *p++ = ' ';

+    pj_memcpy(p, ses->origin.net_type.ptr, ses->origin.net_type.slen);

+    p += ses->origin.net_type.slen;

+    *p++ = ' ';

+    pj_memcpy(p, ses->origin.addr_type.ptr, ses->origin.addr_type.slen);

+    p += ses->origin.addr_type.slen;

+    *p++ = ' ';

+    pj_memcpy(p, ses->origin.addr.ptr, ses->origin.addr.slen);

+    p += ses->origin.addr.slen;

+    *p++ = '\r';

+    *p++ = '\n';

+

+    /* Session name (s=) line. */

+    if ((end-p)  < 8+ses->name.slen) {

+	return -1;

+    }

+    *p++ = 's';

+    *p++ = '=';

+    pj_memcpy(p, ses->name.ptr, ses->name.slen);

+    p += ses->name.slen;

+    *p++ = '\r';

+    *p++ = '\n';

+

+    /* Time */

+    if ((end-p) < 24) {

+	return -1;

+    }

+    *p++ = 't';

+    *p++ = '=';

+    printed = pj_utoa(ses->time.start, p);

+    p += printed;

+    *p++ = ' ';

+    printed = pj_utoa(ses->time.stop, p);

+    p += printed;

+    *p++ = '\r';

+    *p++ = '\n';

+

+    /* Connection line (c=) if exist. */

+    if (ses->conn) {

+	printed = print_connection_info(ses->conn, p, end-p);

+	if (printed < 1) {

+	    return -1;

+	}

+	p += printed;

+    }

+

+    /* Print all attribute (a=) lines. */

+    for (i=0; i<ses->attr_count; ++i) {

+	printed = print_attr(ses->attr[i], p, end-p);

+	if (printed < 0) {

+	    return -1;

+	}

+	p += printed;

+    }

+

+    /* Print media (m=) lines. */

+    for (i=0; i<ses->media_count; ++i) {

+	printed = print_media_desc(ses->media[i], p, end-p);

+	if (printed < 0) {

+	    return -1;

+	}

+	p += printed;

+    }

+

+    return p-buf;

+}

+

+/******************************************************************************

+ * PARSERS

+ */

+

+static void parse_version(pj_scanner *scanner)

+{

+    pj_scan_advance_n(scanner, 3, SKIP_WS);

+    pj_scan_get_newline(scanner);

+}

+

+static void parse_origin(pj_scanner *scanner, pjsdp_session_desc *ses)

+{

+    pj_str_t str;

+

+    /* o= */

+    pj_scan_advance_n(scanner, 2, SKIP_WS);

+

+    /* username. */

+    pj_scan_get_until_ch(scanner, ' ', &ses->origin.user);

+    pj_scan_get_char(scanner);

+

+    /* id */

+    pj_scan_get_until_ch(scanner, ' ', &str);

+    ses->origin.id = pj_strtoul(&str);

+    pj_scan_get_char(scanner);

+

+    /* version */

+    pj_scan_get_until_ch(scanner, ' ', &str);

+    ses->origin.version = pj_strtoul(&str);

+    pj_scan_get_char(scanner);

+

+    /* network-type */

+    pj_scan_get_until_ch(scanner, ' ', &ses->origin.net_type);

+    pj_scan_get_char(scanner);

+

+    /* addr-type */

+    pj_scan_get_until_ch(scanner, ' ', &ses->origin.addr_type);

+    pj_scan_get_char(scanner);

+

+    /* address */

+    pj_scan_get_until_ch(scanner, '\r', &ses->origin.addr);

+

+    /* newline */

+    pj_scan_get_newline(scanner);

+}

+

+static void parse_time(pj_scanner *scanner, pjsdp_session_desc *ses)

+{

+    pj_str_t str;

+

+    /* t= */

+    pj_scan_advance_n(scanner, 2, SKIP_WS);

+

+    /* start time */

+    pj_scan_get_until_ch(scanner, ' ', &str);

+    ses->time.start = pj_strtoul(&str);

+

+    pj_scan_get_char(scanner);

+

+    /* stop time */

+    pj_scan_get_until_ch(scanner, '\r', &str);

+    ses->time.stop = pj_strtoul(&str);

+

+    /* newline */

+    pj_scan_get_newline(scanner);

+}

+

+static void parse_generic_line(pj_scanner *scanner, pj_str_t *str)

+{

+    /* x= */

+    pj_scan_advance_n(scanner, 2, SKIP_WS);

+

+    /* get anything until newline. */

+    pj_scan_get_until_ch(scanner, '\r', str);

+

+    /* newline. */

+    pj_scan_get_newline(scanner);

+}

+

+static void parse_connection_info(pj_scanner *scanner, pjsdp_conn_info *conn)

+{

+    /* c= */

+    pj_scan_advance_n(scanner, 2, SKIP_WS);

+

+    /* network-type */

+    pj_scan_get_until_ch(scanner, ' ', &conn->net_type);

+    pj_scan_get_char(scanner);

+

+    /* addr-type */

+    pj_scan_get_until_ch(scanner, ' ', &conn->addr_type);

+    pj_scan_get_char(scanner);

+

+    /* address. */

+    pj_scan_get_until_ch(scanner, '\r', &conn->addr);

+

+    /* newline */

+    pj_scan_get_newline(scanner);

+}

+

+static void parse_media(pj_scanner *scanner, pjsdp_media_desc *med)

+{

+    pj_str_t str;

+

+    /* m= */

+    pj_scan_advance_n(scanner, 2, SKIP_WS);

+

+    /* type */

+    pj_scan_get_until_ch(scanner, ' ', &med->desc.media);

+    pj_scan_get_char(scanner);

+

+    /* port */

+    pj_scan_get(scanner, cs_token, &str);

+    med->desc.port = (unsigned short)pj_strtoul(&str);

+    if (*scanner->current == '/') {

+	/* port count */

+	pj_scan_get_char(scanner);

+	pj_scan_get(scanner, cs_token, &str);

+	med->desc.port_count = pj_strtoul(&str);

+

+    } else {

+	med->desc.port_count = 0;

+    }

+

+    if (pj_scan_get_char(scanner) != ' ') {

+	PJ_THROW(SYNTAX_ERROR);

+    }

+

+    /* transport */

+    pj_scan_get_until_ch(scanner, ' ', &med->desc.transport);

+

+    /* format list */

+    med->desc.fmt_count = 0;

+    while (*scanner->current == ' ') {

+	pj_scan_get_char(scanner);

+	pj_scan_get(scanner, cs_token, &med->desc.fmt[med->desc.fmt_count++]);

+    }

+

+    /* newline */

+    pj_scan_get_newline(scanner);

+}

+

+static pjsdp_rtpmap_attr * parse_rtpmap_attr( pj_pool_t *pool, pj_scanner *scanner )

+{

+    pjsdp_rtpmap_attr *rtpmap;

+    pj_str_t str;

+

+    rtpmap = pj_pool_calloc(pool, 1, sizeof(*rtpmap));

+    if (pj_scan_get_char(scanner) != ':') {

+	PJ_THROW(SYNTAX_ERROR);

+    }

+    pj_scan_get_until_ch(scanner, ' ', &str);

+    rtpmap->payload_type = pj_strtoul(&str);

+    pj_scan_get_char(scanner);

+

+    pj_scan_get_until_ch(scanner, '/', &rtpmap->encoding_name);

+    pj_scan_get_char(scanner);

+    pj_scan_get(scanner, cs_token, &str);

+    rtpmap->clock_rate = pj_strtoul(&str);

+

+    if (*scanner->current == '/') {

+	pj_scan_get_char(scanner);

+	pj_scan_get_until_ch(scanner, '\r', &rtpmap->parameter);

+    }

+

+    return rtpmap;

+}

+

+static pjsdp_attr_string * parse_generic_string_attr( pj_pool_t *pool, pj_scanner *scanner )

+{

+    pjsdp_attr_string *attr;

+    attr = pj_pool_calloc(pool, 1, sizeof(*attr));

+

+    if (pj_scan_get_char(scanner) != ':') {

+	PJ_THROW(SYNTAX_ERROR);

+    }

+    pj_scan_get_until_ch(scanner, '\r', &attr->value);

+    return attr;

+}

+

+static pjsdp_attr_num *	parse_generic_num_attr( pj_pool_t *pool, pj_scanner *scanner )

+{

+    pjsdp_attr_num *attr;

+    pj_str_t str;

+

+    attr = pj_pool_calloc(pool, 1, sizeof(*attr));

+

+    if (pj_scan_get_char(scanner) != ':') {

+	PJ_THROW(SYNTAX_ERROR);

+    }

+    pj_scan_get_until_ch(scanner, '\r', &str);

+    attr->value = pj_strtoul(&str);

+    return attr;

+}

+

+static pjsdp_attr * parse_name_only_attr( pj_pool_t *pool, pj_scanner *scanner )

+{

+    pjsdp_attr *attr;

+

+    PJ_UNUSED_ARG(scanner)

+    attr = pj_pool_calloc(pool, 1, sizeof(*attr));

+    return attr;

+}

+

+static pjsdp_fmtp_attr * parse_fmtp_attr( pj_pool_t *pool, pj_scanner *scanner )

+{

+    pjsdp_fmtp_attr *fmtp;

+

+    fmtp = pj_pool_calloc(pool, 1, sizeof(*fmtp));

+

+    if (pj_scan_get_char(scanner) != ':') {

+	PJ_THROW(SYNTAX_ERROR);

+    }

+    pj_scan_get_until_ch(scanner, ' ', &fmtp->format);

+    pj_scan_get_char(scanner);

+    pj_scan_get_until_ch(scanner, '\r', &fmtp->param);

+    return fmtp;

+}

+

+static pjsdp_attr *parse_attr( pj_pool_t *pool, pj_scanner *scanner)

+{

+    void * (*parse_func)(pj_pool_t *pool, pj_scanner *scanner) = NULL;

+    pj_str_t attrname;

+    unsigned i;

+    pjsdp_attr *attr;

+

+    /* skip a= */

+    pj_scan_advance_n(scanner, 2, SKIP_WS);

+    

+    /* get attr name. */

+    pj_scan_get(scanner, cs_token, &attrname);

+

+    /* find entry to handle attrname */

+    for (i=0; i<PJ_ARRAY_SIZE(attr_map); ++i) {

+	struct attr_map_rec *p = &attr_map[i];

+	if (pj_strcmp(&attrname, &p->name) == 0) {

+	    parse_func = p->parse_attr;

+	    break;

+	}

+    }

+

+    /* fallback to generic string parser. */

+    if (parse_func == NULL) {

+	parse_func = &parse_generic_string_attr;

+    }

+

+    attr = (*parse_func)(pool, scanner);

+    attr->type = i;

+	

+    /* newline */

+    pj_scan_get_newline(scanner);

+

+    return attr;

+}

+

+static void on_scanner_error(pj_scanner *scanner)

+{

+    PJ_UNUSED_ARG(scanner)

+

+    PJ_THROW(SYNTAX_ERROR);

+}

+

+/*

+ * Parse SDP message.

+ */

+PJ_DEF(pjsdp_session_desc*) pjsdp_parse( char *buf, pj_size_t len, 

+					 pj_pool_t *pool)

+{

+    pj_scanner scanner;

+    pjsdp_session_desc *session;

+    pjsdp_media_desc *media = NULL;

+    void *attr;

+    pjsdp_conn_info *conn;

+    pj_str_t dummy;

+    int cur_name = 254;

+    PJ_USE_EXCEPTION;

+

+    init_sdp_parser();

+

+    pj_scan_init(&scanner, buf, len, 0, &on_scanner_error);

+    session = pj_pool_calloc(pool, 1, sizeof(*session));

+

+    PJ_TRY {

+	while (!pj_scan_is_eof(&scanner)) {

+		cur_name = *scanner.current;

+		switch (cur_name) {

+		case 'a':

+		    attr = parse_attr(pool, &scanner);

+		    if (attr) {

+			if (media) {

+			    media->attr[media->attr_count++] = attr;

+			} else {

+			    session->attr[session->attr_count++] = attr;

+			}

+		    }

+		    break;

+		case 'o':

+		    parse_origin(&scanner, session);

+		    break;

+		case 's':

+		    parse_generic_line(&scanner, &session->name);

+		    break;

+		case 'c':

+		    conn = pj_pool_calloc(pool, 1, sizeof(*conn));

+		    parse_connection_info(&scanner, conn);

+		    if (media) {

+			media->conn = conn;

+		    } else {

+			session->conn = conn;

+		    }

+		    break;

+		case 't':

+		    parse_time(&scanner, session);

+		    break;

+		case 'm':

+		    media = pj_pool_calloc(pool, 1, sizeof(*media));

+		    parse_media(&scanner, media);

+		    session->media[ session->media_count++ ] = media;

+		    break;

+		case 'v':

+		    parse_version(&scanner);

+		    break;

+		default:

+		    parse_generic_line(&scanner, &dummy);

+		    break;

+		}

+	}

+    }

+    PJ_CATCH(SYNTAX_ERROR) {

+	PJ_LOG(2, (LOG_THIS, "Syntax error in SDP parser '%c' line %d col %d",

+		cur_name, scanner.line, scanner.col));

+	if (!pj_scan_is_eof(&scanner)) {

+	    if (*scanner.current != '\r') {

+		pj_scan_get_until_ch(&scanner, '\r', &dummy);

+	    }

+	    pj_scan_get_newline(&scanner);

+	}

+    }

+    PJ_END;

+

+    pj_scan_fini(&scanner);

+    return session;

+}

+

+/*

+ * Print SDP description.

+ */

+PJ_DEF(int) pjsdp_print( const pjsdp_session_desc *desc, char *buf, pj_size_t size)

+{

+    return print_session(desc, buf, size);

+}

+

+

diff --git a/pjmedia/src/pjmedia/sdp.h b/pjmedia/src/pjmedia/sdp.h
index 6fc4ec4..5d537c9 100644
--- a/pjmedia/src/pjmedia/sdp.h
+++ b/pjmedia/src/pjmedia/sdp.h
@@ -1,318 +1,339 @@
-/* $Id$
- *
- */
-
-#ifndef __PJSDP_SDP_H__
-#define __PJSDP_SDP_H__
-
-/**
- * @defgroup PJSDP SDP Library
- */
-/**
- * @file sdp.h
- * @brief SDP header file.
- */
-/**
- * @defgroup PJ_SDP_H SDP stack.
- * @ingroup PJSDP
- * @{
- *
- * This SDP module consists of SDP parser, SDP structure, and function to
- * print back the structure as SDP message.
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-#define PJSDP_MAX_FMT	32
-#define PJSDP_MAX_ATTR	32
-#define PJSDP_MAX_MEDIA	16
-
-/**
- * This enumeration describes the attribute type.
- */
-typedef enum pjsdp_attr_type_e
-{
-    PJSDP_ATTR_RTPMAP,
-    PJSDP_ATTR_CAT,
-    PJSDP_ATTR_KEYWORDS,
-    PJSDP_ATTR_TOOL,
-    PJSDP_ATTR_PTIME,
-    PJSDP_ATTR_RECV_ONLY,
-    PJSDP_ATTR_SEND_ONLY,
-    PJSDP_ATTR_SEND_RECV,
-    PJSDP_ATTR_ORIENT,
-    PJSDP_ATTR_TYPE,
-    PJSDP_ATTR_CHARSET,
-    PJSDP_ATTR_SDP_LANG,
-    PJSDP_ATTR_LANG,
-    PJSDP_ATTR_FRAME_RATE,
-    PJSDP_ATTR_QUALITY,
-    PJSDP_ATTR_FMTP,
-    PJSDP_ATTR_INACTIVE,
-    PJSDP_ATTR_GENERIC,
-    PJSDP_END_OF_ATTR,
-} pjsdp_attr_type_e;
-
-
-/**
- * This structure keeps the common attributes that all 'descendants' 
- * will have.
- */
-typedef struct pjsdp_attr
-{
-    pjsdp_attr_type_e	type;	/**< Attribute type. */
-} pjsdp_attr;
-
-
-/**
- * This is the structure to represent generic attribute which has a 
- * string value.
- */
-typedef struct pjsdp_attr_string
-{
-    pjsdp_attr_type_e	type;
-    pj_str_t		value;
-} pjsdp_attr_string;
-
-
-/**
- * This is the structure to represent generic SDP attribute which has
- * a numeric value.
- */
-typedef struct pjsdp_attr_num
-{
-    pjsdp_attr_type_e	type;
-    pj_uint32_t		value;
-} pjsdp_attr_num;
-
-
-/**
- * SDP \a rtpmap attribute.
- */
-typedef struct pjsdp_rtpmap_attr
-{
-    pjsdp_attr_type_e	type;
-    unsigned		payload_type;
-    pj_str_t		encoding_name;
-    unsigned		clock_rate;
-    pj_str_t		parameter;
-} pjsdp_rtpmap_attr;
-
-
-/**
- * SDP \a fmtp attribute.
- */
-typedef struct pjsdp_fmtp_attr
-{
-    pjsdp_attr_type_e	type;
-    pj_str_t		format;
-    pj_str_t		param;
-} pjsdp_fmtp_attr;
-
-
-/** 
- * SDP generic attribute.
- */
-typedef struct pjsdp_generic_attr
-{
-    pjsdp_attr_type_e	type;
-    pj_str_t		name;
-    pj_str_t		value;
-} pjsdp_generic_attr;
-
-
-/** SDP \a cat attribute. */
-typedef struct pjsdp_attr_string pjsdp_cat_attr;
-
-/** SDP \a keywds attribute. */
-typedef struct pjsdp_attr_string pjsdp_keywds_attr;
-
-/** SDP \a tool attribute. */
-typedef struct pjsdp_attr_string pjsdp_tool_attr;
-
-/** SDP \a ptime attribute. */
-typedef struct pjsdp_attr_num pjsdp_ptime_attr;
-
-/** SDP \a recvonly attribute. */
-typedef struct pjsdp_attr pjsdp_recv_only_attr;
-
-/** SDP \a sendonly attribute. */
-typedef struct pjsdp_attr pjsdp_send_only_attr;
-
-/** SDP \a sendrecv attribute. */
-typedef struct pjsdp_attr pjsdp_send_recv_attr;
-
-/** SDP \a orient attribute. */
-typedef struct pjsdp_attr_string pjsdp_orient_attr;
-
-/** SDP \a type attribute. */
-typedef struct pjsdp_attr_string pjsdp_type_attr;
-
-/** SDP \a charset attribute. */
-typedef struct pjsdp_attr_string pjsdp_charset_attr;
-
-/** SDP \a sdplang attribute. */
-typedef struct pjsdp_attr_string pjsdp_sdp_lang_attr;
-
-/** SDP \a lang attribute. */
-typedef struct pjsdp_attr_string pjsdp_lang_attr;
-
-/** SDP \a framerate attribute. */
-typedef struct pjsdp_attr_string pjsdp_frame_rate_attr;
-
-/** SDP \a quality attribute. */
-typedef struct pjsdp_attr_num pjsdp_quality_attr;
-
-/** SDP \a inactive attribute. */
-typedef struct pjsdp_attr pjsdp_inactive_attr;
-
-/** Clone attribute */
-PJ_DECL(pjsdp_attr*) pjsdp_attr_clone (pj_pool_t *pool, const pjsdp_attr *rhs);
-
-/** Find attribute */
-PJ_DECL(const pjsdp_attr*) pjsdp_attr_find (int count, const pjsdp_attr *attr_array[], int type);
-
-/**
- * SDP connection info.
- */
-typedef struct pjsdp_conn_info
-{
-    pj_str_t	net_type;
-    pj_str_t	addr_type;
-    pj_str_t	addr;
-} pjsdp_conn_info;
-
-/** 
- *Clone connection info. 
- * 
- * @param pool	    Pool to allocate memory for the new connection info.
- * @param rhs	    The connection into to clone.
- *
- * @return the new connection info.
- */
-PJ_DECL(pjsdp_conn_info*) pjsdp_conn_info_clone (pj_pool_t *pool, 
-						 const pjsdp_conn_info *rhs);
-
-/**
- * SDP media description.
- */
-typedef struct pjsdp_media_desc
-{
-    struct
-    {
-	pj_str_t    media;
-	pj_uint16_t port;
-	unsigned    port_count;
-	pj_str_t    transport;
-	unsigned    fmt_count;
-	pj_str_t    fmt[PJSDP_MAX_FMT];
-    } desc;
-
-    pjsdp_conn_info *conn;
-    unsigned	    attr_count;
-    pjsdp_attr	   *attr[PJSDP_MAX_ATTR];
-
-} pjsdp_media_desc;
-
-/** 
- * Clone SDP media description. 
- *
- * @param pool	    Pool to allocate memory for the new media description.
- * @param rhs	    The media descriptin to clone.
- *
- * @return a new media description.
- */
-PJ_DECL(pjsdp_media_desc*) pjsdp_media_desc_clone (pj_pool_t *pool, 
-						   const pjsdp_media_desc *rhs);
-
-/** 
- * Check if the media description has the specified attribute.
- *
- * @param m		The SDP media description.
- * @param attr_type	The attribute type.
- *
- * @return nonzero if true.
- */
-PJ_DECL(pj_bool_t) pjsdp_media_desc_has_attr (const pjsdp_media_desc *m, 
-					      pjsdp_attr_type_e attr_type);
-
-/** 
- * Find rtpmap attribute for the specified payload type. 
- *
- * @param m	    The SDP media description.
- * @param pt	    RTP payload type.
- *
- * @return the SDP rtpmap attribute for the payload type, or NULL if not found.
- */
-PJ_DECL(const pjsdp_rtpmap_attr*) 
-pjsdp_media_desc_find_rtpmap (const pjsdp_media_desc *m, unsigned pt);
-
-
-/**
- * This structure describes SDP session description.
- */
-typedef struct pjsdp_session_desc
-{
-    struct
-    {
-	pj_str_t    user;
-	pj_uint32_t id;
-	pj_uint32_t version;
-	pj_str_t    net_type;
-	pj_str_t    addr_type;
-	pj_str_t    addr;
-    } origin;
-
-    pj_str_t	     name;
-    pjsdp_conn_info *conn;
-    
-    struct
-    {
-	pj_uint32_t start;
-	pj_uint32_t stop;
-    } time;
-
-    unsigned	    attr_count;
-    pjsdp_attr	   *attr[PJSDP_MAX_ATTR];
-
-    unsigned	      media_count;
-    pjsdp_media_desc *media[PJSDP_MAX_MEDIA];
-
-} pjsdp_session_desc;
-
-
-/**
- * Parse SDP message.
- *
- * @param buf	    The message buffer.
- * @param len	    The length of the message.
- * @param pool	    The pool to allocate SDP session description.
- *
- * @return SDP session description.
- */
-PJ_DECL(pjsdp_session_desc*) pjsdp_parse( char *buf, pj_size_t len, 
-					  pj_pool_t *pool);
-
-/**
- * Print SDP description to a buffer.
- *
- * @param buf	    The buffer.
- * @param size	    The buffer length.
- * @param desc	    The SDP session description.
- *
- * @return the length printed, or -1.
- */
-PJ_DECL(int) pjsdp_print( const pjsdp_session_desc *desc, 
-			  char *buf, pj_size_t size);
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSDP_SDP_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJSDP_SDP_H__

+#define __PJSDP_SDP_H__

+

+/**

+ * @defgroup PJSDP SDP Library

+ */

+/**

+ * @file sdp.h

+ * @brief SDP header file.

+ */

+/**

+ * @defgroup PJ_SDP_H SDP stack.

+ * @ingroup PJSDP

+ * @{

+ *

+ * This SDP module consists of SDP parser, SDP structure, and function to

+ * print back the structure as SDP message.

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+#define PJSDP_MAX_FMT	32

+#define PJSDP_MAX_ATTR	32

+#define PJSDP_MAX_MEDIA	16

+

+/**

+ * This enumeration describes the attribute type.

+ */

+typedef enum pjsdp_attr_type_e

+{

+    PJSDP_ATTR_RTPMAP,

+    PJSDP_ATTR_CAT,

+    PJSDP_ATTR_KEYWORDS,

+    PJSDP_ATTR_TOOL,

+    PJSDP_ATTR_PTIME,

+    PJSDP_ATTR_RECV_ONLY,

+    PJSDP_ATTR_SEND_ONLY,

+    PJSDP_ATTR_SEND_RECV,

+    PJSDP_ATTR_ORIENT,

+    PJSDP_ATTR_TYPE,

+    PJSDP_ATTR_CHARSET,

+    PJSDP_ATTR_SDP_LANG,

+    PJSDP_ATTR_LANG,

+    PJSDP_ATTR_FRAME_RATE,

+    PJSDP_ATTR_QUALITY,

+    PJSDP_ATTR_FMTP,

+    PJSDP_ATTR_INACTIVE,

+    PJSDP_ATTR_GENERIC,

+    PJSDP_END_OF_ATTR,

+} pjsdp_attr_type_e;

+

+

+/**

+ * This structure keeps the common attributes that all 'descendants' 

+ * will have.

+ */

+typedef struct pjsdp_attr

+{

+    pjsdp_attr_type_e	type;	/**< Attribute type. */

+} pjsdp_attr;

+

+

+/**

+ * This is the structure to represent generic attribute which has a 

+ * string value.

+ */

+typedef struct pjsdp_attr_string

+{

+    pjsdp_attr_type_e	type;

+    pj_str_t		value;

+} pjsdp_attr_string;

+

+

+/**

+ * This is the structure to represent generic SDP attribute which has

+ * a numeric value.

+ */

+typedef struct pjsdp_attr_num

+{

+    pjsdp_attr_type_e	type;

+    pj_uint32_t		value;

+} pjsdp_attr_num;

+

+

+/**

+ * SDP \a rtpmap attribute.

+ */

+typedef struct pjsdp_rtpmap_attr

+{

+    pjsdp_attr_type_e	type;

+    unsigned		payload_type;

+    pj_str_t		encoding_name;

+    unsigned		clock_rate;

+    pj_str_t		parameter;

+} pjsdp_rtpmap_attr;

+

+

+/**

+ * SDP \a fmtp attribute.

+ */

+typedef struct pjsdp_fmtp_attr

+{

+    pjsdp_attr_type_e	type;

+    pj_str_t		format;

+    pj_str_t		param;

+} pjsdp_fmtp_attr;

+

+

+/** 

+ * SDP generic attribute.

+ */

+typedef struct pjsdp_generic_attr

+{

+    pjsdp_attr_type_e	type;

+    pj_str_t		name;

+    pj_str_t		value;

+} pjsdp_generic_attr;

+

+

+/** SDP \a cat attribute. */

+typedef struct pjsdp_attr_string pjsdp_cat_attr;

+

+/** SDP \a keywds attribute. */

+typedef struct pjsdp_attr_string pjsdp_keywds_attr;

+

+/** SDP \a tool attribute. */

+typedef struct pjsdp_attr_string pjsdp_tool_attr;

+

+/** SDP \a ptime attribute. */

+typedef struct pjsdp_attr_num pjsdp_ptime_attr;

+

+/** SDP \a recvonly attribute. */

+typedef struct pjsdp_attr pjsdp_recv_only_attr;

+

+/** SDP \a sendonly attribute. */

+typedef struct pjsdp_attr pjsdp_send_only_attr;

+

+/** SDP \a sendrecv attribute. */

+typedef struct pjsdp_attr pjsdp_send_recv_attr;

+

+/** SDP \a orient attribute. */

+typedef struct pjsdp_attr_string pjsdp_orient_attr;

+

+/** SDP \a type attribute. */

+typedef struct pjsdp_attr_string pjsdp_type_attr;

+

+/** SDP \a charset attribute. */

+typedef struct pjsdp_attr_string pjsdp_charset_attr;

+

+/** SDP \a sdplang attribute. */

+typedef struct pjsdp_attr_string pjsdp_sdp_lang_attr;

+

+/** SDP \a lang attribute. */

+typedef struct pjsdp_attr_string pjsdp_lang_attr;

+

+/** SDP \a framerate attribute. */

+typedef struct pjsdp_attr_string pjsdp_frame_rate_attr;

+

+/** SDP \a quality attribute. */

+typedef struct pjsdp_attr_num pjsdp_quality_attr;

+

+/** SDP \a inactive attribute. */

+typedef struct pjsdp_attr pjsdp_inactive_attr;

+

+/** Clone attribute */

+PJ_DECL(pjsdp_attr*) pjsdp_attr_clone (pj_pool_t *pool, const pjsdp_attr *rhs);

+

+/** Find attribute */

+PJ_DECL(const pjsdp_attr*) pjsdp_attr_find (int count, const pjsdp_attr *attr_array[], int type);

+

+/**

+ * SDP connection info.

+ */

+typedef struct pjsdp_conn_info

+{

+    pj_str_t	net_type;

+    pj_str_t	addr_type;

+    pj_str_t	addr;

+} pjsdp_conn_info;

+

+/** 

+ *Clone connection info. 

+ * 

+ * @param pool	    Pool to allocate memory for the new connection info.

+ * @param rhs	    The connection into to clone.

+ *

+ * @return the new connection info.

+ */

+PJ_DECL(pjsdp_conn_info*) pjsdp_conn_info_clone (pj_pool_t *pool, 

+						 const pjsdp_conn_info *rhs);

+

+/**

+ * SDP media description.

+ */

+typedef struct pjsdp_media_desc

+{

+    struct

+    {

+	pj_str_t    media;

+	pj_uint16_t port;

+	unsigned    port_count;

+	pj_str_t    transport;

+	unsigned    fmt_count;

+	pj_str_t    fmt[PJSDP_MAX_FMT];

+    } desc;

+

+    pjsdp_conn_info *conn;

+    unsigned	    attr_count;

+    pjsdp_attr	   *attr[PJSDP_MAX_ATTR];

+

+} pjsdp_media_desc;

+

+/** 

+ * Clone SDP media description. 

+ *

+ * @param pool	    Pool to allocate memory for the new media description.

+ * @param rhs	    The media descriptin to clone.

+ *

+ * @return a new media description.

+ */

+PJ_DECL(pjsdp_media_desc*) pjsdp_media_desc_clone (pj_pool_t *pool, 

+						   const pjsdp_media_desc *rhs);

+

+/** 

+ * Check if the media description has the specified attribute.

+ *

+ * @param m		The SDP media description.

+ * @param attr_type	The attribute type.

+ *

+ * @return nonzero if true.

+ */

+PJ_DECL(pj_bool_t) pjsdp_media_desc_has_attr (const pjsdp_media_desc *m, 

+					      pjsdp_attr_type_e attr_type);

+

+/** 

+ * Find rtpmap attribute for the specified payload type. 

+ *

+ * @param m	    The SDP media description.

+ * @param pt	    RTP payload type.

+ *

+ * @return the SDP rtpmap attribute for the payload type, or NULL if not found.

+ */

+PJ_DECL(const pjsdp_rtpmap_attr*) 

+pjsdp_media_desc_find_rtpmap (const pjsdp_media_desc *m, unsigned pt);

+

+

+/**

+ * This structure describes SDP session description.

+ */

+typedef struct pjsdp_session_desc

+{

+    struct

+    {

+	pj_str_t    user;

+	pj_uint32_t id;

+	pj_uint32_t version;

+	pj_str_t    net_type;

+	pj_str_t    addr_type;

+	pj_str_t    addr;

+    } origin;

+

+    pj_str_t	     name;

+    pjsdp_conn_info *conn;

+    

+    struct

+    {

+	pj_uint32_t start;

+	pj_uint32_t stop;

+    } time;

+

+    unsigned	    attr_count;

+    pjsdp_attr	   *attr[PJSDP_MAX_ATTR];

+

+    unsigned	      media_count;

+    pjsdp_media_desc *media[PJSDP_MAX_MEDIA];

+

+} pjsdp_session_desc;

+

+

+/**

+ * Parse SDP message.

+ *

+ * @param buf	    The message buffer.

+ * @param len	    The length of the message.

+ * @param pool	    The pool to allocate SDP session description.

+ *

+ * @return SDP session description.

+ */

+PJ_DECL(pjsdp_session_desc*) pjsdp_parse( char *buf, pj_size_t len, 

+					  pj_pool_t *pool);

+

+/**

+ * Print SDP description to a buffer.

+ *

+ * @param buf	    The buffer.

+ * @param size	    The buffer length.

+ * @param desc	    The SDP session description.

+ *

+ * @return the length printed, or -1.

+ */

+PJ_DECL(int) pjsdp_print( const pjsdp_session_desc *desc, 

+			  char *buf, pj_size_t size);

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSDP_SDP_H__ */

+

diff --git a/pjmedia/src/pjmedia/session.c b/pjmedia/src/pjmedia/session.c
index d8e5b67..56a5e9f 100644
--- a/pjmedia/src/pjmedia/session.c
+++ b/pjmedia/src/pjmedia/session.c
@@ -1,818 +1,839 @@
-/* $Id$
- *
- */
-#include <pjmedia/session.h>
-#include <pj/log.h>
-#include <pj/os.h> 
-#include <pj/pool.h>
-#include <pj/string.h>
-
-typedef struct pj_media_stream_desc
-{
-    pj_media_stream_info    info;
-    pj_media_stream_t	   *enc_stream, *dec_stream;
-} pj_media_stream_desc;
-
-struct pj_media_session_t
-{
-    pj_pool_t		   *pool;
-    pj_med_mgr_t	   *mediamgr;
-    unsigned		    stream_cnt;
-    pj_media_stream_desc   *stream_desc[PJSDP_MAX_MEDIA];
-};
-
-#define THIS_FILE		"session.c"
-
-#define PJ_MEDIA_SESSION_SIZE	(48*1024)
-#define PJ_MEDIA_SESSION_INC	1024
-
-static const pj_str_t ID_AUDIO = { "audio", 5};
-static const pj_str_t ID_VIDEO = { "video", 5};
-static const pj_str_t ID_IN = { "IN", 2 };
-static const pj_str_t ID_IP4 = { "IP4", 3};
-static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 };
-static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 };
-
-static void session_init (pj_media_session_t *ses)
-{
-    pj_memset (ses, 0, sizeof(pj_media_session_t));
-}
-
-
-/**
- * Create new session offering.
- */
-PJ_DEF(pj_media_session_t*) 
-pj_media_session_create (pj_med_mgr_t *mgr, const pj_media_sock_info *sock_info)
-{
-    pj_pool_factory *pf;
-    pj_pool_t *pool;
-    pj_media_session_t *session;
-    pj_media_stream_desc *sd;
-    unsigned i, codec_cnt;
-    pj_codec_mgr *cm;
-    const pj_codec_id *codecs[PJSDP_MAX_FMT];
-
-    pf = pj_med_mgr_get_pool_factory(mgr);
-
-    pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL);
-    if (!pool)
-	return NULL;
-
-    session = pj_pool_alloc(pool, sizeof(pj_media_session_t));
-    if (!session)
-	return NULL;
-
-    session_init (session);
-
-    session->pool = pool;
-    session->mediamgr = mgr;
-
-    /* Create first stream  */
-    sd = pj_pool_calloc (pool, 1, sizeof(pj_media_stream_desc));
-    if (!sd)
-	return NULL;
-
-    sd->info.type = ID_AUDIO;
-    sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING;
-    sd->info.transport = ID_RTP_AVP;
-    pj_memcpy(&sd->info.sock_info, sock_info, sizeof(*sock_info));
-
-    /* Enum audio codecs. */
-    sd->info.fmt_cnt = 0;
-    cm = pj_med_mgr_get_codec_mgr (mgr);
-    codec_cnt = pj_codec_mgr_enum_codecs(cm, PJSDP_MAX_FMT, codecs);
-    if (codec_cnt > PJSDP_MAX_FMT) codec_cnt = PJSDP_MAX_FMT;
-    for (i=0; i<codec_cnt; ++i) {
-	if (codecs[i]->type != PJ_MEDIA_TYPE_AUDIO)
-	    continue;
-
-	sd->info.fmt[sd->info.fmt_cnt].pt = codecs[i]->pt;
-	sd->info.fmt[sd->info.fmt_cnt].sample_rate = codecs[i]->sample_rate;
-	pj_strdup (pool, &sd->info.fmt[sd->info.fmt_cnt].encoding_name, &codecs[i]->encoding_name);
-	++sd->info.fmt_cnt;
-    }
-
-    session->stream_desc[session->stream_cnt++] = sd;
-
-    return session;
-}
-
-static int sdp_check (const pjsdp_session_desc *sdp)
-{
-    int has_conn = 0;
-    unsigned i;
-
-    if (sdp->conn)
-	has_conn = 1;
-
-    if (sdp->media_count == 0) {
-	PJ_LOG(4,(THIS_FILE, "SDP check failed: no media stream definition"));
-	return -1;
-    }
-
-    for (i=0; i<sdp->media_count; ++i) {
-	pjsdp_media_desc *m = sdp->media[i];
-
-	if (!m) {
-	    pj_assert(0);
-	    return -1;
-	}
-
-	if (m->desc.fmt_count == 0) {
-	    PJ_LOG(4,(THIS_FILE, "SDP check failed: no format listed in media stream"));
-	    return -1;
-	}
-
-	if (!has_conn && m->conn == NULL) {
-	    PJ_LOG(4,(THIS_FILE, "SDP check failed: no connection information for media"));
-	    return -1;
-	}
-    }
-
-    return 0;
-}
-
-/*
- * Create local stream definition that matches SDP received from peer.
- */
-static pj_media_stream_desc* 
-create_stream_from_sdp (pj_pool_t *pool, pj_med_mgr_t *mgr, const pjsdp_conn_info *conn,
-			const pjsdp_media_desc *m, const pj_media_sock_info *sock_info)
-{
-    pj_media_stream_desc *sd;
-
-    sd = pj_pool_calloc (pool, 1, sizeof(pj_media_stream_desc));
-    if (!sd) {
-	PJ_LOG(2,(THIS_FILE, "No memory to allocate stream descriptor"));
-	return NULL;
-    }
-
-    if (pj_stricmp(&conn->net_type, &ID_IN)==0 && 
-	pj_stricmp(&conn->addr_type, &ID_IP4)==0 &&
-	pj_stricmp(&m->desc.media, &ID_AUDIO)==0 &&
-	pj_stricmp(&m->desc.transport, &ID_RTP_AVP) == 0) 
-    {
-	/*
-	 * Got audio stream.
-	 */
-	unsigned i, codec_cnt;
-	pj_codec_mgr *cm;
-	const pj_codec_id *codecs[PJSDP_MAX_FMT];
-
-	sd->info.type = ID_AUDIO;
-	sd->info.transport = ID_RTP_AVP;
-	pj_memcpy(&sd->info.sock_info, sock_info, sizeof(*sock_info));
-	sd->info.rem_port = m->desc.port;
-	pj_strdup (pool, &sd->info.rem_addr, &conn->addr);
-
-	/* Enum audio codecs. */
-	sd->info.fmt_cnt = 0;
-	cm = pj_med_mgr_get_codec_mgr (mgr);
-	codec_cnt = pj_codec_mgr_enum_codecs (cm, PJSDP_MAX_FMT, codecs);
-	if (codec_cnt > PJSDP_MAX_FMT) codec_cnt = PJSDP_MAX_FMT;
-
-	/* Find just one codec which we can support. */
-	for (i=0; i<m->desc.fmt_count && sd->info.fmt_cnt == 0; ++i) {
-	    unsigned j, fmt_i;
-
-	    /* For static payload, just match payload type. */
-	    /* Else match clock rate and encoding name. */
-	    fmt_i = pj_strtoul(&m->desc.fmt[i]);
-	    if (fmt_i < PJ_RTP_PT_DYNAMIC) {
-		for (j=0; j<codec_cnt; ++j) {
-		    if (codecs[j]->pt == fmt_i) {
-			sd->info.fmt_cnt = 1;
-			sd->info.fmt[0].type = PJ_MEDIA_TYPE_AUDIO;
-			sd->info.fmt[0].pt = codecs[j]->pt;
-			sd->info.fmt[0].sample_rate = codecs[j]->sample_rate;
-			pj_strdup (pool, &sd->info.fmt[0].encoding_name, &codecs[j]->encoding_name);
-			break;
-		    }
-		}
-	    } else {
-
-		/* Find the rtpmap for the payload type. */
-		const pjsdp_rtpmap_attr *rtpmap = pjsdp_media_desc_find_rtpmap (m, fmt_i);
-
-		/* Don't accept the media if no rtpmap for dynamic PT. */
-		if (rtpmap == NULL) {
-		    PJ_LOG(4,(THIS_FILE, "SDP: No rtpmap found for payload id %d", m->desc.fmt[i]));
-		    continue;
-		}
-
-		/* Check whether we can take this codec. */
-		for (j=0; j<codec_cnt; ++j) {
-		    if (rtpmap->clock_rate == codecs[j]->sample_rate && 
-			pj_stricmp(&rtpmap->encoding_name, &codecs[j]->encoding_name) == 0)
-		    {
-			sd->info.fmt_cnt = 1;
-			sd->info.fmt[0].type = PJ_MEDIA_TYPE_AUDIO;
-			sd->info.fmt[0].pt = codecs[j]->pt;
-			sd->info.fmt[0].sample_rate = codecs[j]->sample_rate;
-			sd->info.fmt[0].encoding_name = codecs[j]->encoding_name;
-			break;
-		    }
-		}
-	    }
-	}
-
-	/* Match codec and direction. */
-	if (sd->info.fmt_cnt == 0 || m->desc.port == 0 || 
-	    pjsdp_media_desc_has_attr(m, PJSDP_ATTR_INACTIVE)) 
-	{
-	    sd->info.dir = PJ_MEDIA_DIR_NONE;
-	}
-	else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_RECV_ONLY)) {
-	    sd->info.dir = PJ_MEDIA_DIR_ENCODING;
-	}
-	else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_SEND_ONLY)) {
-	    sd->info.dir = PJ_MEDIA_DIR_DECODING;
-	}
-	else {
-	    sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING;
-	}
-
-    } else {
-	/* Unsupported media stream. */
-	unsigned fmt_num;
-	const pjsdp_rtpmap_attr *rtpmap = NULL;
-
-	pj_strdup(pool, &sd->info.type, &m->desc.media);
-	pj_strdup(pool, &sd->info.transport, &m->desc.transport);
-	pj_memset(&sd->info.sock_info, 0, sizeof(*sock_info));
-	pj_strdup (pool, &sd->info.rem_addr, &conn->addr);
-	sd->info.rem_port = m->desc.port;
-
-	/* Just put one format and rtpmap, so that we don't have to make 
-	 * special exception when we convert this stream to SDP.
-	 */
-
-	/* Find the rtpmap for the payload type. */
-	fmt_num = pj_strtoul(&m->desc.fmt[0]);
-	rtpmap = pjsdp_media_desc_find_rtpmap (m, fmt_num);
-
-	sd->info.fmt_cnt = 1;
-	if (pj_stricmp(&m->desc.media, &ID_VIDEO)==0) {
-	    sd->info.fmt[0].type = PJ_MEDIA_TYPE_VIDEO;
-	    sd->info.fmt[0].pt = fmt_num;
-	    if (rtpmap) {
-		pj_strdup (pool, &sd->info.fmt[0].encoding_name, 
-			   &rtpmap->encoding_name);
-		sd->info.fmt[0].sample_rate = rtpmap->clock_rate;
-	    }
-	} else {
-	    sd->info.fmt[0].type = PJ_MEDIA_TYPE_UNKNOWN;
-	    pj_strdup(pool, &sd->info.fmt[0].encoding_name, &m->desc.fmt[0]);
-	}
-	
-	sd->info.dir = PJ_MEDIA_DIR_NONE;
-    }
-
-    return sd;
-}
-
-/**
- * Create new session based on peer's offering.
- */
-PJ_DEF(pj_media_session_t*) 
-pj_media_session_create_from_sdp (pj_med_mgr_t *mgr, const pjsdp_session_desc *sdp,
-				  const pj_media_sock_info *sock_info)
-{
-    pj_pool_factory *pf;
-    pj_pool_t *pool;
-    pj_media_session_t *session;
-    unsigned i;
-
-    if (sdp_check(sdp) != 0)
-	return NULL;
-
-    pf = pj_med_mgr_get_pool_factory(mgr);
-    pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL);
-    if (!pool)
-	return NULL;
-
-    session = pj_pool_alloc(pool, sizeof(pj_media_session_t));
-    if (!session) {
-	PJ_LOG(3,(THIS_FILE, "No memory to create media session descriptor"));
-	pj_pool_release (pool);
-	return NULL;
-    }
-
-    session_init (session);
-
-    session->pool = pool;
-    session->mediamgr = mgr;
-
-    /* Enumerate each media stream and create our peer. */
-    for (i=0; i<sdp->media_count; ++i) {
-	const pjsdp_conn_info *conn;
-	const pjsdp_media_desc *m;
-	pj_media_stream_desc *sd;
-
-	m = sdp->media[i];
-	conn = m->conn ? m->conn : sdp->conn;
-
-	/*
-	 * Bug:
-	 *  the sock_info below is used by more than one 'm' lines
-	 */
-	PJ_TODO(SUPPORT_MORE_THAN_ONE_SDP_M_LINES)
-
-	sd = create_stream_from_sdp (pool, mgr, conn, m, sock_info);
-	pj_assert (sd);
-
-	session->stream_desc[session->stream_cnt++] = sd;
-    }
-
-    return session;
-}
-
-/**
- * Duplicate session. The new session is inactive.
- */
-PJ_DEF(pj_media_session_t*)
-pj_media_session_clone (const pj_media_session_t *rhs)
-{
-    pj_pool_factory *pf;
-    pj_pool_t *pool;
-    pj_media_session_t *session;
-    unsigned i;
-
-    pf = pj_med_mgr_get_pool_factory(rhs->mediamgr);
-    pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL);
-    if (!pool) {
-	return NULL;
-    }
-
-    session = pj_pool_alloc (pool, sizeof(*session));
-    if (!session) {
-	PJ_LOG(3,(THIS_FILE, "No memory to create media session descriptor"));
-	pj_pool_release (pool);
-	return NULL;
-    }
-
-    session->pool = pool;
-    session->mediamgr = rhs->mediamgr;
-    session->stream_cnt = rhs->stream_cnt;
-
-    for (i=0; i<rhs->stream_cnt; ++i) {
-	pj_media_stream_desc *sd1 = pj_pool_alloc (session->pool, sizeof(pj_media_stream_desc));
-	const pj_media_stream_desc *sd2 = rhs->stream_desc[i];
-
-	if (!sd1) {
-	    PJ_LOG(3,(THIS_FILE, "No memory to create media stream descriptor"));
-	    pj_pool_release (pool);
-	    return NULL;
-	}
-
-	session->stream_desc[i] = sd1;
-	sd1->enc_stream = sd1->dec_stream = NULL;
-	pj_strdup (pool, &sd1->info.type, &sd2->info.type);
-	sd1->info.dir = sd2->info.dir;
-	pj_strdup (pool, &sd1->info.transport, &sd2->info.transport);
-	pj_memcpy(&sd1->info.sock_info, &sd2->info.sock_info, sizeof(pj_media_sock_info));
-	pj_strdup (pool, &sd1->info.rem_addr, &sd2->info.rem_addr);
-	sd1->info.rem_port = sd2->info.rem_port;
-	sd1->info.fmt_cnt = sd2->info.fmt_cnt;
-	pj_memcpy (sd1->info.fmt, sd2->info.fmt, sizeof(sd2->info.fmt));
-    }
-
-    return session;
-}
-
-/**
- * Create SDP description from the session.
- */
-PJ_DEF(pjsdp_session_desc*)
-pj_media_session_create_sdp (const pj_media_session_t *session, pj_pool_t *pool,
-			     pj_bool_t only_first_fmt)
-{
-    pjsdp_session_desc *sdp;
-    pj_time_val tv;
-    unsigned i;
-    pj_media_sock_info *c_addr = NULL;
-
-    if (session->stream_cnt == 0) {
-	pj_assert(0);
-	return NULL;
-    }
-
-    sdp = pj_pool_calloc (pool, 1, sizeof(pjsdp_session_desc));
-    if (!sdp) {
-	PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP session descriptor"));
-	return NULL;
-    }
-
-    pj_gettimeofday(&tv);
-
-    sdp->origin.user = pj_str("-");
-    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;
-    sdp->origin.net_type = ID_IN;
-    sdp->origin.addr_type = ID_IP4;
-    sdp->origin.addr = *pj_gethostname();
-
-    sdp->name = ID_SDP_NAME;
-
-    /* If all media addresses are the same, then put the connection
-     * info in the session level, otherwise put it in media stream
-     * level.
-     */
-    for (i=0; i<session->stream_cnt; ++i) {
-	if (c_addr == NULL) {
-	    c_addr = &session->stream_desc[i]->info.sock_info;
-	} else if (c_addr->rtp_addr_name.sin_addr.s_addr != session->stream_desc[i]->info.sock_info.rtp_addr_name.sin_addr.s_addr)
-	{
-	    c_addr = NULL;
-	    break;
-	}
-    }
-
-    if (c_addr) {
-	/* All addresses are the same, put connection info in session level. */
-	sdp->conn = pj_pool_alloc (pool, sizeof(pjsdp_conn_info));
-	if (!sdp->conn) {
-	    PJ_LOG(2,(THIS_FILE, "No memory to allocate SDP connection info"));
-	    return NULL;
-	}
-
-	sdp->conn->net_type = ID_IN;
-	sdp->conn->addr_type = ID_IP4;
-	pj_strdup2 (pool, &sdp->conn->addr, pj_inet_ntoa(c_addr->rtp_addr_name.sin_addr));
-    }
-
-    sdp->time.start = sdp->time.stop = 0;
-    sdp->attr_count = 0;
-
-    /* Create each media. */
-    sdp->media_count = 0;
-    for (i=0; i<session->stream_cnt; ++i) {
-	const pj_media_stream_desc *sd = session->stream_desc[i];
-	pjsdp_media_desc *m;
-	unsigned j;
-	unsigned fmt_cnt;
-	pjsdp_attr *attr;
-
-	m = pj_pool_calloc (pool, 1, sizeof(pjsdp_media_desc));
-	if (!m) {
-	    PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP media stream descriptor"));
-	    return NULL;
-	}
-
-	sdp->media[sdp->media_count++] = m;
-
-	pj_strdup (pool, &m->desc.media, &sd->info.type);
-	m->desc.port = pj_ntohs(sd->info.sock_info.rtp_addr_name.sin_port);
-	m->desc.port_count = 1;
-	pj_strdup (pool, &m->desc.transport, &sd->info.transport);
-
-	/* Add format and rtpmap for each codec. */
-	m->desc.fmt_count = 0;
-	m->attr_count = 0;
-	fmt_cnt = sd->info.fmt_cnt;
-	if (fmt_cnt > 0 && only_first_fmt)
-	    fmt_cnt = 1;
-	for (j=0; j<fmt_cnt; ++j) {
-	    pjsdp_rtpmap_attr *rtpmap;
-	    pj_str_t *fmt = &m->desc.fmt[m->desc.fmt_count++];
-
-	    if (sd->info.fmt[j].type==PJ_MEDIA_TYPE_UNKNOWN) {
-		pj_strdup(pool, fmt, &sd->info.fmt[j].encoding_name);
-	    } else {
-		fmt->ptr = pj_pool_alloc(pool, 8);
-		fmt->slen = pj_utoa(sd->info.fmt[j].pt, fmt->ptr);
-
-		rtpmap = pj_pool_calloc(pool, 1, sizeof(pjsdp_rtpmap_attr));
-		if (rtpmap) {
-		    m->attr[m->attr_count++] = (pjsdp_attr*)rtpmap;
-		    rtpmap->type = PJSDP_ATTR_RTPMAP;
-		    rtpmap->payload_type = sd->info.fmt[j].pt;
-		    rtpmap->clock_rate = sd->info.fmt[j].sample_rate;
-		    pj_strdup (pool, &rtpmap->encoding_name, &sd->info.fmt[j].encoding_name);
-		} else {
-		    PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP rtpmap descriptor"));
-		}
-	    }
-	}
-
-	/* If we don't have connection info in session level, create one. */
-	if (sdp->conn == NULL) {
-	    m->conn = pj_pool_alloc (pool, sizeof(pjsdp_conn_info));
-	    if (m->conn) {
-		m->conn->net_type = ID_IN;
-		m->conn->addr_type = ID_IP4;
-		pj_strdup2 (pool, &m->conn->addr, pj_inet_ntoa(sd->info.sock_info.rtp_addr_name.sin_addr));
-	    } else {
-		PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP media connection info"));
-		return NULL;
-	    }
-	}
-
-	/* Add additional attribute to the media stream. */
-	attr = pj_pool_alloc(pool, sizeof(pjsdp_attr));
-	if (!attr) {
-	    PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP attribute"));
-	    return NULL;
-	}
-	m->attr[m->attr_count++] = attr;
-
-	switch (sd->info.dir) {
-	case PJ_MEDIA_DIR_NONE:
-	    attr->type = PJSDP_ATTR_INACTIVE;
-	    break;
-	case PJ_MEDIA_DIR_ENCODING:
-	    attr->type = PJSDP_ATTR_SEND_ONLY;
-	    break;
-	case PJ_MEDIA_DIR_DECODING:
-	    attr->type = PJSDP_ATTR_RECV_ONLY;
-	    break;
-	case PJ_MEDIA_DIR_ENCODING_DECODING:
-	    attr->type = PJSDP_ATTR_SEND_RECV;
-	    break;
-	}
-    }
-
-    return sdp;
-}
-
-/**
- * Update session with SDP answer from peer.
- */
-PJ_DEF(pj_status_t)
-pj_media_session_update (pj_media_session_t *session, 
-			 const pjsdp_session_desc *sdp)
-{
-    unsigned i;
-    unsigned count;
-
-    /* Check SDP */
-    if (sdp_check (sdp) != 0) {
-	return -1;
-    }
-
-    /* If the media stream count doesn't match, only update one. */
-    if (session->stream_cnt != sdp->media_count) {
-	PJ_LOG(3,(THIS_FILE, "pj_media_session_update : "
-		 "SDP media count mismatch! (rmt=%d, lcl=%d)",
-		 sdp->media_count, session->stream_cnt));
-	count = (session->stream_cnt < sdp->media_count) ?
-	    session->stream_cnt : sdp->media_count;
-    } else {
-	count = session->stream_cnt;
-    }
-
-    for (i=0; i<count; ++i) {
-	pj_media_stream_desc *sd = session->stream_desc[i];
-	const pjsdp_media_desc *m = sdp->media[i];
-	const pjsdp_conn_info *conn;
-	unsigned j;
-
-	/* Check that the session is not active. */
-	pj_assert (sd->enc_stream == NULL && sd->dec_stream == NULL);
-
-	conn = m->conn ? m->conn : sdp->conn;
-	pj_assert(conn);
-
-	/* Update remote address. */
-	sd->info.rem_port = m->desc.port;
-	pj_strdup (session->pool, &sd->info.rem_addr, &conn->addr);
-
-	/* Select one active codec according to what peer wants. */
-	for (j=0; j<sd->info.fmt_cnt; ++j) {
-	    unsigned fmt_0 = pj_strtoul(&m->desc.fmt[0]);
-	    if (sd->info.fmt[j].pt == fmt_0) {
-		pj_codec_id temp;
-
-		/* Put active format to the front. */
-		if (j == 0)
-		    break;
-
-		pj_memcpy(&temp, &sd->info.fmt[0], sizeof(temp));
-		pj_memcpy(&sd->info.fmt[0], &sd->info.fmt[j], sizeof(temp));
-		pj_memcpy(&sd->info.fmt[j], &temp, sizeof(temp));
-		break;
-	    }
-	}
-
-	if (j == sd->info.fmt_cnt) {
-	    /* Peer has answered SDP with new codec, which doesn't exist
-	     * in the offer!
-	     * Mute this media.
-	     */
-	    PJ_LOG(3,(THIS_FILE, "Peer has answered SDP with new codec!"));
-	    sd->info.dir = PJ_MEDIA_DIR_NONE;
-	    continue;
-	}
-
-	/* Check direction. */
-	if (m->desc.port == 0 || pjsdp_media_desc_has_attr(m, PJSDP_ATTR_INACTIVE)) {
-	    sd->info.dir = PJ_MEDIA_DIR_NONE;
-	}
-	else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_RECV_ONLY)) {
-	    sd->info.dir = PJ_MEDIA_DIR_ENCODING;
-	}
-	else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_SEND_ONLY)) {
-	    sd->info.dir = PJ_MEDIA_DIR_DECODING;
-	}
-	else {
-	    sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING;
-	}
-    }
-
-    return 0;
-}
-
-/**
- * Enumerate media streams in the session.
- */
-PJ_DEF(unsigned)
-pj_media_session_enum_streams (const pj_media_session_t *session, 
-			       unsigned count, const pj_media_stream_info *info[])
-{
-    unsigned i;
-
-    if (count > session->stream_cnt)
-	count = session->stream_cnt;
-
-    for (i=0; i<count; ++i) {
-	info[i] = &session->stream_desc[i]->info;
-    }
-
-    return session->stream_cnt;
-}
-
-/**
- * Get statistics
- */
-PJ_DEF(pj_status_t)
-pj_media_session_get_stat (const pj_media_session_t *session, unsigned index,
-			   pj_media_stream_stat *tx_stat,
-			   pj_media_stream_stat *rx_stat)
-{
-    pj_media_stream_desc *sd;
-    int stat_cnt = 0;
-
-    if (index >= session->stream_cnt) {
-	pj_assert(0);
-	return -1;
-    }
-    
-    sd = session->stream_desc[index];
-
-    if (sd->enc_stream && tx_stat) {
-	pj_media_stream_get_stat (sd->enc_stream, tx_stat);
-	++stat_cnt;
-    } else if (tx_stat) {
-	pj_memset (tx_stat, 0, sizeof(*tx_stat));
-    }
-
-    if (sd->dec_stream && rx_stat) {
-	pj_media_stream_get_stat (sd->dec_stream, rx_stat);
-	++stat_cnt;
-    } else if (rx_stat) {
-	pj_memset (rx_stat, 0, sizeof(*rx_stat));
-    }
-
-    return stat_cnt ? 0 : -1;
-}
-
-/**
- * Modify stream, only when stream is inactive.
- */
-PJ_DEF(pj_status_t)
-pj_media_session_modify_stream (pj_media_session_t *session, unsigned index,
-				unsigned modify_flag, const pj_media_stream_info *info)
-{
-    pj_media_stream_desc *sd;
-
-    if (index >= session->stream_cnt) {
-	pj_assert(0);
-	return -1;
-    }
-    
-    sd = session->stream_desc[index];
-
-    if (sd->enc_stream || sd->dec_stream) {
-	pj_assert(0);
-	return -1;
-    }
-
-    if (modify_flag & PJ_MEDIA_STREAM_MODIFY_DIR) {
-	sd->info.dir = info->dir;
-    }
-
-    return 0;
-}
-
-/**
- * Activate media session.
- */
-PJ_DEF(pj_status_t)
-pj_media_session_activate (pj_media_session_t *session)
-{
-    unsigned i;
-    pj_status_t status = 0;
-
-    for (i=0; i<session->stream_cnt; ++i) {
-	pj_status_t rc;
-	rc = pj_media_session_activate_stream (session, i);
-	if (status == 0)
-	    status = rc;
-    }
-    return status;
-}
-
-/**
- * Activate individual stream in media session.
- */
-PJ_DEF(pj_status_t)
-pj_media_session_activate_stream (pj_media_session_t *session, unsigned index)
-{
-    pj_media_stream_desc *sd;
-    pj_media_stream_create_param scp;
-    pj_status_t status;
-    pj_time_val tv;
-
-    if (index < 0 || index >= session->stream_cnt) {
-	pj_assert(0);
-	return -1;
-    }
-
-    sd = session->stream_desc[index];
-
-    if (sd->enc_stream || sd->dec_stream) {
-	/* Stream already active. */
-	pj_assert(0);
-	return 0;
-    }
-
-    pj_gettimeofday(&tv);
-
-    /* Initialize parameter to create stream. */
-    pj_memset (&scp, 0, sizeof(scp));
-    scp.codec_id = &sd->info.fmt[0];
-    scp.mediamgr = session->mediamgr;
-    scp.dir = sd->info.dir;
-    scp.rtp_sock = sd->info.sock_info.rtp_sock;
-    scp.rtcp_sock = sd->info.sock_info.rtcp_sock;
-    scp.remote_addr = pj_pool_calloc (session->pool, 1, sizeof(pj_sockaddr_in));
-    pj_sockaddr_init (scp.remote_addr, &sd->info.rem_addr, sd->info.rem_port);
-    scp.ssrc = tv.sec;
-    scp.jb_min = 1;
-    scp.jb_max = 15;
-    scp.jb_maxcnt = 16;
-
-    /* Build the stream! */
-    status = pj_media_stream_create (session->pool, &sd->enc_stream, &sd->dec_stream, &scp);
-
-    if (status==0 && sd->enc_stream) {
-	status = pj_media_stream_start (sd->enc_stream);
-	if (status != 0)
-	    goto on_error;
-    }
-    if (status==0 && sd->dec_stream) {
-	status = pj_media_stream_start (sd->dec_stream);
-	if (status != 0)
-	    goto on_error;
-    }
-    return status;
-
-on_error:
-    if (sd->enc_stream) {
-	pj_media_stream_destroy (sd->enc_stream);
-	sd->enc_stream = NULL;
-    }
-    if (sd->dec_stream) {
-	pj_media_stream_destroy (sd->dec_stream);
-	sd->dec_stream = NULL;
-    }
-    return status;
-}
-
-/**
- * Destroy media session.
- */
-PJ_DEF(pj_status_t)
-pj_media_session_destroy (pj_media_session_t *session)
-{
-    unsigned i;
-
-    if (!session)
-	return -1;
-
-    for (i=0; i<session->stream_cnt; ++i) {
-	pj_media_stream_desc *sd = session->stream_desc[i];
-
-	if (sd->enc_stream) {
-	    pj_media_stream_destroy (sd->enc_stream);
-	    sd->enc_stream = NULL;
-	}
-	if (sd->dec_stream) {
-	    pj_media_stream_destroy (sd->dec_stream);
-	    sd->dec_stream = NULL;
-	}
-    }
-    pj_pool_release (session->pool);
-    return 0;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjmedia/session.h>

+#include <pj/log.h>

+#include <pj/os.h> 

+#include <pj/pool.h>

+#include <pj/string.h>

+

+typedef struct pj_media_stream_desc

+{

+    pj_media_stream_info    info;

+    pj_media_stream_t	   *enc_stream, *dec_stream;

+} pj_media_stream_desc;

+

+struct pj_media_session_t

+{

+    pj_pool_t		   *pool;

+    pj_med_mgr_t	   *mediamgr;

+    unsigned		    stream_cnt;

+    pj_media_stream_desc   *stream_desc[PJSDP_MAX_MEDIA];

+};

+

+#define THIS_FILE		"session.c"

+

+#define PJ_MEDIA_SESSION_SIZE	(48*1024)

+#define PJ_MEDIA_SESSION_INC	1024

+

+static const pj_str_t ID_AUDIO = { "audio", 5};

+static const pj_str_t ID_VIDEO = { "video", 5};

+static const pj_str_t ID_IN = { "IN", 2 };

+static const pj_str_t ID_IP4 = { "IP4", 3};

+static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 };

+static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 };

+

+static void session_init (pj_media_session_t *ses)

+{

+    pj_memset (ses, 0, sizeof(pj_media_session_t));

+}

+

+

+/**

+ * Create new session offering.

+ */

+PJ_DEF(pj_media_session_t*) 

+pj_media_session_create (pj_med_mgr_t *mgr, const pj_media_sock_info *sock_info)

+{

+    pj_pool_factory *pf;

+    pj_pool_t *pool;

+    pj_media_session_t *session;

+    pj_media_stream_desc *sd;

+    unsigned i, codec_cnt;

+    pj_codec_mgr *cm;

+    const pj_codec_id *codecs[PJSDP_MAX_FMT];

+

+    pf = pj_med_mgr_get_pool_factory(mgr);

+

+    pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL);

+    if (!pool)

+	return NULL;

+

+    session = pj_pool_alloc(pool, sizeof(pj_media_session_t));

+    if (!session)

+	return NULL;

+

+    session_init (session);

+

+    session->pool = pool;

+    session->mediamgr = mgr;

+

+    /* Create first stream  */

+    sd = pj_pool_calloc (pool, 1, sizeof(pj_media_stream_desc));

+    if (!sd)

+	return NULL;

+

+    sd->info.type = ID_AUDIO;

+    sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING;

+    sd->info.transport = ID_RTP_AVP;

+    pj_memcpy(&sd->info.sock_info, sock_info, sizeof(*sock_info));

+

+    /* Enum audio codecs. */

+    sd->info.fmt_cnt = 0;

+    cm = pj_med_mgr_get_codec_mgr (mgr);

+    codec_cnt = pj_codec_mgr_enum_codecs(cm, PJSDP_MAX_FMT, codecs);

+    if (codec_cnt > PJSDP_MAX_FMT) codec_cnt = PJSDP_MAX_FMT;

+    for (i=0; i<codec_cnt; ++i) {

+	if (codecs[i]->type != PJ_MEDIA_TYPE_AUDIO)

+	    continue;

+

+	sd->info.fmt[sd->info.fmt_cnt].pt = codecs[i]->pt;

+	sd->info.fmt[sd->info.fmt_cnt].sample_rate = codecs[i]->sample_rate;

+	pj_strdup (pool, &sd->info.fmt[sd->info.fmt_cnt].encoding_name, &codecs[i]->encoding_name);

+	++sd->info.fmt_cnt;

+    }

+

+    session->stream_desc[session->stream_cnt++] = sd;

+

+    return session;

+}

+

+static int sdp_check (const pjsdp_session_desc *sdp)

+{

+    int has_conn = 0;

+    unsigned i;

+

+    if (sdp->conn)

+	has_conn = 1;

+

+    if (sdp->media_count == 0) {

+	PJ_LOG(4,(THIS_FILE, "SDP check failed: no media stream definition"));

+	return -1;

+    }

+

+    for (i=0; i<sdp->media_count; ++i) {

+	pjsdp_media_desc *m = sdp->media[i];

+

+	if (!m) {

+	    pj_assert(0);

+	    return -1;

+	}

+

+	if (m->desc.fmt_count == 0) {

+	    PJ_LOG(4,(THIS_FILE, "SDP check failed: no format listed in media stream"));

+	    return -1;

+	}

+

+	if (!has_conn && m->conn == NULL) {

+	    PJ_LOG(4,(THIS_FILE, "SDP check failed: no connection information for media"));

+	    return -1;

+	}

+    }

+

+    return 0;

+}

+

+/*

+ * Create local stream definition that matches SDP received from peer.

+ */

+static pj_media_stream_desc* 

+create_stream_from_sdp (pj_pool_t *pool, pj_med_mgr_t *mgr, const pjsdp_conn_info *conn,

+			const pjsdp_media_desc *m, const pj_media_sock_info *sock_info)

+{

+    pj_media_stream_desc *sd;

+

+    sd = pj_pool_calloc (pool, 1, sizeof(pj_media_stream_desc));

+    if (!sd) {

+	PJ_LOG(2,(THIS_FILE, "No memory to allocate stream descriptor"));

+	return NULL;

+    }

+

+    if (pj_stricmp(&conn->net_type, &ID_IN)==0 && 

+	pj_stricmp(&conn->addr_type, &ID_IP4)==0 &&

+	pj_stricmp(&m->desc.media, &ID_AUDIO)==0 &&

+	pj_stricmp(&m->desc.transport, &ID_RTP_AVP) == 0) 

+    {

+	/*

+	 * Got audio stream.

+	 */

+	unsigned i, codec_cnt;

+	pj_codec_mgr *cm;

+	const pj_codec_id *codecs[PJSDP_MAX_FMT];

+

+	sd->info.type = ID_AUDIO;

+	sd->info.transport = ID_RTP_AVP;

+	pj_memcpy(&sd->info.sock_info, sock_info, sizeof(*sock_info));

+	sd->info.rem_port = m->desc.port;

+	pj_strdup (pool, &sd->info.rem_addr, &conn->addr);

+

+	/* Enum audio codecs. */

+	sd->info.fmt_cnt = 0;

+	cm = pj_med_mgr_get_codec_mgr (mgr);

+	codec_cnt = pj_codec_mgr_enum_codecs (cm, PJSDP_MAX_FMT, codecs);

+	if (codec_cnt > PJSDP_MAX_FMT) codec_cnt = PJSDP_MAX_FMT;

+

+	/* Find just one codec which we can support. */

+	for (i=0; i<m->desc.fmt_count && sd->info.fmt_cnt == 0; ++i) {

+	    unsigned j, fmt_i;

+

+	    /* For static payload, just match payload type. */

+	    /* Else match clock rate and encoding name. */

+	    fmt_i = pj_strtoul(&m->desc.fmt[i]);

+	    if (fmt_i < PJ_RTP_PT_DYNAMIC) {

+		for (j=0; j<codec_cnt; ++j) {

+		    if (codecs[j]->pt == fmt_i) {

+			sd->info.fmt_cnt = 1;

+			sd->info.fmt[0].type = PJ_MEDIA_TYPE_AUDIO;

+			sd->info.fmt[0].pt = codecs[j]->pt;

+			sd->info.fmt[0].sample_rate = codecs[j]->sample_rate;

+			pj_strdup (pool, &sd->info.fmt[0].encoding_name, &codecs[j]->encoding_name);

+			break;

+		    }

+		}

+	    } else {

+

+		/* Find the rtpmap for the payload type. */

+		const pjsdp_rtpmap_attr *rtpmap = pjsdp_media_desc_find_rtpmap (m, fmt_i);

+

+		/* Don't accept the media if no rtpmap for dynamic PT. */

+		if (rtpmap == NULL) {

+		    PJ_LOG(4,(THIS_FILE, "SDP: No rtpmap found for payload id %d", m->desc.fmt[i]));

+		    continue;

+		}

+

+		/* Check whether we can take this codec. */

+		for (j=0; j<codec_cnt; ++j) {

+		    if (rtpmap->clock_rate == codecs[j]->sample_rate && 

+			pj_stricmp(&rtpmap->encoding_name, &codecs[j]->encoding_name) == 0)

+		    {

+			sd->info.fmt_cnt = 1;

+			sd->info.fmt[0].type = PJ_MEDIA_TYPE_AUDIO;

+			sd->info.fmt[0].pt = codecs[j]->pt;

+			sd->info.fmt[0].sample_rate = codecs[j]->sample_rate;

+			sd->info.fmt[0].encoding_name = codecs[j]->encoding_name;

+			break;

+		    }

+		}

+	    }

+	}

+

+	/* Match codec and direction. */

+	if (sd->info.fmt_cnt == 0 || m->desc.port == 0 || 

+	    pjsdp_media_desc_has_attr(m, PJSDP_ATTR_INACTIVE)) 

+	{

+	    sd->info.dir = PJ_MEDIA_DIR_NONE;

+	}

+	else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_RECV_ONLY)) {

+	    sd->info.dir = PJ_MEDIA_DIR_ENCODING;

+	}

+	else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_SEND_ONLY)) {

+	    sd->info.dir = PJ_MEDIA_DIR_DECODING;

+	}

+	else {

+	    sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING;

+	}

+

+    } else {

+	/* Unsupported media stream. */

+	unsigned fmt_num;

+	const pjsdp_rtpmap_attr *rtpmap = NULL;

+

+	pj_strdup(pool, &sd->info.type, &m->desc.media);

+	pj_strdup(pool, &sd->info.transport, &m->desc.transport);

+	pj_memset(&sd->info.sock_info, 0, sizeof(*sock_info));

+	pj_strdup (pool, &sd->info.rem_addr, &conn->addr);

+	sd->info.rem_port = m->desc.port;

+

+	/* Just put one format and rtpmap, so that we don't have to make 

+	 * special exception when we convert this stream to SDP.

+	 */

+

+	/* Find the rtpmap for the payload type. */

+	fmt_num = pj_strtoul(&m->desc.fmt[0]);

+	rtpmap = pjsdp_media_desc_find_rtpmap (m, fmt_num);

+

+	sd->info.fmt_cnt = 1;

+	if (pj_stricmp(&m->desc.media, &ID_VIDEO)==0) {

+	    sd->info.fmt[0].type = PJ_MEDIA_TYPE_VIDEO;

+	    sd->info.fmt[0].pt = fmt_num;

+	    if (rtpmap) {

+		pj_strdup (pool, &sd->info.fmt[0].encoding_name, 

+			   &rtpmap->encoding_name);

+		sd->info.fmt[0].sample_rate = rtpmap->clock_rate;

+	    }

+	} else {

+	    sd->info.fmt[0].type = PJ_MEDIA_TYPE_UNKNOWN;

+	    pj_strdup(pool, &sd->info.fmt[0].encoding_name, &m->desc.fmt[0]);

+	}

+	

+	sd->info.dir = PJ_MEDIA_DIR_NONE;

+    }

+

+    return sd;

+}

+

+/**

+ * Create new session based on peer's offering.

+ */

+PJ_DEF(pj_media_session_t*) 

+pj_media_session_create_from_sdp (pj_med_mgr_t *mgr, const pjsdp_session_desc *sdp,

+				  const pj_media_sock_info *sock_info)

+{

+    pj_pool_factory *pf;

+    pj_pool_t *pool;

+    pj_media_session_t *session;

+    unsigned i;

+

+    if (sdp_check(sdp) != 0)

+	return NULL;

+

+    pf = pj_med_mgr_get_pool_factory(mgr);

+    pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL);

+    if (!pool)

+	return NULL;

+

+    session = pj_pool_alloc(pool, sizeof(pj_media_session_t));

+    if (!session) {

+	PJ_LOG(3,(THIS_FILE, "No memory to create media session descriptor"));

+	pj_pool_release (pool);

+	return NULL;

+    }

+

+    session_init (session);

+

+    session->pool = pool;

+    session->mediamgr = mgr;

+

+    /* Enumerate each media stream and create our peer. */

+    for (i=0; i<sdp->media_count; ++i) {

+	const pjsdp_conn_info *conn;

+	const pjsdp_media_desc *m;

+	pj_media_stream_desc *sd;

+

+	m = sdp->media[i];

+	conn = m->conn ? m->conn : sdp->conn;

+

+	/*

+	 * Bug:

+	 *  the sock_info below is used by more than one 'm' lines

+	 */

+	PJ_TODO(SUPPORT_MORE_THAN_ONE_SDP_M_LINES)

+

+	sd = create_stream_from_sdp (pool, mgr, conn, m, sock_info);

+	pj_assert (sd);

+

+	session->stream_desc[session->stream_cnt++] = sd;

+    }

+

+    return session;

+}

+

+/**

+ * Duplicate session. The new session is inactive.

+ */

+PJ_DEF(pj_media_session_t*)

+pj_media_session_clone (const pj_media_session_t *rhs)

+{

+    pj_pool_factory *pf;

+    pj_pool_t *pool;

+    pj_media_session_t *session;

+    unsigned i;

+

+    pf = pj_med_mgr_get_pool_factory(rhs->mediamgr);

+    pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL);

+    if (!pool) {

+	return NULL;

+    }

+

+    session = pj_pool_alloc (pool, sizeof(*session));

+    if (!session) {

+	PJ_LOG(3,(THIS_FILE, "No memory to create media session descriptor"));

+	pj_pool_release (pool);

+	return NULL;

+    }

+

+    session->pool = pool;

+    session->mediamgr = rhs->mediamgr;

+    session->stream_cnt = rhs->stream_cnt;

+

+    for (i=0; i<rhs->stream_cnt; ++i) {

+	pj_media_stream_desc *sd1 = pj_pool_alloc (session->pool, sizeof(pj_media_stream_desc));

+	const pj_media_stream_desc *sd2 = rhs->stream_desc[i];

+

+	if (!sd1) {

+	    PJ_LOG(3,(THIS_FILE, "No memory to create media stream descriptor"));

+	    pj_pool_release (pool);

+	    return NULL;

+	}

+

+	session->stream_desc[i] = sd1;

+	sd1->enc_stream = sd1->dec_stream = NULL;

+	pj_strdup (pool, &sd1->info.type, &sd2->info.type);

+	sd1->info.dir = sd2->info.dir;

+	pj_strdup (pool, &sd1->info.transport, &sd2->info.transport);

+	pj_memcpy(&sd1->info.sock_info, &sd2->info.sock_info, sizeof(pj_media_sock_info));

+	pj_strdup (pool, &sd1->info.rem_addr, &sd2->info.rem_addr);

+	sd1->info.rem_port = sd2->info.rem_port;

+	sd1->info.fmt_cnt = sd2->info.fmt_cnt;

+	pj_memcpy (sd1->info.fmt, sd2->info.fmt, sizeof(sd2->info.fmt));

+    }

+

+    return session;

+}

+

+/**

+ * Create SDP description from the session.

+ */

+PJ_DEF(pjsdp_session_desc*)

+pj_media_session_create_sdp (const pj_media_session_t *session, pj_pool_t *pool,

+			     pj_bool_t only_first_fmt)

+{

+    pjsdp_session_desc *sdp;

+    pj_time_val tv;

+    unsigned i;

+    pj_media_sock_info *c_addr = NULL;

+

+    if (session->stream_cnt == 0) {

+	pj_assert(0);

+	return NULL;

+    }

+

+    sdp = pj_pool_calloc (pool, 1, sizeof(pjsdp_session_desc));

+    if (!sdp) {

+	PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP session descriptor"));

+	return NULL;

+    }

+

+    pj_gettimeofday(&tv);

+

+    sdp->origin.user = pj_str("-");

+    sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL;

+    sdp->origin.net_type = ID_IN;

+    sdp->origin.addr_type = ID_IP4;

+    sdp->origin.addr = *pj_gethostname();

+

+    sdp->name = ID_SDP_NAME;

+

+    /* If all media addresses are the same, then put the connection

+     * info in the session level, otherwise put it in media stream

+     * level.

+     */

+    for (i=0; i<session->stream_cnt; ++i) {

+	if (c_addr == NULL) {

+	    c_addr = &session->stream_desc[i]->info.sock_info;

+	} else if (c_addr->rtp_addr_name.sin_addr.s_addr != session->stream_desc[i]->info.sock_info.rtp_addr_name.sin_addr.s_addr)

+	{

+	    c_addr = NULL;

+	    break;

+	}

+    }

+

+    if (c_addr) {

+	/* All addresses are the same, put connection info in session level. */

+	sdp->conn = pj_pool_alloc (pool, sizeof(pjsdp_conn_info));

+	if (!sdp->conn) {

+	    PJ_LOG(2,(THIS_FILE, "No memory to allocate SDP connection info"));

+	    return NULL;

+	}

+

+	sdp->conn->net_type = ID_IN;

+	sdp->conn->addr_type = ID_IP4;

+	pj_strdup2 (pool, &sdp->conn->addr, pj_inet_ntoa(c_addr->rtp_addr_name.sin_addr));

+    }

+

+    sdp->time.start = sdp->time.stop = 0;

+    sdp->attr_count = 0;

+

+    /* Create each media. */

+    sdp->media_count = 0;

+    for (i=0; i<session->stream_cnt; ++i) {

+	const pj_media_stream_desc *sd = session->stream_desc[i];

+	pjsdp_media_desc *m;

+	unsigned j;

+	unsigned fmt_cnt;

+	pjsdp_attr *attr;

+

+	m = pj_pool_calloc (pool, 1, sizeof(pjsdp_media_desc));

+	if (!m) {

+	    PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP media stream descriptor"));

+	    return NULL;

+	}

+

+	sdp->media[sdp->media_count++] = m;

+

+	pj_strdup (pool, &m->desc.media, &sd->info.type);

+	m->desc.port = pj_ntohs(sd->info.sock_info.rtp_addr_name.sin_port);

+	m->desc.port_count = 1;

+	pj_strdup (pool, &m->desc.transport, &sd->info.transport);

+

+	/* Add format and rtpmap for each codec. */

+	m->desc.fmt_count = 0;

+	m->attr_count = 0;

+	fmt_cnt = sd->info.fmt_cnt;

+	if (fmt_cnt > 0 && only_first_fmt)

+	    fmt_cnt = 1;

+	for (j=0; j<fmt_cnt; ++j) {

+	    pjsdp_rtpmap_attr *rtpmap;

+	    pj_str_t *fmt = &m->desc.fmt[m->desc.fmt_count++];

+

+	    if (sd->info.fmt[j].type==PJ_MEDIA_TYPE_UNKNOWN) {

+		pj_strdup(pool, fmt, &sd->info.fmt[j].encoding_name);

+	    } else {

+		fmt->ptr = pj_pool_alloc(pool, 8);

+		fmt->slen = pj_utoa(sd->info.fmt[j].pt, fmt->ptr);

+

+		rtpmap = pj_pool_calloc(pool, 1, sizeof(pjsdp_rtpmap_attr));

+		if (rtpmap) {

+		    m->attr[m->attr_count++] = (pjsdp_attr*)rtpmap;

+		    rtpmap->type = PJSDP_ATTR_RTPMAP;

+		    rtpmap->payload_type = sd->info.fmt[j].pt;

+		    rtpmap->clock_rate = sd->info.fmt[j].sample_rate;

+		    pj_strdup (pool, &rtpmap->encoding_name, &sd->info.fmt[j].encoding_name);

+		} else {

+		    PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP rtpmap descriptor"));

+		}

+	    }

+	}

+

+	/* If we don't have connection info in session level, create one. */

+	if (sdp->conn == NULL) {

+	    m->conn = pj_pool_alloc (pool, sizeof(pjsdp_conn_info));

+	    if (m->conn) {

+		m->conn->net_type = ID_IN;

+		m->conn->addr_type = ID_IP4;

+		pj_strdup2 (pool, &m->conn->addr, pj_inet_ntoa(sd->info.sock_info.rtp_addr_name.sin_addr));

+	    } else {

+		PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP media connection info"));

+		return NULL;

+	    }

+	}

+

+	/* Add additional attribute to the media stream. */

+	attr = pj_pool_alloc(pool, sizeof(pjsdp_attr));

+	if (!attr) {

+	    PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP attribute"));

+	    return NULL;

+	}

+	m->attr[m->attr_count++] = attr;

+

+	switch (sd->info.dir) {

+	case PJ_MEDIA_DIR_NONE:

+	    attr->type = PJSDP_ATTR_INACTIVE;

+	    break;

+	case PJ_MEDIA_DIR_ENCODING:

+	    attr->type = PJSDP_ATTR_SEND_ONLY;

+	    break;

+	case PJ_MEDIA_DIR_DECODING:

+	    attr->type = PJSDP_ATTR_RECV_ONLY;

+	    break;

+	case PJ_MEDIA_DIR_ENCODING_DECODING:

+	    attr->type = PJSDP_ATTR_SEND_RECV;

+	    break;

+	}

+    }

+

+    return sdp;

+}

+

+/**

+ * Update session with SDP answer from peer.

+ */

+PJ_DEF(pj_status_t)

+pj_media_session_update (pj_media_session_t *session, 

+			 const pjsdp_session_desc *sdp)

+{

+    unsigned i;

+    unsigned count;

+

+    /* Check SDP */

+    if (sdp_check (sdp) != 0) {

+	return -1;

+    }

+

+    /* If the media stream count doesn't match, only update one. */

+    if (session->stream_cnt != sdp->media_count) {

+	PJ_LOG(3,(THIS_FILE, "pj_media_session_update : "

+		 "SDP media count mismatch! (rmt=%d, lcl=%d)",

+		 sdp->media_count, session->stream_cnt));

+	count = (session->stream_cnt < sdp->media_count) ?

+	    session->stream_cnt : sdp->media_count;

+    } else {

+	count = session->stream_cnt;

+    }

+

+    for (i=0; i<count; ++i) {

+	pj_media_stream_desc *sd = session->stream_desc[i];

+	const pjsdp_media_desc *m = sdp->media[i];

+	const pjsdp_conn_info *conn;

+	unsigned j;

+

+	/* Check that the session is not active. */

+	pj_assert (sd->enc_stream == NULL && sd->dec_stream == NULL);

+

+	conn = m->conn ? m->conn : sdp->conn;

+	pj_assert(conn);

+

+	/* Update remote address. */

+	sd->info.rem_port = m->desc.port;

+	pj_strdup (session->pool, &sd->info.rem_addr, &conn->addr);

+

+	/* Select one active codec according to what peer wants. */

+	for (j=0; j<sd->info.fmt_cnt; ++j) {

+	    unsigned fmt_0 = pj_strtoul(&m->desc.fmt[0]);

+	    if (sd->info.fmt[j].pt == fmt_0) {

+		pj_codec_id temp;

+

+		/* Put active format to the front. */

+		if (j == 0)

+		    break;

+

+		pj_memcpy(&temp, &sd->info.fmt[0], sizeof(temp));

+		pj_memcpy(&sd->info.fmt[0], &sd->info.fmt[j], sizeof(temp));

+		pj_memcpy(&sd->info.fmt[j], &temp, sizeof(temp));

+		break;

+	    }

+	}

+

+	if (j == sd->info.fmt_cnt) {

+	    /* Peer has answered SDP with new codec, which doesn't exist

+	     * in the offer!

+	     * Mute this media.

+	     */

+	    PJ_LOG(3,(THIS_FILE, "Peer has answered SDP with new codec!"));

+	    sd->info.dir = PJ_MEDIA_DIR_NONE;

+	    continue;

+	}

+

+	/* Check direction. */

+	if (m->desc.port == 0 || pjsdp_media_desc_has_attr(m, PJSDP_ATTR_INACTIVE)) {

+	    sd->info.dir = PJ_MEDIA_DIR_NONE;

+	}

+	else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_RECV_ONLY)) {

+	    sd->info.dir = PJ_MEDIA_DIR_ENCODING;

+	}

+	else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_SEND_ONLY)) {

+	    sd->info.dir = PJ_MEDIA_DIR_DECODING;

+	}

+	else {

+	    sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING;

+	}

+    }

+

+    return 0;

+}

+

+/**

+ * Enumerate media streams in the session.

+ */

+PJ_DEF(unsigned)

+pj_media_session_enum_streams (const pj_media_session_t *session, 

+			       unsigned count, const pj_media_stream_info *info[])

+{

+    unsigned i;

+

+    if (count > session->stream_cnt)

+	count = session->stream_cnt;

+

+    for (i=0; i<count; ++i) {

+	info[i] = &session->stream_desc[i]->info;

+    }

+

+    return session->stream_cnt;

+}

+

+/**

+ * Get statistics

+ */

+PJ_DEF(pj_status_t)

+pj_media_session_get_stat (const pj_media_session_t *session, unsigned index,

+			   pj_media_stream_stat *tx_stat,

+			   pj_media_stream_stat *rx_stat)

+{

+    pj_media_stream_desc *sd;

+    int stat_cnt = 0;

+

+    if (index >= session->stream_cnt) {

+	pj_assert(0);

+	return -1;

+    }

+    

+    sd = session->stream_desc[index];

+

+    if (sd->enc_stream && tx_stat) {

+	pj_media_stream_get_stat (sd->enc_stream, tx_stat);

+	++stat_cnt;

+    } else if (tx_stat) {

+	pj_memset (tx_stat, 0, sizeof(*tx_stat));

+    }

+

+    if (sd->dec_stream && rx_stat) {

+	pj_media_stream_get_stat (sd->dec_stream, rx_stat);

+	++stat_cnt;

+    } else if (rx_stat) {

+	pj_memset (rx_stat, 0, sizeof(*rx_stat));

+    }

+

+    return stat_cnt ? 0 : -1;

+}

+

+/**

+ * Modify stream, only when stream is inactive.

+ */

+PJ_DEF(pj_status_t)

+pj_media_session_modify_stream (pj_media_session_t *session, unsigned index,

+				unsigned modify_flag, const pj_media_stream_info *info)

+{

+    pj_media_stream_desc *sd;

+

+    if (index >= session->stream_cnt) {

+	pj_assert(0);

+	return -1;

+    }

+    

+    sd = session->stream_desc[index];

+

+    if (sd->enc_stream || sd->dec_stream) {

+	pj_assert(0);

+	return -1;

+    }

+

+    if (modify_flag & PJ_MEDIA_STREAM_MODIFY_DIR) {

+	sd->info.dir = info->dir;

+    }

+

+    return 0;

+}

+

+/**

+ * Activate media session.

+ */

+PJ_DEF(pj_status_t)

+pj_media_session_activate (pj_media_session_t *session)

+{

+    unsigned i;

+    pj_status_t status = 0;

+

+    for (i=0; i<session->stream_cnt; ++i) {

+	pj_status_t rc;

+	rc = pj_media_session_activate_stream (session, i);

+	if (status == 0)

+	    status = rc;

+    }

+    return status;

+}

+

+/**

+ * Activate individual stream in media session.

+ */

+PJ_DEF(pj_status_t)

+pj_media_session_activate_stream (pj_media_session_t *session, unsigned index)

+{

+    pj_media_stream_desc *sd;

+    pj_media_stream_create_param scp;

+    pj_status_t status;

+    pj_time_val tv;

+

+    if (index < 0 || index >= session->stream_cnt) {

+	pj_assert(0);

+	return -1;

+    }

+

+    sd = session->stream_desc[index];

+

+    if (sd->enc_stream || sd->dec_stream) {

+	/* Stream already active. */

+	pj_assert(0);

+	return 0;

+    }

+

+    pj_gettimeofday(&tv);

+

+    /* Initialize parameter to create stream. */

+    pj_memset (&scp, 0, sizeof(scp));

+    scp.codec_id = &sd->info.fmt[0];

+    scp.mediamgr = session->mediamgr;

+    scp.dir = sd->info.dir;

+    scp.rtp_sock = sd->info.sock_info.rtp_sock;

+    scp.rtcp_sock = sd->info.sock_info.rtcp_sock;

+    scp.remote_addr = pj_pool_calloc (session->pool, 1, sizeof(pj_sockaddr_in));

+    pj_sockaddr_init (scp.remote_addr, &sd->info.rem_addr, sd->info.rem_port);

+    scp.ssrc = tv.sec;

+    scp.jb_min = 1;

+    scp.jb_max = 15;

+    scp.jb_maxcnt = 16;

+

+    /* Build the stream! */

+    status = pj_media_stream_create (session->pool, &sd->enc_stream, &sd->dec_stream, &scp);

+

+    if (status==0 && sd->enc_stream) {

+	status = pj_media_stream_start (sd->enc_stream);

+	if (status != 0)

+	    goto on_error;

+    }

+    if (status==0 && sd->dec_stream) {

+	status = pj_media_stream_start (sd->dec_stream);

+	if (status != 0)

+	    goto on_error;

+    }

+    return status;

+

+on_error:

+    if (sd->enc_stream) {

+	pj_media_stream_destroy (sd->enc_stream);

+	sd->enc_stream = NULL;

+    }

+    if (sd->dec_stream) {

+	pj_media_stream_destroy (sd->dec_stream);

+	sd->dec_stream = NULL;

+    }

+    return status;

+}

+

+/**

+ * Destroy media session.

+ */

+PJ_DEF(pj_status_t)

+pj_media_session_destroy (pj_media_session_t *session)

+{

+    unsigned i;

+

+    if (!session)

+	return -1;

+

+    for (i=0; i<session->stream_cnt; ++i) {

+	pj_media_stream_desc *sd = session->stream_desc[i];

+

+	if (sd->enc_stream) {

+	    pj_media_stream_destroy (sd->enc_stream);

+	    sd->enc_stream = NULL;

+	}

+	if (sd->dec_stream) {

+	    pj_media_stream_destroy (sd->dec_stream);

+	    sd->dec_stream = NULL;

+	}

+    }

+    pj_pool_release (session->pool);

+    return 0;

+}

+

diff --git a/pjmedia/src/pjmedia/session.h b/pjmedia/src/pjmedia/session.h
index 3ae9d40..411b7f8 100644
--- a/pjmedia/src/pjmedia/session.h
+++ b/pjmedia/src/pjmedia/session.h
@@ -1,138 +1,159 @@
-/* $Id$
- *
- */
-
-#ifndef __PJMEDIA_SESSION_H__
-#define __PJMEDIA_SESSION_H__
-
-
-/**
- * @file session.h
- * @brief Media Session.
- */
-
-#include <pj/types.h>
-#include <pjmedia/mediamgr.h>
-#include <pjmedia/stream.h>
-#include <pjmedia/sdp.h>
-
-PJ_BEGIN_DECL 
-
-/**
- * @defgroup PJMED_SES Media session
- * @ingroup PJMEDIA
- * @{
- */
-
-/** Opaque declaration of media session. */
-typedef struct pj_media_session_t pj_media_session_t;
-
-/** Media socket info. */
-typedef struct pj_media_sock_info
-{
-    pj_sock_t	    rtp_sock, rtcp_sock;
-    pj_sockaddr_in  rtp_addr_name;
-} pj_media_sock_info;
-
-/** Stream info. */
-typedef struct pj_media_stream_info
-{
-    pj_str_t		type;
-    pj_media_dir_t	dir;
-    pj_str_t		transport;
-    pj_media_sock_info	sock_info;
-    pj_str_t		rem_addr;
-    unsigned short	rem_port;
-    unsigned		fmt_cnt;
-    pj_codec_id		fmt[PJSDP_MAX_FMT];
-
-} pj_media_stream_info;
-
-/** Flag for modifying stream. */
-enum
-{
-    PJ_MEDIA_STREAM_MODIFY_DIR = 1,
-};
-
-/**
- * Create new session offering.
- */
-PJ_DECL(pj_media_session_t*) 
-pj_media_session_create ( pj_med_mgr_t *mgr, const pj_media_sock_info *skinfo );
-
-/**
- * Create new session based on peer's offering.
- */
-PJ_DECL(pj_media_session_t*) 
-pj_media_session_create_from_sdp ( pj_med_mgr_t *mgr, const pjsdp_session_desc *sdp,
-				   const pj_media_sock_info *skinfo);
-
-/**
- * Duplicate session. The new session is inactive.
- */
-PJ_DECL(pj_media_session_t*)
-pj_media_session_clone (const pj_media_session_t *session);
-
-/**
- * Create SDP description from the session.
- */
-PJ_DECL(pjsdp_session_desc*)
-pj_media_session_create_sdp ( const pj_media_session_t *session, pj_pool_t *pool,
-			      pj_bool_t only_first_fmt);
-
-/**
- * Update session with SDP answer from peer. The session must NOT active.
- */
-PJ_DECL(pj_status_t)
-pj_media_session_update ( pj_media_session_t *session, 
-			  const pjsdp_session_desc *sdp);
-
-/**
- * Enumerate media streams in the session.
- * @return the actual number of streams.
- */
-PJ_DECL(unsigned)
-pj_media_session_enum_streams (const pj_media_session_t *session, 
-			       unsigned count, const pj_media_stream_info *info[]);
-
-/**
- * Get stream statistics.
- */
-PJ_DECL(pj_status_t)
-pj_media_session_get_stat (const pj_media_session_t *session, unsigned index,
-			   pj_media_stream_stat *tx_stat,
-			   pj_media_stream_stat *rx_stat);
-
-/**
- * Modify stream, only when stream is inactive.
- */
-PJ_DECL(pj_status_t)
-pj_media_session_modify_stream (pj_media_session_t *session, unsigned index,
-				unsigned modify_flag, const pj_media_stream_info *info);
-
-/**
- * Activate all streams in media session.
- */
-PJ_DECL(pj_status_t)
-pj_media_session_activate (pj_media_session_t *session);
-
-/**
- * Activate individual stream in media session.
- */
-PJ_DECL(pj_status_t)
-pj_media_session_activate_stream (pj_media_session_t *session, unsigned index);
-
-/**
- * Destroy media session.
- */
-PJ_DECL(pj_status_t)
-pj_media_session_destroy (pj_media_session_t *session);
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJMEDIA_SESSION_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJMEDIA_SESSION_H__

+#define __PJMEDIA_SESSION_H__

+

+

+/**

+ * @file session.h

+ * @brief Media Session.

+ */

+

+#include <pj/types.h>

+#include <pjmedia/mediamgr.h>

+#include <pjmedia/stream.h>

+#include <pjmedia/sdp.h>

+

+PJ_BEGIN_DECL 

+

+/**

+ * @defgroup PJMED_SES Media session

+ * @ingroup PJMEDIA

+ * @{

+ */

+

+/** Opaque declaration of media session. */

+typedef struct pj_media_session_t pj_media_session_t;

+

+/** Media socket info. */

+typedef struct pj_media_sock_info

+{

+    pj_sock_t	    rtp_sock, rtcp_sock;

+    pj_sockaddr_in  rtp_addr_name;

+} pj_media_sock_info;

+

+/** Stream info. */

+typedef struct pj_media_stream_info

+{

+    pj_str_t		type;

+    pj_media_dir_t	dir;

+    pj_str_t		transport;

+    pj_media_sock_info	sock_info;

+    pj_str_t		rem_addr;

+    unsigned short	rem_port;

+    unsigned		fmt_cnt;

+    pj_codec_id		fmt[PJSDP_MAX_FMT];

+

+} pj_media_stream_info;

+

+/** Flag for modifying stream. */

+enum

+{

+    PJ_MEDIA_STREAM_MODIFY_DIR = 1,

+};

+

+/**

+ * Create new session offering.

+ */

+PJ_DECL(pj_media_session_t*) 

+pj_media_session_create ( pj_med_mgr_t *mgr, const pj_media_sock_info *skinfo );

+

+/**

+ * Create new session based on peer's offering.

+ */

+PJ_DECL(pj_media_session_t*) 

+pj_media_session_create_from_sdp ( pj_med_mgr_t *mgr, const pjsdp_session_desc *sdp,

+				   const pj_media_sock_info *skinfo);

+

+/**

+ * Duplicate session. The new session is inactive.

+ */

+PJ_DECL(pj_media_session_t*)

+pj_media_session_clone (const pj_media_session_t *session);

+

+/**

+ * Create SDP description from the session.

+ */

+PJ_DECL(pjsdp_session_desc*)

+pj_media_session_create_sdp ( const pj_media_session_t *session, pj_pool_t *pool,

+			      pj_bool_t only_first_fmt);

+

+/**

+ * Update session with SDP answer from peer. The session must NOT active.

+ */

+PJ_DECL(pj_status_t)

+pj_media_session_update ( pj_media_session_t *session, 

+			  const pjsdp_session_desc *sdp);

+

+/**

+ * Enumerate media streams in the session.

+ * @return the actual number of streams.

+ */

+PJ_DECL(unsigned)

+pj_media_session_enum_streams (const pj_media_session_t *session, 

+			       unsigned count, const pj_media_stream_info *info[]);

+

+/**

+ * Get stream statistics.

+ */

+PJ_DECL(pj_status_t)

+pj_media_session_get_stat (const pj_media_session_t *session, unsigned index,

+			   pj_media_stream_stat *tx_stat,

+			   pj_media_stream_stat *rx_stat);

+

+/**

+ * Modify stream, only when stream is inactive.

+ */

+PJ_DECL(pj_status_t)

+pj_media_session_modify_stream (pj_media_session_t *session, unsigned index,

+				unsigned modify_flag, const pj_media_stream_info *info);

+

+/**

+ * Activate all streams in media session.

+ */

+PJ_DECL(pj_status_t)

+pj_media_session_activate (pj_media_session_t *session);

+

+/**

+ * Activate individual stream in media session.

+ */

+PJ_DECL(pj_status_t)

+pj_media_session_activate_stream (pj_media_session_t *session, unsigned index);

+

+/**

+ * Destroy media session.

+ */

+PJ_DECL(pj_status_t)

+pj_media_session_destroy (pj_media_session_t *session);

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJMEDIA_SESSION_H__ */

diff --git a/pjmedia/src/pjmedia/sound.h b/pjmedia/src/pjmedia/sound.h
index 997885a..a3f5163 100644
--- a/pjmedia/src/pjmedia/sound.h
+++ b/pjmedia/src/pjmedia/sound.h
@@ -1,187 +1,208 @@
-/* $Id$
- *
- */
-
-#ifndef __PJMEDIA_SOUND_H__
-#define __PJMEDIA_SOUND_H__
-
-
-/**
- * @file sound.h
- * @brief Sound player and recorder device framework.
- */
-
-#include <pj/pool.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJMED_SND Sound device abstraction.
- * @ingroup PJMEDIA
- * @{
- */
-
-/** Opaque data type for audio stream. */
-typedef struct pj_snd_stream pj_snd_stream;
-
-/**
- * Device information structure returned by #pj_snd_get_dev_info.
- */
-typedef struct pj_snd_dev_info
-{
-    char	name[64];	        /**< Device name.		    */
-    unsigned	input_count;	        /**< Max number of input channels.  */
-    unsigned	output_count;	        /**< Max number of output channels. */
-    unsigned	default_samples_per_sec;/**< Default sampling rate.	    */
-} pj_snd_dev_info;
-
-/**
- * Sound device parameter, to be specified when calling #pj_snd_open_recorder
- * or #pj_snd_open_player.
- */
-typedef struct pj_snd_stream_info
-{
-    unsigned samples_per_sec;		/* Sampling rate.	    */
-    unsigned bits_per_sample;		/* No of bits per sample.   */
-    unsigned samples_per_frame;		/* No of samples per frame. */
-    unsigned bytes_per_frame;		/* No of bytes per frame.   */
-    unsigned frames_per_packet;		/* No of frames per packet. */
-} pj_snd_stream_info;
-
-/** 
- * This callback is called by player stream when it needs additional data
- * to be played by the device. Application must fill in the whole of output 
- * buffer with sound samples.
- *
- * @param user_data	User data associated with the stream.
- * @param timestamp	Timestamp, in samples.
- * @param output	Buffer to be filled out by application.
- * @param size		The size requested in bytes, which will be equal to
- *			the size of one whole packet.
- *
- * @return		Non-zero to stop the stream.
- */
-typedef pj_status_t (*pj_snd_play_cb)(/* in */   void *user_data,
-				      /* in */   pj_uint32_t timestamp,
-				      /* out */  void *output,
-				      /* out */  unsigned size);
-
-/**
- * This callback is called by recorder stream when it has captured the whole
- * packet worth of audio samples.
- *
- * @param user_data	User data associated with the stream.
- * @param timestamp	Timestamp, in samples.
- * @param output	Buffer containing the captured audio samples.
- * @param size		The size of the data in the buffer, in bytes.
- *
- * @return		Non-zero to stop the stream.
- */
-typedef pj_status_t (*pj_snd_rec_cb)(/* in */   void *user_data,
-				     /* in */   pj_uint32_t timestamp,
-				     /* in */   const void *input,
-				     /* in*/    unsigned size);
-
-/**
- * Init the sound library.
- *
- * @param factory	The sound factory.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_snd_init(pj_pool_factory *factory);
-
-
-/**
- * Get the number of devices detected by the library.
- *
- * @return		Number of devices.
- */
-PJ_DECL(int) pj_snd_get_dev_count(void);
-
-
-/**
- * Get device info.
- *
- * @param index		The index of the device, which should be in the range
- *			from zero to #pj_snd_get_dev_count - 1.
- */
-PJ_DECL(const pj_snd_dev_info*) pj_snd_get_dev_info(unsigned index);
-
-
-/**
- * Create a new audio stream for audio capture purpose.
- *
- * @param index		Device index, or -1 to let the library choose the first
- *			available device, or -2 to use NULL device.
- * @param param		Stream parameters.
- * @param rec_cb	Callback to handle captured audio samples.
- * @param user_data	User data to be associated with the stream.
- *
- * @return		Audio stream, or NULL if failed.
- */
-PJ_DECL(pj_snd_stream*) pj_snd_open_recorder(int index,
-					     const pj_snd_stream_info *param,
-					     pj_snd_rec_cb rec_cb,
-					     void *user_data);
-
-/**
- * Create a new audio stream for playing audio samples.
- *
- * @param index		Device index, or -1 to let the library choose the first
- *			available device, or -2 to use NULL device.
- * @param param		Stream parameters.
- * @param play_cb	Callback to supply audio samples.
- * @param user_data	User data to be associated with the stream.
- *
- * @return		Audio stream, or NULL if failed.
- */
-PJ_DECL(pj_snd_stream*) pj_snd_open_player(int index,
-					   const pj_snd_stream_info *param,
-					   pj_snd_play_cb play_cb,
-					   void *user_data);
-
-/**
- * Start the stream.
- *
- * @param stream	The recorder or player stream.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_snd_stream_start(pj_snd_stream *stream);
-
-/**
- * Stop the stream.
- *
- * @param stream	The recorder or player stream.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_snd_stream_stop(pj_snd_stream *stream);
-
-/**
- * Destroy the stream.
- *
- * @param stream	The recorder of player stream.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_snd_stream_close(pj_snd_stream *stream);
-
-/**
- * Deinitialize sound library.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pj_snd_deinit(void);
-
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-
-#endif	/* __PJMEDIA_SOUND_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJMEDIA_SOUND_H__

+#define __PJMEDIA_SOUND_H__

+

+

+/**

+ * @file sound.h

+ * @brief Sound player and recorder device framework.

+ */

+

+#include <pj/pool.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJMED_SND Sound device abstraction.

+ * @ingroup PJMEDIA

+ * @{

+ */

+

+/** Opaque data type for audio stream. */

+typedef struct pj_snd_stream pj_snd_stream;

+

+/**

+ * Device information structure returned by #pj_snd_get_dev_info.

+ */

+typedef struct pj_snd_dev_info

+{

+    char	name[64];	        /**< Device name.		    */

+    unsigned	input_count;	        /**< Max number of input channels.  */

+    unsigned	output_count;	        /**< Max number of output channels. */

+    unsigned	default_samples_per_sec;/**< Default sampling rate.	    */

+} pj_snd_dev_info;

+

+/**

+ * Sound device parameter, to be specified when calling #pj_snd_open_recorder

+ * or #pj_snd_open_player.

+ */

+typedef struct pj_snd_stream_info

+{

+    unsigned samples_per_sec;		/* Sampling rate.	    */

+    unsigned bits_per_sample;		/* No of bits per sample.   */

+    unsigned samples_per_frame;		/* No of samples per frame. */

+    unsigned bytes_per_frame;		/* No of bytes per frame.   */

+    unsigned frames_per_packet;		/* No of frames per packet. */

+} pj_snd_stream_info;

+

+/** 

+ * This callback is called by player stream when it needs additional data

+ * to be played by the device. Application must fill in the whole of output 

+ * buffer with sound samples.

+ *

+ * @param user_data	User data associated with the stream.

+ * @param timestamp	Timestamp, in samples.

+ * @param output	Buffer to be filled out by application.

+ * @param size		The size requested in bytes, which will be equal to

+ *			the size of one whole packet.

+ *

+ * @return		Non-zero to stop the stream.

+ */

+typedef pj_status_t (*pj_snd_play_cb)(/* in */   void *user_data,

+				      /* in */   pj_uint32_t timestamp,

+				      /* out */  void *output,

+				      /* out */  unsigned size);

+

+/**

+ * This callback is called by recorder stream when it has captured the whole

+ * packet worth of audio samples.

+ *

+ * @param user_data	User data associated with the stream.

+ * @param timestamp	Timestamp, in samples.

+ * @param output	Buffer containing the captured audio samples.

+ * @param size		The size of the data in the buffer, in bytes.

+ *

+ * @return		Non-zero to stop the stream.

+ */

+typedef pj_status_t (*pj_snd_rec_cb)(/* in */   void *user_data,

+				     /* in */   pj_uint32_t timestamp,

+				     /* in */   const void *input,

+				     /* in*/    unsigned size);

+

+/**

+ * Init the sound library.

+ *

+ * @param factory	The sound factory.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_snd_init(pj_pool_factory *factory);

+

+

+/**

+ * Get the number of devices detected by the library.

+ *

+ * @return		Number of devices.

+ */

+PJ_DECL(int) pj_snd_get_dev_count(void);

+

+

+/**

+ * Get device info.

+ *

+ * @param index		The index of the device, which should be in the range

+ *			from zero to #pj_snd_get_dev_count - 1.

+ */

+PJ_DECL(const pj_snd_dev_info*) pj_snd_get_dev_info(unsigned index);

+

+

+/**

+ * Create a new audio stream for audio capture purpose.

+ *

+ * @param index		Device index, or -1 to let the library choose the first

+ *			available device, or -2 to use NULL device.

+ * @param param		Stream parameters.

+ * @param rec_cb	Callback to handle captured audio samples.

+ * @param user_data	User data to be associated with the stream.

+ *

+ * @return		Audio stream, or NULL if failed.

+ */

+PJ_DECL(pj_snd_stream*) pj_snd_open_recorder(int index,

+					     const pj_snd_stream_info *param,

+					     pj_snd_rec_cb rec_cb,

+					     void *user_data);

+

+/**

+ * Create a new audio stream for playing audio samples.

+ *

+ * @param index		Device index, or -1 to let the library choose the first

+ *			available device, or -2 to use NULL device.

+ * @param param		Stream parameters.

+ * @param play_cb	Callback to supply audio samples.

+ * @param user_data	User data to be associated with the stream.

+ *

+ * @return		Audio stream, or NULL if failed.

+ */

+PJ_DECL(pj_snd_stream*) pj_snd_open_player(int index,

+					   const pj_snd_stream_info *param,

+					   pj_snd_play_cb play_cb,

+					   void *user_data);

+

+/**

+ * Start the stream.

+ *

+ * @param stream	The recorder or player stream.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_snd_stream_start(pj_snd_stream *stream);

+

+/**

+ * Stop the stream.

+ *

+ * @param stream	The recorder or player stream.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_snd_stream_stop(pj_snd_stream *stream);

+

+/**

+ * Destroy the stream.

+ *

+ * @param stream	The recorder of player stream.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_snd_stream_close(pj_snd_stream *stream);

+

+/**

+ * Deinitialize sound library.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pj_snd_deinit(void);

+

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+

+#endif	/* __PJMEDIA_SOUND_H__ */

diff --git a/pjmedia/src/pjmedia/stream.c b/pjmedia/src/pjmedia/stream.c
index 1420a67..7419984 100644
--- a/pjmedia/src/pjmedia/stream.c
+++ b/pjmedia/src/pjmedia/stream.c
@@ -1,630 +1,651 @@
-/* $Id$
- *
- */
-
-#include <pjmedia/stream.h>
-#include <pjmedia/rtp.h>
-#include <pjmedia/rtcp.h>
-#include <pjmedia/jbuf.h>
-#include <pj/os.h>
-#include <pj/log.h>
-#include <pj/string.h>	    /* memcpy() */
-#include <pj/pool.h>
-#include <stdlib.h>
-
-#define THISFILE    "stream.c"
-#define ERRLEVEL    1
-
-#define PJ_MAX_FRAME_DURATION_MS    200
-#define PJ_MAX_BUFFER_SIZE_MS	    2000
-#define PJ_MAX_MTU		    1500
-
-struct jb_frame
-{
-    unsigned size;
-    void    *buf;
-};
-
-#define pj_fifobuf_alloc(fifo,size)	malloc(size)
-#define pj_fifobuf_unalloc(fifo,buf)	free(buf)
-#define pj_fifobuf_free(fifo, buf)	free(buf)
-
-enum stream_state
-{
-    STREAM_STOPPED,
-    STREAM_STARTED,
-};
-
-struct pj_media_stream_t
-{
-    pj_media_dir_t	    dir;
-    int			    pt;
-    int			    state;
-    pj_media_stream_stat    stat;
-    pj_media_stream_t	   *peer;
-    pj_snd_stream_info	    snd_info;
-    pj_snd_stream	   *snd_stream;
-    pj_mutex_t		   *mutex;
-    unsigned		    in_pkt_size;
-    void		   *in_pkt;
-    unsigned		    out_pkt_size;
-    void		   *out_pkt;
-    unsigned		    pcm_buf_size;
-    void		   *pcm_buf;
-    //pj_fifobuf_t	    fifobuf;
-    pj_codec_mgr	   *codec_mgr;
-    pj_codec		   *codec;
-    pj_rtp_session	    rtp;
-    pj_rtcp_session	   *rtcp;
-    pj_jitter_buffer	   *jb;
-    pj_sock_t		    rtp_sock;
-    pj_sock_t		    rtcp_sock;
-    pj_sockaddr_in	    dst_addr;
-    pj_thread_t		   *transport_thread;
-    int			    thread_quit_flag;
-};
-
-
-static pj_status_t play_callback(/* in */   void *user_data,
-				 /* in */   pj_uint32_t timestamp,
-				 /* out */  void *frame,
-				 /*inout*/  unsigned size)
-{
-    pj_media_stream_t *channel = user_data;
-    struct jb_frame *jb_frame;
-    void *p;
-    pj_uint32_t extseq;
-    pj_status_t status;
-    struct pj_audio_frame frame_in, frame_out;
-
-    PJ_UNUSED_ARG(timestamp)
-
-    /* Lock mutex */
-    pj_mutex_lock (channel->mutex);
-
-    if (!channel->codec) {
-	pj_mutex_unlock (channel->mutex);
-	return -1;
-    }
-
-    /* Get frame from jitter buffer. */
-    status = pj_jb_get (channel->jb, &extseq, &p);
-    jb_frame = p;
-    if (status != 0 || jb_frame == NULL) {
-	pj_memset(frame, 0, size);
-	pj_mutex_unlock(channel->mutex);
-	return 0;
-    }
-
-    /* Decode */
-    frame_in.buf = jb_frame->buf;
-    frame_in.size = jb_frame->size;
-    frame_in.type = PJ_AUDIO_FRAME_AUDIO;  /* ignored */
-    frame_out.buf = channel->pcm_buf;
-    status = channel->codec->op->decode (channel->codec, &frame_in,
-					 channel->pcm_buf_size, &frame_out);
-    if (status != 0) {
-	PJ_LOG(3, (THISFILE, "decode() has return error status %d", 
-			  status));
-
-	pj_memset(frame, 0, size);
-	pj_fifobuf_free (&channel->fifobuf, jb_frame);
-	pj_mutex_unlock(channel->mutex);
-	return 0;
-    }
-
-    /* Put in sound buffer. */
-    if (frame_out.size > size) {
-	PJ_LOG(3, (THISFILE, "Sound playout buffer truncated %d bytes", 
-			  frame_out.size - size));
-	frame_out.size = size;
-    }
-
-    pj_memcpy(frame, frame_out.buf, size);
-
-    pj_fifobuf_free (&channel->fifobuf, jb_frame);
-    pj_mutex_unlock(channel->mutex);
-    return 0;
-}
-
-static pj_status_t rec_callback( /* in */ void *user_data,
-			         /* in */ pj_uint32_t timestamp,
-			         /* in */ const void *frame,
-			         /* in */ unsigned size)
-{
-    pj_media_stream_t *channel = user_data;
-    pj_status_t status = 0;
-    struct pj_audio_frame frame_in, frame_out;
-    int ts_len;
-    void *rtphdr;
-    int rtphdrlen;
-    int sent;
-#if 0
-    static FILE *fhnd = NULL;
-#endif
-
-    PJ_UNUSED_ARG(timestamp)
-
-    /* Start locking channel mutex */
-    pj_mutex_lock (channel->mutex);
-
-    if (!channel->codec) {
-	status = -1;
-	goto on_return;
-    }
-
-    /* Encode. */
-    frame_in.type = PJ_MEDIA_TYPE_AUDIO;
-    frame_in.buf = (void*)frame;
-    frame_in.size = size;
-    frame_out.buf = ((char*)channel->out_pkt) + sizeof(pj_rtp_hdr);
-    status = channel->codec->op->encode (channel->codec, &frame_in, 
-					 channel->out_pkt_size - sizeof(pj_rtp_hdr), 
-					 &frame_out);
-    if (status != 0) {
-	PJ_LOG(3,(THISFILE, "Codec encode() has returned error status %d", 
-			     status));
-	goto on_return;
-    }
-
-    /* Encapsulate. */
-    ts_len = size / (channel->snd_info.bits_per_sample / 8);
-    status = pj_rtp_encode_rtp (&channel->rtp, channel->pt, 0, 
-				frame_out.size, ts_len, 
-				(const void**)&rtphdr, &rtphdrlen);
-    if (status != 0) {
-	PJ_LOG(3,(THISFILE, "RTP encode_rtp() has returned error status %d", 
-			    status));
-	goto on_return;
-    }
-
-    if (rtphdrlen != sizeof(pj_rtp_hdr)) {
-	/* We don't support RTP with extended header yet. */
-	PJ_TODO(SUPPORT_SENDING_RTP_WITH_EXTENDED_HEADER);
-	PJ_LOG(3,(THISFILE, "Unsupported extended RTP header for transmission"));
-	goto on_return;
-    }
-
-    pj_memcpy(channel->out_pkt, rtphdr, sizeof(pj_rtp_hdr));
-
-    /* Send. */
-    sent = pj_sock_sendto (channel->rtp_sock, channel->out_pkt, frame_out.size+sizeof(pj_rtp_hdr), 0, 
-			   &channel->dst_addr, sizeof(channel->dst_addr));
-    if (sent != (int)frame_out.size + (int)sizeof(pj_rtp_hdr))  {
-	pj_perror(THISFILE, "Error sending RTP packet to %s:%d", 
-		  pj_sockaddr_get_str_addr(&channel->dst_addr),
-		  pj_sockaddr_get_port(&channel->dst_addr));
-	goto on_return;
-    }
-
-    /* Update stat */
-    channel->stat.pkt_tx++;
-    channel->stat.oct_tx += frame_out.size+sizeof(pj_rtp_hdr);
-
-#if 0
-    if (fhnd == NULL) {
-	fhnd = fopen("RTP.DAT", "wb");
-	if (fhnd) {
-	    fwrite (channel->out_pkt, frame_out.size+sizeof(pj_rtp_hdr), 1, fhnd);
-	    fclose(fhnd);
-	}
-    }
-#endif
-
-on_return:
-    pj_mutex_unlock (channel->mutex);
-    return status;
-}
-
-
-static void* PJ_THREAD_FUNC stream_decoder_transport_thread (void*arg)
-{
-    pj_media_stream_t *channel = arg;
-
-    while (!channel->thread_quit_flag) {
-	int len, size;
-	const pj_rtp_hdr *hdr;
-	const void *payload;
-	unsigned payloadlen;
-	int status;
-	struct jb_frame *jb_frame;
-
-	/* Wait for packet. */
-	fd_set fds;
-	pj_time_val timeout;
-
-	PJ_FD_ZERO (&fds);
-	PJ_FD_SET (channel->rtp_sock, &fds);
-	timeout.sec = 0;
-	timeout.msec = 100;
-
-	/* Wait with timeout. */
-	status = pj_sock_select(channel->rtp_sock, &fds, NULL, NULL, &timeout);
-	if (status != 1)
-	    continue;
-
-	/* Get packet from socket. */
-	len = pj_sock_recv (channel->rtp_sock, channel->in_pkt, channel->in_pkt_size, 0);
-	if (len < 1) {
-	    if (pj_getlasterror() == PJ_ECONNRESET) {
-		/* On Win2K SP2 (or above) and WinXP, recv() will get WSAECONNRESET
-		   when the sending side receives ICMP port unreachable.
-		 */
-		continue;
-	    }
-	    pj_perror(THISFILE, "Error receiving packet from socket (len=%d)", len);
-	    pj_thread_sleep(1);
-	    continue;
-	}
-
-	if (channel->state != STREAM_STARTED)
-	    continue;
-
-	if (channel->thread_quit_flag)
-	    break;
-
-	/* Start locking the channel. */
-	pj_mutex_lock (channel->mutex);
-
-	/* Update RTP and RTCP session. */
-	status = pj_rtp_decode_rtp (&channel->rtp, channel->in_pkt, len, &hdr, &payload, &payloadlen);
-	if (status != 0) {
-	    pj_mutex_unlock (channel->mutex);
-	    PJ_LOG(4,(THISFILE, "RTP decode_rtp() has returned error status %d", status));
-	    continue;
-	}
-	status = pj_rtp_session_update (&channel->rtp, hdr);
-	if (status != 0 && status != PJ_RTP_ERR_SESSION_PROBATION && status != PJ_RTP_ERR_SESSION_RESTARTED) {
-	    pj_mutex_unlock (channel->mutex);
-	    PJ_LOG(4,(THISFILE, "RTP session_update() has returned error status %d", status));
-	    continue;
-	}
-	pj_rtcp_rx_rtp (channel->rtcp, pj_ntohs(hdr->seq), pj_ntohl(hdr->ts));
-
-	/* Update stat */
-	channel->stat.pkt_rx++;
-	channel->stat.oct_rx += len;
-
-	/* Copy to FIFO buffer. */
-	size = payloadlen+sizeof(struct jb_frame);
-	jb_frame = pj_fifobuf_alloc (&channel->fifobuf, size);
-	if (jb_frame == NULL) {
-	    pj_mutex_unlock (channel->mutex);
-	    PJ_LOG(4,(THISFILE, "Unable to allocate %d bytes FIFO buffer", size));
-	    continue;
-	}
-
-	/* Copy the payload */
-	jb_frame->size = payloadlen;
-	jb_frame->buf = ((char*)jb_frame) + sizeof(struct jb_frame);
-	pj_memcpy (jb_frame->buf, payload, payloadlen);
-
-	/* Put to jitter buffer. */
-	status = pj_jb_put (channel->jb, pj_ntohs(hdr->seq), jb_frame);
-	if (status != 0) {
-	    pj_fifobuf_unalloc (&channel->fifobuf, jb_frame);
-	    pj_mutex_unlock (channel->mutex);
-	    PJ_LOG(4,(THISFILE, "Jitter buffer put() has returned error status %d", status));
-	    continue;
-	}
-
-	pj_mutex_unlock (channel->mutex);
-    }
-
-    return NULL;
-}
-
-static void init_snd_param_from_codec_attr (pj_snd_stream_info *param,
-					    const pj_codec_attr *attr)
-{
-    param->bits_per_sample = attr->pcm_bits_per_sample;
-    param->bytes_per_frame = 2;
-    param->frames_per_packet = attr->sample_rate * attr->ptime / 1000;
-    param->samples_per_frame = 1;
-    param->samples_per_sec = attr->sample_rate;
-}
-
-static pj_media_stream_t *create_channel ( pj_pool_t *pool,
-					   pj_media_dir_t dir,
-					   pj_media_stream_t *peer,
-					   pj_codec_id *codec_id,
-					   pj_media_stream_create_param *param)
-{
-    pj_media_stream_t *channel;
-    pj_codec_attr codec_attr;
-    void *ptr;
-    unsigned size;
-    int status;
-    
-    /* Allocate memory for channel descriptor */
-    size = sizeof(pj_media_stream_t);
-    channel = pj_pool_calloc(pool, 1, size);
-    if (!channel) {
-	PJ_LOG(1,(THISFILE, "Unable to allocate %u bytes channel descriptor", 
-			 size));
-	return NULL;
-    }
-
-    channel->dir = dir;
-    channel->pt = codec_id->pt;
-    channel->peer = peer;
-    channel->codec_mgr = pj_med_mgr_get_codec_mgr (param->mediamgr);
-    channel->rtp_sock = param->rtp_sock;
-    channel->rtcp_sock = param->rtcp_sock;
-    channel->dst_addr = *param->remote_addr;
-    channel->state = STREAM_STOPPED;
-
-    /* Create mutex for the channel. */
-    channel->mutex = pj_mutex_create(pool, NULL, PJ_MUTEX_SIMPLE);
-    if (channel->mutex == NULL)
-	goto err_cleanup;
-
-    /* Create and initialize codec, only if peer is not present.
-       We only use one codec instance for both encoder and decoder.
-     */
-    if (peer && peer->codec) {
-	channel->codec = peer->codec;
-	status = channel->codec->factory->op->default_attr(channel->codec->factory, codec_id, 
-							   &codec_attr);
-	if (status != 0) {
-	    goto err_cleanup;
-	}
-
-    } else {
-	channel->codec = pj_codec_mgr_alloc_codec(channel->codec_mgr, codec_id);
-	if (channel->codec == NULL) {
-	    goto err_cleanup;
-	}
-
-	status = channel->codec->factory->op->default_attr(channel->codec->factory, codec_id, 
-							   &codec_attr);
-	if (status != 0) {
-	    goto err_cleanup;
-	}
-
-	codec_attr.pt = codec_id->pt;
-	status = channel->codec->op->open(channel->codec, &codec_attr);
-	if (status != 0) {
-	    goto err_cleanup;
-	}
-    }
-
-    /* Allocate buffer for incoming packet. */
-    channel->in_pkt_size = PJ_MAX_MTU;
-    channel->in_pkt = pj_pool_alloc(pool, channel->in_pkt_size);
-    if (!channel->in_pkt) {
-	PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes incoming packet buffer", 
-			  channel->in_pkt_size));
-	goto err_cleanup;
-    }
-
-    /* Allocate buffer for outgoing packet. */
-    channel->out_pkt_size = sizeof(pj_rtp_hdr) + 
-			    codec_attr.avg_bps / 8 * PJ_MAX_FRAME_DURATION_MS / 1000;
-    if (channel->out_pkt_size > PJ_MAX_MTU)
-	channel->out_pkt_size = PJ_MAX_MTU;
-    channel->out_pkt = pj_pool_alloc(pool, channel->out_pkt_size);
-    if (!channel->out_pkt) {
-	PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes encoding buffer", 
-			  channel->out_pkt_size));
-	goto err_cleanup;
-    }
-
-    /* Allocate buffer for decoding to PCM */
-    channel->pcm_buf_size = codec_attr.sample_rate * 
-			    codec_attr.pcm_bits_per_sample / 8 *
-			    PJ_MAX_FRAME_DURATION_MS / 1000;
-    channel->pcm_buf = pj_pool_alloc (pool, channel->pcm_buf_size);
-    if (!channel->pcm_buf) {
-	PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes PCM buffer", 
-			  channel->pcm_buf_size));
-	goto err_cleanup;
-    }
-
-    /* Allocate buffer for frames put in jitter buffer. */
-    size = codec_attr.avg_bps / 8 * PJ_MAX_BUFFER_SIZE_MS / 1000;
-    ptr = pj_pool_alloc(pool, size);
-    if (!ptr) {
-	PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes jitter buffer", 
-			  channel->pcm_buf_size));
-	goto err_cleanup;
-    }
-    //pj_fifobuf_init (&channel->fifobuf, ptr, size);
-
-    /* Create and initialize sound device */
-    init_snd_param_from_codec_attr (&channel->snd_info, &codec_attr);
-
-    if (dir == PJ_MEDIA_DIR_ENCODING)
-	channel->snd_stream = pj_snd_open_recorder(-1, &channel->snd_info, 
-						   &rec_callback, channel);
-    else
-	channel->snd_stream = pj_snd_open_player(-1, &channel->snd_info, 
-						 &play_callback, channel);
-
-    if (!channel->snd_stream)
-	goto err_cleanup;
-
-    /* Create RTP and RTCP sessions. */
-    if (pj_rtp_session_init(&channel->rtp, codec_id->pt, param->ssrc) != 0) {
-	PJ_LOG(1, (THISFILE, "RTP session initialization error"));
-	goto err_cleanup;
-    }
-
-    /* For decoder, create RTCP session, jitter buffer, and transport thread. */
-    if (dir == PJ_MEDIA_DIR_DECODING) {
-	channel->rtcp = pj_pool_calloc(pool, 1, sizeof(pj_rtcp_session));
-	if (!channel->rtcp) {
-	    PJ_LOG(1, (THISFILE, "Unable to allocate RTCP session"));
-	    goto err_cleanup;
-	}
-
-	pj_rtcp_init(channel->rtcp, param->ssrc);
-
-	channel->jb = pj_pool_calloc(pool, 1, sizeof(pj_jitter_buffer));
-	if (!channel->jb) {
-	    PJ_LOG(1, (THISFILE, "Unable to allocate jitter buffer descriptor"));
-	    goto err_cleanup;
-	}
-	if (pj_jb_init(channel->jb, pool, param->jb_min, param->jb_max, param->jb_maxcnt)) {
-	    PJ_LOG(1, (THISFILE, "Unable to allocate jitter buffer"));
-	    goto err_cleanup;
-	}
-
-	channel->transport_thread = pj_thread_create(pool, "decode", 
-						     &stream_decoder_transport_thread, channel,
-						     0, NULL, 0);
-	if (!channel->transport_thread) {
-	    pj_perror(THISFILE, "Unable to create transport thread");
-	    goto err_cleanup;
-	}
-    }
-
-    /* Done. */
-    return channel;
-
-err_cleanup:
-    pj_media_stream_destroy(channel);
-    return NULL;
-}
-
-
-PJ_DEF(pj_status_t) pj_media_stream_create (pj_pool_t *pool,
-					    pj_media_stream_t **enc_stream,
-					    pj_media_stream_t **dec_stream,
-					    pj_media_stream_create_param *param)
-{
-    *dec_stream = *enc_stream = NULL;
-
-    if (param->dir & PJ_MEDIA_DIR_DECODING) {
-	*dec_stream = 
-	    create_channel(pool, PJ_MEDIA_DIR_DECODING, NULL, param->codec_id, param);
-	if (!*dec_stream)
-	    return -1;
-    }
-
-    if (param->dir & PJ_MEDIA_DIR_ENCODING) {
-	*enc_stream = 
-	    create_channel(pool, PJ_MEDIA_DIR_ENCODING, *dec_stream, param->codec_id, param);
-	if (!*enc_stream) {
-	    if (*dec_stream) {
-		pj_media_stream_destroy(*dec_stream);
-		*dec_stream = NULL;
-	    }
-	    return -1;
-	}
-
-	if (*dec_stream) {
-	    (*dec_stream)->peer = *enc_stream;
-	}
-    }
-
-    return 0;
-}
-
-PJ_DEF(pj_status_t) pj_media_stream_start (pj_media_stream_t *channel)
-{
-    pj_status_t status;
-
-    status = pj_snd_stream_start(channel->snd_stream);
-
-    if (status == 0)
-	channel->state = STREAM_STARTED;
-    return status;
-}
-
-PJ_DEF(pj_status_t)  pj_media_stream_get_stat (const pj_media_stream_t *stream,
-					       pj_media_stream_stat *stat)
-{
-    if (stream->dir == PJ_MEDIA_DIR_ENCODING) {
-	pj_memcpy (stat, &stream->stat, sizeof(*stat));
-    } else {
-	pj_rtcp_pkt *rtcp_pkt;
-	int len;
-
-	pj_memset (stat, 0, sizeof(*stat));
-	pj_assert (stream->rtcp != 0);
-	pj_rtcp_build_rtcp (stream->rtcp, &rtcp_pkt, &len);
-
-	stat->pkt_rx = stream->stat.pkt_rx;
-	stat->oct_rx = stream->stat.oct_rx;
-
-	PJ_TODO(SUPPORT_JITTER_CALCULATION_FOR_NON_8KHZ_SAMPLE_RATE)
-	stat->jitter = pj_ntohl(rtcp_pkt->rr.jitter) / 8;
-	stat->pkt_lost = (rtcp_pkt->rr.total_lost_2 << 16) +
-			 (rtcp_pkt->rr.total_lost_1 << 8) +
-			 rtcp_pkt->rr.total_lost_0;
-    }
-    return 0;
-}
-
-PJ_DEF(pj_status_t) pj_media_stream_pause (pj_media_stream_t *channel)
-{
-    PJ_UNUSED_ARG(channel)
-    return -1;
-}
-
-PJ_DEF(pj_status_t) pj_media_stream_resume (pj_media_stream_t *channel)
-{
-    PJ_UNUSED_ARG(channel)
-    return -1;
-}
-
-PJ_DEF(pj_status_t) pj_media_stream_destroy (pj_media_stream_t *channel)
-{
-    channel->thread_quit_flag = 1;
-
-    pj_mutex_lock (channel->mutex);
-    if (channel->peer)
-	pj_mutex_lock (channel->peer->mutex);
-
-    if (channel->jb) {
-	/* No need to deinitialize jitter buffer. */
-    }
-    if (channel->transport_thread) {
-	pj_thread_join(channel->transport_thread);
-	pj_thread_destroy(channel->transport_thread);
-	channel->transport_thread = NULL;
-    }
-    if (channel->snd_stream != NULL) {
-	pj_mutex_unlock (channel->mutex);
-	pj_snd_stream_stop(channel->snd_stream);
-	pj_mutex_lock (channel->mutex);
-	pj_snd_stream_close(channel->snd_stream);
-	channel->snd_stream = NULL;
-    }
-    if (channel->codec) {
-	channel->codec->op->close(channel->codec);
-	pj_codec_mgr_dealloc_codec(channel->codec_mgr, channel->codec);
-	channel->codec = NULL;
-    }
-    if (channel->peer) {
-	pj_media_stream_t *peer = channel->peer;
-	peer->peer = NULL;
-	peer->codec = NULL;
-	peer->thread_quit_flag = 1;
-	if (peer->transport_thread) {
-	    pj_mutex_unlock (peer->mutex);
-	    pj_thread_join(peer->transport_thread);
-	    pj_mutex_lock (peer->mutex);
-	    pj_thread_destroy(peer->transport_thread);
-	    peer->transport_thread = NULL;
-	}
-	if (peer->snd_stream) {
-	    pj_mutex_unlock (peer->mutex);
-	    pj_snd_stream_stop(peer->snd_stream);
-	    pj_mutex_lock (peer->mutex);
-	    pj_snd_stream_close(peer->snd_stream);
-	    peer->snd_stream = NULL;
-	}
-    }
-
-    channel->state = STREAM_STOPPED;
-
-    if (channel->peer)
-	pj_mutex_unlock (channel->peer->mutex);
-    pj_mutex_unlock(channel->mutex);
-    pj_mutex_destroy(channel->mutex);
-
-    return 0;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#include <pjmedia/stream.h>

+#include <pjmedia/rtp.h>

+#include <pjmedia/rtcp.h>

+#include <pjmedia/jbuf.h>

+#include <pj/os.h>

+#include <pj/log.h>

+#include <pj/string.h>	    /* memcpy() */

+#include <pj/pool.h>

+#include <stdlib.h>

+

+#define THISFILE    "stream.c"

+#define ERRLEVEL    1

+

+#define PJ_MAX_FRAME_DURATION_MS    200

+#define PJ_MAX_BUFFER_SIZE_MS	    2000

+#define PJ_MAX_MTU		    1500

+

+struct jb_frame

+{

+    unsigned size;

+    void    *buf;

+};

+

+#define pj_fifobuf_alloc(fifo,size)	malloc(size)

+#define pj_fifobuf_unalloc(fifo,buf)	free(buf)

+#define pj_fifobuf_free(fifo, buf)	free(buf)

+

+enum stream_state

+{

+    STREAM_STOPPED,

+    STREAM_STARTED,

+};

+

+struct pj_media_stream_t

+{

+    pj_media_dir_t	    dir;

+    int			    pt;

+    int			    state;

+    pj_media_stream_stat    stat;

+    pj_media_stream_t	   *peer;

+    pj_snd_stream_info	    snd_info;

+    pj_snd_stream	   *snd_stream;

+    pj_mutex_t		   *mutex;

+    unsigned		    in_pkt_size;

+    void		   *in_pkt;

+    unsigned		    out_pkt_size;

+    void		   *out_pkt;

+    unsigned		    pcm_buf_size;

+    void		   *pcm_buf;

+    //pj_fifobuf_t	    fifobuf;

+    pj_codec_mgr	   *codec_mgr;

+    pj_codec		   *codec;

+    pj_rtp_session	    rtp;

+    pj_rtcp_session	   *rtcp;

+    pj_jitter_buffer	   *jb;

+    pj_sock_t		    rtp_sock;

+    pj_sock_t		    rtcp_sock;

+    pj_sockaddr_in	    dst_addr;

+    pj_thread_t		   *transport_thread;

+    int			    thread_quit_flag;

+};

+

+

+static pj_status_t play_callback(/* in */   void *user_data,

+				 /* in */   pj_uint32_t timestamp,

+				 /* out */  void *frame,

+				 /*inout*/  unsigned size)

+{

+    pj_media_stream_t *channel = user_data;

+    struct jb_frame *jb_frame;

+    void *p;

+    pj_uint32_t extseq;

+    pj_status_t status;

+    struct pj_audio_frame frame_in, frame_out;

+

+    PJ_UNUSED_ARG(timestamp)

+

+    /* Lock mutex */

+    pj_mutex_lock (channel->mutex);

+

+    if (!channel->codec) {

+	pj_mutex_unlock (channel->mutex);

+	return -1;

+    }

+

+    /* Get frame from jitter buffer. */

+    status = pj_jb_get (channel->jb, &extseq, &p);

+    jb_frame = p;

+    if (status != 0 || jb_frame == NULL) {

+	pj_memset(frame, 0, size);

+	pj_mutex_unlock(channel->mutex);

+	return 0;

+    }

+

+    /* Decode */

+    frame_in.buf = jb_frame->buf;

+    frame_in.size = jb_frame->size;

+    frame_in.type = PJ_AUDIO_FRAME_AUDIO;  /* ignored */

+    frame_out.buf = channel->pcm_buf;

+    status = channel->codec->op->decode (channel->codec, &frame_in,

+					 channel->pcm_buf_size, &frame_out);

+    if (status != 0) {

+	PJ_LOG(3, (THISFILE, "decode() has return error status %d", 

+			  status));

+

+	pj_memset(frame, 0, size);

+	pj_fifobuf_free (&channel->fifobuf, jb_frame);

+	pj_mutex_unlock(channel->mutex);

+	return 0;

+    }

+

+    /* Put in sound buffer. */

+    if (frame_out.size > size) {

+	PJ_LOG(3, (THISFILE, "Sound playout buffer truncated %d bytes", 

+			  frame_out.size - size));

+	frame_out.size = size;

+    }

+

+    pj_memcpy(frame, frame_out.buf, size);

+

+    pj_fifobuf_free (&channel->fifobuf, jb_frame);

+    pj_mutex_unlock(channel->mutex);

+    return 0;

+}

+

+static pj_status_t rec_callback( /* in */ void *user_data,

+			         /* in */ pj_uint32_t timestamp,

+			         /* in */ const void *frame,

+			         /* in */ unsigned size)

+{

+    pj_media_stream_t *channel = user_data;

+    pj_status_t status = 0;

+    struct pj_audio_frame frame_in, frame_out;

+    int ts_len;

+    void *rtphdr;

+    int rtphdrlen;

+    int sent;

+#if 0

+    static FILE *fhnd = NULL;

+#endif

+

+    PJ_UNUSED_ARG(timestamp)

+

+    /* Start locking channel mutex */

+    pj_mutex_lock (channel->mutex);

+

+    if (!channel->codec) {

+	status = -1;

+	goto on_return;

+    }

+

+    /* Encode. */

+    frame_in.type = PJ_MEDIA_TYPE_AUDIO;

+    frame_in.buf = (void*)frame;

+    frame_in.size = size;

+    frame_out.buf = ((char*)channel->out_pkt) + sizeof(pj_rtp_hdr);

+    status = channel->codec->op->encode (channel->codec, &frame_in, 

+					 channel->out_pkt_size - sizeof(pj_rtp_hdr), 

+					 &frame_out);

+    if (status != 0) {

+	PJ_LOG(3,(THISFILE, "Codec encode() has returned error status %d", 

+			     status));

+	goto on_return;

+    }

+

+    /* Encapsulate. */

+    ts_len = size / (channel->snd_info.bits_per_sample / 8);

+    status = pj_rtp_encode_rtp (&channel->rtp, channel->pt, 0, 

+				frame_out.size, ts_len, 

+				(const void**)&rtphdr, &rtphdrlen);

+    if (status != 0) {

+	PJ_LOG(3,(THISFILE, "RTP encode_rtp() has returned error status %d", 

+			    status));

+	goto on_return;

+    }

+

+    if (rtphdrlen != sizeof(pj_rtp_hdr)) {

+	/* We don't support RTP with extended header yet. */

+	PJ_TODO(SUPPORT_SENDING_RTP_WITH_EXTENDED_HEADER);

+	PJ_LOG(3,(THISFILE, "Unsupported extended RTP header for transmission"));

+	goto on_return;

+    }

+

+    pj_memcpy(channel->out_pkt, rtphdr, sizeof(pj_rtp_hdr));

+

+    /* Send. */

+    sent = pj_sock_sendto (channel->rtp_sock, channel->out_pkt, frame_out.size+sizeof(pj_rtp_hdr), 0, 

+			   &channel->dst_addr, sizeof(channel->dst_addr));

+    if (sent != (int)frame_out.size + (int)sizeof(pj_rtp_hdr))  {

+	pj_perror(THISFILE, "Error sending RTP packet to %s:%d", 

+		  pj_sockaddr_get_str_addr(&channel->dst_addr),

+		  pj_sockaddr_get_port(&channel->dst_addr));

+	goto on_return;

+    }

+

+    /* Update stat */

+    channel->stat.pkt_tx++;

+    channel->stat.oct_tx += frame_out.size+sizeof(pj_rtp_hdr);

+

+#if 0

+    if (fhnd == NULL) {

+	fhnd = fopen("RTP.DAT", "wb");

+	if (fhnd) {

+	    fwrite (channel->out_pkt, frame_out.size+sizeof(pj_rtp_hdr), 1, fhnd);

+	    fclose(fhnd);

+	}

+    }

+#endif

+

+on_return:

+    pj_mutex_unlock (channel->mutex);

+    return status;

+}

+

+

+static void* PJ_THREAD_FUNC stream_decoder_transport_thread (void*arg)

+{

+    pj_media_stream_t *channel = arg;

+

+    while (!channel->thread_quit_flag) {

+	int len, size;

+	const pj_rtp_hdr *hdr;

+	const void *payload;

+	unsigned payloadlen;

+	int status;

+	struct jb_frame *jb_frame;

+

+	/* Wait for packet. */

+	fd_set fds;

+	pj_time_val timeout;

+

+	PJ_FD_ZERO (&fds);

+	PJ_FD_SET (channel->rtp_sock, &fds);

+	timeout.sec = 0;

+	timeout.msec = 100;

+

+	/* Wait with timeout. */

+	status = pj_sock_select(channel->rtp_sock, &fds, NULL, NULL, &timeout);

+	if (status != 1)

+	    continue;

+

+	/* Get packet from socket. */

+	len = pj_sock_recv (channel->rtp_sock, channel->in_pkt, channel->in_pkt_size, 0);

+	if (len < 1) {

+	    if (pj_getlasterror() == PJ_ECONNRESET) {

+		/* On Win2K SP2 (or above) and WinXP, recv() will get WSAECONNRESET

+		   when the sending side receives ICMP port unreachable.

+		 */

+		continue;

+	    }

+	    pj_perror(THISFILE, "Error receiving packet from socket (len=%d)", len);

+	    pj_thread_sleep(1);

+	    continue;

+	}

+

+	if (channel->state != STREAM_STARTED)

+	    continue;

+

+	if (channel->thread_quit_flag)

+	    break;

+

+	/* Start locking the channel. */

+	pj_mutex_lock (channel->mutex);

+

+	/* Update RTP and RTCP session. */

+	status = pj_rtp_decode_rtp (&channel->rtp, channel->in_pkt, len, &hdr, &payload, &payloadlen);

+	if (status != 0) {

+	    pj_mutex_unlock (channel->mutex);

+	    PJ_LOG(4,(THISFILE, "RTP decode_rtp() has returned error status %d", status));

+	    continue;

+	}

+	status = pj_rtp_session_update (&channel->rtp, hdr);

+	if (status != 0 && status != PJ_RTP_ERR_SESSION_PROBATION && status != PJ_RTP_ERR_SESSION_RESTARTED) {

+	    pj_mutex_unlock (channel->mutex);

+	    PJ_LOG(4,(THISFILE, "RTP session_update() has returned error status %d", status));

+	    continue;

+	}

+	pj_rtcp_rx_rtp (channel->rtcp, pj_ntohs(hdr->seq), pj_ntohl(hdr->ts));

+

+	/* Update stat */

+	channel->stat.pkt_rx++;

+	channel->stat.oct_rx += len;

+

+	/* Copy to FIFO buffer. */

+	size = payloadlen+sizeof(struct jb_frame);

+	jb_frame = pj_fifobuf_alloc (&channel->fifobuf, size);

+	if (jb_frame == NULL) {

+	    pj_mutex_unlock (channel->mutex);

+	    PJ_LOG(4,(THISFILE, "Unable to allocate %d bytes FIFO buffer", size));

+	    continue;

+	}

+

+	/* Copy the payload */

+	jb_frame->size = payloadlen;

+	jb_frame->buf = ((char*)jb_frame) + sizeof(struct jb_frame);

+	pj_memcpy (jb_frame->buf, payload, payloadlen);

+

+	/* Put to jitter buffer. */

+	status = pj_jb_put (channel->jb, pj_ntohs(hdr->seq), jb_frame);

+	if (status != 0) {

+	    pj_fifobuf_unalloc (&channel->fifobuf, jb_frame);

+	    pj_mutex_unlock (channel->mutex);

+	    PJ_LOG(4,(THISFILE, "Jitter buffer put() has returned error status %d", status));

+	    continue;

+	}

+

+	pj_mutex_unlock (channel->mutex);

+    }

+

+    return NULL;

+}

+

+static void init_snd_param_from_codec_attr (pj_snd_stream_info *param,

+					    const pj_codec_attr *attr)

+{

+    param->bits_per_sample = attr->pcm_bits_per_sample;

+    param->bytes_per_frame = 2;

+    param->frames_per_packet = attr->sample_rate * attr->ptime / 1000;

+    param->samples_per_frame = 1;

+    param->samples_per_sec = attr->sample_rate;

+}

+

+static pj_media_stream_t *create_channel ( pj_pool_t *pool,

+					   pj_media_dir_t dir,

+					   pj_media_stream_t *peer,

+					   pj_codec_id *codec_id,

+					   pj_media_stream_create_param *param)

+{

+    pj_media_stream_t *channel;

+    pj_codec_attr codec_attr;

+    void *ptr;

+    unsigned size;

+    int status;

+    

+    /* Allocate memory for channel descriptor */

+    size = sizeof(pj_media_stream_t);

+    channel = pj_pool_calloc(pool, 1, size);

+    if (!channel) {

+	PJ_LOG(1,(THISFILE, "Unable to allocate %u bytes channel descriptor", 

+			 size));

+	return NULL;

+    }

+

+    channel->dir = dir;

+    channel->pt = codec_id->pt;

+    channel->peer = peer;

+    channel->codec_mgr = pj_med_mgr_get_codec_mgr (param->mediamgr);

+    channel->rtp_sock = param->rtp_sock;

+    channel->rtcp_sock = param->rtcp_sock;

+    channel->dst_addr = *param->remote_addr;

+    channel->state = STREAM_STOPPED;

+

+    /* Create mutex for the channel. */

+    channel->mutex = pj_mutex_create(pool, NULL, PJ_MUTEX_SIMPLE);

+    if (channel->mutex == NULL)

+	goto err_cleanup;

+

+    /* Create and initialize codec, only if peer is not present.

+       We only use one codec instance for both encoder and decoder.

+     */

+    if (peer && peer->codec) {

+	channel->codec = peer->codec;

+	status = channel->codec->factory->op->default_attr(channel->codec->factory, codec_id, 

+							   &codec_attr);

+	if (status != 0) {

+	    goto err_cleanup;

+	}

+

+    } else {

+	channel->codec = pj_codec_mgr_alloc_codec(channel->codec_mgr, codec_id);

+	if (channel->codec == NULL) {

+	    goto err_cleanup;

+	}

+

+	status = channel->codec->factory->op->default_attr(channel->codec->factory, codec_id, 

+							   &codec_attr);

+	if (status != 0) {

+	    goto err_cleanup;

+	}

+

+	codec_attr.pt = codec_id->pt;

+	status = channel->codec->op->open(channel->codec, &codec_attr);

+	if (status != 0) {

+	    goto err_cleanup;

+	}

+    }

+

+    /* Allocate buffer for incoming packet. */

+    channel->in_pkt_size = PJ_MAX_MTU;

+    channel->in_pkt = pj_pool_alloc(pool, channel->in_pkt_size);

+    if (!channel->in_pkt) {

+	PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes incoming packet buffer", 

+			  channel->in_pkt_size));

+	goto err_cleanup;

+    }

+

+    /* Allocate buffer for outgoing packet. */

+    channel->out_pkt_size = sizeof(pj_rtp_hdr) + 

+			    codec_attr.avg_bps / 8 * PJ_MAX_FRAME_DURATION_MS / 1000;

+    if (channel->out_pkt_size > PJ_MAX_MTU)

+	channel->out_pkt_size = PJ_MAX_MTU;

+    channel->out_pkt = pj_pool_alloc(pool, channel->out_pkt_size);

+    if (!channel->out_pkt) {

+	PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes encoding buffer", 

+			  channel->out_pkt_size));

+	goto err_cleanup;

+    }

+

+    /* Allocate buffer for decoding to PCM */

+    channel->pcm_buf_size = codec_attr.sample_rate * 

+			    codec_attr.pcm_bits_per_sample / 8 *

+			    PJ_MAX_FRAME_DURATION_MS / 1000;

+    channel->pcm_buf = pj_pool_alloc (pool, channel->pcm_buf_size);

+    if (!channel->pcm_buf) {

+	PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes PCM buffer", 

+			  channel->pcm_buf_size));

+	goto err_cleanup;

+    }

+

+    /* Allocate buffer for frames put in jitter buffer. */

+    size = codec_attr.avg_bps / 8 * PJ_MAX_BUFFER_SIZE_MS / 1000;

+    ptr = pj_pool_alloc(pool, size);

+    if (!ptr) {

+	PJ_LOG(1, (THISFILE, "Unable to allocate %u bytes jitter buffer", 

+			  channel->pcm_buf_size));

+	goto err_cleanup;

+    }

+    //pj_fifobuf_init (&channel->fifobuf, ptr, size);

+

+    /* Create and initialize sound device */

+    init_snd_param_from_codec_attr (&channel->snd_info, &codec_attr);

+

+    if (dir == PJ_MEDIA_DIR_ENCODING)

+	channel->snd_stream = pj_snd_open_recorder(-1, &channel->snd_info, 

+						   &rec_callback, channel);

+    else

+	channel->snd_stream = pj_snd_open_player(-1, &channel->snd_info, 

+						 &play_callback, channel);

+

+    if (!channel->snd_stream)

+	goto err_cleanup;

+

+    /* Create RTP and RTCP sessions. */

+    if (pj_rtp_session_init(&channel->rtp, codec_id->pt, param->ssrc) != 0) {

+	PJ_LOG(1, (THISFILE, "RTP session initialization error"));

+	goto err_cleanup;

+    }

+

+    /* For decoder, create RTCP session, jitter buffer, and transport thread. */

+    if (dir == PJ_MEDIA_DIR_DECODING) {

+	channel->rtcp = pj_pool_calloc(pool, 1, sizeof(pj_rtcp_session));

+	if (!channel->rtcp) {

+	    PJ_LOG(1, (THISFILE, "Unable to allocate RTCP session"));

+	    goto err_cleanup;

+	}

+

+	pj_rtcp_init(channel->rtcp, param->ssrc);

+

+	channel->jb = pj_pool_calloc(pool, 1, sizeof(pj_jitter_buffer));

+	if (!channel->jb) {

+	    PJ_LOG(1, (THISFILE, "Unable to allocate jitter buffer descriptor"));

+	    goto err_cleanup;

+	}

+	if (pj_jb_init(channel->jb, pool, param->jb_min, param->jb_max, param->jb_maxcnt)) {

+	    PJ_LOG(1, (THISFILE, "Unable to allocate jitter buffer"));

+	    goto err_cleanup;

+	}

+

+	channel->transport_thread = pj_thread_create(pool, "decode", 

+						     &stream_decoder_transport_thread, channel,

+						     0, NULL, 0);

+	if (!channel->transport_thread) {

+	    pj_perror(THISFILE, "Unable to create transport thread");

+	    goto err_cleanup;

+	}

+    }

+

+    /* Done. */

+    return channel;

+

+err_cleanup:

+    pj_media_stream_destroy(channel);

+    return NULL;

+}

+

+

+PJ_DEF(pj_status_t) pj_media_stream_create (pj_pool_t *pool,

+					    pj_media_stream_t **enc_stream,

+					    pj_media_stream_t **dec_stream,

+					    pj_media_stream_create_param *param)

+{

+    *dec_stream = *enc_stream = NULL;

+

+    if (param->dir & PJ_MEDIA_DIR_DECODING) {

+	*dec_stream = 

+	    create_channel(pool, PJ_MEDIA_DIR_DECODING, NULL, param->codec_id, param);

+	if (!*dec_stream)

+	    return -1;

+    }

+

+    if (param->dir & PJ_MEDIA_DIR_ENCODING) {

+	*enc_stream = 

+	    create_channel(pool, PJ_MEDIA_DIR_ENCODING, *dec_stream, param->codec_id, param);

+	if (!*enc_stream) {

+	    if (*dec_stream) {

+		pj_media_stream_destroy(*dec_stream);

+		*dec_stream = NULL;

+	    }

+	    return -1;

+	}

+

+	if (*dec_stream) {

+	    (*dec_stream)->peer = *enc_stream;

+	}

+    }

+

+    return 0;

+}

+

+PJ_DEF(pj_status_t) pj_media_stream_start (pj_media_stream_t *channel)

+{

+    pj_status_t status;

+

+    status = pj_snd_stream_start(channel->snd_stream);

+

+    if (status == 0)

+	channel->state = STREAM_STARTED;

+    return status;

+}

+

+PJ_DEF(pj_status_t)  pj_media_stream_get_stat (const pj_media_stream_t *stream,

+					       pj_media_stream_stat *stat)

+{

+    if (stream->dir == PJ_MEDIA_DIR_ENCODING) {

+	pj_memcpy (stat, &stream->stat, sizeof(*stat));

+    } else {

+	pj_rtcp_pkt *rtcp_pkt;

+	int len;

+

+	pj_memset (stat, 0, sizeof(*stat));

+	pj_assert (stream->rtcp != 0);

+	pj_rtcp_build_rtcp (stream->rtcp, &rtcp_pkt, &len);

+

+	stat->pkt_rx = stream->stat.pkt_rx;

+	stat->oct_rx = stream->stat.oct_rx;

+

+	PJ_TODO(SUPPORT_JITTER_CALCULATION_FOR_NON_8KHZ_SAMPLE_RATE)

+	stat->jitter = pj_ntohl(rtcp_pkt->rr.jitter) / 8;

+	stat->pkt_lost = (rtcp_pkt->rr.total_lost_2 << 16) +

+			 (rtcp_pkt->rr.total_lost_1 << 8) +

+			 rtcp_pkt->rr.total_lost_0;

+    }

+    return 0;

+}

+

+PJ_DEF(pj_status_t) pj_media_stream_pause (pj_media_stream_t *channel)

+{

+    PJ_UNUSED_ARG(channel)

+    return -1;

+}

+

+PJ_DEF(pj_status_t) pj_media_stream_resume (pj_media_stream_t *channel)

+{

+    PJ_UNUSED_ARG(channel)

+    return -1;

+}

+

+PJ_DEF(pj_status_t) pj_media_stream_destroy (pj_media_stream_t *channel)

+{

+    channel->thread_quit_flag = 1;

+

+    pj_mutex_lock (channel->mutex);

+    if (channel->peer)

+	pj_mutex_lock (channel->peer->mutex);

+

+    if (channel->jb) {

+	/* No need to deinitialize jitter buffer. */

+    }

+    if (channel->transport_thread) {

+	pj_thread_join(channel->transport_thread);

+	pj_thread_destroy(channel->transport_thread);

+	channel->transport_thread = NULL;

+    }

+    if (channel->snd_stream != NULL) {

+	pj_mutex_unlock (channel->mutex);

+	pj_snd_stream_stop(channel->snd_stream);

+	pj_mutex_lock (channel->mutex);

+	pj_snd_stream_close(channel->snd_stream);

+	channel->snd_stream = NULL;

+    }

+    if (channel->codec) {

+	channel->codec->op->close(channel->codec);

+	pj_codec_mgr_dealloc_codec(channel->codec_mgr, channel->codec);

+	channel->codec = NULL;

+    }

+    if (channel->peer) {

+	pj_media_stream_t *peer = channel->peer;

+	peer->peer = NULL;

+	peer->codec = NULL;

+	peer->thread_quit_flag = 1;

+	if (peer->transport_thread) {

+	    pj_mutex_unlock (peer->mutex);

+	    pj_thread_join(peer->transport_thread);

+	    pj_mutex_lock (peer->mutex);

+	    pj_thread_destroy(peer->transport_thread);

+	    peer->transport_thread = NULL;

+	}

+	if (peer->snd_stream) {

+	    pj_mutex_unlock (peer->mutex);

+	    pj_snd_stream_stop(peer->snd_stream);

+	    pj_mutex_lock (peer->mutex);

+	    pj_snd_stream_close(peer->snd_stream);

+	    peer->snd_stream = NULL;

+	}

+    }

+

+    channel->state = STREAM_STOPPED;

+

+    if (channel->peer)

+	pj_mutex_unlock (channel->peer->mutex);

+    pj_mutex_unlock(channel->mutex);

+    pj_mutex_destroy(channel->mutex);

+

+    return 0;

+}

+

diff --git a/pjmedia/src/pjmedia/stream.h b/pjmedia/src/pjmedia/stream.h
index d9f38a0..a9d43a2 100644
--- a/pjmedia/src/pjmedia/stream.h
+++ b/pjmedia/src/pjmedia/stream.h
@@ -1,85 +1,106 @@
-/* $Id$
- *
- */
-
-#ifndef __PJMEDIA_STREAM_H__
-#define __PJMEDIA_STREAM_H__
-
-
-/**
- * @file stream.h
- * @brief Stream of media.
- */
-
-#include <pjmedia/sound.h>
-#include <pjmedia/codec.h>
-#include <pjmedia/mediamgr.h>
-#include <pj/sock.h>
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJMED_SES Media session
- * @ingroup PJMEDIA
- * @{
- */
-
-typedef struct pj_media_stream_t pj_media_stream_t;
-
-/** Parameter for creating channel. */
-typedef struct pj_media_stream_create_param
-{
-    /** Codec ID, must NOT be NULL. */
-    pj_codec_id		 *codec_id;
-
-    /** Media manager, must NOT be NULL. */
-    pj_med_mgr_t	 *mediamgr;
-
-    /** Direction: IN_OUT, or IN only, or OUT only. */
-    pj_media_dir_t	  dir;
-
-    /** RTP socket. */
-    pj_sock_t		 rtp_sock;
-
-    /** RTCP socket. */
-    pj_sock_t		 rtcp_sock;
-
-    /** Address of remote */
-    pj_sockaddr_in	 *remote_addr;
-
-    /** RTP SSRC */
-    pj_uint32_t		  ssrc;
-
-    /** Jitter buffer parameters. */
-    int			  jb_min, jb_max, jb_maxcnt;
-
-} pj_media_stream_create_param;
-
-typedef struct pj_media_stream_stat
-{
-    pj_uint32_t pkt_tx, pkt_rx;	/* packets transmitted/received */
-    pj_uint32_t oct_tx, oct_rx;	/* octets transmitted/received */
-    pj_uint32_t jitter;		/* receive jitter in ms */
-    pj_uint32_t pkt_lost;	/* total packet lost count */
-} pj_media_stream_stat;
-
-PJ_DECL(pj_status_t) pj_media_stream_create (pj_pool_t *pool,
-					     pj_media_stream_t **enc_stream,
-					     pj_media_stream_t **dec_stream,
-					     pj_media_stream_create_param *param);
-PJ_DECL(pj_status_t) pj_media_stream_start (pj_media_stream_t *stream);
-PJ_DECL(pj_status_t) pj_media_stream_get_stat (const pj_media_stream_t *stream,
-					       pj_media_stream_stat *stat);
-PJ_DECL(pj_status_t) pj_media_stream_pause (pj_media_stream_t *stream);
-PJ_DECL(pj_status_t) pj_media_stream_resume (pj_media_stream_t *stream);
-PJ_DECL(pj_status_t) pj_media_stream_destroy (pj_media_stream_t *stream);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-
-#endif	/* __PJMEDIA_STREAM_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+

+#ifndef __PJMEDIA_STREAM_H__

+#define __PJMEDIA_STREAM_H__

+

+

+/**

+ * @file stream.h

+ * @brief Stream of media.

+ */

+

+#include <pjmedia/sound.h>

+#include <pjmedia/codec.h>

+#include <pjmedia/mediamgr.h>

+#include <pj/sock.h>

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJMED_SES Media session

+ * @ingroup PJMEDIA

+ * @{

+ */

+

+typedef struct pj_media_stream_t pj_media_stream_t;

+

+/** Parameter for creating channel. */

+typedef struct pj_media_stream_create_param

+{

+    /** Codec ID, must NOT be NULL. */

+    pj_codec_id		 *codec_id;

+

+    /** Media manager, must NOT be NULL. */

+    pj_med_mgr_t	 *mediamgr;

+

+    /** Direction: IN_OUT, or IN only, or OUT only. */

+    pj_media_dir_t	  dir;

+

+    /** RTP socket. */

+    pj_sock_t		 rtp_sock;

+

+    /** RTCP socket. */

+    pj_sock_t		 rtcp_sock;

+

+    /** Address of remote */

+    pj_sockaddr_in	 *remote_addr;

+

+    /** RTP SSRC */

+    pj_uint32_t		  ssrc;

+

+    /** Jitter buffer parameters. */

+    int			  jb_min, jb_max, jb_maxcnt;

+

+} pj_media_stream_create_param;

+

+typedef struct pj_media_stream_stat

+{

+    pj_uint32_t pkt_tx, pkt_rx;	/* packets transmitted/received */

+    pj_uint32_t oct_tx, oct_rx;	/* octets transmitted/received */

+    pj_uint32_t jitter;		/* receive jitter in ms */

+    pj_uint32_t pkt_lost;	/* total packet lost count */

+} pj_media_stream_stat;

+

+PJ_DECL(pj_status_t) pj_media_stream_create (pj_pool_t *pool,

+					     pj_media_stream_t **enc_stream,

+					     pj_media_stream_t **dec_stream,

+					     pj_media_stream_create_param *param);

+PJ_DECL(pj_status_t) pj_media_stream_start (pj_media_stream_t *stream);

+PJ_DECL(pj_status_t) pj_media_stream_get_stat (const pj_media_stream_t *stream,

+					       pj_media_stream_stat *stat);

+PJ_DECL(pj_status_t) pj_media_stream_pause (pj_media_stream_t *stream);

+PJ_DECL(pj_status_t) pj_media_stream_resume (pj_media_stream_t *stream);

+PJ_DECL(pj_status_t) pj_media_stream_destroy (pj_media_stream_t *stream);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+

+#endif	/* __PJMEDIA_STREAM_H__ */

diff --git a/pjmedia/src/test/audio_tool.c b/pjmedia/src/test/audio_tool.c
index 8282258..5e046b8 100644
--- a/pjmedia/src/test/audio_tool.c
+++ b/pjmedia/src/test/audio_tool.c
@@ -1,394 +1,415 @@
-/* $Id$
- *
- */
-#include <pjmedia.h>
-#include <pjlib.h>
-#include <stdio.h>
-
-#define THIS_FILE	"audio_tool.c"
-
-static pj_caching_pool caching_pool;
-static pj_pool_factory *pf;
-static FILE *fhnd;
-static pj_med_mgr_t *mm;
-static pj_codec *codec;
-static pj_codec_attr cattr;
-
-
-#define WRITE_ORIGINAL_PCM 0
-#if WRITE_ORIGINAL_PCM
-static FILE *fhnd_pcm;
-#endif
-
-static char talker_sdp[] = 
-    "v=0\r\n"
-    "o=- 0 0 IN IP4 127.0.0.1\r\n"
-    "s=-\r\n"
-    "c=IN IP4 127.0.0.1\r\n"
-    "t=0 0\r\n"
-    "m=audio 4002 RTP/AVP 0\r\n"
-    "a=rtpmap:0 PCMU/8000\r\n"
-    "a=sendonly\r\n";
-static char listener_sdp[] = 
-    "v=0\r\n"
-    "o=- 0 0 IN IP4 127.0.0.1\r\n"
-    "s=-\r\n"
-    "c=IN IP4 127.0.0.1\r\n"
-    "t=0 0\r\n"
-    "m=audio 4000 RTP/AVP 0\r\n"
-    "a=rtpmap:0 PCMU/8000\r\n"
-    "a=recvonly\r\n";
-
-static pj_status_t play_callback(/* in */   void *user_data,
-				 /* in */   pj_uint32_t timestamp,
-				 /* out */  void *frame,
-				 /* out */  unsigned size)
-{
-    char pkt[160];
-    struct pj_audio_frame in, out;
-    int frmsz = cattr.avg_bps / 8 * cattr.ptime / 1000;
-
-    if (fread(pkt, frmsz, 1, fhnd) != 1) {
-	puts("EOF");
-	return -1;
-    } else {
-	in.type = PJ_AUDIO_FRAME_AUDIO;
-	in.buf = pkt;
-	in.size = frmsz;
-	out.buf = frame;
-	if (codec->op->decode (codec, &in, size, &out) != 0)
-	    return -1;
-
-	size = out.size;
-	return 0;
-    }
-}
-
-static pj_status_t rec_callback( /* in */   void *user_data,
-			         /* in */   pj_uint32_t timestamp,
-			         /* in */   const void *frame,
-			         /* in*/    unsigned size)
-{
-    char pkt[160];
-    struct pj_audio_frame in, out;
-    //int frmsz = cattr.avg_bps / 8 * cattr.ptime / 1000;
-
-#if WRITE_ORIGINAL_PCM
-    fwrite(frame, size, 1, fhnd_pcm);
-#endif
-
-    in.type = PJ_AUDIO_FRAME_AUDIO;
-    in.buf = (void*)frame;
-    in.size = size;
-    out.buf = pkt;
-
-    if (codec->op->encode(codec, &in, sizeof(pkt), &out) != 0)
-	return -1;
-
-    if (fwrite(pkt, out.size, 1, fhnd) != 1)
-	return -1;
-    return 0;
-}
-
-static pj_status_t init()
-{
-    pj_codec_mgr *cm;
-    pj_codec_id id;
-    int i;
-
-    pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, 0);
-    pf = &caching_pool.factory;
-
-    if (pj_snd_init(&caching_pool.factory))
-	return -1;
-
-    PJ_LOG(3,(THIS_FILE, "Dumping audio devices:"));
-    for (i=0; i<pj_snd_get_dev_count(); ++i) {
-	const pj_snd_dev_info *info;
-	info = pj_snd_get_dev_info(i);
-	PJ_LOG(3,(THIS_FILE, "  %d: %s\t(%d in, %d out", 
-			     i, info->name, 
-			     info->input_count, info->output_count));
-    }
-
-    mm = pj_med_mgr_create (&caching_pool.factory);
-    cm = pj_med_mgr_get_codec_mgr (mm);
-
-    id.type = PJ_MEDIA_TYPE_AUDIO;
-    id.pt = 0;
-    id.encoding_name = pj_str("PCMU");
-    id.sample_rate = 8000;
-
-    codec = pj_codec_mgr_alloc_codec (cm, &id);
-    codec->op->default_attr(codec, &cattr);
-    codec->op->open(codec, &cattr);
-    return 0;
-}
-
-static pj_status_t deinit()
-{
-    pj_codec_mgr *cm;
-    cm = pj_med_mgr_get_codec_mgr (mm);
-    codec->op->close(codec);
-    pj_codec_mgr_dealloc_codec (cm, codec);
-    pj_med_mgr_destroy (mm);
-    pj_caching_pool_destroy(&caching_pool);
-    return 0;
-}
-
-static pj_status_t record_file (const char *filename)
-{
-    pj_snd_stream *stream;
-    pj_snd_stream_info info;
-    int status;
-    char s[10];
-
-    printf("Recording to file %s...\n", filename);
-
-    fhnd = fopen(filename, "wb");
-    if (!fhnd)
-	return -1;
-
-#if WRITE_ORIGINAL_PCM
-    fhnd_pcm = fopen("ORIGINAL.PCM", "wb");
-    if (!fhnd_pcm)
-	return -1;
-#endif
-
-    pj_memset(&info, 0, sizeof(info));
-    info.bits_per_sample = 16;
-    info.bytes_per_frame = 2;
-    info.frames_per_packet = 160;
-    info.samples_per_frame = 1;
-    info.samples_per_sec = 8000;
-
-    stream = pj_snd_open_recorder(-1, &info, &rec_callback, NULL);
-    if (!stream)
-	return -1;
-
-    status = pj_snd_stream_start(stream);
-    if (status != 0)
-	goto on_error;
-
-    puts("Press <ENTER> to exit recording");
-    fgets(s, sizeof(s), stdin);
-
-    pj_snd_stream_stop(stream);
-    pj_snd_stream_close(stream);
-
-#if WRITE_ORIGINAL_PCM
-    fclose(fhnd_pcm);
-#endif
-    fclose(fhnd);
-    return 0;
-
-on_error:
-    pj_snd_stream_stop(stream);
-    pj_snd_stream_close(stream);
-    return -1;
-}
-
-
-static pj_status_t play_file (const char *filename)
-{
-    pj_snd_stream *stream;
-    pj_snd_stream_info info;
-    int status;
-    char s[10];
-
-    printf("Playing file %s...\n", filename);
-
-    fhnd = fopen(filename, "rb");
-    if (!fhnd)
-	return -1;
-
-    pj_memset(&info, 0, sizeof(info));
-    info.bits_per_sample = 16;
-    info.bytes_per_frame = 2;
-    info.frames_per_packet = 160;
-    info.samples_per_frame = 1;
-    info.samples_per_sec = 8000;
-
-    stream = pj_snd_open_player(-1, &info, &play_callback, NULL);
-    if (!stream)
-	return -1;
-
-    status = pj_snd_stream_start(stream);
-    if (status != 0)
-	goto on_error;
-
-    puts("Press <ENTER> to exit playing");
-    fgets(s, sizeof(s), stdin);
-
-    pj_snd_stream_stop(stream);
-    pj_snd_stream_close(stream);
-
-    fclose(fhnd);
-    return 0;
-
-on_error:
-    pj_snd_stream_stop(stream);
-    pj_snd_stream_close(stream);
-    return -1;
-}
-
-static int create_ses_by_remote_sdp(int local_port, char *sdp)
-{
-    pj_media_session_t *ses = NULL;
-    pjsdp_session_desc *sdp_ses;
-    pj_media_sock_info skinfo;
-    pj_pool_t *pool;
-    char s[4];
-    const pj_media_stream_info *info[2];
-    int i, count;
-
-    pool = pj_pool_create(pf, "sdp", 1024, 0, NULL);
-    if (!pool) {
-	PJ_LOG(1,(THIS_FILE, "Unable to create pool"));
-	return -1;
-    }
-
-    pj_memset(&skinfo, 0, sizeof(skinfo));
-    skinfo.rtp_sock = skinfo.rtcp_sock = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, 0);
-    if (skinfo.rtp_sock == PJ_INVALID_SOCKET) {
-	PJ_LOG(1,(THIS_FILE, "Unable to create socket"));
-	goto on_error;
-    }
-
-    pj_sockaddr_init2(&skinfo.rtp_addr_name, "0.0.0.0", local_port);
-    if (pj_sock_bind(skinfo.rtp_sock, (struct pj_sockaddr*)&skinfo.rtp_addr_name, sizeof(pj_sockaddr_in)) != 0) {
-	PJ_LOG(1,(THIS_FILE, "Unable to bind socket"));
-	goto on_error;
-    }
-
-    sdp_ses = pjsdp_parse(sdp, strlen(sdp), pool);
-    if (!sdp_ses) {
-	PJ_LOG(1,(THIS_FILE, "Error parsing SDP"));
-	goto on_error;
-    }
-
-    ses = pj_media_session_create_from_sdp(mm, sdp_ses, &skinfo);
-    if (!ses) {
-	PJ_LOG(1,(THIS_FILE, "Unable to create session from SDP"));
-	goto on_error;
-    }
-
-    if (pj_media_session_activate(ses) != 0) {
-	PJ_LOG(1,(THIS_FILE, "Error activating session"));
-	goto on_error;
-    }
-
-    count = pj_media_session_enum_streams(ses, 2, info);
-    printf("\nDumping streams: \n");
-    for (i=0; i<count; ++i) {
-	const char *dir;
-	char *local_ip;
-
-	switch (info[i]->dir) {
-	case PJ_MEDIA_DIR_NONE:
-	    dir = "- NONE -"; break;
-	case PJ_MEDIA_DIR_ENCODING:
-	    dir = "SENDONLY"; break;
-	case PJ_MEDIA_DIR_DECODING:
-	    dir = "RECVONLY"; break;
-	case PJ_MEDIA_DIR_ENCODING_DECODING:
-	    dir = "SENDRECV"; break;
-	default:
-	    dir = "?UNKNOWN"; break;
-	}
-
-	local_ip = pj_sockaddr_get_str_addr(&info[i]->sock_info.rtp_addr_name);
-
-	printf("  Stream %d: %.*s %s local=%s:%d remote=%.*s:%d\n",
-	       i, info[i]->type.slen, info[i]->type.ptr,
-	       dir, 
-	       local_ip, pj_sockaddr_get_port(&info[i]->sock_info.rtp_addr_name),
-	       info[i]->rem_addr.slen, info[i]->rem_addr.ptr, info[i]->rem_port);
-    }
-
-    puts("Press <ENTER> to quit");
-    fgets(s, sizeof(s), stdin);
-
-    pj_media_session_destroy(ses);
-    pj_sock_close(skinfo.rtp_sock);
-    pj_pool_release(pool);
-
-    return 0;
-
-on_error:
-    if (ses)
-	pj_media_session_destroy(ses);
-    if (skinfo.rtp_sock != PJ_INVALID_SOCKET)
-	pj_sock_close(skinfo.rtp_sock);
-    if (pool)
-	pj_pool_release(pool);
-    return -1;
-}
-
-#if WRITE_ORIGINAL_PCM
-static pj_status_t convert(const char *src, const char *dst)
-{
-    char pcm[320];
-    char frame[160];
-    struct pj_audio_frame in, out;
-
-    fhnd_pcm = fopen(src, "rb");
-    if (!fhnd_pcm)
-	return -1;
-    fhnd = fopen(dst, "wb");
-    if (!fhnd)
-	return -1;
-
-    while (fread(pcm, 320, 1, fhnd_pcm) == 1) {
-
-	in.type = PJ_AUDIO_FRAME_AUDIO;
-	in.buf = pcm;
-	in.size = 320;
-	out.buf = frame;
-
-	if (codec->op->encode(codec, &in, 160, &out) != 0)
-	    break;
-
-	if (fwrite(frame, out.size, 1, fhnd) != 1)
-	    break;
-
-    }
-
-    fclose(fhnd);
-    fclose(fhnd_pcm);
-    return 0;
-}
-#endif
-
-static void usage(const char *exe)
-{
-    printf("Usage: %s <command> <file>\n", exe);
-    puts("where:");
-    puts("  <command>     play|record|send|recv");
-}
-
-int main(int argc, char *argv[])
-{
-    if (argc < 2) {
-	usage(argv[0]);
-	return 1;
-    }
-
-    pj_init();
-
-    init();
-
-    if (stricmp(argv[1], "record")==0) {
-	record_file("FILE.PCM");
-    } else if (stricmp(argv[1], "play")==0) {
-	play_file("FILE.PCM");
-    } else if (stricmp(argv[1], "send")==0) {
-	create_ses_by_remote_sdp(4002, listener_sdp);
-    } else if (stricmp(argv[1], "recv")==0) {
-	create_ses_by_remote_sdp(4000, talker_sdp);
-    } else {
-	usage(argv[0]);
-    }
-    deinit();
-    return 0;
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjmedia.h>

+#include <pjlib.h>

+#include <stdio.h>

+

+#define THIS_FILE	"audio_tool.c"

+

+static pj_caching_pool caching_pool;

+static pj_pool_factory *pf;

+static FILE *fhnd;

+static pj_med_mgr_t *mm;

+static pj_codec *codec;

+static pj_codec_attr cattr;

+

+

+#define WRITE_ORIGINAL_PCM 0

+#if WRITE_ORIGINAL_PCM

+static FILE *fhnd_pcm;

+#endif

+

+static char talker_sdp[] = 

+    "v=0\r\n"

+    "o=- 0 0 IN IP4 127.0.0.1\r\n"

+    "s=-\r\n"

+    "c=IN IP4 127.0.0.1\r\n"

+    "t=0 0\r\n"

+    "m=audio 4002 RTP/AVP 0\r\n"

+    "a=rtpmap:0 PCMU/8000\r\n"

+    "a=sendonly\r\n";

+static char listener_sdp[] = 

+    "v=0\r\n"

+    "o=- 0 0 IN IP4 127.0.0.1\r\n"

+    "s=-\r\n"

+    "c=IN IP4 127.0.0.1\r\n"

+    "t=0 0\r\n"

+    "m=audio 4000 RTP/AVP 0\r\n"

+    "a=rtpmap:0 PCMU/8000\r\n"

+    "a=recvonly\r\n";

+

+static pj_status_t play_callback(/* in */   void *user_data,

+				 /* in */   pj_uint32_t timestamp,

+				 /* out */  void *frame,

+				 /* out */  unsigned size)

+{

+    char pkt[160];

+    struct pj_audio_frame in, out;

+    int frmsz = cattr.avg_bps / 8 * cattr.ptime / 1000;

+

+    if (fread(pkt, frmsz, 1, fhnd) != 1) {

+	puts("EOF");

+	return -1;

+    } else {

+	in.type = PJ_AUDIO_FRAME_AUDIO;

+	in.buf = pkt;

+	in.size = frmsz;

+	out.buf = frame;

+	if (codec->op->decode (codec, &in, size, &out) != 0)

+	    return -1;

+

+	size = out.size;

+	return 0;

+    }

+}

+

+static pj_status_t rec_callback( /* in */   void *user_data,

+			         /* in */   pj_uint32_t timestamp,

+			         /* in */   const void *frame,

+			         /* in*/    unsigned size)

+{

+    char pkt[160];

+    struct pj_audio_frame in, out;

+    //int frmsz = cattr.avg_bps / 8 * cattr.ptime / 1000;

+

+#if WRITE_ORIGINAL_PCM

+    fwrite(frame, size, 1, fhnd_pcm);

+#endif

+

+    in.type = PJ_AUDIO_FRAME_AUDIO;

+    in.buf = (void*)frame;

+    in.size = size;

+    out.buf = pkt;

+

+    if (codec->op->encode(codec, &in, sizeof(pkt), &out) != 0)

+	return -1;

+

+    if (fwrite(pkt, out.size, 1, fhnd) != 1)

+	return -1;

+    return 0;

+}

+

+static pj_status_t init()

+{

+    pj_codec_mgr *cm;

+    pj_codec_id id;

+    int i;

+

+    pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, 0);

+    pf = &caching_pool.factory;

+

+    if (pj_snd_init(&caching_pool.factory))

+	return -1;

+

+    PJ_LOG(3,(THIS_FILE, "Dumping audio devices:"));

+    for (i=0; i<pj_snd_get_dev_count(); ++i) {

+	const pj_snd_dev_info *info;

+	info = pj_snd_get_dev_info(i);

+	PJ_LOG(3,(THIS_FILE, "  %d: %s\t(%d in, %d out", 

+			     i, info->name, 

+			     info->input_count, info->output_count));

+    }

+

+    mm = pj_med_mgr_create (&caching_pool.factory);

+    cm = pj_med_mgr_get_codec_mgr (mm);

+

+    id.type = PJ_MEDIA_TYPE_AUDIO;

+    id.pt = 0;

+    id.encoding_name = pj_str("PCMU");

+    id.sample_rate = 8000;

+

+    codec = pj_codec_mgr_alloc_codec (cm, &id);

+    codec->op->default_attr(codec, &cattr);

+    codec->op->open(codec, &cattr);

+    return 0;

+}

+

+static pj_status_t deinit()

+{

+    pj_codec_mgr *cm;

+    cm = pj_med_mgr_get_codec_mgr (mm);

+    codec->op->close(codec);

+    pj_codec_mgr_dealloc_codec (cm, codec);

+    pj_med_mgr_destroy (mm);

+    pj_caching_pool_destroy(&caching_pool);

+    return 0;

+}

+

+static pj_status_t record_file (const char *filename)

+{

+    pj_snd_stream *stream;

+    pj_snd_stream_info info;

+    int status;

+    char s[10];

+

+    printf("Recording to file %s...\n", filename);

+

+    fhnd = fopen(filename, "wb");

+    if (!fhnd)

+	return -1;

+

+#if WRITE_ORIGINAL_PCM

+    fhnd_pcm = fopen("ORIGINAL.PCM", "wb");

+    if (!fhnd_pcm)

+	return -1;

+#endif

+

+    pj_memset(&info, 0, sizeof(info));

+    info.bits_per_sample = 16;

+    info.bytes_per_frame = 2;

+    info.frames_per_packet = 160;

+    info.samples_per_frame = 1;

+    info.samples_per_sec = 8000;

+

+    stream = pj_snd_open_recorder(-1, &info, &rec_callback, NULL);

+    if (!stream)

+	return -1;

+

+    status = pj_snd_stream_start(stream);

+    if (status != 0)

+	goto on_error;

+

+    puts("Press <ENTER> to exit recording");

+    fgets(s, sizeof(s), stdin);

+

+    pj_snd_stream_stop(stream);

+    pj_snd_stream_close(stream);

+

+#if WRITE_ORIGINAL_PCM

+    fclose(fhnd_pcm);

+#endif

+    fclose(fhnd);

+    return 0;

+

+on_error:

+    pj_snd_stream_stop(stream);

+    pj_snd_stream_close(stream);

+    return -1;

+}

+

+

+static pj_status_t play_file (const char *filename)

+{

+    pj_snd_stream *stream;

+    pj_snd_stream_info info;

+    int status;

+    char s[10];

+

+    printf("Playing file %s...\n", filename);

+

+    fhnd = fopen(filename, "rb");

+    if (!fhnd)

+	return -1;

+

+    pj_memset(&info, 0, sizeof(info));

+    info.bits_per_sample = 16;

+    info.bytes_per_frame = 2;

+    info.frames_per_packet = 160;

+    info.samples_per_frame = 1;

+    info.samples_per_sec = 8000;

+

+    stream = pj_snd_open_player(-1, &info, &play_callback, NULL);

+    if (!stream)

+	return -1;

+

+    status = pj_snd_stream_start(stream);

+    if (status != 0)

+	goto on_error;

+

+    puts("Press <ENTER> to exit playing");

+    fgets(s, sizeof(s), stdin);

+

+    pj_snd_stream_stop(stream);

+    pj_snd_stream_close(stream);

+

+    fclose(fhnd);

+    return 0;

+

+on_error:

+    pj_snd_stream_stop(stream);

+    pj_snd_stream_close(stream);

+    return -1;

+}

+

+static int create_ses_by_remote_sdp(int local_port, char *sdp)

+{

+    pj_media_session_t *ses = NULL;

+    pjsdp_session_desc *sdp_ses;

+    pj_media_sock_info skinfo;

+    pj_pool_t *pool;

+    char s[4];

+    const pj_media_stream_info *info[2];

+    int i, count;

+

+    pool = pj_pool_create(pf, "sdp", 1024, 0, NULL);

+    if (!pool) {

+	PJ_LOG(1,(THIS_FILE, "Unable to create pool"));

+	return -1;

+    }

+

+    pj_memset(&skinfo, 0, sizeof(skinfo));

+    skinfo.rtp_sock = skinfo.rtcp_sock = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, 0);

+    if (skinfo.rtp_sock == PJ_INVALID_SOCKET) {

+	PJ_LOG(1,(THIS_FILE, "Unable to create socket"));

+	goto on_error;

+    }

+

+    pj_sockaddr_init2(&skinfo.rtp_addr_name, "0.0.0.0", local_port);

+    if (pj_sock_bind(skinfo.rtp_sock, (struct pj_sockaddr*)&skinfo.rtp_addr_name, sizeof(pj_sockaddr_in)) != 0) {

+	PJ_LOG(1,(THIS_FILE, "Unable to bind socket"));

+	goto on_error;

+    }

+

+    sdp_ses = pjsdp_parse(sdp, strlen(sdp), pool);

+    if (!sdp_ses) {

+	PJ_LOG(1,(THIS_FILE, "Error parsing SDP"));

+	goto on_error;

+    }

+

+    ses = pj_media_session_create_from_sdp(mm, sdp_ses, &skinfo);

+    if (!ses) {

+	PJ_LOG(1,(THIS_FILE, "Unable to create session from SDP"));

+	goto on_error;

+    }

+

+    if (pj_media_session_activate(ses) != 0) {

+	PJ_LOG(1,(THIS_FILE, "Error activating session"));

+	goto on_error;

+    }

+

+    count = pj_media_session_enum_streams(ses, 2, info);

+    printf("\nDumping streams: \n");

+    for (i=0; i<count; ++i) {

+	const char *dir;

+	char *local_ip;

+

+	switch (info[i]->dir) {

+	case PJ_MEDIA_DIR_NONE:

+	    dir = "- NONE -"; break;

+	case PJ_MEDIA_DIR_ENCODING:

+	    dir = "SENDONLY"; break;

+	case PJ_MEDIA_DIR_DECODING:

+	    dir = "RECVONLY"; break;

+	case PJ_MEDIA_DIR_ENCODING_DECODING:

+	    dir = "SENDRECV"; break;

+	default:

+	    dir = "?UNKNOWN"; break;

+	}

+

+	local_ip = pj_sockaddr_get_str_addr(&info[i]->sock_info.rtp_addr_name);

+

+	printf("  Stream %d: %.*s %s local=%s:%d remote=%.*s:%d\n",

+	       i, info[i]->type.slen, info[i]->type.ptr,

+	       dir, 

+	       local_ip, pj_sockaddr_get_port(&info[i]->sock_info.rtp_addr_name),

+	       info[i]->rem_addr.slen, info[i]->rem_addr.ptr, info[i]->rem_port);

+    }

+

+    puts("Press <ENTER> to quit");

+    fgets(s, sizeof(s), stdin);

+

+    pj_media_session_destroy(ses);

+    pj_sock_close(skinfo.rtp_sock);

+    pj_pool_release(pool);

+

+    return 0;

+

+on_error:

+    if (ses)

+	pj_media_session_destroy(ses);

+    if (skinfo.rtp_sock != PJ_INVALID_SOCKET)

+	pj_sock_close(skinfo.rtp_sock);

+    if (pool)

+	pj_pool_release(pool);

+    return -1;

+}

+

+#if WRITE_ORIGINAL_PCM

+static pj_status_t convert(const char *src, const char *dst)

+{

+    char pcm[320];

+    char frame[160];

+    struct pj_audio_frame in, out;

+

+    fhnd_pcm = fopen(src, "rb");

+    if (!fhnd_pcm)

+	return -1;

+    fhnd = fopen(dst, "wb");

+    if (!fhnd)

+	return -1;

+

+    while (fread(pcm, 320, 1, fhnd_pcm) == 1) {

+

+	in.type = PJ_AUDIO_FRAME_AUDIO;

+	in.buf = pcm;

+	in.size = 320;

+	out.buf = frame;

+

+	if (codec->op->encode(codec, &in, 160, &out) != 0)

+	    break;

+

+	if (fwrite(frame, out.size, 1, fhnd) != 1)

+	    break;

+

+    }

+

+    fclose(fhnd);

+    fclose(fhnd_pcm);

+    return 0;

+}

+#endif

+

+static void usage(const char *exe)

+{

+    printf("Usage: %s <command> <file>\n", exe);

+    puts("where:");

+    puts("  <command>     play|record|send|recv");

+}

+

+int main(int argc, char *argv[])

+{

+    if (argc < 2) {

+	usage(argv[0]);

+	return 1;

+    }

+

+    pj_init();

+

+    init();

+

+    if (stricmp(argv[1], "record")==0) {

+	record_file("FILE.PCM");

+    } else if (stricmp(argv[1], "play")==0) {

+	play_file("FILE.PCM");

+    } else if (stricmp(argv[1], "send")==0) {

+	create_ses_by_remote_sdp(4002, listener_sdp);

+    } else if (stricmp(argv[1], "recv")==0) {

+	create_ses_by_remote_sdp(4000, talker_sdp);

+    } else {

+	usage(argv[0]);

+    }

+    deinit();

+    return 0;

+}

diff --git a/pjmedia/src/test/jbuf_test.c b/pjmedia/src/test/jbuf_test.c
index d2ca95a..e5c5eea 100644
--- a/pjmedia/src/test/jbuf_test.c
+++ b/pjmedia/src/test/jbuf_test.c
@@ -1,139 +1,160 @@
-/* $Id$
- *
- */
-#include <stdio.h>
-#include <ctype.h>
-#include <pjmedia/jbuf.h>
-#include <pj/pool.h>
-
-#define JB_MIN	    1
-#define JB_MAX	    8
-#define JB_BUF_SIZE 10
-
-#define REPORT
-//#define PRINT_COMMENT
-
-int jbuf_main(pj_pool_factory *pf)
-{
-    pj_jitter_buffer jb;
-    FILE *input = fopen("JBTEST.DAT", "rt");
-    unsigned lastseq;
-    void *data = "Hello world";
-    char line[1024], *p;
-    int lastget = 0, lastput = 0;
-    pj_pool_t *pool;
-
-    pj_init();
-    pool = pj_pool_create(pf, "JBPOOL", 256*16, 256*16, NULL);
-
-    pj_jb_init(&jb, pool, JB_MIN, JB_MAX, JB_BUF_SIZE);
-
-    lastseq = 1;
-
-    while ((p=fgets(line, sizeof(line), input)) != NULL) {
-
-	while (*p && isspace(*p))
-	    ++p;
-
-	if (!*p)
-	    continue;
-
-	if (*p == '#') {
-#ifdef PRINT_COMMENT
-	    printf("\n%s", p);
-#endif
-	    continue;
-	}
-
-	pj_jb_reset(&jb);
-#ifdef REPORT
-	printf( "Initial\t%c   size=%d  prefetch=%d level=%d\n", 
-	        ' ', jb.lst.count, jb.prefetch, jb.level);
-#endif
-
-	while (*p) {
-	    int c;
-	    unsigned seq = 0;
-	    void *thedata;
-	    int status = 1234;
-	    
-	    c = *p++;
-	    if (isspace(c))
-		continue;
-	    
-	    if (c == '/') {
-		char *end;
-
-		printf("/*");
-
-		do {
-		    putchar(*++p);
-		} while (*p != '/');
-
-		putchar('\n');
-
-		c = *++p;
-		end = p;
-
-	    }
-
-	    if (isspace(c))
-		continue;
-
-	    if (isdigit(c)) {
-		seq = c - '0';
-		while (*p) {
-		    c = *p++;
-		    
-		    if (isspace(c))
-			continue;
-		    
-		    if (!isdigit(c))
-			break;
-		    
-		    seq = seq * 10 + c - '0';
-		}
-	    }
-
-	    if (!*p)
-		break;
-
-	    switch (toupper(c)) {
-	    case 'G':
-		seq = -1;
-		status = pj_jb_get(&jb, &seq, &thedata);
-		lastget = seq;
-		break;
-	    case 'P':
-		if (seq == 0) 
-		    seq = lastseq++;
-		else
-		    lastseq = seq;
-		status = pj_jb_put(&jb, seq, data);
-		if (status == 0)
-		    lastput = seq;
-		break;
-	    default:
-		printf("Unknown character '%c'\n", c);
-		break;
-	    }
-
-#ifdef REPORT
-	    printf("seq=%d\t%c rc=%d\tsize=%d\tpfch=%d\tlvl=%d\tmxl=%d\tdelay=%d\n", 
-		    seq, toupper(c), status, jb.lst.count, jb.prefetch, jb.level, jb.max_level,
-		    (lastget>0 && lastput>0) ? lastput-lastget : -1);
-#endif
-	}
-    }
-
-#ifdef REPORT
-    printf("0\t%c   size=%d  prefetch=%d level=%d\n", 
-	    ' ', jb.lst.count, jb.prefetch, jb.level);
-#endif
-
-    if (input != stdin)
-	fclose(input);
-
-    pj_pool_release(pool);
-    return 0;
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <stdio.h>

+#include <ctype.h>

+#include <pjmedia/jbuf.h>

+#include <pj/pool.h>

+

+#define JB_MIN	    1

+#define JB_MAX	    8

+#define JB_BUF_SIZE 10

+

+#define REPORT

+//#define PRINT_COMMENT

+

+int jbuf_main(pj_pool_factory *pf)

+{

+    pj_jitter_buffer jb;

+    FILE *input = fopen("JBTEST.DAT", "rt");

+    unsigned lastseq;

+    void *data = "Hello world";

+    char line[1024], *p;

+    int lastget = 0, lastput = 0;

+    pj_pool_t *pool;

+

+    pj_init();

+    pool = pj_pool_create(pf, "JBPOOL", 256*16, 256*16, NULL);

+

+    pj_jb_init(&jb, pool, JB_MIN, JB_MAX, JB_BUF_SIZE);

+

+    lastseq = 1;

+

+    while ((p=fgets(line, sizeof(line), input)) != NULL) {

+

+	while (*p && isspace(*p))

+	    ++p;

+

+	if (!*p)

+	    continue;

+

+	if (*p == '#') {

+#ifdef PRINT_COMMENT

+	    printf("\n%s", p);

+#endif

+	    continue;

+	}

+

+	pj_jb_reset(&jb);

+#ifdef REPORT

+	printf( "Initial\t%c   size=%d  prefetch=%d level=%d\n", 

+	        ' ', jb.lst.count, jb.prefetch, jb.level);

+#endif

+

+	while (*p) {

+	    int c;

+	    unsigned seq = 0;

+	    void *thedata;

+	    int status = 1234;

+	    

+	    c = *p++;

+	    if (isspace(c))

+		continue;

+	    

+	    if (c == '/') {

+		char *end;

+

+		printf("/*");

+

+		do {

+		    putchar(*++p);

+		} while (*p != '/');

+

+		putchar('\n');

+

+		c = *++p;

+		end = p;

+

+	    }

+

+	    if (isspace(c))

+		continue;

+

+	    if (isdigit(c)) {

+		seq = c - '0';

+		while (*p) {

+		    c = *p++;

+		    

+		    if (isspace(c))

+			continue;

+		    

+		    if (!isdigit(c))

+			break;

+		    

+		    seq = seq * 10 + c - '0';

+		}

+	    }

+

+	    if (!*p)

+		break;

+

+	    switch (toupper(c)) {

+	    case 'G':

+		seq = -1;

+		status = pj_jb_get(&jb, &seq, &thedata);

+		lastget = seq;

+		break;

+	    case 'P':

+		if (seq == 0) 

+		    seq = lastseq++;

+		else

+		    lastseq = seq;

+		status = pj_jb_put(&jb, seq, data);

+		if (status == 0)

+		    lastput = seq;

+		break;

+	    default:

+		printf("Unknown character '%c'\n", c);

+		break;

+	    }

+

+#ifdef REPORT

+	    printf("seq=%d\t%c rc=%d\tsize=%d\tpfch=%d\tlvl=%d\tmxl=%d\tdelay=%d\n", 

+		    seq, toupper(c), status, jb.lst.count, jb.prefetch, jb.level, jb.max_level,

+		    (lastget>0 && lastput>0) ? lastput-lastget : -1);

+#endif

+	}

+    }

+

+#ifdef REPORT

+    printf("0\t%c   size=%d  prefetch=%d level=%d\n", 

+	    ' ', jb.lst.count, jb.prefetch, jb.level);

+#endif

+

+    if (input != stdin)

+	fclose(input);

+

+    pj_pool_release(pool);

+    return 0;

+}

diff --git a/pjmedia/src/test/main.c b/pjmedia/src/test/main.c
index c6aeb9b..06eedf7 100644
--- a/pjmedia/src/test/main.c
+++ b/pjmedia/src/test/main.c
@@ -1,27 +1,48 @@
-/* $Id$
- *
- */
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pjmedia/sound.h>
-
-pj_status_t session_test (pj_pool_factory *pf);
-pj_status_t rtp_test (pj_pool_factory *pf);
-pj_status_t sdp_test(pj_pool_factory *pf);
-int jbuf_main(pj_pool_factory *pf);
-
-int main()
-{
-    pj_caching_pool caching_pool;
-
-    pj_init();
-    pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, 0);
-
-    sdp_test (&caching_pool.factory);
-    rtp_test(&caching_pool.factory);
-    session_test (&caching_pool.factory);
-    //jbuf_main(&caching_pool.factory);
-
-    pj_caching_pool_destroy(&caching_pool);
-    return 0;
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pj/os.h>

+#include <pj/pool.h>

+#include <pjmedia/sound.h>

+

+pj_status_t session_test (pj_pool_factory *pf);

+pj_status_t rtp_test (pj_pool_factory *pf);

+pj_status_t sdp_test(pj_pool_factory *pf);

+int jbuf_main(pj_pool_factory *pf);

+

+int main()

+{

+    pj_caching_pool caching_pool;

+

+    pj_init();

+    pj_caching_pool_init(&caching_pool, &pj_pool_factory_default_policy, 0);

+

+    sdp_test (&caching_pool.factory);

+    rtp_test(&caching_pool.factory);

+    session_test (&caching_pool.factory);

+    //jbuf_main(&caching_pool.factory);

+

+    pj_caching_pool_destroy(&caching_pool);

+    return 0;

+}

diff --git a/pjmedia/src/test/rtp_test.c b/pjmedia/src/test/rtp_test.c
index 702c6f3..d88d63a 100644
--- a/pjmedia/src/test/rtp_test.c
+++ b/pjmedia/src/test/rtp_test.c
@@ -1,22 +1,43 @@
-/* $Id$
- *
- */
-#include <pjmedia/rtp.h>
-#include <stdio.h>
-
-int rtp_test()
-{
-    pj_rtp_session rtp;
-    FILE *fhnd = fopen("RTP.DAT", "wb");
-    const void *rtphdr;
-    int hdrlen;
-
-    if (!fhnd)
-	return -1;
-
-    pj_rtp_session_init (&rtp, 4, 0x12345678);
-    pj_rtp_encode_rtp (&rtp, 4, 0, 0, 160, &rtphdr, &hdrlen);
-    fwrite (rtphdr, hdrlen, 1, fhnd);
-    fclose(fhnd);
-    return 0;
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjmedia/rtp.h>

+#include <stdio.h>

+

+int rtp_test()

+{

+    pj_rtp_session rtp;

+    FILE *fhnd = fopen("RTP.DAT", "wb");

+    const void *rtphdr;

+    int hdrlen;

+

+    if (!fhnd)

+	return -1;

+

+    pj_rtp_session_init (&rtp, 4, 0x12345678);

+    pj_rtp_encode_rtp (&rtp, 4, 0, 0, 160, &rtphdr, &hdrlen);

+    fwrite (rtphdr, hdrlen, 1, fhnd);

+    fclose(fhnd);

+    return 0;

+}

diff --git a/pjmedia/src/test/sdptest.c b/pjmedia/src/test/sdptest.c
index 1b80e51..07c9a06 100644
--- a/pjmedia/src/test/sdptest.c
+++ b/pjmedia/src/test/sdptest.c
@@ -1,106 +1,127 @@
-/* $Id$
- *
- */
-#include <pjmedia/sdp.h>
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <stdio.h>
-#include <string.h>
-
-static char *sdp[] = {
-    /*
-    "v=0\r\n"
-    "o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4\r\n"
-    "s=SDP Seminar\r\n"
-    "i=A Seminar on the session description protocol\r\n"
-    "u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps\r\n"
-    "e=mjh@isi.edu (Mark Handley)\r\n"
-    "c=IN IP4 224.2.17.12/127\r\n"
-    "t=2873397496 2873404696\r\n"
-    "a=recvonly\r\n"
-    "m=audio 49170 RTP/AVP 0\r\n"
-    "m=video 51372 RTP/AVP 31\r\n"
-    "m=application 32416 udp wb\r\n"
-    "a=orient:portrait\r\n"
-    "m=audio 49230 RTP/AVP 96 97 98\r\n"
-    "a=rtpmap:96 L8/8000\r\n"
-    "a=rtpmap:97 L16/8000\r\n"
-    "a=rtpmap:98 L16/11025/2\r\n",
-    */
-    "v=0\r\n"
-    "o=usera 2890844526 2890844527 IN IP4 alice.example.com\r\n"
-    "s=\r\n"
-    "c=IN IP4 alice.example.com\r\n"
-    "t=0 0\r\n"
-    "m=message 7394 msrp/tcp *\r\n"
-    "a=accept-types: message/cpim text/plain text/html\r\n"
-    "a=path:msrp://alice.example.com:7394/2s93i9;tcp\r\n"
-};
-
-static int sdp_perform_test(pj_pool_factory *pf)
-{
-    pj_pool_t *pool;
-    int inputlen, len;
-    pjsdp_session_desc *ses;
-    char buf[1500];
-    enum { LOOP=1000000 };
-    int i;
-    pj_time_val start, end;
-
-    printf("Parsing and printing %d SDP messages..\n", LOOP);
-
-    pool = pj_pool_create(pf, "", 4096, 0, NULL);
-    inputlen = strlen(sdp[0]);
-    pj_gettimeofday(&start);
-    for (i=0; i<LOOP; ++i) {
-	ses = pjsdp_parse(sdp[0], inputlen, pool);
-	len = pjsdp_print(ses, buf, sizeof(buf));
-	buf[len] = '\0';
-	pj_pool_reset(pool);
-    }
-    pj_gettimeofday(&end);
-
-    printf("Original:\n%s\n", sdp[0]);
-    printf("Parsed:\n%s\n", buf);
-
-    PJ_TIME_VAL_SUB(end, start);
-    printf("Time: %ld:%03lds\n", end.sec, end.msec);
-
-    if (end.msec==0 && end.sec==0) end.msec=1;
-    printf("Performance: %ld msg/sec\n", LOOP*1000/PJ_TIME_VAL_MSEC(end));
-    puts("");
-
-    pj_pool_release(pool);
-    return 0;
-}
-
-static int sdp_conform_test(pj_pool_factory *pf)
-{
-    pj_pool_t *pool;
-    pjsdp_session_desc *ses;
-    int i, len;
-    char buf[1500];
-
-    for (i=0; i<sizeof(sdp)/sizeof(sdp[0]); ++i) {
-	pool = pj_pool_create(pf, "sdp", 4096, 0, NULL);
-	ses = pjsdp_parse(sdp[i], strlen(sdp[i]), pool);
-	len = pjsdp_print(ses, buf, sizeof(buf)); 
-	buf[len] = '\0';
-	printf("%s\n", buf);
-	pj_pool_release(pool);
-    }
-
-    return 0;
-}
-
-pj_status_t sdp_test(pj_pool_factory *pf)
-{
-    if (sdp_conform_test(pf) != 0)
-	return -2;
-
-    if (sdp_perform_test(pf) != 0)
-	return -3;
-
-    return 0;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjmedia/sdp.h>

+#include <pj/os.h>

+#include <pj/pool.h>

+#include <stdio.h>

+#include <string.h>

+

+static char *sdp[] = {

+    /*

+    "v=0\r\n"

+    "o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4\r\n"

+    "s=SDP Seminar\r\n"

+    "i=A Seminar on the session description protocol\r\n"

+    "u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps\r\n"

+    "e=mjh@isi.edu (Mark Handley)\r\n"

+    "c=IN IP4 224.2.17.12/127\r\n"

+    "t=2873397496 2873404696\r\n"

+    "a=recvonly\r\n"

+    "m=audio 49170 RTP/AVP 0\r\n"

+    "m=video 51372 RTP/AVP 31\r\n"

+    "m=application 32416 udp wb\r\n"

+    "a=orient:portrait\r\n"

+    "m=audio 49230 RTP/AVP 96 97 98\r\n"

+    "a=rtpmap:96 L8/8000\r\n"

+    "a=rtpmap:97 L16/8000\r\n"

+    "a=rtpmap:98 L16/11025/2\r\n",

+    */

+    "v=0\r\n"

+    "o=usera 2890844526 2890844527 IN IP4 alice.example.com\r\n"

+    "s=\r\n"

+    "c=IN IP4 alice.example.com\r\n"

+    "t=0 0\r\n"

+    "m=message 7394 msrp/tcp *\r\n"

+    "a=accept-types: message/cpim text/plain text/html\r\n"

+    "a=path:msrp://alice.example.com:7394/2s93i9;tcp\r\n"

+};

+

+static int sdp_perform_test(pj_pool_factory *pf)

+{

+    pj_pool_t *pool;

+    int inputlen, len;

+    pjsdp_session_desc *ses;

+    char buf[1500];

+    enum { LOOP=1000000 };

+    int i;

+    pj_time_val start, end;

+

+    printf("Parsing and printing %d SDP messages..\n", LOOP);

+

+    pool = pj_pool_create(pf, "", 4096, 0, NULL);

+    inputlen = strlen(sdp[0]);

+    pj_gettimeofday(&start);

+    for (i=0; i<LOOP; ++i) {

+	ses = pjsdp_parse(sdp[0], inputlen, pool);

+	len = pjsdp_print(ses, buf, sizeof(buf));

+	buf[len] = '\0';

+	pj_pool_reset(pool);

+    }

+    pj_gettimeofday(&end);

+

+    printf("Original:\n%s\n", sdp[0]);

+    printf("Parsed:\n%s\n", buf);

+

+    PJ_TIME_VAL_SUB(end, start);

+    printf("Time: %ld:%03lds\n", end.sec, end.msec);

+

+    if (end.msec==0 && end.sec==0) end.msec=1;

+    printf("Performance: %ld msg/sec\n", LOOP*1000/PJ_TIME_VAL_MSEC(end));

+    puts("");

+

+    pj_pool_release(pool);

+    return 0;

+}

+

+static int sdp_conform_test(pj_pool_factory *pf)

+{

+    pj_pool_t *pool;

+    pjsdp_session_desc *ses;

+    int i, len;

+    char buf[1500];

+

+    for (i=0; i<sizeof(sdp)/sizeof(sdp[0]); ++i) {

+	pool = pj_pool_create(pf, "sdp", 4096, 0, NULL);

+	ses = pjsdp_parse(sdp[i], strlen(sdp[i]), pool);

+	len = pjsdp_print(ses, buf, sizeof(buf)); 

+	buf[len] = '\0';

+	printf("%s\n", buf);

+	pj_pool_release(pool);

+    }

+

+    return 0;

+}

+

+pj_status_t sdp_test(pj_pool_factory *pf)

+{

+    if (sdp_conform_test(pf) != 0)

+	return -2;

+

+    if (sdp_perform_test(pf) != 0)

+	return -3;

+

+    return 0;

+}

+

diff --git a/pjmedia/src/test/session_test.c b/pjmedia/src/test/session_test.c
index cf13ada..cfb1ee2 100644
--- a/pjmedia/src/test/session_test.c
+++ b/pjmedia/src/test/session_test.c
@@ -1,115 +1,136 @@
-/* $Id$
- *
- */
-#include <pjmedia/mediamgr.h>
-#include <pjmedia/session.h>
-#include <pj/sock.h>
-#include <pj/pool.h>
-#include <stdio.h>
-#include <pj/string.h>
-
-pj_status_t session_test (pj_pool_factory *pf)
-{
-    pj_med_mgr_t *mm;
-    pj_media_session_t *s1, *s2;
-    pj_pool_t *pool;
-    pjsdp_session_desc *sdp;
-    pj_media_stream_info sd_info;
-    char buf[1024];
-    int len;
-    pj_media_stream_stat tx_stat, rx_stat;
-
-    pool = pj_pool_create(pf, "test", 4096, 1024, NULL);
-
-    // Init media manager.
-    mm = pj_med_mgr_create ( pf );
-
-    // Create caller session.
-    // THIS WILL DEFINITELY CRASH (NULL as argument)!
-    s1 = pj_media_session_create (mm, NULL);
-
-    // Set caller's media to send-only.
-    sd_info.dir = PJ_MEDIA_DIR_ENCODING;
-    pj_media_session_modify_stream (s1, 0, PJ_MEDIA_STREAM_MODIFY_DIR, &sd_info);
-
-    // Create caller SDP.
-    sdp = pj_media_session_create_sdp (s1, pool, 0);
-    len = pjsdp_print (sdp, buf, sizeof(buf));
-    buf[len] = '\0';
-    printf("Caller's initial SDP:\n<BEGIN>\n%s\n<END>\n", buf);
-
-    // Parse SDP from caller.
-    sdp = pjsdp_parse (buf, len, pool);
-
-    // Create callee session based on caller's SDP.
-    // THIS WILL DEFINITELY CRASH (NULL as argument)!
-    s2 = pj_media_session_create_from_sdp (mm, sdp, NULL);
-    
-    // Create callee SDP
-    sdp = pj_media_session_create_sdp (s2, pool, 0);
-    len = pjsdp_print (sdp, buf, sizeof(buf));
-    buf[len] = '\0';
-    printf("Callee's SDP:\n<BEGIN>\n%s\n<END>\n", buf);
-
-    // Parse SDP from callee.
-    sdp = pjsdp_parse (buf, len, pool);
-
-    // Update caller
-    pj_media_session_update (s1, sdp);
-    sdp = pj_media_session_create_sdp (s1, pool, 0);
-    pjsdp_print (sdp, buf, sizeof(buf));
-    printf("Caller's SDP after update:\n<BEGIN>\n%s\n<END>\n", buf);
-
-    // Now start media.
-    pj_media_session_activate (s2);
-    pj_media_session_activate (s1);
-
-    // Wait
-    for (;;) {
-	int has_stat;
-
-	printf("Enter q to exit, 1 or 2 to print statistics.\n");
-	fgets (buf, 10, stdin);
-	has_stat = 0;
-
-	switch (buf[0]) {
-	case 'q':
-	case 'Q':
-	    goto done;
-	    break;
-	case '1':
-	    pj_media_session_get_stat (s1, 0, &tx_stat, &rx_stat);
-	    has_stat = 1;
-	    break;
-	case '2':
-	    pj_media_session_get_stat (s2, 0, &tx_stat, &rx_stat);
-	    has_stat = 1;
-	    break;
-	}
-
-	if (has_stat) {
-	    pj_media_stream_stat *stat[2] = { &tx_stat, &rx_stat };
-	    const char *statname[2] = { "TX", "RX" };
-	    int i;
-
-	    for (i=0; i<2; ++i) {
-		printf("%s statistics:\n", statname[i]);
-		printf(" Pkt      TX=%d RX=%d\n", stat[i]->pkt_tx, stat[i]->pkt_rx);
-		printf(" Octets   TX=%d RX=%d\n", stat[i]->oct_tx, stat[i]->oct_rx);
-		printf(" Jitter   %d ms\n", stat[i]->jitter);
-		printf(" Pkt lost %d\n", stat[i]->pkt_lost);
-	    }
-	    printf("\n");
-	}
-    }
-
-done:
-
-    // Done.
-    pj_pool_release (pool);
-    pj_media_session_destroy (s2);
-    pj_media_session_destroy (s1);
-    pj_med_mgr_destroy (mm);
-
-    return 0;
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJMEDIA - Multimedia over IP Stack 

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ */

+#include <pjmedia/mediamgr.h>

+#include <pjmedia/session.h>

+#include <pj/sock.h>

+#include <pj/pool.h>

+#include <stdio.h>

+#include <pj/string.h>

+

+pj_status_t session_test (pj_pool_factory *pf)

+{

+    pj_med_mgr_t *mm;

+    pj_media_session_t *s1, *s2;

+    pj_pool_t *pool;

+    pjsdp_session_desc *sdp;

+    pj_media_stream_info sd_info;

+    char buf[1024];

+    int len;

+    pj_media_stream_stat tx_stat, rx_stat;

+

+    pool = pj_pool_create(pf, "test", 4096, 1024, NULL);

+

+    // Init media manager.

+    mm = pj_med_mgr_create ( pf );

+

+    // Create caller session.

+    // THIS WILL DEFINITELY CRASH (NULL as argument)!

+    s1 = pj_media_session_create (mm, NULL);

+

+    // Set caller's media to send-only.

+    sd_info.dir = PJ_MEDIA_DIR_ENCODING;

+    pj_media_session_modify_stream (s1, 0, PJ_MEDIA_STREAM_MODIFY_DIR, &sd_info);

+

+    // Create caller SDP.

+    sdp = pj_media_session_create_sdp (s1, pool, 0);

+    len = pjsdp_print (sdp, buf, sizeof(buf));

+    buf[len] = '\0';

+    printf("Caller's initial SDP:\n<BEGIN>\n%s\n<END>\n", buf);

+

+    // Parse SDP from caller.

+    sdp = pjsdp_parse (buf, len, pool);

+

+    // Create callee session based on caller's SDP.

+    // THIS WILL DEFINITELY CRASH (NULL as argument)!

+    s2 = pj_media_session_create_from_sdp (mm, sdp, NULL);

+    

+    // Create callee SDP

+    sdp = pj_media_session_create_sdp (s2, pool, 0);

+    len = pjsdp_print (sdp, buf, sizeof(buf));

+    buf[len] = '\0';

+    printf("Callee's SDP:\n<BEGIN>\n%s\n<END>\n", buf);

+

+    // Parse SDP from callee.

+    sdp = pjsdp_parse (buf, len, pool);

+

+    // Update caller

+    pj_media_session_update (s1, sdp);

+    sdp = pj_media_session_create_sdp (s1, pool, 0);

+    pjsdp_print (sdp, buf, sizeof(buf));

+    printf("Caller's SDP after update:\n<BEGIN>\n%s\n<END>\n", buf);

+

+    // Now start media.

+    pj_media_session_activate (s2);

+    pj_media_session_activate (s1);

+

+    // Wait

+    for (;;) {

+	int has_stat;

+

+	printf("Enter q to exit, 1 or 2 to print statistics.\n");

+	fgets (buf, 10, stdin);

+	has_stat = 0;

+

+	switch (buf[0]) {

+	case 'q':

+	case 'Q':

+	    goto done;

+	    break;

+	case '1':

+	    pj_media_session_get_stat (s1, 0, &tx_stat, &rx_stat);

+	    has_stat = 1;

+	    break;

+	case '2':

+	    pj_media_session_get_stat (s2, 0, &tx_stat, &rx_stat);

+	    has_stat = 1;

+	    break;

+	}

+

+	if (has_stat) {

+	    pj_media_stream_stat *stat[2] = { &tx_stat, &rx_stat };

+	    const char *statname[2] = { "TX", "RX" };

+	    int i;

+

+	    for (i=0; i<2; ++i) {

+		printf("%s statistics:\n", statname[i]);

+		printf(" Pkt      TX=%d RX=%d\n", stat[i]->pkt_tx, stat[i]->pkt_rx);

+		printf(" Octets   TX=%d RX=%d\n", stat[i]->oct_tx, stat[i]->oct_rx);

+		printf(" Jitter   %d ms\n", stat[i]->jitter);

+		printf(" Pkt lost %d\n", stat[i]->pkt_lost);

+	    }

+	    printf("\n");

+	}

+    }

+

+done:

+

+    // Done.

+    pj_pool_release (pool);

+    pj_media_session_destroy (s2);

+    pj_media_session_destroy (s1);

+    pj_med_mgr_destroy (mm);

+

+    return 0;

+}

diff --git a/pjsip/include/pjsip-simple/event_notify.h b/pjsip/include/pjsip-simple/event_notify.h
index 91b5365..6cfee4e 100644
--- a/pjsip/include/pjsip-simple/event_notify.h
+++ b/pjsip/include/pjsip-simple/event_notify.h
@@ -1,315 +1,337 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_SIMPLE_EVENT_NOTIFY_H__
-#define __PJSIP_SIMPLE_EVENT_NOTIFY_H__
-
-/**
- * @file event_notify.h
- * @brief SIP Specific Event Notification Extension (RFC 3265)
- */
-
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_auth.h>
-#include <pjsip_simple/event_notify_msg.h>
-#include <pj/timer.h>
-
-/**
- * @defgroup PJSIP_EVENT_NOT SIP Event Notification (RFC 3265) Module
- * @ingroup PJSIP_SIMPLE
- * @{
- *
- * This module provides the implementation of SIP Extension for SIP Specific
- * Event Notification (RFC 3265). It extends PJSIP by supporting SUBSCRIBE and
- * NOTIFY methods.
- *
- * This module itself is extensible; new event packages can be registered to
- * this module to handle specific extensions (such as presence).
- */
-
-PJ_BEGIN_DECL
-
-typedef struct pjsip_event_sub_cb pjsip_event_sub_cb;
-typedef struct pjsip_event_sub pjsip_event_sub;
-
-/**
- * This enumeration describes subscription state as described in the RFC 3265.
- * The standard specifies that extensions may define additional states. In the
- * case where the state is not known, the subscription state will be set to
- * PJSIP_EVENT_SUB_STATE_UNKNOWN, and the token will be kept in state_str
- * member of the susbcription structure.
- */
-typedef enum pjsip_event_sub_state
-{
-    /** State is NULL. */
-    PJSIP_EVENT_SUB_STATE_NULL,
-
-    /** Subscription is active. */
-    PJSIP_EVENT_SUB_STATE_ACTIVE,
-
-    /** Subscription is pending. */
-    PJSIP_EVENT_SUB_STATE_PENDING,
-
-    /** Subscription is terminated. */
-    PJSIP_EVENT_SUB_STATE_TERMINATED,
-
-    /** Subscription state can not be determined. Application can query
-     *  the state information in state_str member.
-     */
-    PJSIP_EVENT_SUB_STATE_UNKNOWN,
-
-} pjsip_event_sub_state;
-
-/**
- * This structure describes notification to be called when incoming SUBSCRIBE
- * request is received. The module will call the callback registered by package
- * that matches the event description in the incoming SUBSCRIBE.
- */
-typedef struct pjsip_event_sub_pkg_cb
-{
-    /**
-     * This callback is called to first enquery the package whether it wants
-     * to accept incoming SUBSCRIBE request. If it does, then on_subscribe
-     * will be called.
-     *
-     * @param rdata	The incoming request.
-     * @param status	The status code to be returned back to subscriber.
-     */
-    void (*on_query_subscribe)(pjsip_rx_data *rdata, int *status);
-
-    /**
-     * This callback is called when the module receives incoming SUBSCRIBE
-     * request.
-     *
-     * @param sub	The subscription instance.
-     * @param rdata	The received buffer.
-     * @param cb	Callback to be registered to the subscription instance.
-     * @param expires	The expiration to be set.
-     */
-    void (*on_subscribe)(pjsip_event_sub *sub, pjsip_rx_data *rdata,
-			 pjsip_event_sub_cb **cb, int *expires);
-
-} pjsip_event_sub_pkg_cb;
-
-/**
- * This structure describes callback that is registered by application or
- * package to receive notifications about a subscription.
- */
-struct pjsip_event_sub_cb
-{
-    /**
-     * This callback is used by both subscriber and notifier. It is called 
-     * when the subscription has been terminated.
-     *
-     * @param sub	The subscription instance.
-     * @param reason	The termination reason.
-     */
-    void (*on_sub_terminated)(pjsip_event_sub *sub, const pj_str_t *reason);
-
-    /**
-     * This callback is called when we received SUBSCRIBE request to refresh
-     * the subscription.
-     *
-     * @param sub	The subscription instance.
-     * @param rdata	The received SUBSCRIBE request.
-     */
-    void (*on_received_refresh)(pjsip_event_sub *sub, pjsip_rx_data *rdata);
-
-    /**
-     * This callback is called when the module receives final response on
-     * previously sent SUBSCRIBE request.
-     *
-     * @param sub	The subscription instance.
-     * @param event	The event.
-     */
-    void (*on_received_sub_response)(pjsip_event_sub *sub, pjsip_event *event);
-
-    /**
-     * This callback is called when the module receives incoming NOTIFY
-     * request.
-     *
-     * @param sub	The subscription instance.
-     * @param rdata	The received data.
-     */
-    void (*on_received_notify)(pjsip_event_sub *sub, pjsip_rx_data *rdata);
-
-    /**
-     * This callback is called when the module receives final response to
-     * previously sent NOTIFY request.
-     *
-     * @param sub	The subscription instance.
-     * @param event	The event.
-     */
-    void (*on_received_notify_response)(pjsip_event_sub *sub, pjsip_event *event);
-
-};
-
-/**
- * This structure describes an event subscription record. The structure is used
- * to represent both subscriber and notifier.
- */
-struct pjsip_event_sub
-{
-    pj_pool_t		*pool;		    /**< Pool. */
-    pjsip_endpoint	*endpt;		    /**< Endpoint. */
-    pjsip_event_sub_cb	 cb;		    /**< Callback. */
-    pj_mutex_t		*mutex;		    /**< Mutex. */
-    pjsip_role_e	 role;		    /**< Role (UAC=subscriber, UAS=notifier) */
-    pjsip_event_sub_state state;	    /**< Subscription state. */
-    pj_str_t		 state_str;	    /**< String describing the state. */
-    pjsip_from_hdr	*from;		    /**< Cached local info (From) */
-    pjsip_to_hdr	*to;		    /**< Cached remote info (To) */
-    pjsip_contact_hdr	*contact;	    /**< Cached local contact. */
-    pjsip_cid_hdr	*call_id;	    /**< Cached Call-ID */
-    int			 cseq;		    /**< Outgoing CSeq */
-    pjsip_event_hdr	*event;		    /**< Event description. */
-    pjsip_expires_hdr	*uac_expires;	    /**< Cached Expires header (UAC only). */
-    pjsip_accept_hdr	*local_accept;	    /**< Local Accept header. */
-    pjsip_route_hdr	 route_set;	    /**< Route-set. */
-
-    pj_str_t		 key;		    /**< Key in the hash table. */
-    void		*user_data;	    /**< Application data. */
-    int			 default_interval;  /**< Refresh interval. */
-    pj_timer_entry	 timer;		    /**< Internal timer. */
-    pj_time_val		 expiry_time;	    /**< Time when subscription expires. */
-    int			 pending_tsx;	    /**< Number of pending transactions. */
-    pj_bool_t		 delete_flag;	    /**< Pending deletion flag. */
-
-    pjsip_auth_session	 auth_sess;	    /**< Authorization sessions.	*/
-    unsigned		 cred_cnt;	    /**< Number of credentials.		*/
-    pjsip_cred_info	*cred_info;	    /**< Array of credentials.		*/
-};
-
-
-
-
-/**
- * Initialize the module and get the instance of the module to be registered to
- * endpoint.
- *
- * @return		The module instance.
- */
-PJ_DECL(pjsip_module*) pjsip_event_sub_get_module(void);
-
-
-/**
- * Register event package.
- *
- * @param event		The event identification for the package.
- * @param accept_cnt	Number of strings in Accept array.
- * @param accept	Array of Accept value.
- * @param cb		Callback to receive incoming SUBSCRIBE for the package.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_event_sub_register_pkg( const pj_str_t *event_name,
-						   int accept_cnt,
-						   const pj_str_t accept[],
-						   const pjsip_event_sub_pkg_cb *cb );
-
-
-/**
- * Create initial subscription instance (client).
- *
- * @param endpt		The endpoint.
- * @param from		URL to put in From header.
- * @param to		The target resource.
- * @param event		Event package.
- * @param expires	Expiration time.
- * @param accept	Accept specification.
- * @param user_data	Application data to attach to this subscription.
- *
- * @return		New client subscription instance.
- */
-PJ_DECL(pjsip_event_sub*) pjsip_event_sub_create( pjsip_endpoint *endpt,
-						  const pj_str_t *from,
-						  const pj_str_t *to,
-						  const pj_str_t *event,
-						  int expires,
-						  int accept_cnt,
-						  const pj_str_t accept[],
-						  void *user_data,
-						  const pjsip_event_sub_cb *cb);
-
-/**
- * Set credentials to be used for outgoing request messages.
- *
- * @param sub		Subscription instance.
- * @param count		Number of credentials.
- * @param cred		Array of credential info.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_event_sub_set_credentials( pjsip_event_sub *sub,
-						      int count,
-						      const pjsip_cred_info cred[]);
-
-/**
- * Set route set for outgoing requests.
- *
- * @param sub		Subscription instance.
- * @param route_set	List of route headers.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_event_sub_set_route_set( pjsip_event_sub *sub,
-						    const pjsip_route_hdr *route_set );
-
-
-/**
- * Send SUBSCRIBE request.
- *
- * @param sub		Subscription instance.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_event_sub_subscribe( pjsip_event_sub *sub );
-
-/**
- * Terminate subscription (client). This will send unsubscription request to
- * notifier.
- *
- * @param sub		Client subscription instance.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_event_sub_unsubscribe( pjsip_event_sub *sub );
-
-
-/**
- * For notifier, send NOTIFY request to subscriber, and set the state of
- * the subscription.
- *
- * @param sub		The server subscription (notifier) instance.
- * @param state		New state to set.
- * @param reason	Specify reason if new state is terminated, otherwise
- *			put NULL.
- * @param type		Description of content type.
- * @param body		Text body to send with the NOTIFY, or NULL if the
- *			NOTIFY request should not contain any message body.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_event_sub_notify( pjsip_event_sub *sub,
-					     pjsip_event_sub_state state,
-					     const pj_str_t *reason,
-					     pjsip_msg_body *body);
-
-/**
- * Destroy subscription instance.
- *
- * @param sub		The client or server subscription instance.
- *
- * @return		Zero on success, one if the subscription will be
- *			deleted automatically later, or -1 on error.
- */
-PJ_DECL(pj_status_t) pjsip_event_sub_destroy(pjsip_event_sub *sub);
-
-
-PJ_END_DECL
-
-/**
- * @}
- */
-
-#endif	/* __PJSIP_SIMPLE_EVENT_NOTIFY_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIMPLE_EVENT_NOTIFY_H__

+#define __PJSIP_SIMPLE_EVENT_NOTIFY_H__

+

+/**

+ * @file event_notify.h

+ * @brief SIP Specific Event Notification Extension (RFC 3265)

+ */

+

+#include <pjsip/sip_types.h>

+#include <pjsip/sip_auth.h>

+#include <pjsip_simple/event_notify_msg.h>

+#include <pj/timer.h>

+

+/**

+ * @defgroup PJSIP_EVENT_NOT SIP Event Notification (RFC 3265) Module

+ * @ingroup PJSIP_SIMPLE

+ * @{

+ *

+ * This module provides the implementation of SIP Extension for SIP Specific

+ * Event Notification (RFC 3265). It extends PJSIP by supporting SUBSCRIBE and

+ * NOTIFY methods.

+ *

+ * This module itself is extensible; new event packages can be registered to

+ * this module to handle specific extensions (such as presence).

+ */

+

+PJ_BEGIN_DECL

+

+typedef struct pjsip_event_sub_cb pjsip_event_sub_cb;

+typedef struct pjsip_event_sub pjsip_event_sub;

+

+/**

+ * This enumeration describes subscription state as described in the RFC 3265.

+ * The standard specifies that extensions may define additional states. In the

+ * case where the state is not known, the subscription state will be set to

+ * PJSIP_EVENT_SUB_STATE_UNKNOWN, and the token will be kept in state_str

+ * member of the susbcription structure.

+ */

+typedef enum pjsip_event_sub_state

+{

+    /** State is NULL. */

+    PJSIP_EVENT_SUB_STATE_NULL,

+

+    /** Subscription is active. */

+    PJSIP_EVENT_SUB_STATE_ACTIVE,

+

+    /** Subscription is pending. */

+    PJSIP_EVENT_SUB_STATE_PENDING,

+

+    /** Subscription is terminated. */

+    PJSIP_EVENT_SUB_STATE_TERMINATED,

+

+    /** Subscription state can not be determined. Application can query

+     *  the state information in state_str member.

+     */

+    PJSIP_EVENT_SUB_STATE_UNKNOWN,

+

+} pjsip_event_sub_state;

+

+/**

+ * This structure describes notification to be called when incoming SUBSCRIBE

+ * request is received. The module will call the callback registered by package

+ * that matches the event description in the incoming SUBSCRIBE.

+ */

+typedef struct pjsip_event_sub_pkg_cb

+{

+    /**

+     * This callback is called to first enquery the package whether it wants

+     * to accept incoming SUBSCRIBE request. If it does, then on_subscribe

+     * will be called.

+     *

+     * @param rdata	The incoming request.

+     * @param status	The status code to be returned back to subscriber.

+     */

+    void (*on_query_subscribe)(pjsip_rx_data *rdata, int *status);

+

+    /**

+     * This callback is called when the module receives incoming SUBSCRIBE

+     * request.

+     *

+     * @param sub	The subscription instance.

+     * @param rdata	The received buffer.

+     * @param cb	Callback to be registered to the subscription instance.

+     * @param expires	The expiration to be set.

+     */

+    void (*on_subscribe)(pjsip_event_sub *sub, pjsip_rx_data *rdata,

+			 pjsip_event_sub_cb **cb, int *expires);

+

+} pjsip_event_sub_pkg_cb;

+

+/**

+ * This structure describes callback that is registered by application or

+ * package to receive notifications about a subscription.

+ */

+struct pjsip_event_sub_cb

+{

+    /**

+     * This callback is used by both subscriber and notifier. It is called 

+     * when the subscription has been terminated.

+     *

+     * @param sub	The subscription instance.

+     * @param reason	The termination reason.

+     */

+    void (*on_sub_terminated)(pjsip_event_sub *sub, const pj_str_t *reason);

+

+    /**

+     * This callback is called when we received SUBSCRIBE request to refresh

+     * the subscription.

+     *

+     * @param sub	The subscription instance.

+     * @param rdata	The received SUBSCRIBE request.

+     */

+    void (*on_received_refresh)(pjsip_event_sub *sub, pjsip_rx_data *rdata);

+

+    /**

+     * This callback is called when the module receives final response on

+     * previously sent SUBSCRIBE request.

+     *

+     * @param sub	The subscription instance.

+     * @param event	The event.

+     */

+    void (*on_received_sub_response)(pjsip_event_sub *sub, pjsip_event *event);

+

+    /**

+     * This callback is called when the module receives incoming NOTIFY

+     * request.

+     *

+     * @param sub	The subscription instance.

+     * @param rdata	The received data.

+     */

+    void (*on_received_notify)(pjsip_event_sub *sub, pjsip_rx_data *rdata);

+

+    /**

+     * This callback is called when the module receives final response to

+     * previously sent NOTIFY request.

+     *

+     * @param sub	The subscription instance.

+     * @param event	The event.

+     */

+    void (*on_received_notify_response)(pjsip_event_sub *sub, pjsip_event *event);

+

+};

+

+/**

+ * This structure describes an event subscription record. The structure is used

+ * to represent both subscriber and notifier.

+ */

+struct pjsip_event_sub

+{

+    pj_pool_t		*pool;		    /**< Pool. */

+    pjsip_endpoint	*endpt;		    /**< Endpoint. */

+    pjsip_event_sub_cb	 cb;		    /**< Callback. */

+    pj_mutex_t		*mutex;		    /**< Mutex. */

+    pjsip_role_e	 role;		    /**< Role (UAC=subscriber, UAS=notifier) */

+    pjsip_event_sub_state state;	    /**< Subscription state. */

+    pj_str_t		 state_str;	    /**< String describing the state. */

+    pjsip_from_hdr	*from;		    /**< Cached local info (From) */

+    pjsip_to_hdr	*to;		    /**< Cached remote info (To) */

+    pjsip_contact_hdr	*contact;	    /**< Cached local contact. */

+    pjsip_cid_hdr	*call_id;	    /**< Cached Call-ID */

+    int			 cseq;		    /**< Outgoing CSeq */

+    pjsip_event_hdr	*event;		    /**< Event description. */

+    pjsip_expires_hdr	*uac_expires;	    /**< Cached Expires header (UAC only). */

+    pjsip_accept_hdr	*local_accept;	    /**< Local Accept header. */

+    pjsip_route_hdr	 route_set;	    /**< Route-set. */

+

+    pj_str_t		 key;		    /**< Key in the hash table. */

+    void		*user_data;	    /**< Application data. */

+    int			 default_interval;  /**< Refresh interval. */

+    pj_timer_entry	 timer;		    /**< Internal timer. */

+    pj_time_val		 expiry_time;	    /**< Time when subscription expires. */

+    int			 pending_tsx;	    /**< Number of pending transactions. */

+    pj_bool_t		 delete_flag;	    /**< Pending deletion flag. */

+

+    pjsip_auth_session	 auth_sess;	    /**< Authorization sessions.	*/

+    unsigned		 cred_cnt;	    /**< Number of credentials.		*/

+    pjsip_cred_info	*cred_info;	    /**< Array of credentials.		*/

+};

+

+

+

+

+/**

+ * Initialize the module and get the instance of the module to be registered to

+ * endpoint.

+ *

+ * @return		The module instance.

+ */

+PJ_DECL(pjsip_module*) pjsip_event_sub_get_module(void);

+

+

+/**

+ * Register event package.

+ *

+ * @param event		The event identification for the package.

+ * @param accept_cnt	Number of strings in Accept array.

+ * @param accept	Array of Accept value.

+ * @param cb		Callback to receive incoming SUBSCRIBE for the package.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_event_sub_register_pkg( const pj_str_t *event_name,

+						   int accept_cnt,

+						   const pj_str_t accept[],

+						   const pjsip_event_sub_pkg_cb *cb );

+

+

+/**

+ * Create initial subscription instance (client).

+ *

+ * @param endpt		The endpoint.

+ * @param from		URL to put in From header.

+ * @param to		The target resource.

+ * @param event		Event package.

+ * @param expires	Expiration time.

+ * @param accept	Accept specification.

+ * @param user_data	Application data to attach to this subscription.

+ *

+ * @return		New client subscription instance.

+ */

+PJ_DECL(pjsip_event_sub*) pjsip_event_sub_create( pjsip_endpoint *endpt,

+						  const pj_str_t *from,

+						  const pj_str_t *to,

+						  const pj_str_t *event,

+						  int expires,

+						  int accept_cnt,

+						  const pj_str_t accept[],

+						  void *user_data,

+						  const pjsip_event_sub_cb *cb);

+

+/**

+ * Set credentials to be used for outgoing request messages.

+ *

+ * @param sub		Subscription instance.

+ * @param count		Number of credentials.

+ * @param cred		Array of credential info.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_event_sub_set_credentials( pjsip_event_sub *sub,

+						      int count,

+						      const pjsip_cred_info cred[]);

+

+/**

+ * Set route set for outgoing requests.

+ *

+ * @param sub		Subscription instance.

+ * @param route_set	List of route headers.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_event_sub_set_route_set( pjsip_event_sub *sub,

+						    const pjsip_route_hdr *route_set );

+

+

+/**

+ * Send SUBSCRIBE request.

+ *

+ * @param sub		Subscription instance.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_event_sub_subscribe( pjsip_event_sub *sub );

+

+/**

+ * Terminate subscription (client). This will send unsubscription request to

+ * notifier.

+ *

+ * @param sub		Client subscription instance.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_event_sub_unsubscribe( pjsip_event_sub *sub );

+

+

+/**

+ * For notifier, send NOTIFY request to subscriber, and set the state of

+ * the subscription.

+ *

+ * @param sub		The server subscription (notifier) instance.

+ * @param state		New state to set.

+ * @param reason	Specify reason if new state is terminated, otherwise

+ *			put NULL.

+ * @param type		Description of content type.

+ * @param body		Text body to send with the NOTIFY, or NULL if the

+ *			NOTIFY request should not contain any message body.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_event_sub_notify( pjsip_event_sub *sub,

+					     pjsip_event_sub_state state,

+					     const pj_str_t *reason,

+					     pjsip_msg_body *body);

+

+/**

+ * Destroy subscription instance.

+ *

+ * @param sub		The client or server subscription instance.

+ *

+ * @return		Zero on success, one if the subscription will be

+ *			deleted automatically later, or -1 on error.

+ */

+PJ_DECL(pj_status_t) pjsip_event_sub_destroy(pjsip_event_sub *sub);

+

+

+PJ_END_DECL

+

+/**

+ * @}

+ */

+

+#endif	/* __PJSIP_SIMPLE_EVENT_NOTIFY_H__ */

diff --git a/pjsip/include/pjsip-simple/event_notify_msg.h b/pjsip/include/pjsip-simple/event_notify_msg.h
index ab66a05..c88bab6 100644
--- a/pjsip/include/pjsip-simple/event_notify_msg.h
+++ b/pjsip/include/pjsip-simple/event_notify_msg.h
@@ -1,102 +1,124 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_SIMPLE_EVENT_NOTIFY_MSG_H__
-#define __PJSIP_SIMPLE_EVENT_NOTIFY_MSG_H__
-
-/**
- * @file event_notify_msg.h
- * @brief SIP Event Notification Headers (RFC 3265)
- */
-#include <pjsip/sip_msg.h>
-
-/**
- * @ingroup PJSIP_EVENT_NOT
- * @{
- */
-
-PJ_BEGIN_DECL
-
-
-/** Max events in Allow-Events header. */
-#define PJSIP_MAX_ALLOW_EVENTS	16
-
-/**
- * This structure describes Event header.
- */
-typedef struct pjsip_event_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_event_hdr)
-    pj_str_t	    event_type;	    /**< Event name. */
-    pj_str_t	    id_param;	    /**< Optional event ID parameter. */
-    pj_str_t	    other_param;    /**< Other parameter, concatenated together. */
-} pjsip_event_hdr;
-
-/**
- * Create an Event header.
- *
- * @param pool	    The pool.
- *
- * @return	    New Event header instance.
- */
-PJ_DECL(pjsip_event_hdr*) pjsip_event_hdr_create(pj_pool_t *pool);
-
-
-/**
- * This structure describes Allow-Events header.
- */
-typedef struct pjsip_allow_events_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_allow_events_hdr)
-    int		    event_cnt;			    /**< Number of event names. */
-    pj_str_t	    events[PJSIP_MAX_ALLOW_EVENTS]; /**< Event names. */
-} pjsip_allow_events_hdr;
-
-
-/**
- * Create a new Allow-Events header.
- *
- * @param pool.	    The pool.
- *
- * @return	    Allow-Events header.
- */
-PJ_DECL(pjsip_allow_events_hdr*) pjsip_allow_events_hdr_create(pj_pool_t *pool);
-
-
-/**
- * This structure describes Subscription-State header.
- */
-typedef struct pjsip_sub_state_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_sub_state_hdr)
-    pj_str_t	    sub_state;		/**< Subscription state. */
-    pj_str_t	    reason_param;	/**< Optional termination reason. */
-    int		    expires_param;	/**< Expires param, or -1. */
-    int		    retry_after;	/**< Retry after param, or -1. */
-    pj_str_t	    other_param;	/**< Other parameter, concatenated together. */
-} pjsip_sub_state_hdr;
-
-/**
- * Create new Subscription-State header.
- *
- * @param pool	    The pool.
- *
- * @return	    Subscription-State header.
- */
-PJ_DECL(pjsip_sub_state_hdr*) pjsip_sub_state_hdr_create(pj_pool_t *pool);
-
-/**
- * Initialize parser for event notify module.
- */
-PJ_DEF(void) pjsip_event_notify_init_parser(void);
-
-
-PJ_END_DECL
-
-
-/**
- * @}
- */
-
-#endif	/* __PJSIP_SIMPLE_EVENT_NOTIFY_MSG_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIMPLE_EVENT_NOTIFY_MSG_H__

+#define __PJSIP_SIMPLE_EVENT_NOTIFY_MSG_H__

+

+/**

+ * @file event_notify_msg.h

+ * @brief SIP Event Notification Headers (RFC 3265)

+ */

+#include <pjsip/sip_msg.h>

+

+/**

+ * @ingroup PJSIP_EVENT_NOT

+ * @{

+ */

+

+PJ_BEGIN_DECL

+

+

+/** Max events in Allow-Events header. */

+#define PJSIP_MAX_ALLOW_EVENTS	16

+

+/**

+ * This structure describes Event header.

+ */

+typedef struct pjsip_event_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_event_hdr)

+    pj_str_t	    event_type;	    /**< Event name. */

+    pj_str_t	    id_param;	    /**< Optional event ID parameter. */

+    pj_str_t	    other_param;    /**< Other parameter, concatenated together. */

+} pjsip_event_hdr;

+

+/**

+ * Create an Event header.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    New Event header instance.

+ */

+PJ_DECL(pjsip_event_hdr*) pjsip_event_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * This structure describes Allow-Events header.

+ */

+typedef struct pjsip_allow_events_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_allow_events_hdr)

+    int		    event_cnt;			    /**< Number of event names. */

+    pj_str_t	    events[PJSIP_MAX_ALLOW_EVENTS]; /**< Event names. */

+} pjsip_allow_events_hdr;

+

+

+/**

+ * Create a new Allow-Events header.

+ *

+ * @param pool.	    The pool.

+ *

+ * @return	    Allow-Events header.

+ */

+PJ_DECL(pjsip_allow_events_hdr*) pjsip_allow_events_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * This structure describes Subscription-State header.

+ */

+typedef struct pjsip_sub_state_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_sub_state_hdr)

+    pj_str_t	    sub_state;		/**< Subscription state. */

+    pj_str_t	    reason_param;	/**< Optional termination reason. */

+    int		    expires_param;	/**< Expires param, or -1. */

+    int		    retry_after;	/**< Retry after param, or -1. */

+    pj_str_t	    other_param;	/**< Other parameter, concatenated together. */

+} pjsip_sub_state_hdr;

+

+/**

+ * Create new Subscription-State header.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    Subscription-State header.

+ */

+PJ_DECL(pjsip_sub_state_hdr*) pjsip_sub_state_hdr_create(pj_pool_t *pool);

+

+/**

+ * Initialize parser for event notify module.

+ */

+PJ_DEF(void) pjsip_event_notify_init_parser(void);

+

+

+PJ_END_DECL

+

+

+/**

+ * @}

+ */

+

+#endif	/* __PJSIP_SIMPLE_EVENT_NOTIFY_MSG_H__ */

+

diff --git a/pjsip/include/pjsip-simple/messaging.h b/pjsip/include/pjsip-simple/messaging.h
index ef7484b..22ef467 100644
--- a/pjsip/include/pjsip-simple/messaging.h
+++ b/pjsip/include/pjsip-simple/messaging.h
@@ -1,253 +1,275 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_SIMPLE_MESSAGING_H__
-#define __PJSIP_SIMPLE_MESSAGING_H__
-
-/**
- * @file messaging.h
- * @brief Instant Messaging Extension (RFC 3428)
- */
-
-#include <pjsip/sip_msg.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_MESSAGING SIP Instant Messaging (RFC 3428) Module
- * @ingroup PJSIP_SIMPLE
- * @{
- *
- * This module provides the implementation of SIP Extension for Instant
- * Messaging (RFC 3428). It extends PJSIP by supporting MESSAGE method.
- *
- * The RFC 3428 doesn't provide any means of dialog for the purpose of sending/
- * receiving instant messaging. IM with SIP is basicly sessionless, which means
- * that there is absolutely no correlation between IM messages sent or received
- * by a host. Any correlation between IM messages is only perceivable by
- * user, phsychologically.
- *
- * However, the RFC doesn't prohibit sending IM within a dialog (presumably
- * using the same Call-ID and CSeq namespace), although it prohibits creating
- * a dialog specificly for creating IM session.
- *
- * The implementation here is modeled to support both ways of sending IM msgs,
- * i.e. sending IM message individually and sending IM message within a dialog.
- * Although IM message can be associated with a dialog, this implementation of
- * IM module is completely independent of the User Agent library in PJSIP. Yes,
- * that's what is called modularity, and it demonstrates the clearness 
- * of PJSIP design (the last sentence is of course marketing crap :)).
- *
- * To send an IM message as part of dialog, application would first create the
- * message using #pjsip_messaging_create_msg, using dialog's Call-ID, CSeq,
- * From, and To header, then send the message using #pjsip_dlg_send_msg instead
- * of #pjsip_messaging_send_msg. 
- *
- * To send IM messages individually, application has two options. The first is
- * to create the request with #pjsip_messaging_create_msg then send it with
- * #pjsip_messaging_send_msg. But this way, application has to pre-construct
- * From and To header first, which is not too convenient.
- *
- * The second option (to send IM messages not associated with a dialog) is to
- * first create an 'IM session'. An 'IM session' here is not a SIP dialog, as
- * it doesn't have Contact header etc. An 'IM session' here is just a local
- * state to cache most of IM headers, for convenience and optimization. Appl 
- * creates an IM session with #pjsip_messaging_create_session, and destroy
- * the session with #pjsip_messaging_destroy_session. To create an outgoing
- * IM message, application would call #pjsip_messaging_session_create_msg,
- * and to send the message it would use #pjsip_messaging_send_msg.
- *
- * Message authorization is handled by application, as usual, by inserting a 
- * proper WWW-Authenticate or Proxy-Authenticate header before sending the 
- * message.
- *
- * And the last bit, to handle incoing IM messages.
- *
- * To handle incoming IM messages, application would register a global callback
- * to be called when incoming messages arrive, by registering with function
- * #pjsip_messaging_set_incoming_callback. This will be the global callback
- * for all incoming IM messages. Although the message was sent as part of
- * a dialog, it would still come here. And as long as the request has proper
- * identification (Call-ID, From/To tag), the dialog will be aware of the
- * request and update it's state (remote CSeq) accordingly.
- */
-
-
-
-/**
- * Typedef for callback to be called when outgoing message has been sent
- * and a final response has been received.
- */
-typedef void (*pjsip_messaging_cb)(void *token, int status_code);
-
-/**
- * Typedef for callback to receive incoming message.
- *
- * @param rdata	    Incoming message data.
- *
- * @return	    The status code to be returned back to original sender.
- *		    Application must return a final status code upon returning
- *		    from this function, or otherwise the stack will respond
- *		    with error.
- */
-typedef int (*pjsip_on_new_msg_cb)(pjsip_rx_data *rdata);
-
-/**
- * Opaque data type for instant messaging session.
- */
-typedef struct pjsip_messaging_session pjsip_messaging_session;
-
-/**
- * Get the messaging module.
- *
- * @return SIP module.
- */
-PJ_DECL(pjsip_module*) pjsip_messaging_get_module();
-
-/**
- * Set the global callback to be called when incoming message is received.
- *
- * @param cb	    The callback to be called when incoming message is received.
- *
- * @return	    The previous callback.
- */
-PJ_DECL(pjsip_on_new_msg_cb) 
-pjsip_messaging_set_incoming_callback(pjsip_on_new_msg_cb cb);
-
-
-/**
- * Create an instant message transmit data buffer using the specified arguments.
- * The returned transmit data buffers will have it's reference counter set
- * to 1, and when application send the buffer, the send function will decrement
- * the reference counter. When the reference counter reach zero, the buffer
- * will be deleted. As long as the function does not increment the buffer's 
- * reference counter between creating and sending the request,  the buffer 
- * will always be deleted and no memory leak will occur.
- *
- * @param endpt	    Endpoint instance.
- * @param target    Target URL.
- * @param from	    The "From" header, which content will be copied to request.
- *		    If the "From" header doesn't have a tag parameter, the
- *		    function will generate one.
- * @param to	    The "To" header, which content will be copied to request.
- * @param call_id   Optionally specify Call-ID, or put NULL to make this
- *		    function generate a unique Call-ID automatically.
- * @param cseq	    Optionally specify CSeq, or put -1 to make this function
- *		    generate a random CSeq.
- * @param text	    Optionally specify "text/plain" message body, or put NULL 
- *		    if application wants to put body other than "text/plain"
- *		    manually.
- *
- * @return	    SIP transmit data buffer, which reference count has been
- *		    set to 1.
- */
-PJ_DECL(pjsip_tx_data*) 
-pjsip_messaging_create_msg_from_hdr(pjsip_endpoint *endpt, 
-				    const pjsip_uri *target,
-				    const pjsip_from_hdr *from,
-				    const pjsip_to_hdr *to, 
-				    const pjsip_cid_hdr *call_id,
-				    int cseq, 
-				    const pj_str_t *text);
-
-/**
- * Create instant message, by specifying URL string for both From and To header.
- *
- * @param endpt	    Endpoint instance.
- * @param target    Target URL.
- * @param from	    URL of the sender.
- * @param to	    URL of the recipient.
- * @param call_id   Optionally specify Call-ID, or put NULL to make this
- *		    function generate a unique Call-ID automatically.
- * @param cseq	    Optionally specify CSeq, or put -1 to make this function
- *		    generate a random CSeq.
- * @param text	    Optionally specify "text/plain" message body, or put NULL 
- *		    if application wants to put body other than "text/plain"
- *		    manually.
- *
- * @return	    SIP transmit data buffer, which reference count has been
- *		    set to 1.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_messaging_create_msg( pjsip_endpoint *endpt, 
-						    const pj_str_t *target,
-						    const pj_str_t *from,
-						    const pj_str_t *to, 
-						    const pj_str_t *call_id,
-						    int cseq, 
-						    const pj_str_t *text);
-
-/**
- * Send the instant message transmit buffer and attach a callback to be called
- * when the request has received a final response. This function will decrement
- * the transmit buffer's reference counter, and when the reference counter
- * reach zero, the buffer will be deleted. As long as the function does not
- * increment the buffer's reference counter between creating the request and
- * calling this function, the buffer will always be deleted regardless whether
- * the sending was failed or succeeded.
- *
- * @param endpt	    Endpoint instance.
- * @param tdata	    Transmit data buffer.
- * @param token	    Token to be associated with the SIP transaction which sends
- *		    this request.
- * @param cb	    The callback to be called when the SIP request has received
- *		    a final response from destination.
- *
- * @return	    Zero if the transaction was started successfully. Note that
- *		    this doesn't mean the request has been received successfully
- *		    by remote recipient.
- */
-PJ_DECL(pj_status_t) pjsip_messaging_send_msg( pjsip_endpoint *endpt, 
-					       pjsip_tx_data *tdata, 
-					       void *token, 
-					       pjsip_messaging_cb cb );
-
-/**
- * Create an instant messaging session, which can conveniently be used to send
- * multiple instant messages to the same recipient.
- *
- * @param endpt	    Endpoint instance.
- * @param from	    URI of sender. The function will add a unique tag parameter
- *		    to this URI in the From header.
- * @param to	    URI of recipient.
- *
- * @return	    Messaging session.
- */
-PJ_DECL(pjsip_messaging_session*) 
-pjsip_messaging_create_session( pjsip_endpoint *endpt, 
-			        const pj_str_t *from,
-			        const pj_str_t *to );
-
-/**
- * Create an instant message using instant messaging session, and optionally
- * attach a text message.
- *
- * @param ses	    The instant messaging session.
- * @param text	    Optional "text/plain" message to be attached as the
- *		    message body. If this parameter is NULL, then no message
- *		    body will be created, and application can attach any
- *		    type of message body before the request is sent.
- *
- * @return	    SIP transmit data buffer, which reference counter has been
- *		    set to 1.
- */
-PJ_DECL(pjsip_tx_data*)
-pjsip_messaging_session_create_msg( pjsip_messaging_session *ses, 
-				    const pj_str_t *text );
-
-/**
- * Destroy an instant messaging session.
- *
- * @param ses	    The instant messaging session.
- *
- * @return	    Zero on successfull.
- */
-PJ_DECL(pj_status_t)
-pjsip_messaging_destroy_session( pjsip_messaging_session *ses );
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIMPLE_MESSAGING_H__

+#define __PJSIP_SIMPLE_MESSAGING_H__

+

+/**

+ * @file messaging.h

+ * @brief Instant Messaging Extension (RFC 3428)

+ */

+

+#include <pjsip/sip_msg.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_MESSAGING SIP Instant Messaging (RFC 3428) Module

+ * @ingroup PJSIP_SIMPLE

+ * @{

+ *

+ * This module provides the implementation of SIP Extension for Instant

+ * Messaging (RFC 3428). It extends PJSIP by supporting MESSAGE method.

+ *

+ * The RFC 3428 doesn't provide any means of dialog for the purpose of sending/

+ * receiving instant messaging. IM with SIP is basicly sessionless, which means

+ * that there is absolutely no correlation between IM messages sent or received

+ * by a host. Any correlation between IM messages is only perceivable by

+ * user, phsychologically.

+ *

+ * However, the RFC doesn't prohibit sending IM within a dialog (presumably

+ * using the same Call-ID and CSeq namespace), although it prohibits creating

+ * a dialog specificly for creating IM session.

+ *

+ * The implementation here is modeled to support both ways of sending IM msgs,

+ * i.e. sending IM message individually and sending IM message within a dialog.

+ * Although IM message can be associated with a dialog, this implementation of

+ * IM module is completely independent of the User Agent library in PJSIP. Yes,

+ * that's what is called modularity, and it demonstrates the clearness 

+ * of PJSIP design (the last sentence is of course marketing crap :)).

+ *

+ * To send an IM message as part of dialog, application would first create the

+ * message using #pjsip_messaging_create_msg, using dialog's Call-ID, CSeq,

+ * From, and To header, then send the message using #pjsip_dlg_send_msg instead

+ * of #pjsip_messaging_send_msg. 

+ *

+ * To send IM messages individually, application has two options. The first is

+ * to create the request with #pjsip_messaging_create_msg then send it with

+ * #pjsip_messaging_send_msg. But this way, application has to pre-construct

+ * From and To header first, which is not too convenient.

+ *

+ * The second option (to send IM messages not associated with a dialog) is to

+ * first create an 'IM session'. An 'IM session' here is not a SIP dialog, as

+ * it doesn't have Contact header etc. An 'IM session' here is just a local

+ * state to cache most of IM headers, for convenience and optimization. Appl 

+ * creates an IM session with #pjsip_messaging_create_session, and destroy

+ * the session with #pjsip_messaging_destroy_session. To create an outgoing

+ * IM message, application would call #pjsip_messaging_session_create_msg,

+ * and to send the message it would use #pjsip_messaging_send_msg.

+ *

+ * Message authorization is handled by application, as usual, by inserting a 

+ * proper WWW-Authenticate or Proxy-Authenticate header before sending the 

+ * message.

+ *

+ * And the last bit, to handle incoing IM messages.

+ *

+ * To handle incoming IM messages, application would register a global callback

+ * to be called when incoming messages arrive, by registering with function

+ * #pjsip_messaging_set_incoming_callback. This will be the global callback

+ * for all incoming IM messages. Although the message was sent as part of

+ * a dialog, it would still come here. And as long as the request has proper

+ * identification (Call-ID, From/To tag), the dialog will be aware of the

+ * request and update it's state (remote CSeq) accordingly.

+ */

+

+

+

+/**

+ * Typedef for callback to be called when outgoing message has been sent

+ * and a final response has been received.

+ */

+typedef void (*pjsip_messaging_cb)(void *token, int status_code);

+

+/**

+ * Typedef for callback to receive incoming message.

+ *

+ * @param rdata	    Incoming message data.

+ *

+ * @return	    The status code to be returned back to original sender.

+ *		    Application must return a final status code upon returning

+ *		    from this function, or otherwise the stack will respond

+ *		    with error.

+ */

+typedef int (*pjsip_on_new_msg_cb)(pjsip_rx_data *rdata);

+

+/**

+ * Opaque data type for instant messaging session.

+ */

+typedef struct pjsip_messaging_session pjsip_messaging_session;

+

+/**

+ * Get the messaging module.

+ *

+ * @return SIP module.

+ */

+PJ_DECL(pjsip_module*) pjsip_messaging_get_module();

+

+/**

+ * Set the global callback to be called when incoming message is received.

+ *

+ * @param cb	    The callback to be called when incoming message is received.

+ *

+ * @return	    The previous callback.

+ */

+PJ_DECL(pjsip_on_new_msg_cb) 

+pjsip_messaging_set_incoming_callback(pjsip_on_new_msg_cb cb);

+

+

+/**

+ * Create an instant message transmit data buffer using the specified arguments.

+ * The returned transmit data buffers will have it's reference counter set

+ * to 1, and when application send the buffer, the send function will decrement

+ * the reference counter. When the reference counter reach zero, the buffer

+ * will be deleted. As long as the function does not increment the buffer's 

+ * reference counter between creating and sending the request,  the buffer 

+ * will always be deleted and no memory leak will occur.

+ *

+ * @param endpt	    Endpoint instance.

+ * @param target    Target URL.

+ * @param from	    The "From" header, which content will be copied to request.

+ *		    If the "From" header doesn't have a tag parameter, the

+ *		    function will generate one.

+ * @param to	    The "To" header, which content will be copied to request.

+ * @param call_id   Optionally specify Call-ID, or put NULL to make this

+ *		    function generate a unique Call-ID automatically.

+ * @param cseq	    Optionally specify CSeq, or put -1 to make this function

+ *		    generate a random CSeq.

+ * @param text	    Optionally specify "text/plain" message body, or put NULL 

+ *		    if application wants to put body other than "text/plain"

+ *		    manually.

+ *

+ * @return	    SIP transmit data buffer, which reference count has been

+ *		    set to 1.

+ */

+PJ_DECL(pjsip_tx_data*) 

+pjsip_messaging_create_msg_from_hdr(pjsip_endpoint *endpt, 

+				    const pjsip_uri *target,

+				    const pjsip_from_hdr *from,

+				    const pjsip_to_hdr *to, 

+				    const pjsip_cid_hdr *call_id,

+				    int cseq, 

+				    const pj_str_t *text);

+

+/**

+ * Create instant message, by specifying URL string for both From and To header.

+ *

+ * @param endpt	    Endpoint instance.

+ * @param target    Target URL.

+ * @param from	    URL of the sender.

+ * @param to	    URL of the recipient.

+ * @param call_id   Optionally specify Call-ID, or put NULL to make this

+ *		    function generate a unique Call-ID automatically.

+ * @param cseq	    Optionally specify CSeq, or put -1 to make this function

+ *		    generate a random CSeq.

+ * @param text	    Optionally specify "text/plain" message body, or put NULL 

+ *		    if application wants to put body other than "text/plain"

+ *		    manually.

+ *

+ * @return	    SIP transmit data buffer, which reference count has been

+ *		    set to 1.

+ */

+PJ_DECL(pjsip_tx_data*) pjsip_messaging_create_msg( pjsip_endpoint *endpt, 

+						    const pj_str_t *target,

+						    const pj_str_t *from,

+						    const pj_str_t *to, 

+						    const pj_str_t *call_id,

+						    int cseq, 

+						    const pj_str_t *text);

+

+/**

+ * Send the instant message transmit buffer and attach a callback to be called

+ * when the request has received a final response. This function will decrement

+ * the transmit buffer's reference counter, and when the reference counter

+ * reach zero, the buffer will be deleted. As long as the function does not

+ * increment the buffer's reference counter between creating the request and

+ * calling this function, the buffer will always be deleted regardless whether

+ * the sending was failed or succeeded.

+ *

+ * @param endpt	    Endpoint instance.

+ * @param tdata	    Transmit data buffer.

+ * @param token	    Token to be associated with the SIP transaction which sends

+ *		    this request.

+ * @param cb	    The callback to be called when the SIP request has received

+ *		    a final response from destination.

+ *

+ * @return	    Zero if the transaction was started successfully. Note that

+ *		    this doesn't mean the request has been received successfully

+ *		    by remote recipient.

+ */

+PJ_DECL(pj_status_t) pjsip_messaging_send_msg( pjsip_endpoint *endpt, 

+					       pjsip_tx_data *tdata, 

+					       void *token, 

+					       pjsip_messaging_cb cb );

+

+/**

+ * Create an instant messaging session, which can conveniently be used to send

+ * multiple instant messages to the same recipient.

+ *

+ * @param endpt	    Endpoint instance.

+ * @param from	    URI of sender. The function will add a unique tag parameter

+ *		    to this URI in the From header.

+ * @param to	    URI of recipient.

+ *

+ * @return	    Messaging session.

+ */

+PJ_DECL(pjsip_messaging_session*) 

+pjsip_messaging_create_session( pjsip_endpoint *endpt, 

+			        const pj_str_t *from,

+			        const pj_str_t *to );

+

+/**

+ * Create an instant message using instant messaging session, and optionally

+ * attach a text message.

+ *

+ * @param ses	    The instant messaging session.

+ * @param text	    Optional "text/plain" message to be attached as the

+ *		    message body. If this parameter is NULL, then no message

+ *		    body will be created, and application can attach any

+ *		    type of message body before the request is sent.

+ *

+ * @return	    SIP transmit data buffer, which reference counter has been

+ *		    set to 1.

+ */

+PJ_DECL(pjsip_tx_data*)

+pjsip_messaging_session_create_msg( pjsip_messaging_session *ses, 

+				    const pj_str_t *text );

+

+/**

+ * Destroy an instant messaging session.

+ *

+ * @param ses	    The instant messaging session.

+ *

+ * @return	    Zero on successfull.

+ */

+PJ_DECL(pj_status_t)

+pjsip_messaging_destroy_session( pjsip_messaging_session *ses );

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif

diff --git a/pjsip/include/pjsip-simple/pidf.h b/pjsip/include/pjsip-simple/pidf.h
index a6caeb6..f95bdc8 100644
--- a/pjsip/include/pjsip-simple/pidf.h
+++ b/pjsip/include/pjsip-simple/pidf.h
@@ -1,161 +1,183 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_SIMPLE_PIDF_H__
-#define __PJSIP_SIMPLE_PIDF_H__
-
-/**
- * @file pidf.h
- * @brief PIDF/Presence Information Data Format (RFC 3863)
- */
-#include <pj/types.h>
-#include <pj/xml.h>
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJSIP_SIMPLE_PIDF PIDF/Presence Information Data Format (RFC 3863)
- * @ingroup PJSIP_SIMPLE
- * @{
- *
- * This file provides tools for manipulating Presence Information Data 
- * Format (PIDF) as described in RFC 3863.
- */
-typedef struct pj_xml_node pjpidf_pres;
-typedef struct pj_xml_node pjpidf_tuple;
-typedef struct pj_xml_node pjpidf_status;
-typedef struct pj_xml_node pjpidf_note;
-
-typedef struct pjpidf_status_op
-{
-    void	    (*construct)(pj_pool_t*, pjpidf_status*);
-    pj_bool_t	    (*is_basic_open)(const pjpidf_status*);
-    void	    (*set_basic_open)(pjpidf_status*, pj_bool_t);
-} pjpidf_status_op;
-
-typedef struct pjpidf_tuple_op
-{
-    void	    (*construct)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);
-
-    const pj_str_t* (*get_id)(const pjpidf_tuple* );
-    void	    (*set_id)(pj_pool_t*, pjpidf_tuple *, const pj_str_t*);
-
-    pjpidf_status*  (*get_status)(pjpidf_tuple* );
-
-    const pj_str_t* (*get_contact)(const pjpidf_tuple*);
-    void	    (*set_contact)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);
-    void	    (*set_contact_prio)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);
-    const pj_str_t* (*get_contact_prio)(const pjpidf_tuple*);
-
-    pjpidf_note*    (*add_note)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);
-    pjpidf_note*    (*get_first_note)(pjpidf_tuple*);
-    pjpidf_note*    (*get_next_note)(pjpidf_tuple*, pjpidf_note*);
-
-    const pj_str_t* (*get_timestamp)(const pjpidf_tuple*);
-    void	    (*set_timestamp)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);
-    void	    (*set_timestamp_np)(pj_pool_t*,pjpidf_tuple*, pj_str_t*);
-
-} pjpidf_tuple_op;
-
-typedef struct pjpidf_pres_op
-{
-    void	    (*construct)(pj_pool_t*, pjpidf_pres*, const pj_str_t*);
-
-    pjpidf_tuple*   (*add_tuple)(pj_pool_t*, pjpidf_pres*, const pj_str_t*);
-    pjpidf_tuple*   (*get_first_tuple)(pjpidf_pres*);
-    pjpidf_tuple*   (*get_next_tuple)(pjpidf_pres*, pjpidf_tuple*);
-    pjpidf_tuple*   (*find_tuple)(pjpidf_pres*, const pj_str_t*);
-    void	    (*remove_tuple)(pjpidf_pres*, pjpidf_tuple*);
-
-    pjpidf_note*    (*add_note)(pj_pool_t*, pjpidf_pres*, const pj_str_t*);
-    pjpidf_note*    (*get_first_note)(pjpidf_pres*);
-    pjpidf_note*    (*get_next_note)(pjpidf_pres*, pjpidf_note*);
-
-} pjpidf_pres_op;
-
-
-extern struct pjpidf_op_desc
-{
-    pjpidf_pres_op	pres;
-    pjpidf_tuple_op	tuple;
-    pjpidf_status_op	status;
-} pjpidf_op;
-
-
-/******************************************************************************
- * Top level API for managing presence document. 
- *****************************************************************************/
-PJ_DECL(pjpidf_pres*)    pjpidf_create(pj_pool_t *pool, const pj_str_t *entity);
-PJ_DECL(pjpidf_pres*)	 pjpidf_parse(pj_pool_t *pool, char *text, int len);
-PJ_DECL(int)		 pjpidf_print(const pjpidf_pres* pres, char *buf, int len);
-
-
-/******************************************************************************
- * API for managing Presence node.
- *****************************************************************************/
-PJ_DECL(void)		 pjpidf_pres_construct(pj_pool_t *pool, pjpidf_pres *pres,
-					       const pj_str_t *entity);
-PJ_DECL(pjpidf_tuple*)	 pjpidf_pres_add_tuple(pj_pool_t *pool, pjpidf_pres *pres, 
-					       const pj_str_t *id);
-PJ_DECL(pjpidf_tuple*)	 pjpidf_pres_get_first_tuple(pjpidf_pres *pres);
-PJ_DECL(pjpidf_tuple*)	 pjpidf_pres_get_next_tuple(pjpidf_pres *pres, 
-						    pjpidf_tuple *t);
-PJ_DECL(pjpidf_tuple*)	 pjpidf_pres_find_tuple(pjpidf_pres *pres, 
-						const pj_str_t *id);
-PJ_DECL(void)		 pjpidf_pres_remove_tuple(pjpidf_pres *pres, 
-						  pjpidf_tuple*);
-
-PJ_DECL(pjpidf_note*)	 pjpidf_pres_add_note(pj_pool_t *pool, pjpidf_pres *pres, 
-					      const pj_str_t *text);
-PJ_DECL(pjpidf_note*)	 pjpidf_pres_get_first_note(pjpidf_pres *pres);
-PJ_DECL(pjpidf_note*)	 pjpidf_pres_get_next_note(pjpidf_pres*, pjpidf_note*);
-
-
-/******************************************************************************
- * API for managing Tuple node.
- *****************************************************************************/
-PJ_DECL(void)		 pjpidf_tuple_construct(pj_pool_t *pool, pjpidf_tuple *t,
-						const pj_str_t *id);
-PJ_DECL(const pj_str_t*) pjpidf_tuple_get_id(const pjpidf_tuple *t );
-PJ_DECL(void)		 pjpidf_tuple_set_id(pj_pool_t *pool, pjpidf_tuple *t, 
-					     const pj_str_t *id);
-
-PJ_DECL(pjpidf_status*)  pjpidf_tuple_get_status(pjpidf_tuple *t);
-
-PJ_DECL(const pj_str_t*) pjpidf_tuple_get_contact(const pjpidf_tuple *t);
-PJ_DECL(void)		 pjpidf_tuple_set_contact(pj_pool_t *pool, pjpidf_tuple *t, 
-						  const pj_str_t *contact);
-PJ_DECL(void)		 pjpidf_tuple_set_contact_prio(pj_pool_t *pool, pjpidf_tuple *t, 
-						       const pj_str_t *prio);
-PJ_DECL(const pj_str_t*) pjpidf_tuple_get_contact_prio(const pjpidf_tuple *t);
-
-PJ_DECL(pjpidf_note*)	 pjpidf_tuple_add_note(pj_pool_t *pool, pjpidf_tuple *t,
-					       const pj_str_t *text);
-PJ_DECL(pjpidf_note*)	 pjpidf_tuple_get_first_note(pjpidf_tuple *t);
-PJ_DECL(pjpidf_note*)	 pjpidf_tuple_get_next_note(pjpidf_tuple *t, pjpidf_note *n);
-
-PJ_DECL(const pj_str_t*) pjpidf_tuple_get_timestamp(const pjpidf_tuple *t);
-PJ_DECL(void)		 pjpidf_tuple_set_timestamp(pj_pool_t *pool, pjpidf_tuple *t,
-						    const pj_str_t *ts);
-PJ_DECL(void)		 pjpidf_tuple_set_timestamp_np(	pj_pool_t*, pjpidf_tuple *t,
-							pj_str_t *ts);
-
-
-/******************************************************************************
- * API for managing Status node.
- *****************************************************************************/
-PJ_DECL(void)		 pjpidf_status_construct(pj_pool_t*, pjpidf_status*);
-PJ_DECL(pj_bool_t)	 pjpidf_status_is_basic_open(const pjpidf_status*);
-PJ_DECL(void)		 pjpidf_status_set_basic_open(pjpidf_status*, pj_bool_t);
-
-
-/**
- * @}
- */
-
-
-PJ_END_DECL
-
-
-#endif	/* __PJSIP_SIMPLE_PIDF_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIMPLE_PIDF_H__

+#define __PJSIP_SIMPLE_PIDF_H__

+

+/**

+ * @file pidf.h

+ * @brief PIDF/Presence Information Data Format (RFC 3863)

+ */

+#include <pj/types.h>

+#include <pj/xml.h>

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJSIP_SIMPLE_PIDF PIDF/Presence Information Data Format (RFC 3863)

+ * @ingroup PJSIP_SIMPLE

+ * @{

+ *

+ * This file provides tools for manipulating Presence Information Data 

+ * Format (PIDF) as described in RFC 3863.

+ */

+typedef struct pj_xml_node pjpidf_pres;

+typedef struct pj_xml_node pjpidf_tuple;

+typedef struct pj_xml_node pjpidf_status;

+typedef struct pj_xml_node pjpidf_note;

+

+typedef struct pjpidf_status_op

+{

+    void	    (*construct)(pj_pool_t*, pjpidf_status*);

+    pj_bool_t	    (*is_basic_open)(const pjpidf_status*);

+    void	    (*set_basic_open)(pjpidf_status*, pj_bool_t);

+} pjpidf_status_op;

+

+typedef struct pjpidf_tuple_op

+{

+    void	    (*construct)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);

+

+    const pj_str_t* (*get_id)(const pjpidf_tuple* );

+    void	    (*set_id)(pj_pool_t*, pjpidf_tuple *, const pj_str_t*);

+

+    pjpidf_status*  (*get_status)(pjpidf_tuple* );

+

+    const pj_str_t* (*get_contact)(const pjpidf_tuple*);

+    void	    (*set_contact)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);

+    void	    (*set_contact_prio)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);

+    const pj_str_t* (*get_contact_prio)(const pjpidf_tuple*);

+

+    pjpidf_note*    (*add_note)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);

+    pjpidf_note*    (*get_first_note)(pjpidf_tuple*);

+    pjpidf_note*    (*get_next_note)(pjpidf_tuple*, pjpidf_note*);

+

+    const pj_str_t* (*get_timestamp)(const pjpidf_tuple*);

+    void	    (*set_timestamp)(pj_pool_t*, pjpidf_tuple*, const pj_str_t*);

+    void	    (*set_timestamp_np)(pj_pool_t*,pjpidf_tuple*, pj_str_t*);

+

+} pjpidf_tuple_op;

+

+typedef struct pjpidf_pres_op

+{

+    void	    (*construct)(pj_pool_t*, pjpidf_pres*, const pj_str_t*);

+

+    pjpidf_tuple*   (*add_tuple)(pj_pool_t*, pjpidf_pres*, const pj_str_t*);

+    pjpidf_tuple*   (*get_first_tuple)(pjpidf_pres*);

+    pjpidf_tuple*   (*get_next_tuple)(pjpidf_pres*, pjpidf_tuple*);

+    pjpidf_tuple*   (*find_tuple)(pjpidf_pres*, const pj_str_t*);

+    void	    (*remove_tuple)(pjpidf_pres*, pjpidf_tuple*);

+

+    pjpidf_note*    (*add_note)(pj_pool_t*, pjpidf_pres*, const pj_str_t*);

+    pjpidf_note*    (*get_first_note)(pjpidf_pres*);

+    pjpidf_note*    (*get_next_note)(pjpidf_pres*, pjpidf_note*);

+

+} pjpidf_pres_op;

+

+

+extern struct pjpidf_op_desc

+{

+    pjpidf_pres_op	pres;

+    pjpidf_tuple_op	tuple;

+    pjpidf_status_op	status;

+} pjpidf_op;

+

+

+/******************************************************************************

+ * Top level API for managing presence document. 

+ *****************************************************************************/

+PJ_DECL(pjpidf_pres*)    pjpidf_create(pj_pool_t *pool, const pj_str_t *entity);

+PJ_DECL(pjpidf_pres*)	 pjpidf_parse(pj_pool_t *pool, char *text, int len);

+PJ_DECL(int)		 pjpidf_print(const pjpidf_pres* pres, char *buf, int len);

+

+

+/******************************************************************************

+ * API for managing Presence node.

+ *****************************************************************************/

+PJ_DECL(void)		 pjpidf_pres_construct(pj_pool_t *pool, pjpidf_pres *pres,

+					       const pj_str_t *entity);

+PJ_DECL(pjpidf_tuple*)	 pjpidf_pres_add_tuple(pj_pool_t *pool, pjpidf_pres *pres, 

+					       const pj_str_t *id);

+PJ_DECL(pjpidf_tuple*)	 pjpidf_pres_get_first_tuple(pjpidf_pres *pres);

+PJ_DECL(pjpidf_tuple*)	 pjpidf_pres_get_next_tuple(pjpidf_pres *pres, 

+						    pjpidf_tuple *t);

+PJ_DECL(pjpidf_tuple*)	 pjpidf_pres_find_tuple(pjpidf_pres *pres, 

+						const pj_str_t *id);

+PJ_DECL(void)		 pjpidf_pres_remove_tuple(pjpidf_pres *pres, 

+						  pjpidf_tuple*);

+

+PJ_DECL(pjpidf_note*)	 pjpidf_pres_add_note(pj_pool_t *pool, pjpidf_pres *pres, 

+					      const pj_str_t *text);

+PJ_DECL(pjpidf_note*)	 pjpidf_pres_get_first_note(pjpidf_pres *pres);

+PJ_DECL(pjpidf_note*)	 pjpidf_pres_get_next_note(pjpidf_pres*, pjpidf_note*);

+

+

+/******************************************************************************

+ * API for managing Tuple node.

+ *****************************************************************************/

+PJ_DECL(void)		 pjpidf_tuple_construct(pj_pool_t *pool, pjpidf_tuple *t,

+						const pj_str_t *id);

+PJ_DECL(const pj_str_t*) pjpidf_tuple_get_id(const pjpidf_tuple *t );

+PJ_DECL(void)		 pjpidf_tuple_set_id(pj_pool_t *pool, pjpidf_tuple *t, 

+					     const pj_str_t *id);

+

+PJ_DECL(pjpidf_status*)  pjpidf_tuple_get_status(pjpidf_tuple *t);

+

+PJ_DECL(const pj_str_t*) pjpidf_tuple_get_contact(const pjpidf_tuple *t);

+PJ_DECL(void)		 pjpidf_tuple_set_contact(pj_pool_t *pool, pjpidf_tuple *t, 

+						  const pj_str_t *contact);

+PJ_DECL(void)		 pjpidf_tuple_set_contact_prio(pj_pool_t *pool, pjpidf_tuple *t, 

+						       const pj_str_t *prio);

+PJ_DECL(const pj_str_t*) pjpidf_tuple_get_contact_prio(const pjpidf_tuple *t);

+

+PJ_DECL(pjpidf_note*)	 pjpidf_tuple_add_note(pj_pool_t *pool, pjpidf_tuple *t,

+					       const pj_str_t *text);

+PJ_DECL(pjpidf_note*)	 pjpidf_tuple_get_first_note(pjpidf_tuple *t);

+PJ_DECL(pjpidf_note*)	 pjpidf_tuple_get_next_note(pjpidf_tuple *t, pjpidf_note *n);

+

+PJ_DECL(const pj_str_t*) pjpidf_tuple_get_timestamp(const pjpidf_tuple *t);

+PJ_DECL(void)		 pjpidf_tuple_set_timestamp(pj_pool_t *pool, pjpidf_tuple *t,

+						    const pj_str_t *ts);

+PJ_DECL(void)		 pjpidf_tuple_set_timestamp_np(	pj_pool_t*, pjpidf_tuple *t,

+							pj_str_t *ts);

+

+

+/******************************************************************************

+ * API for managing Status node.

+ *****************************************************************************/

+PJ_DECL(void)		 pjpidf_status_construct(pj_pool_t*, pjpidf_status*);

+PJ_DECL(pj_bool_t)	 pjpidf_status_is_basic_open(const pjpidf_status*);

+PJ_DECL(void)		 pjpidf_status_set_basic_open(pjpidf_status*, pj_bool_t);

+

+

+/**

+ * @}

+ */

+

+

+PJ_END_DECL

+

+

+#endif	/* __PJSIP_SIMPLE_PIDF_H__ */

diff --git a/pjsip/include/pjsip-simple/presence.h b/pjsip/include/pjsip-simple/presence.h
index 80ed93c..b694d85 100644
--- a/pjsip/include/pjsip-simple/presence.h
+++ b/pjsip/include/pjsip-simple/presence.h
@@ -1,214 +1,236 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_SIMPLE_PRESENCE_H__
-#define __PJSIP_SIMPLE_PRESENCE_H__
-
-/**
- * @file presence.h
- * @brief SIP Extension for Presence (RFC 3856)
- */
-#include <pjsip_simple/event_notify.h>
-#include <pjsip_simple/pidf.h>
-#include <pjsip_simple/xpidf.h>
-
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJSIP_SIMPLE_PRES SIP Extension for Presence (RFC 3856)
- * @ingroup PJSIP_SIMPLE
- * @{
- *
- * This module contains the implementation of SIP Presence Extension as 
- * described in RFC 3856. It uses the SIP Event Notification framework
- * (event_notify.h) and extends the framework by implementing "presence"
- * event package.
- */
-
-/**
- * Presence message body type.
- */
-typedef enum pjsip_pres_type
-{
-    PJSIP_PRES_TYPE_PIDF,
-    PJSIP_PRES_TYPE_XPIDF,
-} pjsip_pres_type;
-
-/**
- * This structure describe a presentity, for both subscriber and notifier.
- */
-typedef struct pjsip_presentity
-{
-    pjsip_event_sub *sub;	    /**< Event subscribtion record.	*/
-    pjsip_pres_type  pres_type;	    /**< Presentity type.		*/
-    pjsip_msg_body  *uas_body;	    /**< Message body (UAS only).	*/
-    union {
-	pjpidf_pres *pidf;
-	pjxpidf_pres *xpidf;
-    }		     uas_data;	    /**< UAS data.			*/
-    pj_str_t	     timestamp;	    /**< Time of last update.		*/
-    void	    *user_data;	    /**< Application data.		*/
-} pjsip_presentity;
-
-
-/**
- * This structure describe callback that is registered to receive notification
- * from the presence module.
- */
-typedef struct pjsip_presence_cb
-{
-    /**
-     * This callback is first called when the module receives incoming 
-     * SUBSCRIBE request to determine whether application wants to accept
-     * the request. If it does, then on_presence_request will be called.
-     *
-     * @param rdata	The received message.
-     * @return		Application should return 2xx to accept the request,
-     *			or failure status (>=300) to reject the request.
-     */
-    void (*accept_presence)(pjsip_rx_data *rdata, int *status);
-
-    /**
-     * This callback is called when the module receive the first presence
-     * subscription request.
-     *
-     * @param pres	The presence descriptor.
-     * @param rdata	The incoming request.
-     * @param timeout	Timeout to be set for incoming request. Otherwise
-     *			app can just leave this and accept the default.
-     */
-    void (*on_received_request)(pjsip_presentity *pres, pjsip_rx_data *rdata,
-				int *timeout);
-
-    /**
-     * This callback is called when the module received subscription refresh
-     * request.
-     *
-     * @param pres	The presence descriptor.
-     * @param rdata	The incoming request.
-     */
-    void (*on_received_refresh)(pjsip_presentity *pres, pjsip_rx_data *rdata);
-
-    /**
-     * This callback is called when the module receives incoming NOTIFY
-     * request.
-     *
-     * @param pres	The presence descriptor.
-     * @param open	The latest status of the presentity.
-     */
-    void (*on_received_update)(pjsip_presentity *pres, pj_bool_t open);
-
-    /**
-     * This callback is called when the subscription has terminated.
-     *
-     * @param sub	The subscription instance.
-     * @param reason	The termination reason.
-     */
-    void (*on_terminated)(pjsip_presentity *pres, const pj_str_t *reason);
-
-} pjsip_presence_cb;
-
-
-/**
- * Initialize the presence module and register callback.
- *
- * @param cb		Callback structure.
- */
-PJ_DECL(void) pjsip_presence_init(const pjsip_presence_cb *cb);
-
-
-/**
- * Create to presence subscription of a presentity URL.
- *
- * @param endpt		Endpoint instance.
- * @param local_url	Local URL.
- * @param remote_url	Remote URL which the presence is being subscribed.
- * @param expires	The expiration.
- * @param user_data	User data to attach to presence subscription.
- *
- * @return		The presence structure if successfull, or NULL if
- *			failed.
- */
-PJ_DECL(pjsip_presentity*) pjsip_presence_create( pjsip_endpoint *endpt,
-						  const pj_str_t *local_url,
-						  const pj_str_t *remote_url,
-						  int expires,
-						  void *user_data );
-
-/**
- * Set credentials to be used by this presentity for outgoing requests.
- *
- * @param pres		Presentity instance.
- * @param count		Number of credentials in the array.
- * @param cred		Array of credentials.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_presence_set_credentials( pjsip_presentity *pres,
-						     int count,
-						     const pjsip_cred_info cred[]);
-
-/**
- * Set route set for outgoing requests.
- *
- * @param pres		Presentity instance.
- * @param route_set	List of route headers.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_presence_set_route_set( pjsip_presentity *pres,
-						   const pjsip_route_hdr *hdr );
-
-/**
- * Send SUBSCRIBE request for the specified presentity.
- *
- * @param pres		The presentity instance.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_presence_subscribe( pjsip_presentity *pres );
-
-/**
- * Ceased the presence subscription.
- *
- * @param pres		The presence structure.
- * 
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_presence_unsubscribe( pjsip_presentity *pres );
-
-/**
- * Notify subscriber about change in local status.
- *
- * @param pres		The presence structure.
- * @param state		Set the state of the subscription.
- * @param open		Set the presence status (open or closed).
- *
- * @return		Zero if a NOTIFY request can be sent.
- */
-PJ_DECL(pj_status_t) pjsip_presence_notify( pjsip_presentity *pres,
-					    pjsip_event_sub_state state,
-					    pj_bool_t open );
-
-/**
- * Destroy presence structure and the underlying subscription.
- *
- * @param pres		The presence structure.
- *
- * @return		Zero if the subscription was destroyed, or one if
- *			the subscription can not be destroyed immediately
- *			and will be destroyed later, or -1 if failed.
- */
-PJ_DECL(pj_status_t) pjsip_presence_destroy( pjsip_presentity *pres );
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-
-#endif	/* __PJSIP_SIMPLE_PRESENCE_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIMPLE_PRESENCE_H__

+#define __PJSIP_SIMPLE_PRESENCE_H__

+

+/**

+ * @file presence.h

+ * @brief SIP Extension for Presence (RFC 3856)

+ */

+#include <pjsip_simple/event_notify.h>

+#include <pjsip_simple/pidf.h>

+#include <pjsip_simple/xpidf.h>

+

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJSIP_SIMPLE_PRES SIP Extension for Presence (RFC 3856)

+ * @ingroup PJSIP_SIMPLE

+ * @{

+ *

+ * This module contains the implementation of SIP Presence Extension as 

+ * described in RFC 3856. It uses the SIP Event Notification framework

+ * (event_notify.h) and extends the framework by implementing "presence"

+ * event package.

+ */

+

+/**

+ * Presence message body type.

+ */

+typedef enum pjsip_pres_type

+{

+    PJSIP_PRES_TYPE_PIDF,

+    PJSIP_PRES_TYPE_XPIDF,

+} pjsip_pres_type;

+

+/**

+ * This structure describe a presentity, for both subscriber and notifier.

+ */

+typedef struct pjsip_presentity

+{

+    pjsip_event_sub *sub;	    /**< Event subscribtion record.	*/

+    pjsip_pres_type  pres_type;	    /**< Presentity type.		*/

+    pjsip_msg_body  *uas_body;	    /**< Message body (UAS only).	*/

+    union {

+	pjpidf_pres *pidf;

+	pjxpidf_pres *xpidf;

+    }		     uas_data;	    /**< UAS data.			*/

+    pj_str_t	     timestamp;	    /**< Time of last update.		*/

+    void	    *user_data;	    /**< Application data.		*/

+} pjsip_presentity;

+

+

+/**

+ * This structure describe callback that is registered to receive notification

+ * from the presence module.

+ */

+typedef struct pjsip_presence_cb

+{

+    /**

+     * This callback is first called when the module receives incoming 

+     * SUBSCRIBE request to determine whether application wants to accept

+     * the request. If it does, then on_presence_request will be called.

+     *

+     * @param rdata	The received message.

+     * @return		Application should return 2xx to accept the request,

+     *			or failure status (>=300) to reject the request.

+     */

+    void (*accept_presence)(pjsip_rx_data *rdata, int *status);

+

+    /**

+     * This callback is called when the module receive the first presence

+     * subscription request.

+     *

+     * @param pres	The presence descriptor.

+     * @param rdata	The incoming request.

+     * @param timeout	Timeout to be set for incoming request. Otherwise

+     *			app can just leave this and accept the default.

+     */

+    void (*on_received_request)(pjsip_presentity *pres, pjsip_rx_data *rdata,

+				int *timeout);

+

+    /**

+     * This callback is called when the module received subscription refresh

+     * request.

+     *

+     * @param pres	The presence descriptor.

+     * @param rdata	The incoming request.

+     */

+    void (*on_received_refresh)(pjsip_presentity *pres, pjsip_rx_data *rdata);

+

+    /**

+     * This callback is called when the module receives incoming NOTIFY

+     * request.

+     *

+     * @param pres	The presence descriptor.

+     * @param open	The latest status of the presentity.

+     */

+    void (*on_received_update)(pjsip_presentity *pres, pj_bool_t open);

+

+    /**

+     * This callback is called when the subscription has terminated.

+     *

+     * @param sub	The subscription instance.

+     * @param reason	The termination reason.

+     */

+    void (*on_terminated)(pjsip_presentity *pres, const pj_str_t *reason);

+

+} pjsip_presence_cb;

+

+

+/**

+ * Initialize the presence module and register callback.

+ *

+ * @param cb		Callback structure.

+ */

+PJ_DECL(void) pjsip_presence_init(const pjsip_presence_cb *cb);

+

+

+/**

+ * Create to presence subscription of a presentity URL.

+ *

+ * @param endpt		Endpoint instance.

+ * @param local_url	Local URL.

+ * @param remote_url	Remote URL which the presence is being subscribed.

+ * @param expires	The expiration.

+ * @param user_data	User data to attach to presence subscription.

+ *

+ * @return		The presence structure if successfull, or NULL if

+ *			failed.

+ */

+PJ_DECL(pjsip_presentity*) pjsip_presence_create( pjsip_endpoint *endpt,

+						  const pj_str_t *local_url,

+						  const pj_str_t *remote_url,

+						  int expires,

+						  void *user_data );

+

+/**

+ * Set credentials to be used by this presentity for outgoing requests.

+ *

+ * @param pres		Presentity instance.

+ * @param count		Number of credentials in the array.

+ * @param cred		Array of credentials.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_presence_set_credentials( pjsip_presentity *pres,

+						     int count,

+						     const pjsip_cred_info cred[]);

+

+/**

+ * Set route set for outgoing requests.

+ *

+ * @param pres		Presentity instance.

+ * @param route_set	List of route headers.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_presence_set_route_set( pjsip_presentity *pres,

+						   const pjsip_route_hdr *hdr );

+

+/**

+ * Send SUBSCRIBE request for the specified presentity.

+ *

+ * @param pres		The presentity instance.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_presence_subscribe( pjsip_presentity *pres );

+

+/**

+ * Ceased the presence subscription.

+ *

+ * @param pres		The presence structure.

+ * 

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_presence_unsubscribe( pjsip_presentity *pres );

+

+/**

+ * Notify subscriber about change in local status.

+ *

+ * @param pres		The presence structure.

+ * @param state		Set the state of the subscription.

+ * @param open		Set the presence status (open or closed).

+ *

+ * @return		Zero if a NOTIFY request can be sent.

+ */

+PJ_DECL(pj_status_t) pjsip_presence_notify( pjsip_presentity *pres,

+					    pjsip_event_sub_state state,

+					    pj_bool_t open );

+

+/**

+ * Destroy presence structure and the underlying subscription.

+ *

+ * @param pres		The presence structure.

+ *

+ * @return		Zero if the subscription was destroyed, or one if

+ *			the subscription can not be destroyed immediately

+ *			and will be destroyed later, or -1 if failed.

+ */

+PJ_DECL(pj_status_t) pjsip_presence_destroy( pjsip_presentity *pres );

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+

+#endif	/* __PJSIP_SIMPLE_PRESENCE_H__ */

diff --git a/pjsip/include/pjsip-simple/xpidf.h b/pjsip/include/pjsip-simple/xpidf.h
index 27254fa..4ca1d70 100644
--- a/pjsip/include/pjsip-simple/xpidf.h
+++ b/pjsip/include/pjsip-simple/xpidf.h
@@ -1,118 +1,140 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_SIMPLE_XPIDF_H__
-#define __PJSIP_SIMPLE_XPIDF_H__
-
-/**
- * @file xpidf.h
- * @brief XPIDF/Presence Information Data Format
- */
-#include <pj/types.h>
-#include <pj/xml.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_SIMPLE_XPIDF XPIDF/Presence Information Data Format
- * @ingroup PJSIP_SIMPLE
- * @{
- *
- * This is an old presence data format as described in:
- * draft-rosenberg-impp-pidf-00.txt.
- *
- * We won't support this format extensively here, as it seems there's not
- * too many implementations support this anymore, as it shouldn't.
- */
-
-/** Type definitions for XPIDF root document. */
-typedef pj_xml_node pjxpidf_pres;
-
-
-/**
- * Create a new XPIDF document.
- *
- * @param pool	    Pool.
- * @param uri	    URI to set in the XPIDF document.
- *
- * @return	    XPIDF document.
- */
-PJ_DECL(pjxpidf_pres*) pjxpidf_create(pj_pool_t *pool, const pj_str_t *uri);
-
-
-/**
- * Parse XPIDF document.
- *
- * @param pool	    Pool.
- * @param text	    Input text.
- * @param len	    Length of input text.
- *
- * @return	    XPIDF document.
- */
-PJ_DECL(pjxpidf_pres*) pjxpidf_parse(pj_pool_t *pool, char *text, pj_size_t len);
-
-
-/**
- * Print XPIDF document.
- *
- * @param pres	    The XPIDF document to print.
- * @param text	    Buffer to place the output.
- * @param len	    Length of the buffer.
- *
- * @return	    The length printed.
- */
-PJ_DECL(int) pjxpidf_print( pjxpidf_pres *pres, char *text, pj_size_t len);
-
-
-/**
- * Get URI in the XPIDF document
- *
- * @param pres	    XPIDF document
- *
- * @return	    The URI, or an empty string.
- */
-PJ_DECL(pj_str_t*) pjxpidf_get_uri(pjxpidf_pres *pres);
-
-
-/**
- * Set the URI of the XPIDF document.
- *
- * @param pool	    Pool.
- * @param pres	    The XPIDF document.
- * @param uri	    URI to set in the XPIDF document.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pjxpidf_set_uri(pj_pool_t *pool, pjxpidf_pres *pres, 
-				     const pj_str_t *uri);
-
-
-/**
- * Get presence status in the XPIDF document.
- *
- * @param pres	    XPIDF document.
- *
- * @return	    True to indicate the contact is online.
- */
-PJ_DECL(pj_bool_t) pjxpidf_get_status(pjxpidf_pres *pres);
-
-
-/**
- * Set presence status in the XPIDF document.
- *
- * @param pres	    XPIDF document.
- * @param status    Status to set, True for online, False for offline.
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pjxpidf_set_status(pjxpidf_pres *pres, pj_bool_t status);
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-
-#endif	/* __PJSIP_SIMPLE_XPIDF_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIMPLE_XPIDF_H__

+#define __PJSIP_SIMPLE_XPIDF_H__

+

+/**

+ * @file xpidf.h

+ * @brief XPIDF/Presence Information Data Format

+ */

+#include <pj/types.h>

+#include <pj/xml.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_SIMPLE_XPIDF XPIDF/Presence Information Data Format

+ * @ingroup PJSIP_SIMPLE

+ * @{

+ *

+ * This is an old presence data format as described in:

+ * draft-rosenberg-impp-pidf-00.txt.

+ *

+ * We won't support this format extensively here, as it seems there's not

+ * too many implementations support this anymore, as it shouldn't.

+ */

+

+/** Type definitions for XPIDF root document. */

+typedef pj_xml_node pjxpidf_pres;

+

+

+/**

+ * Create a new XPIDF document.

+ *

+ * @param pool	    Pool.

+ * @param uri	    URI to set in the XPIDF document.

+ *

+ * @return	    XPIDF document.

+ */

+PJ_DECL(pjxpidf_pres*) pjxpidf_create(pj_pool_t *pool, const pj_str_t *uri);

+

+

+/**

+ * Parse XPIDF document.

+ *

+ * @param pool	    Pool.

+ * @param text	    Input text.

+ * @param len	    Length of input text.

+ *

+ * @return	    XPIDF document.

+ */

+PJ_DECL(pjxpidf_pres*) pjxpidf_parse(pj_pool_t *pool, char *text, pj_size_t len);

+

+

+/**

+ * Print XPIDF document.

+ *

+ * @param pres	    The XPIDF document to print.

+ * @param text	    Buffer to place the output.

+ * @param len	    Length of the buffer.

+ *

+ * @return	    The length printed.

+ */

+PJ_DECL(int) pjxpidf_print( pjxpidf_pres *pres, char *text, pj_size_t len);

+

+

+/**

+ * Get URI in the XPIDF document

+ *

+ * @param pres	    XPIDF document

+ *

+ * @return	    The URI, or an empty string.

+ */

+PJ_DECL(pj_str_t*) pjxpidf_get_uri(pjxpidf_pres *pres);

+

+

+/**

+ * Set the URI of the XPIDF document.

+ *

+ * @param pool	    Pool.

+ * @param pres	    The XPIDF document.

+ * @param uri	    URI to set in the XPIDF document.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pjxpidf_set_uri(pj_pool_t *pool, pjxpidf_pres *pres, 

+				     const pj_str_t *uri);

+

+

+/**

+ * Get presence status in the XPIDF document.

+ *

+ * @param pres	    XPIDF document.

+ *

+ * @return	    True to indicate the contact is online.

+ */

+PJ_DECL(pj_bool_t) pjxpidf_get_status(pjxpidf_pres *pres);

+

+

+/**

+ * Set presence status in the XPIDF document.

+ *

+ * @param pres	    XPIDF document.

+ * @param status    Status to set, True for online, False for offline.

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pjxpidf_set_status(pjxpidf_pres *pres, pj_bool_t status);

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+

+#endif	/* __PJSIP_SIMPLE_XPIDF_H__ */

diff --git a/pjsip/include/pjsip-ua/sip_dialog.h b/pjsip/include/pjsip-ua/sip_dialog.h
index 14f0159..07e98f5 100644
--- a/pjsip/include/pjsip-ua/sip_dialog.h
+++ b/pjsip/include/pjsip-ua/sip_dialog.h
@@ -1,620 +1,642 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_DIALOG_H__
-#define __PJSIP_DIALOG_H__
-
-/**
- * @file dialog.h
- * @brief SIP Dialog abstraction
- */
-
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_auth.h>
-#include <pj/sock.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSUA_DIALOG SIP Dialog
- * @ingroup PJSUA
- * @{
- * \brief
- *   This file contains SIP dialog, a higher level abstraction of SIP session.
- *
- * \par Overview
- * A SIP dialog is an abstraction of communication session between two user 
- * agents that persist for some time. The dialog facilitates sequencing of 
- * messages between the user agents and proper routing of requests between both
- * of them. The dialog represents a context in which to interpret SIP messages.
- * However method independent User Agent processing for requests and responses 
- * outside of a dialog exists, hence a dialog is not necessary for message 
- * processing.
- *
- * A dialog is identified at each User Agent with a dialog Id, which consists 
- * of a Call-Id value, a local tag and a remote tag. 
- *
- * A dialog contains certain pieces of data needed for further message 
- * transmissions within the dialog. This data consists of:
- *  - Dialog Id - used to identify the dialog.
- *  - Local sequence number - used to order requests from the UA to its peer.
- *  - Remote sequence number - used to order requests from its peer to the UA.
- *  - Local URI - the address of the local party.
- *  - Remote URI - the address of the remote party.
- *  - Remote target - the address from the Contact header field of the request 
- *    or response or refresh request or response.
- *  - "secure" boolean - determines if the dialog is secure.
- *  - Route set - an ordered list of URIs. The route set is the list of servers
- *    that need to be traversed to send a request to the peer. 
- *  - Authentication info - array of authentication credentials to be used
- *    by the dialog to authenticate to proxies and servers.
- *
- * \par Manipulating Dialog
- * Application should use functions declared in this file to do something with 
- * the dialog. Among other things, application can:
- *   - create outgoing dialog (#pjsip_dlg_init()).
- *   - sends outgoing invitation (#pjsip_dlg_invite()).
- *   - sends response (provisional and final) to incoming invitation
- *     (#pjsip_dlg_answer())
- *   - disconnect dialog (#pjsip_dlg_disconnect()).
- *   - send other request (#pjsip_dlg_create_request() and #pjsip_dlg_send_msg())
- *
- * \par Getting Dialog's Notification
- * Dialog emits notification about various things that's happening to it (e.g.
- * a message is received, dialog state has changed, etc.). Normally it is in
- * the interest of the application to capture these notifications, by
- * supplying the function to be called when the event occurs in #pjsip_dlg_callback
- * structure, and register this structure to user agent by calling 
- * #pjsip_ua_set_dialog_callback().
- *
- * \par Incoming Invitation
- * Upon receiving a new incoming invitation, user agent will automatically create
- * a new dialog, and inform application via \b pjsip_dlg_callback.
- */
-
-/** Forward declaration for user agent structure. */
-typedef struct pjsip_user_agent pjsip_user_agent;
-
-/** Forward declaration for dialog structure. */
-typedef struct pjsip_dlg pjsip_dlg;
-
-/**
- * \brief Type of events that are reported by the dialog to the application callback
- * function.
- */
-typedef enum pjsip_dlg_event_e
-{
-    /** Dialog state has changed. */
-    PJSIP_DIALOG_EVENT_STATE_CHANGED,
-
-    /** Any mid-call messages (reinvitation, message, etc.). */
-    PJSIP_DIALOG_EVENT_MID_CALL_REQUEST,
-
-    /** Other events (low level events). */
-    PJSIP_DIALOG_EVENT_OTHER,
-
-} pjsip_dlg_event_e;
-
-
-/** 
- * \brief Structure registered by applications to receive dialog notifications 
- * from the User Agent. 
- *
- * Applications registers this structure to get notifications from the User Agent
- * about dialog state changes and other events. Application can set any of
- * the callback function to NULL if it doesn't want to handle the notification,
- * however, setting some callbacks to NULL probably will cause some undesired
- * result (such as setting \b on_incoming to NULL will cause the creation of
- * a lot of dialogs with no owner).
- */
-struct pjsip_dlg_callback
-{
-    /**
-     * This is a low level, uninterpreted callback that is called by framework 
-     * for all kinds of events, such as transaction events, dialog events, etc.
-     * @param dlg	The dialog.
-     * @param dlg_event The type of dialog event.
-     * @param event	The event descriptor.
-     */
-    void (*on_all_events)(pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event, 
-			  pjsip_event *event );
-
-    /**
-     * This is a low level callback that is called by the framework when the
-     * underlying transaction is about to send outgoing message. This callback
-     * is provided to allow application to modify the message before it is 
-     * transmitted. 
-     * @param dlg	The dialog.
-     * @param tsx	The transaction that transmits the message.
-     * @param tdata	The transmission data, which contains the message.
-     * @param retransmission The number of times this message has been sent.
-     *			Zero indicates the message is about to be sent the first time,
-     *			one indicates this is the first retransmission, etc.
-     */
-    void (*on_before_tx)(pjsip_dlg *dlg, pjsip_transaction *tsx,
-			 pjsip_tx_data *tdata, pj_bool_t retransmission);
-
-    /**
-     * This is a low level callback that is called by the framework when the dialog
-     * has sent a message. Note that a receive of retransmission will not trigger
-     * this callback since retransmission is handled internally by transaction.
-     * @param dlg	The dialog.
-     * @param tsx	The transaction that transmits the message.
-     * @param tdata	The transmission data, which contains the message.
-     */
-    void (*on_tx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-		      pjsip_tx_data *tdata);
-
-    /**
-     * This is a low level callback that is called by the framework when the
-     * dialog has received a message. Note that a receipt of retransmission 
-     * will not trigger this callback since retransmission is handled internally
-     * by transaction.
-     * @param dlg	The dialog.
-     * @param tsx	The transaction that receives the message.
-     * @param rdata	The receive data, which contains the message.
-     */
-    void (*on_rx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-		      pjsip_rx_data *rdata);
-
-    /**
-     * This callback is called by the framework when the user agent
-     * instance receives an incoming INVITE message.
-     * @param dlg	The new dialog that's just created to handle the incoming call.
-     * @param tsx	The INVITE transaction that's just created.
-     * @param rdata	The receive data, which contains the INVITE message.
-     */
-    void (*on_incoming)(pjsip_dlg *dlg, pjsip_transaction *tsx,
-		        pjsip_rx_data *rdata);
-
-    /**
-     * This callback is called by the framework when the dialog is sending
-     * the first outgoing INVITE message.
-     * @param dlg	The dialog.
-     * @param tsx	The INVITE transaction.
-     * @param tdata	The transmit data, which contains the INVITE message.
-     */
-    void (*on_calling)(pjsip_dlg *dlg, pjsip_transaction *tsx,
-		       pjsip_tx_data *tdata);
-
-    /**
-     * This callback is called by the framework when the initial INVITE
-     * transaction has sent/received provisional response.
-     * @param dlg	The dialog.
-     * @param tsx	The transaction.
-     * @param event	The event, which src_type will always be either
-     *			PJSIP_EVENT_RX_MSG or PJSIP_EVENT_TX_MSG. The provisional
-     *			response message itself will be in either \b rdata or \b tdata.
-     * @see pjsip_event.
-     */
-    void (*on_provisional)(pjsip_dlg *dlg, pjsip_transaction *tsx,
-			   pjsip_event *event);
-
-    /**
-     * This callback is called for both UAS and UAC dialog when 200 response
-     * to INVITE is sent or received.
-     * @param dlg	The dialog.
-     * @param event	The event, which src_type can only be either 
-     *			PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.
-     * @see pjsip_event
-     */
-    void (*on_connecting)(pjsip_dlg *dlg, pjsip_event *event);
-
-    /**
-     * This callback is called for both UAS and UAC when an ACK request is
-     * sent or received by the dialog.
-     * @param dlg	The dialog.
-     * @param event	The event, which src_type can only be either 
-     *			PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.
-     * @see pjsip_event
-     */
-    void (*on_established)(pjsip_dlg *dlg, pjsip_event *event);
-
-    /**
-     * This callback is called when the dialog is disconnected, i.e. upon
-     * sending/receiving non-200 response to INVITE, sending/receiving
-     * CANCEL to initial INVITE, and sending/receiving BYE.
-     *
-     * @param dlg	The dialog.
-     * @param event	The event.
-     * @see pjsip_event
-     */
-    void (*on_disconnected)(pjsip_dlg *dlg, pjsip_event *event);
-
-    /**
-     * This callback is called when the dialog is about to be destroyed.
-     * @param dlg The dialog.
-     */
-    void (*on_terminated)(pjsip_dlg *dlg);
-
-    /**
-     * This callback will be called when the dialog receives mid call events
-     * such as re-invitation or incoming pager.
-     *
-     * @param dlg	The dialog.
-     * @param event	The event.
-     */
-    void (*on_mid_call_events)(pjsip_dlg *dlg, pjsip_event *event);
-
-};  /* struct pjsip_dlg_callback */
-
-
-
-/**
- * Dialog state.
- */
-typedef enum pjsip_dlg_state_e
-{
-    /** 
-     * State NULL is after the dialog is instantiated but before any
-     * initialization is done. 
-     */
-    PJSIP_DIALOG_STATE_NULL,
-
-    /**
-     * State INCOMING is after the (callee) dialog has been initialized with
-     * the incoming request, but before any responses is sent by the dialog.
-     */
-    PJSIP_DIALOG_STATE_INCOMING,
-
-    /**
-     * State CALLING is after the (caller) dialog has sent outgoing invitation
-     * but before any responses are received.
-     */
-    PJSIP_DIALOG_STATE_CALLING,
-
-    /**
-     * State PROCEEDING is after the dialog sent/received provisional 
-     * responses, but before final response is sent/received.
-     */
-    PJSIP_DIALOG_STATE_PROCEEDING,
-
-    /**
-     * State CONNECTING is after the dialog has sent/received final response
-     * to the invitation, but before acknowledgement is sent.
-     */
-    PJSIP_DIALOG_STATE_CONNECTING,
-
-    /**
-     * State ESTABLISHED occurs after the invitation has been accepted and
-     * acknowledged.
-     */
-    PJSIP_DIALOG_STATE_ESTABLISHED,
-
-    /**
-     * State DISCONNECTED occurs after either party successfully disconnect
-     * the session.
-     */
-    PJSIP_DIALOG_STATE_DISCONNECTED,
-
-    /**
-     * State TERMINATE occurs when the dialog is ready to be destroyed.
-     */
-    PJSIP_DIALOG_STATE_TERMINATED,
-
-} pjsip_dlg_state_e;
-
-
-/**
- * Get the dialog string state.
- *
- * @param state	    Dialog state.
- * @return	    The string describing the state.
- */
-const char *pjsip_dlg_state_str(pjsip_dlg_state_e state);
-
-/**
- * This structure is used to describe dialog's participants, which in this
- * case is local party (i.e. us) and remote party.
- */
-typedef struct pjsip_dlg_party
-{
-    pjsip_uri		*target;    /**< Target URL.			*/
-    pjsip_fromto_hdr	*info;	    /**< URL in From/To header.		*/
-    pj_str_t		 tag;	    /**< Tag.				*/
-    pjsip_contact_hdr	*contact;   /**< URL in Contact.		*/
-    pj_sockaddr_in	 addr;	    /**< The current transport address. */
-    int			 cseq;	    /**< Sequence number counter.	*/
-} pjsip_dlg_party;
-
-
-/**
- * This structure describes the dialog structure.
- */
-struct pjsip_dlg
-{
-    PJ_DECL_LIST_MEMBER(struct pjsip_dlg)
-
-    char	        obj_name[PJ_MAX_OBJ_NAME];  /**< Log identification.	*/
-
-    pjsip_user_agent   *ua;			    /**< User agent instance.	*/
-    pj_pool_t	       *pool;			    /**< Dialog's pool.		*/
-    pjsip_dlg_state_e   state;			    /**< Dialog's call state.	*/
-    pjsip_role_e	role;			    /**< Dialog's role.		*/
-    pj_mutex_t	       *mutex;			    /**< Dialog's mutex.	*/
-
-    pjsip_dlg_party     local;			    /**< Local party info.	*/
-    pjsip_dlg_party     remote;			    /**< Remote party info.	*/
-
-    pjsip_cid_hdr      *call_id;		    /**< Call-ID		*/
-    pj_bool_t	        secure;			    /**< Use secure transport?	*/
-
-    pjsip_route_hdr     route_set;		    /**< Dialog's route set.	*/
-    pjsip_transaction  *invite_tsx;		    /**< Current INVITE transaction. */
-    int			pending_tsx_count;	    /**< Total pending tsx count. */
-
-    int			cred_count;		    /**< Number of credentials. */
-    pjsip_cred_info    *cred_info;		    /**< Array of credentials.	*/
-
-    pjsip_auth_session	auth_sess;		    /**< List of auth session. */
-
-    pjsip_msg_body     *body;
-
-    void	       *user_data;		    /**< Application's data.	*/
-
-    int  (*handle_tsx_event)(struct pjsip_dlg *,    /**< Internal state handler.*/
-			     pjsip_transaction *,
-			     pjsip_event *);
-};
-
-
-/**
- * Initialize dialog with local and remote info. This function is normally
- * called after application creates the dialog with #pjsip_ua_create_dialog
- * for UAC dialogs.
- *
- * This function will initialize local and remote info from the URL, generate
- * a globally unique Call-ID, initialize CSeq, and initialize other dialog's
- * internal attributes.
- *
- * @param dlg		The dialog to initialize.
- * @param local_info	URI/name address to be used as local info 
- *			(From and Contact headers).
- * @param remote_info	URI/name address to be used as remote info (To header).
- * @param target	URI for initial remote's target, or NULL to set the
- *			initial target the same as remote_info.
- *
- * @return		zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,
-				     const pj_str_t *local_info,
-				     const pj_str_t *remote_info,
-				     const pj_str_t *target);
-
-
-/**
- * Set authentication credentials to be used by this dialog.
- *
- * If authentication credentials are set for the dialog, the dialog will try to
- * perform authentication automatically using the credentials supplied, and 
- * also cache the last Authorization or Proxy-Authorization headers for next 
- * requests.
- * 
- * If none of the credentials are suitable or accepted by remote, then
- * the dialog will just pass the authorization failure response back to
- * application.
- *
- * @param dlg		The dialog.
- * @param count		Number of credentials in the array.
- * @param cred		Array of credentials.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_credentials( pjsip_dlg *dlg,
-					        int count,
-						const pjsip_cred_info cred[]);
-
-/**
- * Override local contact details.
- *
- * Call this function to change the contact details to be advertised in Contact
- * header. Application normally need to call this function for incoming calls
- * before answering the call with 200/OK, because for an incoming dialogs, the
- * initial local contact info are generated from the To header, which is 
- * normally not the appropriate one.
- *
- * @param dlg		The dialog.
- * @param contact	The contact to use.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,
-					    const pj_str_t *contact );
-
-
-/**
- * Set initial route set to be used by the dialog. This initial route set
- * governs where and how the initial INVITE request will be routed. This
- * initial route set will be overwritten with the route set found in the
- * 2xx response of INVITE.
- *
- * Application only needs to call this function if it wants to have custom
- * route for individual dialogs. If only a single route for all dialogs is
- * needed, then application can set the global route by calling function
- * #pjsip_endpt_set_proxies().
- *
- * @param dlg		The dialog.
- * @param route_set	The route set list.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,
-					      const pjsip_route_hdr *route_set );
-
-
-/**
- * Variation of #pjsip_dlg_set_route_set where the headers will be used
- * as it is (i.e. without cloned).
- *
- * @param dlg		The dialog.
- * @param route_set	The route set list.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,
-						 pjsip_route_hdr *route_set);
-
-/**
- * Create initial outgoing INVITE message.
- *
- * This function is just a simple wrapper to #pjsip_dlg_create_request(),
- * so it follows the same rule there. In addition, this function also adds
- * \b Allow header to the outgoing request.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg		The dialog.
- *
- * @return		The dialog transmit data, or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg );
-
-
-/**
- * Answer incoming dialog invitation, with either provisional responses
- * or a final response. Application can only call this function when there's
- * a pending invitation to be answered.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg	The dialog.
- * @param code	The response code, which can be:
- *		- 100-199 Provisional response (application can issue multiple 
- *                        provisional responses).
- *		- 200-299 To answer the invitation (normally status code 200
- *                        is sent).
- *              - 300-699 To reject the invitation.
- * @return	Transmit data if successfull.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code );
-
-
-/**
- * High level function to create message to disconnect dialog. Depending 
- * on dialog's  state, this function will either create CANCEL, final response,
- * or BYE message. A status code must be supplied, which will be set if dialog 
- * will be transmitting a final response to INVITE.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg		The dialog.
- * @param status_code	The status code for disconnection.
- * @return		Transmit data if successfull.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg, int status_code);
-
-/**
- * Create CANCEL message to cancel pending outgoing dialog invitation. 
- * Normally application should call #pjsip_dlg_disconnect() instead, because
- * that function will create the correct message regardless of the state of 
- * the dialog. 
- *
- * Application can call this function at anytime after it issues outgoing 
- * invitation and before receiving final response. However, there's no 
- * guarantee that the invitation will be successfully cancelled, since the 
- * CANCEL request and the final response can pass over in the wire. So the 
- * application must prepare to have the dialog connected even after the 
- * dialog is cancelled.
- *
- * The final state of the dialog will be reported in the dialog callback.
- * If the CANCEL request succeeded, then the dialog will be disconnected with
- * status code \a PJSIP_SC_REQUEST_TERMINATED.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. 
- *
- * Upon return of this function, the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg		The dialog.
- * @return		The dialog transmit data containing the CANCEL message,
- *			or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg );
-
-
-/**
- * Create BYE message. Application shouldn't normally need to use this function,
- * but rather it's preferable to use #pjsip_dlg_disconnect() instead because
- * that function will work to disconnect the session no matter what the state
- * is.
- *
- * After the message is successfully created, application must call
- * #pjsip_dlg_send_msg() to actually send the message and update the dialog's
- * state. Note that upon return the reference counter of the transmit data
- * will be set to one.
- *
- * @param dlg		The dialog.
- * @return		The BYE message or NULL.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg );
-
-/**
- * This function is called by application to create new outgoing request
- * message for this dialog. After the request is created, application can
- * modify the message (such adding headers), and eventually send the request
- * by calling #pjsip_dlg_send_msg().
- *
- * This function will initialize the request message with dialog's properties
- * as follows:
- *  - the request line is initialized with the method and the target is
- *    initialized from current remote target.
- *  - \b From, \b To, \b Contact, and \b Call-Id headers will be added.
- *  - An initial \b CSeq header will be provided (although the value will be
- *    verified again when the message is actually sent with #pjsip_dlg_send_msg().
- *  - \b Route headers will be added from dialog's route set.
- *  - Authentication headers (\b Authorization or \b Proxy-Authorization) will
- *    be added from dialog's authorization cache.
- *
- * Note that upon return the reference counter of the transmit data
- * will be set to one. When the message is sent, #pjsip_dlg_send_msg() will
- * decrement the reference counter, and when the reference counter reach zero,
- * the message will be deleted.
- *
- * @param dlg		The dialog.
- * @param method	The request method.
- * @param cseq		Specify CSeq, or -1 to let the dialog specify CSeq.
- *
- * @return		Transmit data for the new request.
- *
- * @see pjsip_dlg_send_msg()
- */
-PJ_DECL(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,
-						  const pjsip_method *method,
-						  int cseq);
-
-
-/**
- * This function can be called by application to send outgoing message (request
- * or response) to remote party. Note that after calling this function, the
- * transmit data will be deleted regardless of the return status. To prevent
- * deletion, application must increase the reference count, but then it will
- * be responsible to delete this transmit data itself (by decreasing the
- * reference count).
- *
- * @param dlg		The dialog.
- * @param tdata		The transmit data, which contains the request message.
- * @return		zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg,
-					 pjsip_tx_data *tdata );
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_DIALOG_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_DIALOG_H__

+#define __PJSIP_DIALOG_H__

+

+/**

+ * @file dialog.h

+ * @brief SIP Dialog abstraction

+ */

+

+#include <pjsip/sip_msg.h>

+#include <pjsip/sip_auth.h>

+#include <pj/sock.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSUA_DIALOG SIP Dialog

+ * @ingroup PJSUA

+ * @{

+ * \brief

+ *   This file contains SIP dialog, a higher level abstraction of SIP session.

+ *

+ * \par Overview

+ * A SIP dialog is an abstraction of communication session between two user 

+ * agents that persist for some time. The dialog facilitates sequencing of 

+ * messages between the user agents and proper routing of requests between both

+ * of them. The dialog represents a context in which to interpret SIP messages.

+ * However method independent User Agent processing for requests and responses 

+ * outside of a dialog exists, hence a dialog is not necessary for message 

+ * processing.

+ *

+ * A dialog is identified at each User Agent with a dialog Id, which consists 

+ * of a Call-Id value, a local tag and a remote tag. 

+ *

+ * A dialog contains certain pieces of data needed for further message 

+ * transmissions within the dialog. This data consists of:

+ *  - Dialog Id - used to identify the dialog.

+ *  - Local sequence number - used to order requests from the UA to its peer.

+ *  - Remote sequence number - used to order requests from its peer to the UA.

+ *  - Local URI - the address of the local party.

+ *  - Remote URI - the address of the remote party.

+ *  - Remote target - the address from the Contact header field of the request 

+ *    or response or refresh request or response.

+ *  - "secure" boolean - determines if the dialog is secure.

+ *  - Route set - an ordered list of URIs. The route set is the list of servers

+ *    that need to be traversed to send a request to the peer. 

+ *  - Authentication info - array of authentication credentials to be used

+ *    by the dialog to authenticate to proxies and servers.

+ *

+ * \par Manipulating Dialog

+ * Application should use functions declared in this file to do something with 

+ * the dialog. Among other things, application can:

+ *   - create outgoing dialog (#pjsip_dlg_init()).

+ *   - sends outgoing invitation (#pjsip_dlg_invite()).

+ *   - sends response (provisional and final) to incoming invitation

+ *     (#pjsip_dlg_answer())

+ *   - disconnect dialog (#pjsip_dlg_disconnect()).

+ *   - send other request (#pjsip_dlg_create_request() and #pjsip_dlg_send_msg())

+ *

+ * \par Getting Dialog's Notification

+ * Dialog emits notification about various things that's happening to it (e.g.

+ * a message is received, dialog state has changed, etc.). Normally it is in

+ * the interest of the application to capture these notifications, by

+ * supplying the function to be called when the event occurs in #pjsip_dlg_callback

+ * structure, and register this structure to user agent by calling 

+ * #pjsip_ua_set_dialog_callback().

+ *

+ * \par Incoming Invitation

+ * Upon receiving a new incoming invitation, user agent will automatically create

+ * a new dialog, and inform application via \b pjsip_dlg_callback.

+ */

+

+/** Forward declaration for user agent structure. */

+typedef struct pjsip_user_agent pjsip_user_agent;

+

+/** Forward declaration for dialog structure. */

+typedef struct pjsip_dlg pjsip_dlg;

+

+/**

+ * \brief Type of events that are reported by the dialog to the application callback

+ * function.

+ */

+typedef enum pjsip_dlg_event_e

+{

+    /** Dialog state has changed. */

+    PJSIP_DIALOG_EVENT_STATE_CHANGED,

+

+    /** Any mid-call messages (reinvitation, message, etc.). */

+    PJSIP_DIALOG_EVENT_MID_CALL_REQUEST,

+

+    /** Other events (low level events). */

+    PJSIP_DIALOG_EVENT_OTHER,

+

+} pjsip_dlg_event_e;

+

+

+/** 

+ * \brief Structure registered by applications to receive dialog notifications 

+ * from the User Agent. 

+ *

+ * Applications registers this structure to get notifications from the User Agent

+ * about dialog state changes and other events. Application can set any of

+ * the callback function to NULL if it doesn't want to handle the notification,

+ * however, setting some callbacks to NULL probably will cause some undesired

+ * result (such as setting \b on_incoming to NULL will cause the creation of

+ * a lot of dialogs with no owner).

+ */

+struct pjsip_dlg_callback

+{

+    /**

+     * This is a low level, uninterpreted callback that is called by framework 

+     * for all kinds of events, such as transaction events, dialog events, etc.

+     * @param dlg	The dialog.

+     * @param dlg_event The type of dialog event.

+     * @param event	The event descriptor.

+     */

+    void (*on_all_events)(pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event, 

+			  pjsip_event *event );

+

+    /**

+     * This is a low level callback that is called by the framework when the

+     * underlying transaction is about to send outgoing message. This callback

+     * is provided to allow application to modify the message before it is 

+     * transmitted. 

+     * @param dlg	The dialog.

+     * @param tsx	The transaction that transmits the message.

+     * @param tdata	The transmission data, which contains the message.

+     * @param retransmission The number of times this message has been sent.

+     *			Zero indicates the message is about to be sent the first time,

+     *			one indicates this is the first retransmission, etc.

+     */

+    void (*on_before_tx)(pjsip_dlg *dlg, pjsip_transaction *tsx,

+			 pjsip_tx_data *tdata, pj_bool_t retransmission);

+

+    /**

+     * This is a low level callback that is called by the framework when the dialog

+     * has sent a message. Note that a receive of retransmission will not trigger

+     * this callback since retransmission is handled internally by transaction.

+     * @param dlg	The dialog.

+     * @param tsx	The transaction that transmits the message.

+     * @param tdata	The transmission data, which contains the message.

+     */

+    void (*on_tx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx, 

+		      pjsip_tx_data *tdata);

+

+    /**

+     * This is a low level callback that is called by the framework when the

+     * dialog has received a message. Note that a receipt of retransmission 

+     * will not trigger this callback since retransmission is handled internally

+     * by transaction.

+     * @param dlg	The dialog.

+     * @param tsx	The transaction that receives the message.

+     * @param rdata	The receive data, which contains the message.

+     */

+    void (*on_rx_msg)(pjsip_dlg *dlg, pjsip_transaction *tsx, 

+		      pjsip_rx_data *rdata);

+

+    /**

+     * This callback is called by the framework when the user agent

+     * instance receives an incoming INVITE message.

+     * @param dlg	The new dialog that's just created to handle the incoming call.

+     * @param tsx	The INVITE transaction that's just created.

+     * @param rdata	The receive data, which contains the INVITE message.

+     */

+    void (*on_incoming)(pjsip_dlg *dlg, pjsip_transaction *tsx,

+		        pjsip_rx_data *rdata);

+

+    /**

+     * This callback is called by the framework when the dialog is sending

+     * the first outgoing INVITE message.

+     * @param dlg	The dialog.

+     * @param tsx	The INVITE transaction.

+     * @param tdata	The transmit data, which contains the INVITE message.

+     */

+    void (*on_calling)(pjsip_dlg *dlg, pjsip_transaction *tsx,

+		       pjsip_tx_data *tdata);

+

+    /**

+     * This callback is called by the framework when the initial INVITE

+     * transaction has sent/received provisional response.

+     * @param dlg	The dialog.

+     * @param tsx	The transaction.

+     * @param event	The event, which src_type will always be either

+     *			PJSIP_EVENT_RX_MSG or PJSIP_EVENT_TX_MSG. The provisional

+     *			response message itself will be in either \b rdata or \b tdata.

+     * @see pjsip_event.

+     */

+    void (*on_provisional)(pjsip_dlg *dlg, pjsip_transaction *tsx,

+			   pjsip_event *event);

+

+    /**

+     * This callback is called for both UAS and UAC dialog when 200 response

+     * to INVITE is sent or received.

+     * @param dlg	The dialog.

+     * @param event	The event, which src_type can only be either 

+     *			PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.

+     * @see pjsip_event

+     */

+    void (*on_connecting)(pjsip_dlg *dlg, pjsip_event *event);

+

+    /**

+     * This callback is called for both UAS and UAC when an ACK request is

+     * sent or received by the dialog.

+     * @param dlg	The dialog.

+     * @param event	The event, which src_type can only be either 

+     *			PJSIP_EVENT_TX_MSG or PJSIP_EVENT_RX_MSG.

+     * @see pjsip_event

+     */

+    void (*on_established)(pjsip_dlg *dlg, pjsip_event *event);

+

+    /**

+     * This callback is called when the dialog is disconnected, i.e. upon

+     * sending/receiving non-200 response to INVITE, sending/receiving

+     * CANCEL to initial INVITE, and sending/receiving BYE.

+     *

+     * @param dlg	The dialog.

+     * @param event	The event.

+     * @see pjsip_event

+     */

+    void (*on_disconnected)(pjsip_dlg *dlg, pjsip_event *event);

+

+    /**

+     * This callback is called when the dialog is about to be destroyed.

+     * @param dlg The dialog.

+     */

+    void (*on_terminated)(pjsip_dlg *dlg);

+

+    /**

+     * This callback will be called when the dialog receives mid call events

+     * such as re-invitation or incoming pager.

+     *

+     * @param dlg	The dialog.

+     * @param event	The event.

+     */

+    void (*on_mid_call_events)(pjsip_dlg *dlg, pjsip_event *event);

+

+};  /* struct pjsip_dlg_callback */

+

+

+

+/**

+ * Dialog state.

+ */

+typedef enum pjsip_dlg_state_e

+{

+    /** 

+     * State NULL is after the dialog is instantiated but before any

+     * initialization is done. 

+     */

+    PJSIP_DIALOG_STATE_NULL,

+

+    /**

+     * State INCOMING is after the (callee) dialog has been initialized with

+     * the incoming request, but before any responses is sent by the dialog.

+     */

+    PJSIP_DIALOG_STATE_INCOMING,

+

+    /**

+     * State CALLING is after the (caller) dialog has sent outgoing invitation

+     * but before any responses are received.

+     */

+    PJSIP_DIALOG_STATE_CALLING,

+

+    /**

+     * State PROCEEDING is after the dialog sent/received provisional 

+     * responses, but before final response is sent/received.

+     */

+    PJSIP_DIALOG_STATE_PROCEEDING,

+

+    /**

+     * State CONNECTING is after the dialog has sent/received final response

+     * to the invitation, but before acknowledgement is sent.

+     */

+    PJSIP_DIALOG_STATE_CONNECTING,

+

+    /**

+     * State ESTABLISHED occurs after the invitation has been accepted and

+     * acknowledged.

+     */

+    PJSIP_DIALOG_STATE_ESTABLISHED,

+

+    /**

+     * State DISCONNECTED occurs after either party successfully disconnect

+     * the session.

+     */

+    PJSIP_DIALOG_STATE_DISCONNECTED,

+

+    /**

+     * State TERMINATE occurs when the dialog is ready to be destroyed.

+     */

+    PJSIP_DIALOG_STATE_TERMINATED,

+

+} pjsip_dlg_state_e;

+

+

+/**

+ * Get the dialog string state.

+ *

+ * @param state	    Dialog state.

+ * @return	    The string describing the state.

+ */

+const char *pjsip_dlg_state_str(pjsip_dlg_state_e state);

+

+/**

+ * This structure is used to describe dialog's participants, which in this

+ * case is local party (i.e. us) and remote party.

+ */

+typedef struct pjsip_dlg_party

+{

+    pjsip_uri		*target;    /**< Target URL.			*/

+    pjsip_fromto_hdr	*info;	    /**< URL in From/To header.		*/

+    pj_str_t		 tag;	    /**< Tag.				*/

+    pjsip_contact_hdr	*contact;   /**< URL in Contact.		*/

+    pj_sockaddr_in	 addr;	    /**< The current transport address. */

+    int			 cseq;	    /**< Sequence number counter.	*/

+} pjsip_dlg_party;

+

+

+/**

+ * This structure describes the dialog structure.

+ */

+struct pjsip_dlg

+{

+    PJ_DECL_LIST_MEMBER(struct pjsip_dlg)

+

+    char	        obj_name[PJ_MAX_OBJ_NAME];  /**< Log identification.	*/

+

+    pjsip_user_agent   *ua;			    /**< User agent instance.	*/

+    pj_pool_t	       *pool;			    /**< Dialog's pool.		*/

+    pjsip_dlg_state_e   state;			    /**< Dialog's call state.	*/

+    pjsip_role_e	role;			    /**< Dialog's role.		*/

+    pj_mutex_t	       *mutex;			    /**< Dialog's mutex.	*/

+

+    pjsip_dlg_party     local;			    /**< Local party info.	*/

+    pjsip_dlg_party     remote;			    /**< Remote party info.	*/

+

+    pjsip_cid_hdr      *call_id;		    /**< Call-ID		*/

+    pj_bool_t	        secure;			    /**< Use secure transport?	*/

+

+    pjsip_route_hdr     route_set;		    /**< Dialog's route set.	*/

+    pjsip_transaction  *invite_tsx;		    /**< Current INVITE transaction. */

+    int			pending_tsx_count;	    /**< Total pending tsx count. */

+

+    int			cred_count;		    /**< Number of credentials. */

+    pjsip_cred_info    *cred_info;		    /**< Array of credentials.	*/

+

+    pjsip_auth_session	auth_sess;		    /**< List of auth session. */

+

+    pjsip_msg_body     *body;

+

+    void	       *user_data;		    /**< Application's data.	*/

+

+    int  (*handle_tsx_event)(struct pjsip_dlg *,    /**< Internal state handler.*/

+			     pjsip_transaction *,

+			     pjsip_event *);

+};

+

+

+/**

+ * Initialize dialog with local and remote info. This function is normally

+ * called after application creates the dialog with #pjsip_ua_create_dialog

+ * for UAC dialogs.

+ *

+ * This function will initialize local and remote info from the URL, generate

+ * a globally unique Call-ID, initialize CSeq, and initialize other dialog's

+ * internal attributes.

+ *

+ * @param dlg		The dialog to initialize.

+ * @param local_info	URI/name address to be used as local info 

+ *			(From and Contact headers).

+ * @param remote_info	URI/name address to be used as remote info (To header).

+ * @param target	URI for initial remote's target, or NULL to set the

+ *			initial target the same as remote_info.

+ *

+ * @return		zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,

+				     const pj_str_t *local_info,

+				     const pj_str_t *remote_info,

+				     const pj_str_t *target);

+

+

+/**

+ * Set authentication credentials to be used by this dialog.

+ *

+ * If authentication credentials are set for the dialog, the dialog will try to

+ * perform authentication automatically using the credentials supplied, and 

+ * also cache the last Authorization or Proxy-Authorization headers for next 

+ * requests.

+ * 

+ * If none of the credentials are suitable or accepted by remote, then

+ * the dialog will just pass the authorization failure response back to

+ * application.

+ *

+ * @param dlg		The dialog.

+ * @param count		Number of credentials in the array.

+ * @param cred		Array of credentials.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_dlg_set_credentials( pjsip_dlg *dlg,

+					        int count,

+						const pjsip_cred_info cred[]);

+

+/**

+ * Override local contact details.

+ *

+ * Call this function to change the contact details to be advertised in Contact

+ * header. Application normally need to call this function for incoming calls

+ * before answering the call with 200/OK, because for an incoming dialogs, the

+ * initial local contact info are generated from the To header, which is 

+ * normally not the appropriate one.

+ *

+ * @param dlg		The dialog.

+ * @param contact	The contact to use.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,

+					    const pj_str_t *contact );

+

+

+/**

+ * Set initial route set to be used by the dialog. This initial route set

+ * governs where and how the initial INVITE request will be routed. This

+ * initial route set will be overwritten with the route set found in the

+ * 2xx response of INVITE.

+ *

+ * Application only needs to call this function if it wants to have custom

+ * route for individual dialogs. If only a single route for all dialogs is

+ * needed, then application can set the global route by calling function

+ * #pjsip_endpt_set_proxies().

+ *

+ * @param dlg		The dialog.

+ * @param route_set	The route set list.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,

+					      const pjsip_route_hdr *route_set );

+

+

+/**

+ * Variation of #pjsip_dlg_set_route_set where the headers will be used

+ * as it is (i.e. without cloned).

+ *

+ * @param dlg		The dialog.

+ * @param route_set	The route set list.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,

+						 pjsip_route_hdr *route_set);

+

+/**

+ * Create initial outgoing INVITE message.

+ *

+ * This function is just a simple wrapper to #pjsip_dlg_create_request(),

+ * so it follows the same rule there. In addition, this function also adds

+ * \b Allow header to the outgoing request.

+ *

+ * After the message is successfully created, application must call

+ * #pjsip_dlg_send_msg() to actually send the message and update the dialog's

+ * state. Note that upon return the reference counter of the transmit data

+ * will be set to one.

+ *

+ * @param dlg		The dialog.

+ *

+ * @return		The dialog transmit data, or NULL.

+ */

+PJ_DECL(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg );

+

+

+/**

+ * Answer incoming dialog invitation, with either provisional responses

+ * or a final response. Application can only call this function when there's

+ * a pending invitation to be answered.

+ *

+ * After the message is successfully created, application must call

+ * #pjsip_dlg_send_msg() to actually send the message and update the dialog's

+ * state. Note that upon return the reference counter of the transmit data

+ * will be set to one.

+ *

+ * @param dlg	The dialog.

+ * @param code	The response code, which can be:

+ *		- 100-199 Provisional response (application can issue multiple 

+ *                        provisional responses).

+ *		- 200-299 To answer the invitation (normally status code 200

+ *                        is sent).

+ *              - 300-699 To reject the invitation.

+ * @return	Transmit data if successfull.

+ */

+PJ_DECL(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code );

+

+

+/**

+ * High level function to create message to disconnect dialog. Depending 

+ * on dialog's  state, this function will either create CANCEL, final response,

+ * or BYE message. A status code must be supplied, which will be set if dialog 

+ * will be transmitting a final response to INVITE.

+ *

+ * After the message is successfully created, application must call

+ * #pjsip_dlg_send_msg to actually send the message and update the dialog's

+ * state. Note that upon return the reference counter of the transmit data

+ * will be set to one.

+ *

+ * @param dlg		The dialog.

+ * @param status_code	The status code for disconnection.

+ * @return		Transmit data if successfull.

+ */

+PJ_DECL(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg, int status_code);

+

+/**

+ * Create CANCEL message to cancel pending outgoing dialog invitation. 

+ * Normally application should call #pjsip_dlg_disconnect() instead, because

+ * that function will create the correct message regardless of the state of 

+ * the dialog. 

+ *

+ * Application can call this function at anytime after it issues outgoing 

+ * invitation and before receiving final response. However, there's no 

+ * guarantee that the invitation will be successfully cancelled, since the 

+ * CANCEL request and the final response can pass over in the wire. So the 

+ * application must prepare to have the dialog connected even after the 

+ * dialog is cancelled.

+ *

+ * The final state of the dialog will be reported in the dialog callback.

+ * If the CANCEL request succeeded, then the dialog will be disconnected with

+ * status code \a PJSIP_SC_REQUEST_TERMINATED.

+ *

+ * After the message is successfully created, application must call

+ * #pjsip_dlg_send_msg() to actually send the message and update the dialog's

+ * state. 

+ *

+ * Upon return of this function, the reference counter of the transmit data

+ * will be set to one.

+ *

+ * @param dlg		The dialog.

+ * @return		The dialog transmit data containing the CANCEL message,

+ *			or NULL.

+ */

+PJ_DECL(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg );

+

+

+/**

+ * Create BYE message. Application shouldn't normally need to use this function,

+ * but rather it's preferable to use #pjsip_dlg_disconnect() instead because

+ * that function will work to disconnect the session no matter what the state

+ * is.

+ *

+ * After the message is successfully created, application must call

+ * #pjsip_dlg_send_msg() to actually send the message and update the dialog's

+ * state. Note that upon return the reference counter of the transmit data

+ * will be set to one.

+ *

+ * @param dlg		The dialog.

+ * @return		The BYE message or NULL.

+ */

+PJ_DECL(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg );

+

+/**

+ * This function is called by application to create new outgoing request

+ * message for this dialog. After the request is created, application can

+ * modify the message (such adding headers), and eventually send the request

+ * by calling #pjsip_dlg_send_msg().

+ *

+ * This function will initialize the request message with dialog's properties

+ * as follows:

+ *  - the request line is initialized with the method and the target is

+ *    initialized from current remote target.

+ *  - \b From, \b To, \b Contact, and \b Call-Id headers will be added.

+ *  - An initial \b CSeq header will be provided (although the value will be

+ *    verified again when the message is actually sent with #pjsip_dlg_send_msg().

+ *  - \b Route headers will be added from dialog's route set.

+ *  - Authentication headers (\b Authorization or \b Proxy-Authorization) will

+ *    be added from dialog's authorization cache.

+ *

+ * Note that upon return the reference counter of the transmit data

+ * will be set to one. When the message is sent, #pjsip_dlg_send_msg() will

+ * decrement the reference counter, and when the reference counter reach zero,

+ * the message will be deleted.

+ *

+ * @param dlg		The dialog.

+ * @param method	The request method.

+ * @param cseq		Specify CSeq, or -1 to let the dialog specify CSeq.

+ *

+ * @return		Transmit data for the new request.

+ *

+ * @see pjsip_dlg_send_msg()

+ */

+PJ_DECL(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,

+						  const pjsip_method *method,

+						  int cseq);

+

+

+/**

+ * This function can be called by application to send outgoing message (request

+ * or response) to remote party. Note that after calling this function, the

+ * transmit data will be deleted regardless of the return status. To prevent

+ * deletion, application must increase the reference count, but then it will

+ * be responsible to delete this transmit data itself (by decreasing the

+ * reference count).

+ *

+ * @param dlg		The dialog.

+ * @param tdata		The transmit data, which contains the request message.

+ * @return		zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg,

+					 pjsip_tx_data *tdata );

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_DIALOG_H__ */

+

diff --git a/pjsip/include/pjsip-ua/sip_regc.h b/pjsip/include/pjsip-ua/sip_regc.h
index 7570c73..0f019e5 100644
--- a/pjsip/include/pjsip-ua/sip_regc.h
+++ b/pjsip/include/pjsip-ua/sip_regc.h
@@ -1,195 +1,217 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_SIP_REG_H__
-#define __PJSIP_SIP_REG_H__
-
-/**
- * @file sip_reg.h
- * @brief SIP Registration Client
- */
-
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_auth.h>
-#include <pjsip_mod_ua/sip_ua.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSUA_REGC SIP Registration Client
- * @ingroup PJSUA
- * @{
- * \brief
- *   API for performing registration for user agent.
- */
-
-/** Typedef for client registration data. */
-typedef struct pjsip_regc pjsip_regc;
-
-/** Maximum contacts in registration. */
-#define PJSIP_REGC_MAX_CONTACT	10
-
-/** Expiration not specified. */
-#define PJSIP_REGC_EXPIRATION_NOT_SPECIFIED	((pj_uint32_t)0xFFFFFFFFUL)
-
-/** Buffer to hold all contacts. */
-#define PJSIP_REGC_CONTACT_BUF_SIZE	512
-
-/** Structure to hold parameters when calling application's callback.
- *  The application's callback is called when the client registration process
- *  has finished.
- */
-struct pjsip_regc_cbparam
-{
-    pjsip_regc		*regc;
-    void		*token;
-    int			 code;
-    pj_str_t		 reason;
-    pjsip_rx_data	*rdata;
-    int			 contact_cnt;
-    int			 expiration;
-    pjsip_contact_hdr	*contact[PJSIP_REGC_MAX_CONTACT];
-};
-
-
-/** Type declaration for callback to receive registration result. */
-typedef void pjsip_regc_cb(struct pjsip_regc_cbparam *param);
-
-
-/**
- * Get the module instance for client registration module.
- *
- * @return	    client registration module.
- */
-PJ_DECL(pjsip_module*) pjsip_regc_get_module(void);
-
-
-/**
- * Create client registration structure.
- *
- * @param endpt	    Endpoint, used to allocate pool from.
- * @param token	    A data to be associated with the client registration struct.
- * @param cb	    Pointer to callback function to receive registration status.
- *
- * @return	    client registration structure.
- */
-PJ_DECL(pjsip_regc*) pjsip_regc_create( pjsip_endpoint *endpt, void *token,
-				        pjsip_regc_cb *cb);
-
-
-/**
- * Destroy client registration structure. If a registration transaction is
- * in progress, then the structure will be deleted only after a final response
- * has been received, and in this case, the callback won't be called.
- *
- * @param regc	    The client registration structure.
- */
-PJ_DECL(void) pjsip_regc_destroy(pjsip_regc *regc);
-
-/**
- * Get the memory pool associated with a registration client handle.
- *
- * @param regc	    The client registration structure.
- * @return pool	    handle.
- */
-PJ_DECL(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc);
-
-/**
- * Initialize client registration structure with various information needed to
- * perform the registration.
- *
- * @param regc	    The client registration structure.
- * @param from_url  The person performing the registration, must be a SIP URL type.
- * @param to_url    The address of record for which the registration is targetd, must
- *		    be a SIP/SIPS URL.
- * @param ccnt	    Number of contacts in the array.
- * @param contact   Array of contacts.
- * @param expires   Default expiration interval (in seconds) to be applied for
- *		    contact URL that doesn't have expiration settings. If the
- *		    value PJSIP_REGC_EXPIRATION_NOT_SPECIFIED is given, then 
- *		    no default expiration will be applied.
- * @return	    zero on success.
- */
-PJ_DECL(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 ccnt,
-				     const pj_str_t contact[],
-				     pj_uint32_t expires);
-
-
-/**
- * Set authentication credentials to use by this registration.
- *
- * @param dlg		The registration structure.
- * @param count		Number of credentials in the array.
- * @param cred		Array of credentials.
- *
- * @return		Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc,
-						 int count,
-						 const pjsip_cred_info cred[] );
-
-/**
- * Create REGISTER request for the specified client registration structure.
- *
- * After successfull registration, application can inspect the contacts in
- * the client registration structure to list what contacts are associaciated
- * with the address of record being targeted in the registration.
- *
- * @param regc	    The client registration structure.
- * @param autoreg   If non zero, the library will automatically refresh the
- *		    next registration until application unregister.
- *
- * @return	    SIP REGISTER request.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg);
-
-
-/**
- * Create REGISTER request to unregister all contacts from server records.
- *
- * @param regc	    The client registration structure.
- *
- * @return	    SIP REGISTER request.
- */
-PJ_DECL(pjsip_tx_data*) pjsip_regc_unregister(pjsip_regc *regc);
-
-/**
- * Update Contact details in the client registration structure.
- *
- * @param regc	    The client registration structure.
- * @param ccnt	    Number of contacts.
- * @param contact   Array of contacts.
- * @return	    zero if sucessfull.
- */
-PJ_DECL(pj_status_t) pjsip_regc_update_contact( pjsip_regc *regc,
-					        int ccnt,
-						const pj_str_t contact[] );
-
-/**
- * Update the expires value.
- *
- * @param regc	    The client registration structure.
- * @param expires   The new expires value.
- * @return	    zero on successfull.
- */
-PJ_DECL(pj_status_t) pjsip_regc_update_expires( pjsip_regc *regc,
-					        pj_uint32_t expires );
-
-/**
- * Sends outgoing REGISTER request.
- * The process will complete asynchronously, and application
- * will be notified via the callback when the process completes.
- *
- * @param regc	    The client registration structure.
- * @param tdata	    Transmit data.
- */
-PJ_DECL(void) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata);
-
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_REG_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_REG_H__

+#define __PJSIP_SIP_REG_H__

+

+/**

+ * @file sip_reg.h

+ * @brief SIP Registration Client

+ */

+

+#include <pjsip/sip_types.h>

+#include <pjsip/sip_auth.h>

+#include <pjsip_mod_ua/sip_ua.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSUA_REGC SIP Registration Client

+ * @ingroup PJSUA

+ * @{

+ * \brief

+ *   API for performing registration for user agent.

+ */

+

+/** Typedef for client registration data. */

+typedef struct pjsip_regc pjsip_regc;

+

+/** Maximum contacts in registration. */

+#define PJSIP_REGC_MAX_CONTACT	10

+

+/** Expiration not specified. */

+#define PJSIP_REGC_EXPIRATION_NOT_SPECIFIED	((pj_uint32_t)0xFFFFFFFFUL)

+

+/** Buffer to hold all contacts. */

+#define PJSIP_REGC_CONTACT_BUF_SIZE	512

+

+/** Structure to hold parameters when calling application's callback.

+ *  The application's callback is called when the client registration process

+ *  has finished.

+ */

+struct pjsip_regc_cbparam

+{

+    pjsip_regc		*regc;

+    void		*token;

+    int			 code;

+    pj_str_t		 reason;

+    pjsip_rx_data	*rdata;

+    int			 contact_cnt;

+    int			 expiration;

+    pjsip_contact_hdr	*contact[PJSIP_REGC_MAX_CONTACT];

+};

+

+

+/** Type declaration for callback to receive registration result. */

+typedef void pjsip_regc_cb(struct pjsip_regc_cbparam *param);

+

+

+/**

+ * Get the module instance for client registration module.

+ *

+ * @return	    client registration module.

+ */

+PJ_DECL(pjsip_module*) pjsip_regc_get_module(void);

+

+

+/**

+ * Create client registration structure.

+ *

+ * @param endpt	    Endpoint, used to allocate pool from.

+ * @param token	    A data to be associated with the client registration struct.

+ * @param cb	    Pointer to callback function to receive registration status.

+ *

+ * @return	    client registration structure.

+ */

+PJ_DECL(pjsip_regc*) pjsip_regc_create( pjsip_endpoint *endpt, void *token,

+				        pjsip_regc_cb *cb);

+

+

+/**

+ * Destroy client registration structure. If a registration transaction is

+ * in progress, then the structure will be deleted only after a final response

+ * has been received, and in this case, the callback won't be called.

+ *

+ * @param regc	    The client registration structure.

+ */

+PJ_DECL(void) pjsip_regc_destroy(pjsip_regc *regc);

+

+/**

+ * Get the memory pool associated with a registration client handle.

+ *

+ * @param regc	    The client registration structure.

+ * @return pool	    handle.

+ */

+PJ_DECL(pj_pool_t*) pjsip_regc_get_pool(pjsip_regc *regc);

+

+/**

+ * Initialize client registration structure with various information needed to

+ * perform the registration.

+ *

+ * @param regc	    The client registration structure.

+ * @param from_url  The person performing the registration, must be a SIP URL type.

+ * @param to_url    The address of record for which the registration is targetd, must

+ *		    be a SIP/SIPS URL.

+ * @param ccnt	    Number of contacts in the array.

+ * @param contact   Array of contacts.

+ * @param expires   Default expiration interval (in seconds) to be applied for

+ *		    contact URL that doesn't have expiration settings. If the

+ *		    value PJSIP_REGC_EXPIRATION_NOT_SPECIFIED is given, then 

+ *		    no default expiration will be applied.

+ * @return	    zero on success.

+ */

+PJ_DECL(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 ccnt,

+				     const pj_str_t contact[],

+				     pj_uint32_t expires);

+

+

+/**

+ * Set authentication credentials to use by this registration.

+ *

+ * @param dlg		The registration structure.

+ * @param count		Number of credentials in the array.

+ * @param cred		Array of credentials.

+ *

+ * @return		Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc,

+						 int count,

+						 const pjsip_cred_info cred[] );

+

+/**

+ * Create REGISTER request for the specified client registration structure.

+ *

+ * After successfull registration, application can inspect the contacts in

+ * the client registration structure to list what contacts are associaciated

+ * with the address of record being targeted in the registration.

+ *

+ * @param regc	    The client registration structure.

+ * @param autoreg   If non zero, the library will automatically refresh the

+ *		    next registration until application unregister.

+ *

+ * @return	    SIP REGISTER request.

+ */

+PJ_DECL(pjsip_tx_data*) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg);

+

+

+/**

+ * Create REGISTER request to unregister all contacts from server records.

+ *

+ * @param regc	    The client registration structure.

+ *

+ * @return	    SIP REGISTER request.

+ */

+PJ_DECL(pjsip_tx_data*) pjsip_regc_unregister(pjsip_regc *regc);

+

+/**

+ * Update Contact details in the client registration structure.

+ *

+ * @param regc	    The client registration structure.

+ * @param ccnt	    Number of contacts.

+ * @param contact   Array of contacts.

+ * @return	    zero if sucessfull.

+ */

+PJ_DECL(pj_status_t) pjsip_regc_update_contact( pjsip_regc *regc,

+					        int ccnt,

+						const pj_str_t contact[] );

+

+/**

+ * Update the expires value.

+ *

+ * @param regc	    The client registration structure.

+ * @param expires   The new expires value.

+ * @return	    zero on successfull.

+ */

+PJ_DECL(pj_status_t) pjsip_regc_update_expires( pjsip_regc *regc,

+					        pj_uint32_t expires );

+

+/**

+ * Sends outgoing REGISTER request.

+ * The process will complete asynchronously, and application

+ * will be notified via the callback when the process completes.

+ *

+ * @param regc	    The client registration structure.

+ * @param tdata	    Transmit data.

+ */

+PJ_DECL(void) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata);

+

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_REG_H__ */

diff --git a/pjsip/include/pjsip-ua/sip_ua.h b/pjsip/include/pjsip-ua/sip_ua.h
index 87e6f3a..307bdc4 100644
--- a/pjsip/include/pjsip-ua/sip_ua.h
+++ b/pjsip/include/pjsip-ua/sip_ua.h
@@ -1,82 +1,104 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_SIP_UA_H__
-#define __PJSIP_SIP_UA_H__
-
-/**
- * @file ua.h
- * @brief SIP User Agent Library
- */
-
-#include <pjsip_mod_ua/sip_dialog.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSUA SIP User Agent Stack
- */
-
-/**
- * @defgroup PJSUA_UA SIP User Agent
- * @ingroup PJSUA
- * @{
- * \brief
- *   User Agent manages the interactions between application and SIP dialogs.
- */
-
-typedef struct pjsip_dlg_callback pjsip_dlg_callback;
-
-/**
- * \brief This structure describes a User Agent instance.
- */
-struct pjsip_user_agent
-{
-    pjsip_endpoint     *endpt;
-    pj_pool_t	       *pool;
-    pj_mutex_t	       *mutex;
-    pj_uint32_t		mod_id;
-    pj_hash_table_t    *dlg_table;
-    pjsip_dlg_callback *dlg_cb;
-    pj_list		dlg_list;
-};
-
-/**
- * Create a new dialog.
- */
-PJ_DECL(pjsip_dlg*) pjsip_ua_create_dialog( pjsip_user_agent *ua,
-					       pjsip_role_e role );
-
-
-/**
- * Destroy dialog.
- */
-PJ_DECL(void) pjsip_ua_destroy_dialog( pjsip_dlg *dlg );
-
-
-/** 
- * Register callback to receive dialog notifications.
- */
-PJ_DECL(void) pjsip_ua_set_dialog_callback( pjsip_user_agent *ua, 
-					    pjsip_dlg_callback *cb );
-
-
-/**
- * Get the module interface for the UA module.
- */
-PJ_DECL(pjsip_module*) pjsip_ua_get_module(void);
-
-
-/**
- * Dump user agent state to log file.
- */
-PJ_DECL(void) pjsip_ua_dump( pjsip_user_agent *ua );
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_UA_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_UA_H__

+#define __PJSIP_SIP_UA_H__

+

+/**

+ * @file ua.h

+ * @brief SIP User Agent Library

+ */

+

+#include <pjsip_mod_ua/sip_dialog.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSUA SIP User Agent Stack

+ */

+

+/**

+ * @defgroup PJSUA_UA SIP User Agent

+ * @ingroup PJSUA

+ * @{

+ * \brief

+ *   User Agent manages the interactions between application and SIP dialogs.

+ */

+

+typedef struct pjsip_dlg_callback pjsip_dlg_callback;

+

+/**

+ * \brief This structure describes a User Agent instance.

+ */

+struct pjsip_user_agent

+{

+    pjsip_endpoint     *endpt;

+    pj_pool_t	       *pool;

+    pj_mutex_t	       *mutex;

+    pj_uint32_t		mod_id;

+    pj_hash_table_t    *dlg_table;

+    pjsip_dlg_callback *dlg_cb;

+    pj_list		dlg_list;

+};

+

+/**

+ * Create a new dialog.

+ */

+PJ_DECL(pjsip_dlg*) pjsip_ua_create_dialog( pjsip_user_agent *ua,

+					       pjsip_role_e role );

+

+

+/**

+ * Destroy dialog.

+ */

+PJ_DECL(void) pjsip_ua_destroy_dialog( pjsip_dlg *dlg );

+

+

+/** 

+ * Register callback to receive dialog notifications.

+ */

+PJ_DECL(void) pjsip_ua_set_dialog_callback( pjsip_user_agent *ua, 

+					    pjsip_dlg_callback *cb );

+

+

+/**

+ * Get the module interface for the UA module.

+ */

+PJ_DECL(pjsip_module*) pjsip_ua_get_module(void);

+

+

+/**

+ * Dump user agent state to log file.

+ */

+PJ_DECL(void) pjsip_ua_dump( pjsip_user_agent *ua );

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_UA_H__ */

+

diff --git a/pjsip/include/pjsip/print_util.h b/pjsip/include/pjsip/print_util.h
index b23d45f..0683eec 100644
--- a/pjsip/include/pjsip/print_util.h
+++ b/pjsip/include/pjsip/print_util.h
@@ -1,99 +1,121 @@
-/* $Id$
- */
-#ifndef __PJSIP_PRINT_H__
-#define __PJSIP_PRINT_H__
-
-#define copy_advance_check(buf,str)   \
-	do { \
-	    if ((str).slen+10 >= (endbuf-buf)) return -1;	\
-	    pj_memcpy(buf, (str).ptr, (str).slen); \
-	    buf += (str).slen; \
-	} while (0)
-
-/*
-static char *imp_copy_advance_pair(char *buf, char *endbuf, const char *str1, int len1, const pj_str_t *str2)
-{
-    if (str2->slen) {
-	int printed = len1+str2->slen;
-	if (printed+10 >= (endbuf-buf)) return NULL;
-	pj_memcpy(buf,str1,len1);
-	pj_memcpy(buf+len1, str2->ptr, str2->slen);
-	return buf + printed;
-    } else
-	return buf;
-}
-*/
-
-#define copy_advance_pair_check(buf,str1,len1,str2)   \
-	do { \
-	    if (str2.slen) { \
-		printed = len1+str2.slen; \
-		if (printed+10 >= (endbuf-buf)) return -1;	\
-		pj_memcpy(buf,str1,len1); \
-		pj_memcpy(buf+len1, str2.ptr, str2.slen); \
-		buf += printed; \
-	    } \
-	} while (0)
-/*
-#define copy_advance_pair(buf,str1,len1,str2)   \
-	do { \
-	    buf = imp_copy_advance_pair(buf, endbuf, str1, len1, &str2); \
-	    if (buf == NULL) return -1; \
-	} while (0)
-*/
-
-#define copy_advance_pair_quote_check(buf,str1,len1,str2,quotebegin,quoteend) \
-	do { \
-	    if (str2.slen) { \
-		printed = len1+str2.slen+2; \
-		if (printed+10 >= (endbuf-buf)) return -1;	\
-		pj_memcpy(buf,str1,len1); \
-		*(buf+len1)=quotebegin; \
-		pj_memcpy(buf+len1+1, str2.ptr, str2.slen); \
-		*(buf+printed-1) = quoteend; \
-		buf += printed; \
-	    } \
-	} while (0)
-
-#define copy_advance_no_check(buf,str)   \
-	pj_memcpy(buf, (str).ptr, (str).slen); \
-	buf += (str).slen;
-
-#define copy_advance_pair_no_check(buf,str1,len1,str2)   \
-	if (str2.slen) { \
-	    pj_memcpy(buf,str1,len1); \
-	    pj_memcpy(buf+len1, str2.ptr, str2.slen); \
-	    buf += len1+str2.slen; \
-	}
-
-#define copy_advance 		copy_advance_check
-#define copy_advance_pair 	copy_advance_pair_check
-#define copy_advance_pair_quote	copy_advance_pair_quote_check
-
-#define copy_advance_pair_quote_cond(buf,str1,len1,str2,quotebegin,quoteend) \
-	do {	\
-	    if (str2.slen && *str2.ptr!=quotebegin) \
-		copy_advance_pair_quote(buf,str1,len1,str2,quotebegin,quoteend); \
-	    else \
-		copy_advance_pair(buf,str1,len1,str2); \
-	} while (0)
-
-/*
- * Internal type declarations.
- */
-typedef void* (*pjsip_hdr_clone_fptr)(pj_pool_t *, const void*);
-typedef int   (*pjsip_hdr_print_fptr)(void *hdr, char *buf, pj_size_t len);
-
-extern const pj_str_t pjsip_hdr_names[];
-
-PJ_INLINE(void) init_hdr(void *hptr, pjsip_hdr_e htype, void *vptr)
-{
-    pjsip_hdr *hdr = hptr;
-    hdr->type = htype;
-    hdr->name = hdr->sname = pjsip_hdr_names[htype];
-    hdr->vptr = vptr;
-    pj_list_init(hdr);
-}
-
-#endif	/* __PJSIP_PRINT_H__ */
-
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_PRINT_H__

+#define __PJSIP_PRINT_H__

+

+#define copy_advance_check(buf,str)   \

+	do { \

+	    if ((str).slen+10 >= (endbuf-buf)) return -1;	\

+	    pj_memcpy(buf, (str).ptr, (str).slen); \

+	    buf += (str).slen; \

+	} while (0)

+

+/*

+static char *imp_copy_advance_pair(char *buf, char *endbuf, const char *str1, int len1, const pj_str_t *str2)

+{

+    if (str2->slen) {

+	int printed = len1+str2->slen;

+	if (printed+10 >= (endbuf-buf)) return NULL;

+	pj_memcpy(buf,str1,len1);

+	pj_memcpy(buf+len1, str2->ptr, str2->slen);

+	return buf + printed;

+    } else

+	return buf;

+}

+*/

+

+#define copy_advance_pair_check(buf,str1,len1,str2)   \

+	do { \

+	    if (str2.slen) { \

+		printed = len1+str2.slen; \

+		if (printed+10 >= (endbuf-buf)) return -1;	\

+		pj_memcpy(buf,str1,len1); \

+		pj_memcpy(buf+len1, str2.ptr, str2.slen); \

+		buf += printed; \

+	    } \

+	} while (0)

+/*

+#define copy_advance_pair(buf,str1,len1,str2)   \

+	do { \

+	    buf = imp_copy_advance_pair(buf, endbuf, str1, len1, &str2); \

+	    if (buf == NULL) return -1; \

+	} while (0)

+*/

+

+#define copy_advance_pair_quote_check(buf,str1,len1,str2,quotebegin,quoteend) \

+	do { \

+	    if (str2.slen) { \

+		printed = len1+str2.slen+2; \

+		if (printed+10 >= (endbuf-buf)) return -1;	\

+		pj_memcpy(buf,str1,len1); \

+		*(buf+len1)=quotebegin; \

+		pj_memcpy(buf+len1+1, str2.ptr, str2.slen); \

+		*(buf+printed-1) = quoteend; \

+		buf += printed; \

+	    } \

+	} while (0)

+

+#define copy_advance_no_check(buf,str)   \

+	pj_memcpy(buf, (str).ptr, (str).slen); \

+	buf += (str).slen;

+

+#define copy_advance_pair_no_check(buf,str1,len1,str2)   \

+	if (str2.slen) { \

+	    pj_memcpy(buf,str1,len1); \

+	    pj_memcpy(buf+len1, str2.ptr, str2.slen); \

+	    buf += len1+str2.slen; \

+	}

+

+#define copy_advance 		copy_advance_check

+#define copy_advance_pair 	copy_advance_pair_check

+#define copy_advance_pair_quote	copy_advance_pair_quote_check

+

+#define copy_advance_pair_quote_cond(buf,str1,len1,str2,quotebegin,quoteend) \

+	do {	\

+	    if (str2.slen && *str2.ptr!=quotebegin) \

+		copy_advance_pair_quote(buf,str1,len1,str2,quotebegin,quoteend); \

+	    else \

+		copy_advance_pair(buf,str1,len1,str2); \

+	} while (0)

+

+/*

+ * Internal type declarations.

+ */

+typedef void* (*pjsip_hdr_clone_fptr)(pj_pool_t *, const void*);

+typedef int   (*pjsip_hdr_print_fptr)(void *hdr, char *buf, pj_size_t len);

+

+extern const pj_str_t pjsip_hdr_names[];

+

+PJ_INLINE(void) init_hdr(void *hptr, pjsip_hdr_e htype, void *vptr)

+{

+    pjsip_hdr *hdr = hptr;

+    hdr->type = htype;

+    hdr->name = hdr->sname = pjsip_hdr_names[htype];

+    hdr->vptr = vptr;

+    pj_list_init(hdr);

+}

+

+#endif	/* __PJSIP_PRINT_H__ */

+

diff --git a/pjsip/include/pjsip/sip_auth.h b/pjsip/include/pjsip/sip_auth.h
index c34ca03..71bbfd6 100644
--- a/pjsip/include/pjsip/sip_auth.h
+++ b/pjsip/include/pjsip/sip_auth.h
@@ -1,231 +1,253 @@
-/* $Id$
- */
-#ifndef __PJSIP_AUTH_SIP_AUTH_H__
-#define __PJSIP_AUTH_SIP_AUTH_H__
-
-/**
- * @file pjsip_auth.h
- * @brief SIP Authorization Module.
- */
-
-#include <pjsip/sip_config.h>
-#include <pjsip/sip_auth_msg.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_AUTH_API Authorization API's
- * @ingroup PJSIP_AUTH
- * @{
- */
-
- /** Type of data in the credential information. */
-typedef enum pjsip_cred_data_type
-{
-    PJSIP_CRED_DATA_PLAIN_PASSWD,   /**< Plain text password.	*/
-    PJSIP_CRED_DATA_DIGEST,	    /**< Hashed digest.		*/
-} pjsip_cred_data_type;
-
-/** Authentication's quality of protection (qop) type. */
-typedef enum pjsip_auth_qop_type
-{
-    PJSIP_AUTH_QOP_NONE,	    /**< No quality of protection. */
-    PJSIP_AUTH_QOP_AUTH,	    /**< Authentication. */
-    PJSIP_AUTH_QOP_AUTH_INT,	    /**< Authentication with integrity protection. */
-    PJSIP_AUTH_QOP_UNKNOWN,	    /**< Unknown protection. */
-} pjsip_auth_qop_type;
-
-
-/** 
- * This structure describes credential information. 
- * A credential information is a static, persistent information that identifies
- * username and password required to authorize to a specific realm.
- */
-struct pjsip_cred_info
-{
-    pj_str_t    realm;		/**< Realm.	    */
-    pj_str_t	scheme;		/**< Scheme.	    */
-    pj_str_t	username;	/**< User name.	    */
-    int		data_type;	/**< Type of data.  */
-    pj_str_t	data;		/**< The data, which can be a plaintext 
-				     password or a hashed digest. */
-};
-
-/**
- * This structure describes cached value of previously sent Authorization
- * or Proxy-Authorization header. The authentication framework keeps a list
- * of this structure and will resend the same header to the same server
- * as long as the method, uri, and nonce stays the same.
- */
-typedef struct pjsip_cached_auth_hdr
-{
-    PJ_DECL_LIST_MEMBER(struct pjsip_cached_auth_hdr);
-
-    pjsip_method	     method;
-    pjsip_authorization_hdr *hdr;
-
-} pjsip_cached_auth_hdr;
-
-
-/**
- * This structure describes authentication information for the specified
- * realm. Each instance of this structure describes authentication "session"
- * between this endpoint and remote server. This "session" information is
- * usefull to keep information that persists for more than one challenge,
- * such as nonce-count and cnonce value.
- *
- * Other than that, this structure also keeps the last authorization headers
- * that have been sent in the cache list.
- */
-typedef struct pjsip_auth_session
-{
-    PJ_DECL_LIST_MEMBER(struct pjsip_auth_session);
-
-    pj_str_t			 realm;
-    pj_bool_t			 is_proxy;
-    pjsip_auth_qop_type		 qop_value;
-#if PJSIP_AUTH_QOP_SUPPORT
-    pj_uint32_t			 nc;
-    pj_str_t			 cnonce;
-#endif
-#if PJSIP_AUTH_AUTO_SEND_NEXT
-    pjsip_www_authenticate_hdr	*last_chal;
-#endif
-#if PJSIP_AUTH_HEADER_CACHING
-    pjsip_cached_auth_hdr	 cached_hdr;
-#endif
-
-} pjsip_auth_session;
-
-
-/**
- * Create authorization header for the specified credential.
- * Application calls this function to create Authorization or Proxy-Authorization
- * header after receiving WWW-Authenticate or Proxy-Authenticate challenge
- * (normally in 401/407 response).
- * If authorization session argument is specified, this function will update
- * the session with the updated information if required (e.g. to update
- * nonce-count when qop is "auth" or "auth-int"). This function will also
- * save the authorization header in the session's cached header list.
- *
- * @param req_pool	Pool to allocate new header for the request.
- * @param hdr		The WWW-Authenticate or Proxy-Authenticate found in 
- *			the response.
- * @param uri		The URI for which authorization is targeted to.
- * @param cred_info	The credential to be used for authentication.
- * @param method	The method.
- * @param sess_pool	Session pool to update session or to allocate message
- *			in the cache. May be NULL if auth_sess is NULL.
- * @param auth_sess	If not NULL, this specifies the specific authentication
- *			session to be used or updated.
- *
- * @return		The Authorization header, which can be typecasted to 
- *			Proxy-Authorization.
- */
-PJ_DECL(pjsip_authorization_hdr*) pjsip_auth_respond( 
-					 pj_pool_t *req_pool,
-					 const pjsip_www_authenticate_hdr *hdr,
-					 const pjsip_uri *uri,
-					 const pjsip_cred_info *cred_info,
-					 const pjsip_method *method,
-					 pj_pool_t *sess_pool,
-					 pjsip_auth_session *auth_sess);
-
-/**
- * Verify digest in the authorization request.
- *
- * @param hdr		The incoming Authorization/Proxy-Authorization header.
- * @param method	The method.
- * @param password	The plaintext password to verify.
- *
- * @return		Non-zero if authorization succeed.
- */
-PJ_DECL(pj_bool_t) pjsip_auth_verify(	const pjsip_authorization_hdr *hdr,
-					const pj_str_t *method,
-					const pjsip_cred_info *cred_info );
-
-
-/**
- * This function can be used to find credential information which matches
- * the specified realm.
- *
- * @param count		Number of credentials in the parameter.
- * @param cred		The array of credentials.
- * @param realm		Realm to search.
- * @param scheme	Authentication scheme.
- *
- * @return		The credential which matches the specified realm.
- */
-PJ_DECL(const pjsip_cred_info*) pjsip_auth_find_cred( unsigned count,
-						      const pjsip_cred_info cred[],
-						      const pj_str_t *realm,
-						      const pj_str_t *scheme );
-
-
-/**
- * Initialize new request message with authorization headers.
- * This function will put Authorization/Proxy-Authorization headers to the
- * outgoing request message. If caching is enabled (PJSIP_AUTH_HEADER_CACHING)
- * and the session has previously sent Authorization/Proxy-Authorization header
- * with the same method, then the same Authorization/Proxy-Authorization header
- * will be resent from the cache only if qop is not present. If the stack is 
- * configured to automatically generate next Authorization/Proxy-Authorization
- * headers (PJSIP_AUTH_AUTO_SEND_NEXT flag), then new Authorization/Proxy-
- * Authorization headers are calculated and generated when they are not present
- * in the case or if authorization session has qop.
- *
- * If both PJSIP_AUTH_HEADER_CACHING flag and PJSIP_AUTH_AUTO_SEND_NEXT flag
- * are not set, this function will do nothing. The stack then will only send
- * Authorization/Proxy-Authorization to respond 401/407 response.
- *
- * @param sess_pool	Session level pool, where memory will be allocated from
- *			for data that persists across requests (e.g. caching).
- * @param tdata		The request message to be initialized.
- * @param sess_list	List of authorization sessions that have been recorded.
- * @param cred_count	Number of credentials.
- * @param cred_info	Array of credentials.
- *
- * @return		Zero if successfull.
- */
-PJ_DECL(pj_status_t) pjsip_auth_init_req( pj_pool_t *sess_pool,
-					  pjsip_tx_data *tdata,
-					  pjsip_auth_session *sess_list,
-					  int cred_count, 
-					  const pjsip_cred_info cred_info[]);
-
-/**
- * Call this function when a transaction failed with 401 or 407 response.
- * This function will reinitialize the original request message with the
- * authentication challenge found in the response message, and add the
- * new authorization header in the authorization cache.
- *
- * Note that upon return the reference counter of the transmit data
- * will be incremented.
- *
- * @param endpt		Endpoint.
- * @param pool		The pool to allocate memory for new cred_info.
- * @param cached_list	Cached authorization headers.
- * @param cred_count	Number of credentials.
- * @param cred_info	Array of credentials to use.
- * @param tdata		The original request message, which normally can be
- *			retrieved from tsx->last_tx.
- * @param rdata		The response message containing 401/407 status.
- *
- * @return		New transmit data buffer, or NULL if the dialog
- *			can not respond to the authorization challenge.
- */
-PJ_DECL(pjsip_tx_data*) 
-pjsip_auth_reinit_req( pjsip_endpoint *endpt,
-		       pj_pool_t *ses_pool,
-		       pjsip_auth_session *sess_list,
-		       int cred_count, const pjsip_cred_info cred_info[],
-		       pjsip_tx_data *tdata, const pjsip_rx_data *rdata);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_AUTH_SIP_AUTH_H__ */
-
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_AUTH_SIP_AUTH_H__

+#define __PJSIP_AUTH_SIP_AUTH_H__

+

+/**

+ * @file pjsip_auth.h

+ * @brief SIP Authorization Module.

+ */

+

+#include <pjsip/sip_config.h>

+#include <pjsip/sip_auth_msg.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_AUTH_API Authorization API's

+ * @ingroup PJSIP_AUTH

+ * @{

+ */

+

+ /** Type of data in the credential information. */

+typedef enum pjsip_cred_data_type

+{

+    PJSIP_CRED_DATA_PLAIN_PASSWD,   /**< Plain text password.	*/

+    PJSIP_CRED_DATA_DIGEST,	    /**< Hashed digest.		*/

+} pjsip_cred_data_type;

+

+/** Authentication's quality of protection (qop) type. */

+typedef enum pjsip_auth_qop_type

+{

+    PJSIP_AUTH_QOP_NONE,	    /**< No quality of protection. */

+    PJSIP_AUTH_QOP_AUTH,	    /**< Authentication. */

+    PJSIP_AUTH_QOP_AUTH_INT,	    /**< Authentication with integrity protection. */

+    PJSIP_AUTH_QOP_UNKNOWN,	    /**< Unknown protection. */

+} pjsip_auth_qop_type;

+

+

+/** 

+ * This structure describes credential information. 

+ * A credential information is a static, persistent information that identifies

+ * username and password required to authorize to a specific realm.

+ */

+struct pjsip_cred_info

+{

+    pj_str_t    realm;		/**< Realm.	    */

+    pj_str_t	scheme;		/**< Scheme.	    */

+    pj_str_t	username;	/**< User name.	    */

+    int		data_type;	/**< Type of data.  */

+    pj_str_t	data;		/**< The data, which can be a plaintext 

+				     password or a hashed digest. */

+};

+

+/**

+ * This structure describes cached value of previously sent Authorization

+ * or Proxy-Authorization header. The authentication framework keeps a list

+ * of this structure and will resend the same header to the same server

+ * as long as the method, uri, and nonce stays the same.

+ */

+typedef struct pjsip_cached_auth_hdr

+{

+    PJ_DECL_LIST_MEMBER(struct pjsip_cached_auth_hdr);

+

+    pjsip_method	     method;

+    pjsip_authorization_hdr *hdr;

+

+} pjsip_cached_auth_hdr;

+

+

+/**

+ * This structure describes authentication information for the specified

+ * realm. Each instance of this structure describes authentication "session"

+ * between this endpoint and remote server. This "session" information is

+ * usefull to keep information that persists for more than one challenge,

+ * such as nonce-count and cnonce value.

+ *

+ * Other than that, this structure also keeps the last authorization headers

+ * that have been sent in the cache list.

+ */

+typedef struct pjsip_auth_session

+{

+    PJ_DECL_LIST_MEMBER(struct pjsip_auth_session);

+

+    pj_str_t			 realm;

+    pj_bool_t			 is_proxy;

+    pjsip_auth_qop_type		 qop_value;

+#if PJSIP_AUTH_QOP_SUPPORT

+    pj_uint32_t			 nc;

+    pj_str_t			 cnonce;

+#endif

+#if PJSIP_AUTH_AUTO_SEND_NEXT

+    pjsip_www_authenticate_hdr	*last_chal;

+#endif

+#if PJSIP_AUTH_HEADER_CACHING

+    pjsip_cached_auth_hdr	 cached_hdr;

+#endif

+

+} pjsip_auth_session;

+

+

+/**

+ * Create authorization header for the specified credential.

+ * Application calls this function to create Authorization or Proxy-Authorization

+ * header after receiving WWW-Authenticate or Proxy-Authenticate challenge

+ * (normally in 401/407 response).

+ * If authorization session argument is specified, this function will update

+ * the session with the updated information if required (e.g. to update

+ * nonce-count when qop is "auth" or "auth-int"). This function will also

+ * save the authorization header in the session's cached header list.

+ *

+ * @param req_pool	Pool to allocate new header for the request.

+ * @param hdr		The WWW-Authenticate or Proxy-Authenticate found in 

+ *			the response.

+ * @param uri		The URI for which authorization is targeted to.

+ * @param cred_info	The credential to be used for authentication.

+ * @param method	The method.

+ * @param sess_pool	Session pool to update session or to allocate message

+ *			in the cache. May be NULL if auth_sess is NULL.

+ * @param auth_sess	If not NULL, this specifies the specific authentication

+ *			session to be used or updated.

+ *

+ * @return		The Authorization header, which can be typecasted to 

+ *			Proxy-Authorization.

+ */

+PJ_DECL(pjsip_authorization_hdr*) pjsip_auth_respond( 

+					 pj_pool_t *req_pool,

+					 const pjsip_www_authenticate_hdr *hdr,

+					 const pjsip_uri *uri,

+					 const pjsip_cred_info *cred_info,

+					 const pjsip_method *method,

+					 pj_pool_t *sess_pool,

+					 pjsip_auth_session *auth_sess);

+

+/**

+ * Verify digest in the authorization request.

+ *

+ * @param hdr		The incoming Authorization/Proxy-Authorization header.

+ * @param method	The method.

+ * @param password	The plaintext password to verify.

+ *

+ * @return		Non-zero if authorization succeed.

+ */

+PJ_DECL(pj_bool_t) pjsip_auth_verify(	const pjsip_authorization_hdr *hdr,

+					const pj_str_t *method,

+					const pjsip_cred_info *cred_info );

+

+

+/**

+ * This function can be used to find credential information which matches

+ * the specified realm.

+ *

+ * @param count		Number of credentials in the parameter.

+ * @param cred		The array of credentials.

+ * @param realm		Realm to search.

+ * @param scheme	Authentication scheme.

+ *

+ * @return		The credential which matches the specified realm.

+ */

+PJ_DECL(const pjsip_cred_info*) pjsip_auth_find_cred( unsigned count,

+						      const pjsip_cred_info cred[],

+						      const pj_str_t *realm,

+						      const pj_str_t *scheme );

+

+

+/**

+ * Initialize new request message with authorization headers.

+ * This function will put Authorization/Proxy-Authorization headers to the

+ * outgoing request message. If caching is enabled (PJSIP_AUTH_HEADER_CACHING)

+ * and the session has previously sent Authorization/Proxy-Authorization header

+ * with the same method, then the same Authorization/Proxy-Authorization header

+ * will be resent from the cache only if qop is not present. If the stack is 

+ * configured to automatically generate next Authorization/Proxy-Authorization

+ * headers (PJSIP_AUTH_AUTO_SEND_NEXT flag), then new Authorization/Proxy-

+ * Authorization headers are calculated and generated when they are not present

+ * in the case or if authorization session has qop.

+ *

+ * If both PJSIP_AUTH_HEADER_CACHING flag and PJSIP_AUTH_AUTO_SEND_NEXT flag

+ * are not set, this function will do nothing. The stack then will only send

+ * Authorization/Proxy-Authorization to respond 401/407 response.

+ *

+ * @param sess_pool	Session level pool, where memory will be allocated from

+ *			for data that persists across requests (e.g. caching).

+ * @param tdata		The request message to be initialized.

+ * @param sess_list	List of authorization sessions that have been recorded.

+ * @param cred_count	Number of credentials.

+ * @param cred_info	Array of credentials.

+ *

+ * @return		Zero if successfull.

+ */

+PJ_DECL(pj_status_t) pjsip_auth_init_req( pj_pool_t *sess_pool,

+					  pjsip_tx_data *tdata,

+					  pjsip_auth_session *sess_list,

+					  int cred_count, 

+					  const pjsip_cred_info cred_info[]);

+

+/**

+ * Call this function when a transaction failed with 401 or 407 response.

+ * This function will reinitialize the original request message with the

+ * authentication challenge found in the response message, and add the

+ * new authorization header in the authorization cache.

+ *

+ * Note that upon return the reference counter of the transmit data

+ * will be incremented.

+ *

+ * @param endpt		Endpoint.

+ * @param pool		The pool to allocate memory for new cred_info.

+ * @param cached_list	Cached authorization headers.

+ * @param cred_count	Number of credentials.

+ * @param cred_info	Array of credentials to use.

+ * @param tdata		The original request message, which normally can be

+ *			retrieved from tsx->last_tx.

+ * @param rdata		The response message containing 401/407 status.

+ *

+ * @return		New transmit data buffer, or NULL if the dialog

+ *			can not respond to the authorization challenge.

+ */

+PJ_DECL(pjsip_tx_data*) 

+pjsip_auth_reinit_req( pjsip_endpoint *endpt,

+		       pj_pool_t *ses_pool,

+		       pjsip_auth_session *sess_list,

+		       int cred_count, const pjsip_cred_info cred_info[],

+		       pjsip_tx_data *tdata, const pjsip_rx_data *rdata);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_AUTH_SIP_AUTH_H__ */

+

diff --git a/pjsip/include/pjsip/sip_auth_msg.h b/pjsip/include/pjsip/sip_auth_msg.h
index 8e68331..e2e703b 100644
--- a/pjsip/include/pjsip/sip_auth_msg.h
+++ b/pjsip/include/pjsip/sip_auth_msg.h
@@ -1,193 +1,215 @@
-/* $Id$
- */
-#ifndef __PJSIP_AUTH_SIP_AUTH_MSG_H__
-#define __PJSIP_AUTH_SIP_AUTH_MSG_H__
-
-#include <pjsip/sip_msg.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_MSG_AUTHORIZATION Header Field: Authorization and Proxy-Authorization
- * @brief Authorization and Proxy-Authorization header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * Common credential.
- */
-struct pjsip_common_credential
-{
-    pj_str_t	realm;
-};
-
-typedef struct pjsip_common_credential pjsip_common_credential;
-
-
-/**
- * This structure describe credential used in Authorization and
- * Proxy-Authorization header for digest authentication scheme.
- */
-struct pjsip_digest_credential
-{
-    pj_str_t	realm;
-    pj_str_t	username;
-    pj_str_t	nonce;
-    pj_str_t	uri;
-    pj_str_t	response;
-    pj_str_t	algorithm;
-    pj_str_t	cnonce;
-    pj_str_t	opaque;
-    pj_str_t	qop;
-    pj_str_t	nc;
-    pj_str_t	other_param;
-};
-
-typedef struct pjsip_digest_credential pjsip_digest_credential;
-
-/**
- * This structure describe credential used in Authorization and
- * Proxy-Authorization header for PGP authentication scheme.
- */
-struct pjsip_pgp_credential
-{
-    pj_str_t	realm;
-    pj_str_t	version;
-    pj_str_t	signature;
-    pj_str_t	signed_by;
-    pj_str_t	nonce;
-};
-
-typedef struct pjsip_pgp_credential pjsip_pgp_credential;
-
-/**
- * This structure describes SIP Authorization header (and also SIP
- * Proxy-Authorization header).
- */
-struct pjsip_authorization_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_authorization_hdr);
-    pj_str_t scheme;
-    union
-    {
-	pjsip_common_credential common;
-	pjsip_digest_credential digest;
-	pjsip_pgp_credential	pgp;
-    } credential;
-};
-
-typedef struct pjsip_authorization_hdr pjsip_authorization_hdr;
-
-/** SIP Proxy-Authorization header shares the same structure as SIP
-    Authorization header.
- */
-typedef struct pjsip_authorization_hdr pjsip_proxy_authorization_hdr;
-
-/**
- * Create SIP Authorization header.
- * @param pool Pool where memory will be allocated from.
- * @return SIP Authorization header.
- */
-PJ_DECL(pjsip_authorization_hdr*) pjsip_authorization_hdr_create(pj_pool_t *pool);
-
-/**
- * Create SIP Proxy-Authorization header.
- * @param pool Pool where memory will be allocated from.
- * @return SIP Proxy-Authorization header.
- */
-PJ_DECL(pjsip_proxy_authorization_hdr*) pjsip_proxy_authorization_hdr_create(pj_pool_t *pool);
-
-
-/**
- * @}
- */
-
-/**
- * @defgroup PJSIP_WWW_AUTH Header Field: Proxy-Authenticate and WWW-Authenticate
- * @brief Proxy-Authenticate and WWW-Authenticate.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-struct pjsip_common_challenge
-{
-    pj_str_t	realm;
-};
-
-typedef struct pjsip_common_challenge pjsip_common_challenge;
-
-/**
- * This structure describes authentication challenge used in Proxy-Authenticate
- * or WWW-Authenticate for digest authentication scheme.
- */
-struct pjsip_digest_challenge
-{
-    pj_str_t	realm;
-    pj_str_t	domain;
-    pj_str_t	nonce;
-    pj_str_t	opaque;
-    int		stale;
-    pj_str_t	algorithm;
-    pj_str_t	qop;
-    pj_str_t	other_param;
-};
-
-typedef struct pjsip_digest_challenge pjsip_digest_challenge;
-
-/**
- * This structure describes authentication challenge used in Proxy-Authenticate
- * or WWW-Authenticate for PGP authentication scheme.
- */
-struct pjsip_pgp_challenge
-{
-    pj_str_t	realm;
-    pj_str_t	version;
-    pj_str_t	micalgorithm;
-    pj_str_t	pubalgorithm;
-    pj_str_t	nonce;
-};
-
-typedef struct pjsip_pgp_challenge pjsip_pgp_challenge;
-
-/**
- * This structure describe SIP WWW-Authenticate header (Proxy-Authenticate
- * header also uses the same structure).
- */
-struct pjsip_www_authenticate_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_www_authenticate_hdr);
-    pj_str_t	scheme;
-    union
-    {
-	pjsip_common_challenge	common;
-	pjsip_digest_challenge	digest;
-	pjsip_pgp_challenge	pgp;
-    } challenge;
-};
-
-typedef struct pjsip_www_authenticate_hdr pjsip_www_authenticate_hdr;
-typedef struct pjsip_www_authenticate_hdr pjsip_proxy_authenticate_hdr;
-
-
-/**
- * Create SIP WWW-Authenticate header.
- * @param pool Pool where memory will be allocated from.
- * @return SIP WWW-Authenticate header.
- */
-PJ_DECL(pjsip_www_authenticate_hdr*) pjsip_www_authenticate_hdr_create(pj_pool_t *pool);
-
-/**
- * Create SIP Proxy-Authenticate header.
- * @param pool Pool where memory will be allocated from.
- * @return SIP Proxy-Authenticate header.
- */
-PJ_DECL(pjsip_proxy_authenticate_hdr*) pjsip_proxy_authenticate_hdr_create(pj_pool_t *pool);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_AUTH_SIP_AUTH_MSG_H__ */
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_AUTH_SIP_AUTH_MSG_H__

+#define __PJSIP_AUTH_SIP_AUTH_MSG_H__

+

+#include <pjsip/sip_msg.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_MSG_AUTHORIZATION Header Field: Authorization and Proxy-Authorization

+ * @brief Authorization and Proxy-Authorization header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * Common credential.

+ */

+struct pjsip_common_credential

+{

+    pj_str_t	realm;

+};

+

+typedef struct pjsip_common_credential pjsip_common_credential;

+

+

+/**

+ * This structure describe credential used in Authorization and

+ * Proxy-Authorization header for digest authentication scheme.

+ */

+struct pjsip_digest_credential

+{

+    pj_str_t	realm;

+    pj_str_t	username;

+    pj_str_t	nonce;

+    pj_str_t	uri;

+    pj_str_t	response;

+    pj_str_t	algorithm;

+    pj_str_t	cnonce;

+    pj_str_t	opaque;

+    pj_str_t	qop;

+    pj_str_t	nc;

+    pj_str_t	other_param;

+};

+

+typedef struct pjsip_digest_credential pjsip_digest_credential;

+

+/**

+ * This structure describe credential used in Authorization and

+ * Proxy-Authorization header for PGP authentication scheme.

+ */

+struct pjsip_pgp_credential

+{

+    pj_str_t	realm;

+    pj_str_t	version;

+    pj_str_t	signature;

+    pj_str_t	signed_by;

+    pj_str_t	nonce;

+};

+

+typedef struct pjsip_pgp_credential pjsip_pgp_credential;

+

+/**

+ * This structure describes SIP Authorization header (and also SIP

+ * Proxy-Authorization header).

+ */

+struct pjsip_authorization_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_authorization_hdr);

+    pj_str_t scheme;

+    union

+    {

+	pjsip_common_credential common;

+	pjsip_digest_credential digest;

+	pjsip_pgp_credential	pgp;

+    } credential;

+};

+

+typedef struct pjsip_authorization_hdr pjsip_authorization_hdr;

+

+/** SIP Proxy-Authorization header shares the same structure as SIP

+    Authorization header.

+ */

+typedef struct pjsip_authorization_hdr pjsip_proxy_authorization_hdr;

+

+/**

+ * Create SIP Authorization header.

+ * @param pool Pool where memory will be allocated from.

+ * @return SIP Authorization header.

+ */

+PJ_DECL(pjsip_authorization_hdr*) pjsip_authorization_hdr_create(pj_pool_t *pool);

+

+/**

+ * Create SIP Proxy-Authorization header.

+ * @param pool Pool where memory will be allocated from.

+ * @return SIP Proxy-Authorization header.

+ */

+PJ_DECL(pjsip_proxy_authorization_hdr*) pjsip_proxy_authorization_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * @}

+ */

+

+/**

+ * @defgroup PJSIP_WWW_AUTH Header Field: Proxy-Authenticate and WWW-Authenticate

+ * @brief Proxy-Authenticate and WWW-Authenticate.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+struct pjsip_common_challenge

+{

+    pj_str_t	realm;

+};

+

+typedef struct pjsip_common_challenge pjsip_common_challenge;

+

+/**

+ * This structure describes authentication challenge used in Proxy-Authenticate

+ * or WWW-Authenticate for digest authentication scheme.

+ */

+struct pjsip_digest_challenge

+{

+    pj_str_t	realm;

+    pj_str_t	domain;

+    pj_str_t	nonce;

+    pj_str_t	opaque;

+    int		stale;

+    pj_str_t	algorithm;

+    pj_str_t	qop;

+    pj_str_t	other_param;

+};

+

+typedef struct pjsip_digest_challenge pjsip_digest_challenge;

+

+/**

+ * This structure describes authentication challenge used in Proxy-Authenticate

+ * or WWW-Authenticate for PGP authentication scheme.

+ */

+struct pjsip_pgp_challenge

+{

+    pj_str_t	realm;

+    pj_str_t	version;

+    pj_str_t	micalgorithm;

+    pj_str_t	pubalgorithm;

+    pj_str_t	nonce;

+};

+

+typedef struct pjsip_pgp_challenge pjsip_pgp_challenge;

+

+/**

+ * This structure describe SIP WWW-Authenticate header (Proxy-Authenticate

+ * header also uses the same structure).

+ */

+struct pjsip_www_authenticate_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_www_authenticate_hdr);

+    pj_str_t	scheme;

+    union

+    {

+	pjsip_common_challenge	common;

+	pjsip_digest_challenge	digest;

+	pjsip_pgp_challenge	pgp;

+    } challenge;

+};

+

+typedef struct pjsip_www_authenticate_hdr pjsip_www_authenticate_hdr;

+typedef struct pjsip_www_authenticate_hdr pjsip_proxy_authenticate_hdr;

+

+

+/**

+ * Create SIP WWW-Authenticate header.

+ * @param pool Pool where memory will be allocated from.

+ * @return SIP WWW-Authenticate header.

+ */

+PJ_DECL(pjsip_www_authenticate_hdr*) pjsip_www_authenticate_hdr_create(pj_pool_t *pool);

+

+/**

+ * Create SIP Proxy-Authenticate header.

+ * @param pool Pool where memory will be allocated from.

+ * @return SIP Proxy-Authenticate header.

+ */

+PJ_DECL(pjsip_proxy_authenticate_hdr*) pjsip_proxy_authenticate_hdr_create(pj_pool_t *pool);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_AUTH_SIP_AUTH_MSG_H__ */

diff --git a/pjsip/include/pjsip/sip_auth_parser.h b/pjsip/include/pjsip/sip_auth_parser.h
index c1d4f23..5794818 100644
--- a/pjsip/include/pjsip/sip_auth_parser.h
+++ b/pjsip/include/pjsip/sip_auth_parser.h
@@ -1,71 +1,93 @@
-/* $Id$
- */
-#ifndef __PJSIP_AUTH_SIP_AUTH_PARSER_H__
-#define __PJSIP_AUTH_SIP_AUTH_PARSER_H__
-
-/**
- * @file pjsip_auth_parser.h
- * @brief SIP Authorization Parser Module.
- */
-
-#include <pj/types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_AUTH_PARSER_MODULE Authorization Parser Module
- * @ingroup PJSIP_AUTH
- * @{
- */
-
-/**
- * Initialize and register authorization parser module.
- * This will register parser handler for various Authorization related headers
- * such as Authorization, WWW-Authenticate, Proxy-Authorizization, and 
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_AUTH_SIP_AUTH_PARSER_H__

+#define __PJSIP_AUTH_SIP_AUTH_PARSER_H__

+

+/**

+ * @file pjsip_auth_parser.h

+ * @brief SIP Authorization Parser Module.

+ */

+

+#include <pj/types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_AUTH_PARSER_MODULE Authorization Parser Module

+ * @ingroup PJSIP_AUTH

+ * @{

+ */

+

+/**

+ * Initialize and register authorization parser module.

+ * This will register parser handler for various Authorization related headers

+ * such as Authorization, WWW-Authenticate, Proxy-Authorizization, and 

  * Proxy-Authenticate headers.

  *

- * @return      PJ_SUCCESS or the appropriate status code.
- */
-PJ_DECL(pj_status_t) pjsip_auth_init_parser(void);
-
-/**
- * DeInitialize authorization parser module.
- */
-PJ_DECL(void) pjsip_auth_deinit_parser();
-
-
-extern const pj_str_t	pjsip_USERNAME_STR,
-			pjsip_REALM_STR,
-			pjsip_NONCE_STR,
-			pjsip_URI_STR,
-			pjsip_RESPONSE_STR,
-			pjsip_ALGORITHM_STR,
-			pjsip_DOMAIN_STR,
-			pjsip_STALE_STR,
-			pjsip_QOP_STR,
-			pjsip_CNONCE_STR,
-			pjsip_OPAQUE_STR,
-			pjsip_NC_STR,
-			pjsip_TRUE_STR,
-			pjsip_FALSE_STR,
-			pjsip_DIGEST_STR,
-			pjsip_PGP_STR,
-			pjsip_MD5_STR,
-			pjsip_AUTH_STR;
-/*
-extern const pj_str_t	pjsip_QUOTED_TRUE_STR,
-			pjsip_QUOTED_FALSE_STR,
-			pjsip_QUOTED_DIGEST_STR,
-			pjsip_QUOTED_PGP_STR,
-			pjsip_QUOTED_MD5_STR,
-			pjsip_QUOTED_AUTH_STR;
-*/
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_AUTH_SIP_AUTH_PARSER_H__ */
-
+ * @return      PJ_SUCCESS or the appropriate status code.

+ */

+PJ_DECL(pj_status_t) pjsip_auth_init_parser(void);

+

+/**

+ * DeInitialize authorization parser module.

+ */

+PJ_DECL(void) pjsip_auth_deinit_parser();

+

+

+extern const pj_str_t	pjsip_USERNAME_STR,

+			pjsip_REALM_STR,

+			pjsip_NONCE_STR,

+			pjsip_URI_STR,

+			pjsip_RESPONSE_STR,

+			pjsip_ALGORITHM_STR,

+			pjsip_DOMAIN_STR,

+			pjsip_STALE_STR,

+			pjsip_QOP_STR,

+			pjsip_CNONCE_STR,

+			pjsip_OPAQUE_STR,

+			pjsip_NC_STR,

+			pjsip_TRUE_STR,

+			pjsip_FALSE_STR,

+			pjsip_DIGEST_STR,

+			pjsip_PGP_STR,

+			pjsip_MD5_STR,

+			pjsip_AUTH_STR;

+/*

+extern const pj_str_t	pjsip_QUOTED_TRUE_STR,

+			pjsip_QUOTED_FALSE_STR,

+			pjsip_QUOTED_DIGEST_STR,

+			pjsip_QUOTED_PGP_STR,

+			pjsip_QUOTED_MD5_STR,

+			pjsip_QUOTED_AUTH_STR;

+*/

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_AUTH_SIP_AUTH_PARSER_H__ */

+

diff --git a/pjsip/include/pjsip/sip_config.h b/pjsip/include/pjsip/sip_config.h
index bba037c..10a6e25 100644
--- a/pjsip/include/pjsip/sip_config.h
+++ b/pjsip/include/pjsip/sip_config.h
@@ -1,138 +1,160 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_CONFIG_H__
-#define __PJSIP_SIP_CONFIG_H__
-
-#include <pj/config.h>
-
-/* Endpoint. */
-#define PJSIP_MAX_TIMER_COUNT		(2*PJSIP_MAX_TSX_COUNT + 2*PJSIP_MAX_DIALOG_COUNT)
-#define PJSIP_POOL_LEN_ENDPT		(2048+64*PJSIP_MAX_TSX_COUNT)
-#define PJSIP_POOL_INC_ENDPT		(1024)
-
-/* Transport related constants. */
-#define PJSIP_MAX_TRANSPORTS		(PJ_IOQUEUE_MAX_HANDLES)
-#define PJSIP_MAX_PKT_LEN		1500
-#define PJSIP_POOL_LEN_RDATA		2500
-#define PJSIP_POOL_INC_RDATA		512
-#define PJSIP_POOL_LEN_TRANSPORT	512
-#define PJSIP_POOL_INC_TRANSPORT	512
-#define PJSIP_POOL_LEN_TDATA		2500
-#define PJSIP_POOL_INC_TDATA		512
-#define PJSIP_POOL_LEN_UA		(64 + 32*PJSIP_MAX_DIALOG_COUNT)
-#define PJSIP_POOL_INC_UA		0
-#define PJSIP_TRANSPORT_CLOSE_TIMEOUT	30
-#define PJSIP_MAX_TRANSPORT_USAGE	16
-
-#define PJSIP_MAX_FORWARDS_VALUE	70
-
-#define PJSIP_RFC3261_BRANCH_ID		"z9hG4bK"
-#define PJSIP_RFC3261_BRANCH_LEN	7
-
-/* Message/URL related constants. */
-#define PJSIP_MAX_CALL_ID_LEN		PJ_GUID_STRING_LENGTH
-#define PJSIP_MAX_TAG_LEN		PJ_GUID_STRING_LENGTH
-#define PJSIP_MAX_BRANCH_LEN		(PJSIP_RFC3261_BRANCH_LEN + PJ_GUID_STRING_LENGTH)
-#define PJSIP_MAX_URL_SIZE		256
-#define PJSIP_MAX_HNAME_LEN		64
-
-/* Transction related constants. */
-#define PJSIP_MAX_TSX_COUNT		(16*1024)
-#define PJSIP_POOL_LEN_TSX		1536 //768
-#define PJSIP_POOL_INC_TSX		256
-#define PJSIP_MAX_TSX_KEY_LEN		(PJSIP_MAX_URL_SIZE*2)
-
-/* Dialog related constants. */
-#define PJSIP_MAX_DIALOG_COUNT		(16*1024)
-#define PJSIP_POOL_LEN_DIALOG		1200
-#define PJSIP_POOL_INC_DIALOG		512
-
-/* Module related constants. */
-#define PJSIP_MAX_MODULE		8
-
-/*****************************************************************************
- *  Default timeout settings, in miliseconds. 
- */
-
-//#define PJSIP_T1_TIMEOUT	15000
-//#define PJSIP_T2_TIMEOUT	60000
-
-/* T1 timeout value. */
-#if !defined(PJSIP_T1_TIMEOUT)
-#  define PJSIP_T1_TIMEOUT	500
-#endif
-
-/* T2 timeout value. */
-#if !defined(PJSIP_T2_TIMEOUT)
-#  define PJSIP_T2_TIMEOUT	4000
-#endif
-
-/* Completed timer for non-INVITE */
-#if !defined(PJSIP_T4_TIMEOUT)
-#  define PJSIP_T4_TIMEOUT	5000
-#endif
-
-/* Completed timer for INVITE */
-#if !defined(PJSIP_TD_TIMEOUT)
-#  define PJSIP_TD_TIMEOUT	32000
-#endif
-
-
-/*****************************************************************************
- *  Authorization
- */
-
-/*
- * If this flag is set, the stack will keep the Authorization/Proxy-Authorization
- * headers that are sent in a cache. Future requests with the same realm and
- * the same method will use the headers in the cache (as long as no qop is
- * required by server).
- *
- * Turning on this flag will make authorization process goes faster, but
- * will grow the memory usage undefinitely until the dialog/registration
- * session is terminated.
- *
- * Default: 1
- */
-#if !defined(PJSIP_AUTH_HEADER_CACHING)
-#   define PJSIP_AUTH_HEADER_CACHING	    1
-#endif
-
-/*
- * If this flag is set, the stack will proactively send Authorization/Proxy-
- * Authorization header for next requests. If next request has the same method
- * with any of previous requests, then the last header which is saved in
- * the cache will be used (if PJSIP_AUTH_CACHING is set). Otherwise a fresh
- * header will be recalculated. If a particular server has requested qop, then
- * a fresh header will always be calculated.
- *
- * If this flag is NOT set, then the stack will only send Authorization/Proxy-
- * Authorization headers when it receives 401/407 response from server.
- *
- * Turning ON this flag will grow memory usage of a dialog/registration pool
- * indefinitely until it is terminated, because the stack needs to keep the
- * last WWW-Authenticate/Proxy-Authenticate challenge.
- *
- * Default: 1
- */
-#if !defined(PJSIP_AUTH_AUTO_SEND_NEXT)
-#   define PJSIP_AUTH_AUTO_SEND_NEXT	    1
-#endif
-
-/*
- * Support qop="auth" directive.
- * This option also requires client to cache the last challenge offered by
- * server.
- *
- * Default: 1
- */
-#if !defined(PJSIP_AUTH_QOP_SUPPORT)
-#   define PJSIP_AUTH_QOP_SUPPORT	    1
-#endif
-
-
-#include <pj/config.h>
-
-
-#endif	/* __PJSIP_SIP_CONFIG_H__ */
-
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_CONFIG_H__

+#define __PJSIP_SIP_CONFIG_H__

+

+#include <pj/config.h>

+

+/* Endpoint. */

+#define PJSIP_MAX_TIMER_COUNT		(2*PJSIP_MAX_TSX_COUNT + 2*PJSIP_MAX_DIALOG_COUNT)

+#define PJSIP_POOL_LEN_ENDPT		(2048+64*PJSIP_MAX_TSX_COUNT)

+#define PJSIP_POOL_INC_ENDPT		(1024)

+

+/* Transport related constants. */

+#define PJSIP_MAX_TRANSPORTS		(PJ_IOQUEUE_MAX_HANDLES)

+#define PJSIP_MAX_PKT_LEN		1500

+#define PJSIP_POOL_LEN_RDATA		2500

+#define PJSIP_POOL_INC_RDATA		512

+#define PJSIP_POOL_LEN_TRANSPORT	512

+#define PJSIP_POOL_INC_TRANSPORT	512

+#define PJSIP_POOL_LEN_TDATA		2500

+#define PJSIP_POOL_INC_TDATA		512

+#define PJSIP_POOL_LEN_UA		(64 + 32*PJSIP_MAX_DIALOG_COUNT)

+#define PJSIP_POOL_INC_UA		0

+#define PJSIP_TRANSPORT_CLOSE_TIMEOUT	30

+#define PJSIP_MAX_TRANSPORT_USAGE	16

+

+#define PJSIP_MAX_FORWARDS_VALUE	70

+

+#define PJSIP_RFC3261_BRANCH_ID		"z9hG4bK"

+#define PJSIP_RFC3261_BRANCH_LEN	7

+

+/* Message/URL related constants. */

+#define PJSIP_MAX_CALL_ID_LEN		PJ_GUID_STRING_LENGTH

+#define PJSIP_MAX_TAG_LEN		PJ_GUID_STRING_LENGTH

+#define PJSIP_MAX_BRANCH_LEN		(PJSIP_RFC3261_BRANCH_LEN + PJ_GUID_STRING_LENGTH)

+#define PJSIP_MAX_URL_SIZE		256

+#define PJSIP_MAX_HNAME_LEN		64

+

+/* Transction related constants. */

+#define PJSIP_MAX_TSX_COUNT		(16*1024)

+#define PJSIP_POOL_LEN_TSX		1536 //768

+#define PJSIP_POOL_INC_TSX		256

+#define PJSIP_MAX_TSX_KEY_LEN		(PJSIP_MAX_URL_SIZE*2)

+

+/* Dialog related constants. */

+#define PJSIP_MAX_DIALOG_COUNT		(16*1024)

+#define PJSIP_POOL_LEN_DIALOG		1200

+#define PJSIP_POOL_INC_DIALOG		512

+

+/* Module related constants. */

+#define PJSIP_MAX_MODULE		8

+

+/*****************************************************************************

+ *  Default timeout settings, in miliseconds. 

+ */

+

+//#define PJSIP_T1_TIMEOUT	15000

+//#define PJSIP_T2_TIMEOUT	60000

+

+/* T1 timeout value. */

+#if !defined(PJSIP_T1_TIMEOUT)

+#  define PJSIP_T1_TIMEOUT	500

+#endif

+

+/* T2 timeout value. */

+#if !defined(PJSIP_T2_TIMEOUT)

+#  define PJSIP_T2_TIMEOUT	4000

+#endif

+

+/* Completed timer for non-INVITE */

+#if !defined(PJSIP_T4_TIMEOUT)

+#  define PJSIP_T4_TIMEOUT	5000

+#endif

+

+/* Completed timer for INVITE */

+#if !defined(PJSIP_TD_TIMEOUT)

+#  define PJSIP_TD_TIMEOUT	32000

+#endif

+

+

+/*****************************************************************************

+ *  Authorization

+ */

+

+/*

+ * If this flag is set, the stack will keep the Authorization/Proxy-Authorization

+ * headers that are sent in a cache. Future requests with the same realm and

+ * the same method will use the headers in the cache (as long as no qop is

+ * required by server).

+ *

+ * Turning on this flag will make authorization process goes faster, but

+ * will grow the memory usage undefinitely until the dialog/registration

+ * session is terminated.

+ *

+ * Default: 1

+ */

+#if !defined(PJSIP_AUTH_HEADER_CACHING)

+#   define PJSIP_AUTH_HEADER_CACHING	    1

+#endif

+

+/*

+ * If this flag is set, the stack will proactively send Authorization/Proxy-

+ * Authorization header for next requests. If next request has the same method

+ * with any of previous requests, then the last header which is saved in

+ * the cache will be used (if PJSIP_AUTH_CACHING is set). Otherwise a fresh

+ * header will be recalculated. If a particular server has requested qop, then

+ * a fresh header will always be calculated.

+ *

+ * If this flag is NOT set, then the stack will only send Authorization/Proxy-

+ * Authorization headers when it receives 401/407 response from server.

+ *

+ * Turning ON this flag will grow memory usage of a dialog/registration pool

+ * indefinitely until it is terminated, because the stack needs to keep the

+ * last WWW-Authenticate/Proxy-Authenticate challenge.

+ *

+ * Default: 1

+ */

+#if !defined(PJSIP_AUTH_AUTO_SEND_NEXT)

+#   define PJSIP_AUTH_AUTO_SEND_NEXT	    1

+#endif

+

+/*

+ * Support qop="auth" directive.

+ * This option also requires client to cache the last challenge offered by

+ * server.

+ *

+ * Default: 1

+ */

+#if !defined(PJSIP_AUTH_QOP_SUPPORT)

+#   define PJSIP_AUTH_QOP_SUPPORT	    1

+#endif

+

+

+#include <pj/config.h>

+

+

+#endif	/* __PJSIP_SIP_CONFIG_H__ */

+

diff --git a/pjsip/include/pjsip/sip_endpoint.h b/pjsip/include/pjsip/sip_endpoint.h
index e67e286..d789672 100644
--- a/pjsip/include/pjsip/sip_endpoint.h
+++ b/pjsip/include/pjsip/sip_endpoint.h
@@ -1,79 +1,101 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_ENDPOINT_H__
-#define __PJSIP_SIP_ENDPOINT_H__
-
-/**
- * @file sip_endpoint.h
- * @brief SIP Endpoint.
- */
-
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_resolve.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP SIP Stack Core
- * Implementation of core SIP protocol stack processing.
- */
-
-/**
- * @defgroup PJSIP_ENDPT SIP Endpoint
- * @ingroup PJSIP
- * @brief
- * Representation of SIP node instance.
- *
- * SIP Endpoint instance (pjsip_endpoint) can be viewed as the master/owner of
- * all SIP objects in an application. It performs the following roles:
- *  - it manages the allocation/deallocation of memory pools for all objects.
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_ENDPOINT_H__

+#define __PJSIP_SIP_ENDPOINT_H__

+

+/**

+ * @file sip_endpoint.h

+ * @brief SIP Endpoint.

+ */

+

+#include <pjsip/sip_transport.h>

+#include <pjsip/sip_resolve.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP SIP Stack Core

+ * Implementation of core SIP protocol stack processing.

+ */

+

+/**

+ * @defgroup PJSIP_ENDPT SIP Endpoint

+ * @ingroup PJSIP

+ * @brief

+ * Representation of SIP node instance.

+ *

+ * SIP Endpoint instance (pjsip_endpoint) can be viewed as the master/owner of

+ * all SIP objects in an application. It performs the following roles:

+ *  - it manages the allocation/deallocation of memory pools for all objects.

  *  - it manages listeners and transports, and how they are used by 

- *    transactions.
- *  - it owns transaction hash table.
- *  - it receives incoming messages from transport layer and automatically
- *    dispatches them to the correct transaction (or create a new one).
- *  - it has a single instance of timer management (timer heap).
- *  - it manages modules, which is the primary means of extending the library.
+ *    transactions.

+ *  - it owns transaction hash table.

+ *  - it receives incoming messages from transport layer and automatically

+ *    dispatches them to the correct transaction (or create a new one).

+ *  - it has a single instance of timer management (timer heap).

+ *  - it manages modules, which is the primary means of extending the library.

  *  - it provides single polling function for all objects and distributes 

- *    events.
- *  - it provides SIP policy such as which outbound proxy to use for all
- *    outgoing SIP request messages.
- *  - it automatically handles incoming requests which can not be handled by
- *    existing modules (such as when incoming request has unsupported method).
- *  - and so on..
- *
- * Theoritically application can have multiple instances of SIP endpoint, 
- * although it's not clear why application may want to do it.
- *
- * @{
- */
-
-/**
- * Create an instance of SIP endpoint from the specified pool factory.
+ *    events.

+ *  - it provides SIP policy such as which outbound proxy to use for all

+ *    outgoing SIP request messages.

+ *  - it automatically handles incoming requests which can not be handled by

+ *    existing modules (such as when incoming request has unsupported method).

+ *  - and so on..

+ *

+ * Theoritically application can have multiple instances of SIP endpoint, 

+ * although it's not clear why application may want to do it.

+ *

+ * @{

+ */

+

+/**

+ * Create an instance of SIP endpoint from the specified pool factory.

  * The pool factory reference then will be kept by the endpoint, so that 

  * future memory allocations by SIP components will be taken from the same

- * pool factory.
- *
+ * pool factory.

+ *

  * @param pf	        Pool factory that will be used for the lifetime of 

  *                      endpoint.

  * @param name          Optional name to be specified for the endpoint.

  *                      If this parameter is NULL, then the name will use

  *                      local host name.

- * @param endpt         Pointer to receive endpoint instance.
- *
- * @return              PJ_SUCCESS on success.
- */
+ * @param endpt         Pointer to receive endpoint instance.

+ *

+ * @return              PJ_SUCCESS on success.

+ */

 PJ_DECL(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,

-                                        pjsip_endpoint **endpt);
+                                        pjsip_endpoint **endpt);

 

-/**
- * Destroy endpoint instance. Application must make sure that all pending
- * transactions have been terminated properly, because this function does not
- * check for the presence of pending transactions.
- *
- * @param endpt		The SIP endpoint to be destroyed.
- */
-PJ_DECL(void) pjsip_endpt_destroy(pjsip_endpoint *endpt);
+/**

+ * Destroy endpoint instance. Application must make sure that all pending

+ * transactions have been terminated properly, because this function does not

+ * check for the presence of pending transactions.

+ *

+ * @param endpt		The SIP endpoint to be destroyed.

+ */

+PJ_DECL(void) pjsip_endpt_destroy(pjsip_endpoint *endpt);

 

 /**

  * Get endpoint name.

@@ -84,276 +106,276 @@
  *                      creation. The string is NULL terminated.

  */

 PJ_DECL(const pj_str_t*) pjsip_endpt_name(const pjsip_endpoint *endpt);

-
-/**
- * Poll for events. Application must call this function periodically to ensure
- * that all events from both transports and timer heap are handled in timely
- * manner.  This function, like all other endpoint functions, is thread safe, 
- * and application may have more than one thread concurrently calling this function.
- *
- * @param endpt		The endpoint.
- * @param max_timeout	Maximum time to wait for events, or NULL to wait forever
- *			until event is received.
- */
-PJ_DECL(void) pjsip_endpt_handle_events( pjsip_endpoint *endpt, 
-					 const pj_time_val *max_timeout);
-
-/**
- * Dump endpoint status to the log. This will print the status to the log
- * with log level 3.
- *
- * @param endpt		The endpoint.
- * @param detail	If non zero, then it will dump a detailed output.
- *			BEWARE that this option may crash the system because
- *			it tries to access all memory pools.
- */
-PJ_DECL(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail );
-
-/**
- * Create pool from the endpoint. All SIP components should allocate their
- * memory pool by calling this function, to make sure that the pools are
- * allocated from the same pool factory. This function, like all other endpoint
- * functions, is thread safe.
- *
- * @param endpt		The SIP endpoint.
- * @param pool_name	Name to be assigned to the pool.
- * @param initial	The initial size of the pool.
- * @param increment	The resize size.
- * @return		Memory pool, or NULL on failure.
- *
- * @see pj_pool_create
- */
-PJ_DECL(pj_pool_t*) pjsip_endpt_create_pool( pjsip_endpoint *endpt,
-					     const char *pool_name,
-					     pj_size_t initial,
-					     pj_size_t increment );
-
-/**
- * Return back pool to endpoint to be released back to the pool factory.
- * This function, like all other endpoint functions, is thread safe.
- *
- * @param endpt	    The endpoint.
- * @param pool	    The pool to be destroyed.
- */
-PJ_DECL(void) pjsip_endpt_destroy_pool( pjsip_endpoint *endpt,
-					pj_pool_t *pool );
-
-/**
- * Schedule timer to endpoint's timer heap. Application must poll the endpoint
- * periodically (by calling #pjsip_endpt_handle_events) to ensure that the
- * timer events are handled in timely manner. When the timeout for the timer
- * has elapsed, the callback specified in the entry argument will be called.
- * This function, like all other endpoint functions, is thread safe.
- *
- * @param endpt	    The endpoint.
- * @param entry	    The timer entry.
- * @param delay	    The relative delay of the timer.
- * @return	    PJ_OK (zero) if successfull.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_schedule_timer( pjsip_endpoint *endpt,
-						 pj_timer_entry *entry,
-						 const pj_time_val *delay );
-
-/**
- * Cancel the previously registered timer.
- * This function, like all other endpoint functions, is thread safe.
- *
- * @param endpt	    The endpoint.
- * @param entry	    The timer entry previously registered.
- */
-PJ_DECL(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt, 
-					pj_timer_entry *entry );
-
-/**
- * Create a new transaction. After creating the transaction, application MUST
- * initialize the transaction as either UAC or UAS (by calling
- * #pjsip_tsx_init_uac or #pjsip_tsx_init_uas), then must register the 
- * transaction to endpoint with #pjsip_endpt_register_tsx.
- * This function, like all other endpoint functions, is thread safe.
- *
+

+/**

+ * Poll for events. Application must call this function periodically to ensure

+ * that all events from both transports and timer heap are handled in timely

+ * manner.  This function, like all other endpoint functions, is thread safe, 

+ * and application may have more than one thread concurrently calling this function.

+ *

+ * @param endpt		The endpoint.

+ * @param max_timeout	Maximum time to wait for events, or NULL to wait forever

+ *			until event is received.

+ */

+PJ_DECL(void) pjsip_endpt_handle_events( pjsip_endpoint *endpt, 

+					 const pj_time_val *max_timeout);

+

+/**

+ * Dump endpoint status to the log. This will print the status to the log

+ * with log level 3.

+ *

+ * @param endpt		The endpoint.

+ * @param detail	If non zero, then it will dump a detailed output.

+ *			BEWARE that this option may crash the system because

+ *			it tries to access all memory pools.

+ */

+PJ_DECL(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail );

+

+/**

+ * Create pool from the endpoint. All SIP components should allocate their

+ * memory pool by calling this function, to make sure that the pools are

+ * allocated from the same pool factory. This function, like all other endpoint

+ * functions, is thread safe.

+ *

+ * @param endpt		The SIP endpoint.

+ * @param pool_name	Name to be assigned to the pool.

+ * @param initial	The initial size of the pool.

+ * @param increment	The resize size.

+ * @return		Memory pool, or NULL on failure.

+ *

+ * @see pj_pool_create

+ */

+PJ_DECL(pj_pool_t*) pjsip_endpt_create_pool( pjsip_endpoint *endpt,

+					     const char *pool_name,

+					     pj_size_t initial,

+					     pj_size_t increment );

+

+/**

+ * Return back pool to endpoint to be released back to the pool factory.

+ * This function, like all other endpoint functions, is thread safe.

+ *

+ * @param endpt	    The endpoint.

+ * @param pool	    The pool to be destroyed.

+ */

+PJ_DECL(void) pjsip_endpt_destroy_pool( pjsip_endpoint *endpt,

+					pj_pool_t *pool );

+

+/**

+ * Schedule timer to endpoint's timer heap. Application must poll the endpoint

+ * periodically (by calling #pjsip_endpt_handle_events) to ensure that the

+ * timer events are handled in timely manner. When the timeout for the timer

+ * has elapsed, the callback specified in the entry argument will be called.

+ * This function, like all other endpoint functions, is thread safe.

+ *

+ * @param endpt	    The endpoint.

+ * @param entry	    The timer entry.

+ * @param delay	    The relative delay of the timer.

+ * @return	    PJ_OK (zero) if successfull.

+ */

+PJ_DECL(pj_status_t) pjsip_endpt_schedule_timer( pjsip_endpoint *endpt,

+						 pj_timer_entry *entry,

+						 const pj_time_val *delay );

+

+/**

+ * Cancel the previously registered timer.

+ * This function, like all other endpoint functions, is thread safe.

+ *

+ * @param endpt	    The endpoint.

+ * @param entry	    The timer entry previously registered.

+ */

+PJ_DECL(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt, 

+					pj_timer_entry *entry );

+

+/**

+ * Create a new transaction. After creating the transaction, application MUST

+ * initialize the transaction as either UAC or UAS (by calling

+ * #pjsip_tsx_init_uac or #pjsip_tsx_init_uas), then must register the 

+ * transaction to endpoint with #pjsip_endpt_register_tsx.

+ * This function, like all other endpoint functions, is thread safe.

+ *

  * @param endpt	    The SIP endpoint.

  * @param p_tsx	    Pointer to receive the transaction.

- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

 PJ_DECL(pj_status_t) pjsip_endpt_create_tsx(pjsip_endpoint *endpt,

-					    pjsip_transaction **p_tsx);
-
-/**
- * Register the transaction to the endpoint's transaction table.
- * Before the transaction is registered, it must have been initialized as
- * either UAS or UAC by calling #pjsip_tsx_init_uac or #pjsip_tsx_init_uas.
- * This function, like all other endpoint functions, is thread safe.
- *
- * @param endpt	    The SIP endpoint.
- * @param tsx	    The transaction.
- */
-PJ_DECL(void) pjsip_endpt_register_tsx( pjsip_endpoint *endpt,
-					pjsip_transaction *tsx);
-
-/**
- * Forcefull destroy the transaction.
- * The only time where application needs to call this function is when the
- * transaction fails to initialize in #pjsip_tsx_init_uac or
- * #pjsip_tsx_init_uas. For other cases. the transaction will be destroyed
- * automaticly by endpoint.
- *
- * @param endpt	    The endpoint.
- * @param tsx	    The transaction to destroy.
- */
-PJ_DECL(void) pjsip_endpt_destroy_tsx( pjsip_endpoint *endpt,
-				      pjsip_transaction *tsx);
-
-/**
- * Create a new transmit data buffer.
- * This function, like all other endpoint functions, is thread safe.
- *
+					    pjsip_transaction **p_tsx);

+

+/**

+ * Register the transaction to the endpoint's transaction table.

+ * Before the transaction is registered, it must have been initialized as

+ * either UAS or UAC by calling #pjsip_tsx_init_uac or #pjsip_tsx_init_uas.

+ * This function, like all other endpoint functions, is thread safe.

+ *

+ * @param endpt	    The SIP endpoint.

+ * @param tsx	    The transaction.

+ */

+PJ_DECL(void) pjsip_endpt_register_tsx( pjsip_endpoint *endpt,

+					pjsip_transaction *tsx);

+

+/**

+ * Forcefull destroy the transaction.

+ * The only time where application needs to call this function is when the

+ * transaction fails to initialize in #pjsip_tsx_init_uac or

+ * #pjsip_tsx_init_uas. For other cases. the transaction will be destroyed

+ * automaticly by endpoint.

+ *

+ * @param endpt	    The endpoint.

+ * @param tsx	    The transaction to destroy.

+ */

+PJ_DECL(void) pjsip_endpt_destroy_tsx( pjsip_endpoint *endpt,

+				      pjsip_transaction *tsx);

+

+/**

+ * Create a new transmit data buffer.

+ * This function, like all other endpoint functions, is thread safe.

+ *

  * @param endpt	    The endpoint.

  * @param p_tdata    Pointer to receive transmit data buffer.

- *
- * @return	    PJ_SUCCESS or the appropriate error code.
- */
+ *

+ * @return	    PJ_SUCCESS or the appropriate error code.

+ */

 PJ_DECL(pj_status_t) pjsip_endpt_create_tdata( pjsip_endpoint *endpt,

-					       pjsip_tx_data **p_tdata);
-
-/**
- * Asynchronously resolve a SIP target host or domain according to rule 
- * specified in RFC 3263 (Locating SIP Servers). When the resolving operation
- * has completed, the callback will be called.
- *
- * Note: at the moment we don't have implementation of RFC 3263 yet!
- *
- * @param resolver  The resolver engine.
- * @param pool	    The pool to allocate resolver job.
- * @param target    The target specification to be resolved.
- * @param token	    A user defined token to be passed back to callback function.
- * @param cb	    The callback function.
- */
-PJ_DECL(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,
-				   pj_pool_t *pool,
-				   pjsip_host_port *target,
-				   void *token,
-				   pjsip_resolver_callback *cb);
-
-/**
- * Find a SIP transport suitable for sending SIP message to the specified
- * address. This function will complete asynchronously when the transport is
- * ready (for example, when TCP socket is connected), and when it completes,
- * the callback will be called with the status of the operation.
- *
- * @see pjsip_transport_get
- */
-PJ_DECL(void) pjsip_endpt_get_transport( pjsip_endpoint *endpt,
-					 pj_pool_t *pool,
-					 pjsip_transport_type_e type,
-					 const pj_sockaddr_in *remote,
-					 void *token,
-					 pjsip_transport_completion_callback *cb);
-
-/**
- * Create listener a new transport listener. A listener is transport object
- * that is capable of receiving SIP messages. For UDP listener, normally
- * application should use #pjsip_endpt_create_udp_listener instead if the 
- * application has already created the socket.
- * This function, like all other endpoint functions, is thread safe.
- *
- * @param endpt	    The endpoint instance.
- * @param type	    Transport type (eg. UDP, TCP, etc.)
- * @param addr	    The bound address of the transport.
- * @param addr_name The address to be advertised in SIP messages. For example,
- *		    the bound address can be 0.0.0.0, but the advertised address
- *		    normally will be the IP address of the host.
- *
- * @return	    Zero if listener is created successfully.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_listener( pjsip_endpoint *endpt,
-						  pjsip_transport_type_e type,
-						  pj_sockaddr_in *addr,
-						  const pj_sockaddr_in *addr_name);
-
-/**
- * Create UDP listener. For UDP, normally the application would create the
- * socket by itself (for STUN purpose), then it can register the socket as
- * listener by calling this function.
- * This function, like all other endpoint functions, is thread safe.
- *
- * @param endpt	    The endpoint instance.
- * @param sock	    The socket handle.
- * @param addr_name The address to be advertised in SIP message. If the socket
- *		    has been resolved with STUN, then application may specify 
- *		    the mapped address in this parameter.
- *
- * @return	    Zero if listener is created successfully.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_udp_listener( pjsip_endpoint *endpt,
-						      pj_sock_t sock,
-						      const pj_sockaddr_in *addr_name);
-
-/**
- * Get additional headers to be put in outgoing request message. 
- * This function is normally called by transaction layer when sending outgoing
- * requests.
- * 
- * @param endpt	    The endpoint.
- *
- * @return	    List of additional headers to be put in outgoing requests.
- */
-PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *endpt);
-
-/**
- * Get "Allow" header from endpoint. The endpoint builds the "Allow" header
- * from the list of methods supported by modules.
- *
- * @param endpt	    The endpoint.
- *
- * @return	    "Allow" header, or NULL if endpoint doesn't have "Allow" header.
- */
-PJ_DECL(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt );
-
-
-/**
- * Find transaction in endpoint's transaction table by the transaction's key.
- * This function normally is only used by modules. The key for a transaction
- * can be created by calling #pjsip_tsx_create_key.
- *
- * @param endpt	    The endpoint instance.
- * @param key	    Transaction key, as created with #pjsip_tsx_create_key.
- *
- * @return	    The transaction, or NULL if it's not found.
- */
-PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
-					          const pj_str_t *key );
-
-/**
- * Set list of SIP proxies to be visited for all outbound request messages.
- * Application can call this function to specify how outgoing request messages
- * should be routed. For example, if outgoing requests should go through an
- * outbound proxy, then application can specify the URL of the proxy when
- * calling this function. More than one proxy can be specified, and the
- * order of which proxy is specified when calling this function specifies
- * the order of which proxy will be visited first by the request messages.
- *
- * @param endpt	    The endpoint instance.
- * @param url_cnt   Number of proxies/URLs in the array.
- * @param url	    Array of proxy URL, which specifies the order of which
- *		    proxy will be visited first (e.g. url[0] will be visited
- *		    before url[1]).
- *
- * @return	    Zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_set_proxies( pjsip_endpoint *endpt,
-					      int url_cnt, const pj_str_t url[]);
-
-/**
- * Get the list of "Route" header that are configured for this endpoint.
- * The "Route" header specifies how outbound request messages will be sent,
- * and is built when application sets the outbound proxy.
- *
- * @param endpt	    The endpoint instance.
- *
- * @return	    List of "Route" header.
- */
-PJ_DECL(const pjsip_route_hdr*) pjsip_endpt_get_routing( pjsip_endpoint *endpt );
+					       pjsip_tx_data **p_tdata);

+

+/**

+ * Asynchronously resolve a SIP target host or domain according to rule 

+ * specified in RFC 3263 (Locating SIP Servers). When the resolving operation

+ * has completed, the callback will be called.

+ *

+ * Note: at the moment we don't have implementation of RFC 3263 yet!

+ *

+ * @param resolver  The resolver engine.

+ * @param pool	    The pool to allocate resolver job.

+ * @param target    The target specification to be resolved.

+ * @param token	    A user defined token to be passed back to callback function.

+ * @param cb	    The callback function.

+ */

+PJ_DECL(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,

+				   pj_pool_t *pool,

+				   pjsip_host_port *target,

+				   void *token,

+				   pjsip_resolver_callback *cb);

+

+/**

+ * Find a SIP transport suitable for sending SIP message to the specified

+ * address. This function will complete asynchronously when the transport is

+ * ready (for example, when TCP socket is connected), and when it completes,

+ * the callback will be called with the status of the operation.

+ *

+ * @see pjsip_transport_get

+ */

+PJ_DECL(void) pjsip_endpt_get_transport( pjsip_endpoint *endpt,

+					 pj_pool_t *pool,

+					 pjsip_transport_type_e type,

+					 const pj_sockaddr_in *remote,

+					 void *token,

+					 pjsip_transport_completion_callback *cb);

+

+/**

+ * Create listener a new transport listener. A listener is transport object

+ * that is capable of receiving SIP messages. For UDP listener, normally

+ * application should use #pjsip_endpt_create_udp_listener instead if the 

+ * application has already created the socket.

+ * This function, like all other endpoint functions, is thread safe.

+ *

+ * @param endpt	    The endpoint instance.

+ * @param type	    Transport type (eg. UDP, TCP, etc.)

+ * @param addr	    The bound address of the transport.

+ * @param addr_name The address to be advertised in SIP messages. For example,

+ *		    the bound address can be 0.0.0.0, but the advertised address

+ *		    normally will be the IP address of the host.

+ *

+ * @return	    Zero if listener is created successfully.

+ */

+PJ_DECL(pj_status_t) pjsip_endpt_create_listener( pjsip_endpoint *endpt,

+						  pjsip_transport_type_e type,

+						  pj_sockaddr_in *addr,

+						  const pj_sockaddr_in *addr_name);

+

+/**

+ * Create UDP listener. For UDP, normally the application would create the

+ * socket by itself (for STUN purpose), then it can register the socket as

+ * listener by calling this function.

+ * This function, like all other endpoint functions, is thread safe.

+ *

+ * @param endpt	    The endpoint instance.

+ * @param sock	    The socket handle.

+ * @param addr_name The address to be advertised in SIP message. If the socket

+ *		    has been resolved with STUN, then application may specify 

+ *		    the mapped address in this parameter.

+ *

+ * @return	    Zero if listener is created successfully.

+ */

+PJ_DECL(pj_status_t) pjsip_endpt_create_udp_listener( pjsip_endpoint *endpt,

+						      pj_sock_t sock,

+						      const pj_sockaddr_in *addr_name);

+

+/**

+ * Get additional headers to be put in outgoing request message. 

+ * This function is normally called by transaction layer when sending outgoing

+ * requests.

+ * 

+ * @param endpt	    The endpoint.

+ *

+ * @return	    List of additional headers to be put in outgoing requests.

+ */

+PJ_DECL(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *endpt);

+

+/**

+ * Get "Allow" header from endpoint. The endpoint builds the "Allow" header

+ * from the list of methods supported by modules.

+ *

+ * @param endpt	    The endpoint.

+ *

+ * @return	    "Allow" header, or NULL if endpoint doesn't have "Allow" header.

+ */

+PJ_DECL(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt );

+

+

+/**

+ * Find transaction in endpoint's transaction table by the transaction's key.

+ * This function normally is only used by modules. The key for a transaction

+ * can be created by calling #pjsip_tsx_create_key.

+ *

+ * @param endpt	    The endpoint instance.

+ * @param key	    Transaction key, as created with #pjsip_tsx_create_key.

+ *

+ * @return	    The transaction, or NULL if it's not found.

+ */

+PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,

+					          const pj_str_t *key );

+

+/**

+ * Set list of SIP proxies to be visited for all outbound request messages.

+ * Application can call this function to specify how outgoing request messages

+ * should be routed. For example, if outgoing requests should go through an

+ * outbound proxy, then application can specify the URL of the proxy when

+ * calling this function. More than one proxy can be specified, and the

+ * order of which proxy is specified when calling this function specifies

+ * the order of which proxy will be visited first by the request messages.

+ *

+ * @param endpt	    The endpoint instance.

+ * @param url_cnt   Number of proxies/URLs in the array.

+ * @param url	    Array of proxy URL, which specifies the order of which

+ *		    proxy will be visited first (e.g. url[0] will be visited

+ *		    before url[1]).

+ *

+ * @return	    Zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_endpt_set_proxies( pjsip_endpoint *endpt,

+					      int url_cnt, const pj_str_t url[]);

+

+/**

+ * Get the list of "Route" header that are configured for this endpoint.

+ * The "Route" header specifies how outbound request messages will be sent,

+ * and is built when application sets the outbound proxy.

+ *

+ * @param endpt	    The endpoint instance.

+ *

+ * @return	    List of "Route" header.

+ */

+PJ_DECL(const pjsip_route_hdr*) pjsip_endpt_get_routing( pjsip_endpoint *endpt );

 

 /**

  * Log an error.

@@ -372,21 +394,21 @@
                 if ((tracing))          \

                     PJ_LOG(4,expr);     \

             } while (0)

-
-/**
- * @}
- */
-
-/*
- * Internal functions.
- */
-/*
- * Receive transaction events from transactions and put in the event queue
- * to be processed later.
- */
-void pjsip_endpt_send_tsx_event( pjsip_endpoint *endpt, pjsip_event *evt );
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_SIP_ENDPOINT_H__ */
-
+

+/**

+ * @}

+ */

+

+/*

+ * Internal functions.

+ */

+/*

+ * Receive transaction events from transactions and put in the event queue

+ * to be processed later.

+ */

+void pjsip_endpt_send_tsx_event( pjsip_endpoint *endpt, pjsip_event *evt );

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_SIP_ENDPOINT_H__ */

+

diff --git a/pjsip/include/pjsip/sip_errno.h b/pjsip/include/pjsip/sip_errno.h
index 6e4a6f7..6fca735 100644
--- a/pjsip/include/pjsip/sip_errno.h
+++ b/pjsip/include/pjsip/sip_errno.h
@@ -1,5 +1,27 @@
 /* $Id$ 

  */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

 #ifndef __PJSIP_SIP_ERRNO_H__

 #define __PJSIP_SIP_ERRNO_H__

 

diff --git a/pjsip/include/pjsip/sip_event.h b/pjsip/include/pjsip/sip_event.h
index 98ac385..2b0cc04 100644
--- a/pjsip/include/pjsip/sip_event.h
+++ b/pjsip/include/pjsip/sip_event.h
@@ -1,85 +1,107 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_EVENT_H__
-#define __PJSIP_SIP_EVENT_H__
-
-/**
- * @file sip_event.h
- * @brief SIP Event
- */
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_EVENT SIP Event
- * @ingroup PJSIP
- * @{
- */
-#include <pj/types.h>
-
-
-/** 
- * Event IDs.
- */
-typedef enum pjsip_event_id_e
-{
-    /** Unidentified event. */
-    PJSIP_EVENT_UNKNOWN,
-
-    /** Timer event, normally only used internally in transaction. */
-    PJSIP_EVENT_TIMER,
-
-    /** Message transmission event. */
-    PJSIP_EVENT_TX_MSG,
-
-    /** Message received event. */
-    PJSIP_EVENT_RX_MSG,
-
-    /** Transport error event. */
-    PJSIP_EVENT_TRANSPORT_ERROR,
-
-    /** Transaction state changed event. */
-    PJSIP_EVENT_TSX_STATE,
-
-    /** 2xx response received event. */
-    PJSIP_EVENT_RX_200_MSG,
-
-    /** ACK request received event. */
-    PJSIP_EVENT_RX_ACK_MSG,
-
-    /** Message discarded event. */
-    PJSIP_EVENT_DISCARD_MSG,
-
-    /** Indicates that the event was triggered by user action. */
-    PJSIP_EVENT_USER,
-
-    /** On before transmitting message. */
-    PJSIP_EVENT_PRE_TX_MSG,
-
-} pjsip_event_id_e;
-
-
-/**
- * \struct
- * \brief Event descriptor to fully identify a SIP event.
- *
- * Events are the only way for a lower layer object to inform something
- * to higher layer objects. Normally this is achieved by means of callback,
- * i.e. the higher layer objects register a callback to handle the event on
- * the lower layer objects.
- *
- * This event descriptor is used for example by transactions, to inform
- * endpoint about events, and by transports, to inform endpoint about
- * unexpected transport error.
- */
-struct pjsip_event
-{
-    /** This is necessary so that we can put events as a list. */
-    PJ_DECL_LIST_MEMBER(struct pjsip_event);
-
-    /** The event type, can be any value of \b pjsip_event_id_e.
-     */
-    pjsip_event_id_e type;
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_EVENT_H__

+#define __PJSIP_SIP_EVENT_H__

+

+/**

+ * @file sip_event.h

+ * @brief SIP Event

+ */

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_EVENT SIP Event

+ * @ingroup PJSIP

+ * @{

+ */

+#include <pj/types.h>

+

+

+/** 

+ * Event IDs.

+ */

+typedef enum pjsip_event_id_e

+{

+    /** Unidentified event. */

+    PJSIP_EVENT_UNKNOWN,

+

+    /** Timer event, normally only used internally in transaction. */

+    PJSIP_EVENT_TIMER,

+

+    /** Message transmission event. */

+    PJSIP_EVENT_TX_MSG,

+

+    /** Message received event. */

+    PJSIP_EVENT_RX_MSG,

+

+    /** Transport error event. */

+    PJSIP_EVENT_TRANSPORT_ERROR,

+

+    /** Transaction state changed event. */

+    PJSIP_EVENT_TSX_STATE,

+

+    /** 2xx response received event. */

+    PJSIP_EVENT_RX_200_MSG,

+

+    /** ACK request received event. */

+    PJSIP_EVENT_RX_ACK_MSG,

+

+    /** Message discarded event. */

+    PJSIP_EVENT_DISCARD_MSG,

+

+    /** Indicates that the event was triggered by user action. */

+    PJSIP_EVENT_USER,

+

+    /** On before transmitting message. */

+    PJSIP_EVENT_PRE_TX_MSG,

+

+} pjsip_event_id_e;

+

+

+/**

+ * \struct

+ * \brief Event descriptor to fully identify a SIP event.

+ *

+ * Events are the only way for a lower layer object to inform something

+ * to higher layer objects. Normally this is achieved by means of callback,

+ * i.e. the higher layer objects register a callback to handle the event on

+ * the lower layer objects.

+ *

+ * This event descriptor is used for example by transactions, to inform

+ * endpoint about events, and by transports, to inform endpoint about

+ * unexpected transport error.

+ */

+struct pjsip_event

+{

+    /** This is necessary so that we can put events as a list. */

+    PJ_DECL_LIST_MEMBER(struct pjsip_event);

+

+    /** The event type, can be any value of \b pjsip_event_id_e.

+     */

+    pjsip_event_id_e type;

 

     /*

      * The event body.

@@ -174,7 +196,7 @@
         } user;

 

     } body;

-};
+};

 

 /**

  * Init timer event.

@@ -277,18 +299,18 @@
             (event).body.pre_tx_msg.retcnt = pretcnt;	\

         } while (0)

 

-
-/**
- * Get the event string from the event ID.
- * @param e the event ID.
- * @notes defined in sip_misc.c
- */
-PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_SIP_EVENT_H__ */
+

+/**

+ * Get the event string from the event ID.

+ * @param e the event ID.

+ * @notes defined in sip_misc.c

+ */

+PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_SIP_EVENT_H__ */

diff --git a/pjsip/include/pjsip/sip_misc.h b/pjsip/include/pjsip/sip_misc.h
index 4101dbc..d81af9c 100644
--- a/pjsip/include/pjsip/sip_misc.h
+++ b/pjsip/include/pjsip/sip_misc.h
@@ -1,176 +1,198 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_MISC_H__
-#define __PJSIP_SIP_MISC_H__
-
-#include <pjsip/sip_msg.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_ENDPT SIP Endpoint
- * @ingroup PJSIP
- * @{
- */
-
-/**
- * Create an independent request message. This can be used to build any
- * request outside a dialog, such as OPTIONS, MESSAGE, etc. To create a request
- * inside a dialog, application should use #pjsip_dlg_create_request.
- *
- * Once a transmit data is created, the reference counter is initialized to 1.
- *
- * @param endpt	    Endpoint instance.
- * @param method    SIP Method.
- * @param target    Target URI.
- * @param from	    URL to put in From header.
- * @param to	    URL to put in To header.
- * @param contact   URL to put in Contact header.
- * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).
- * @param cseq	    Optional CSeq (put -1 to generate random CSeq).
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_MISC_H__

+#define __PJSIP_SIP_MISC_H__

+

+#include <pjsip/sip_msg.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_ENDPT SIP Endpoint

+ * @ingroup PJSIP

+ * @{

+ */

+

+/**

+ * Create an independent request message. This can be used to build any

+ * request outside a dialog, such as OPTIONS, MESSAGE, etc. To create a request

+ * inside a dialog, application should use #pjsip_dlg_create_request.

+ *

+ * Once a transmit data is created, the reference counter is initialized to 1.

+ *

+ * @param endpt	    Endpoint instance.

+ * @param method    SIP Method.

+ * @param target    Target URI.

+ * @param from	    URL to put in From header.

+ * @param to	    URL to put in To header.

+ * @param contact   URL to put in Contact header.

+ * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).

+ * @param cseq	    Optional CSeq (put -1 to generate random CSeq).

  * @param text	    Optional text body (put NULL to omit body).

- * @param p_tdata   Pointer to receive the transmit data.
- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_request( pjsip_endpoint *endpt, 
-						 const pjsip_method *method,
-						 const pj_str_t *target,
-						 const pj_str_t *from,
-						 const pj_str_t *to, 
-						 const pj_str_t *contact,
-						 const pj_str_t *call_id,
-						 int cseq, 
-						 const pj_str_t *text,

-						 pjsip_tx_data **p_tdata);
-
-/**
- * Create an independent request message from the specified headers. This
- * function will shallow clone the headers and put them in the request.
- *
- * Once a transmit data is created, the reference counter is initialized to 1.
- *
- * @param endpt	    Endpoint instance.
- * @param method    SIP Method.
- * @param target    Target URI.
- * @param from	    URL to put in From header.
- * @param to	    URL to put in To header.
- * @param contact   URL to put in Contact header.
- * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).
- * @param cseq	    Optional CSeq (put -1 to generate random CSeq).
- * @param text	    Optional text body (put NULL to omit body).

- * @param p_tdata   Pointer to receive the transmit data.
- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t)
-pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,
-				     const pjsip_method *method,
-				     const pjsip_uri *target,
-				     const pjsip_from_hdr *from,
-				     const pjsip_to_hdr *to,
-				     const pjsip_contact_hdr *contact,
-				     const pjsip_cid_hdr *call_id,
-				     int cseq,
-				     const pj_str_t *text,

-				     pjsip_tx_data **p_tdata);
-
-/**
- * Send outgoing request and initiate UAC transaction for the request.
- * This is an auxiliary function to be used by application to send arbitrary
- * requests outside a dialog. To send a request within a dialog, application
- * should use #pjsip_dlg_send_msg instead.
- *
- * @param endpt	    The endpoint instance.
- * @param tdata	    The transmit data to be sent.
- * @param timeout   Optional timeout for final response to be received, or -1 
- *		    if the transaction should not have a timeout restriction.
- * @param token	    Optional token to be associated with the transaction, and 
- *		    to be passed to the callback.
- * @param cb	    Optional callback to be called when the transaction has
- *		    received a final response. The callback will be called with
- *		    the previously registered token and the event that triggers
- *		    the completion of the transaction.
- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt,
-					       pjsip_tx_data *tdata,
-					       int timeout,
-					       void *token,
-					       void (*cb)(void*,pjsip_event*));
-
-/**
- * Construct a minimal response message for the received request. This function
- * will construct all the Via, Record-Route, Call-ID, From, To, CSeq, and 
- * Call-ID headers from the request.
- *
- * Note: the txdata reference counter is set to ZERO!.
- *
- * @param endpt	    The endpoint.
- * @param rdata	    The request receive data.
- * @param code	    Status code to be put in the response.

- * @param p_tdata   Pointer to receive the transmit data.
- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
-						  const pjsip_rx_data *rdata,
-						  int code,

-						  pjsip_tx_data **p_tdata);
-
-/**
- * Construct a full ACK request for the received non-2xx final response.
- * This utility function is normally called by the transaction to construct
- * an ACK request to 3xx-6xx final response.
- * The generation of ACK message for 2xx final response is different than
- * this one.
- * 
- * @param endpt	    The endpoint.
- * @param tdata	    On input, this contains the original INVITE request, and on
- *		    output, it contains the ACK message.
- * @param rdata	    The final response message.
- */
-PJ_DECL(void) pjsip_endpt_create_ack( pjsip_endpoint *endpt,
-				      pjsip_tx_data *tdata,
-				      const pjsip_rx_data *rdata );
-
-
-/**
- * Construct CANCEL request for the previously sent request.
- *
- * @param endpt	    The endpoint.
- * @param tdata	    The transmit buffer for the request being cancelled.
  * @param p_tdata   Pointer to receive the transmit data.

- *
- * @return	    PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
+ *

+ * @return	    PJ_SUCCESS, or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pjsip_endpt_create_request( pjsip_endpoint *endpt, 

+						 const pjsip_method *method,

+						 const pj_str_t *target,

+						 const pj_str_t *from,

+						 const pj_str_t *to, 

+						 const pj_str_t *contact,

+						 const pj_str_t *call_id,

+						 int cseq, 

+						 const pj_str_t *text,

+						 pjsip_tx_data **p_tdata);

+

+/**

+ * Create an independent request message from the specified headers. This

+ * function will shallow clone the headers and put them in the request.

+ *

+ * Once a transmit data is created, the reference counter is initialized to 1.

+ *

+ * @param endpt	    Endpoint instance.

+ * @param method    SIP Method.

+ * @param target    Target URI.

+ * @param from	    URL to put in From header.

+ * @param to	    URL to put in To header.

+ * @param contact   URL to put in Contact header.

+ * @param call_id   Optional Call-ID (put NULL to generate unique Call-ID).

+ * @param cseq	    Optional CSeq (put -1 to generate random CSeq).

+ * @param text	    Optional text body (put NULL to omit body).

+ * @param p_tdata   Pointer to receive the transmit data.

+ *

+ * @return	    PJ_SUCCESS, or the appropriate error code.

+ */

+PJ_DECL(pj_status_t)

+pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,

+				     const pjsip_method *method,

+				     const pjsip_uri *target,

+				     const pjsip_from_hdr *from,

+				     const pjsip_to_hdr *to,

+				     const pjsip_contact_hdr *contact,

+				     const pjsip_cid_hdr *call_id,

+				     int cseq,

+				     const pj_str_t *text,

+				     pjsip_tx_data **p_tdata);

+

+/**

+ * Send outgoing request and initiate UAC transaction for the request.

+ * This is an auxiliary function to be used by application to send arbitrary

+ * requests outside a dialog. To send a request within a dialog, application

+ * should use #pjsip_dlg_send_msg instead.

+ *

+ * @param endpt	    The endpoint instance.

+ * @param tdata	    The transmit data to be sent.

+ * @param timeout   Optional timeout for final response to be received, or -1 

+ *		    if the transaction should not have a timeout restriction.

+ * @param token	    Optional token to be associated with the transaction, and 

+ *		    to be passed to the callback.

+ * @param cb	    Optional callback to be called when the transaction has

+ *		    received a final response. The callback will be called with

+ *		    the previously registered token and the event that triggers

+ *		    the completion of the transaction.

+ *

+ * @return	    PJ_SUCCESS, or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pjsip_endpt_send_request( pjsip_endpoint *endpt,

+					       pjsip_tx_data *tdata,

+					       int timeout,

+					       void *token,

+					       void (*cb)(void*,pjsip_event*));

+

+/**

+ * Construct a minimal response message for the received request. This function

+ * will construct all the Via, Record-Route, Call-ID, From, To, CSeq, and 

+ * Call-ID headers from the request.

+ *

+ * Note: the txdata reference counter is set to ZERO!.

+ *

+ * @param endpt	    The endpoint.

+ * @param rdata	    The request receive data.

+ * @param code	    Status code to be put in the response.

+ * @param p_tdata   Pointer to receive the transmit data.

+ *

+ * @return	    PJ_SUCCESS, or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,

+						  const pjsip_rx_data *rdata,

+						  int code,

+						  pjsip_tx_data **p_tdata);

+

+/**

+ * Construct a full ACK request for the received non-2xx final response.

+ * This utility function is normally called by the transaction to construct

+ * an ACK request to 3xx-6xx final response.

+ * The generation of ACK message for 2xx final response is different than

+ * this one.

+ * 

+ * @param endpt	    The endpoint.

+ * @param tdata	    On input, this contains the original INVITE request, and on

+ *		    output, it contains the ACK message.

+ * @param rdata	    The final response message.

+ */

+PJ_DECL(void) pjsip_endpt_create_ack( pjsip_endpoint *endpt,

+				      pjsip_tx_data *tdata,

+				      const pjsip_rx_data *rdata );

+

+

+/**

+ * Construct CANCEL request for the previously sent request.

+ *

+ * @param endpt	    The endpoint.

+ * @param tdata	    The transmit buffer for the request being cancelled.

+ * @param p_tdata   Pointer to receive the transmit data.

+ *

+ * @return	    PJ_SUCCESS, or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,

 						pjsip_tx_data *tdata,

-						pjsip_tx_data **p_tdata);
-
-
-/**
- * Get the address parameters (host, port, flag, TTL, etc) to send the
- * response.
- *
- * @param pool	    The pool.
- * @param tr	    The transport where the request was received.
- * @param via	    The top-most Via header of the request.
- * @param addr	    The send address concluded from the calculation.
- *
- * @return	    zero (PJ_OK) if successfull.
- */
-PJ_DECL(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,
-					     const pjsip_transport_t *tr,
-					     const pjsip_via_hdr *via,
-					     pjsip_host_port *addr);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_SIP_MISC_H__ */
-
+						pjsip_tx_data **p_tdata);

+

+

+/**

+ * Get the address parameters (host, port, flag, TTL, etc) to send the

+ * response.

+ *

+ * @param pool	    The pool.

+ * @param tr	    The transport where the request was received.

+ * @param via	    The top-most Via header of the request.

+ * @param addr	    The send address concluded from the calculation.

+ *

+ * @return	    zero (PJ_OK) if successfull.

+ */

+PJ_DECL(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,

+					     const pjsip_transport_t *tr,

+					     const pjsip_via_hdr *via,

+					     pjsip_host_port *addr);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_SIP_MISC_H__ */

+

diff --git a/pjsip/include/pjsip/sip_module.h b/pjsip/include/pjsip/sip_module.h
index 7bf53ab..aecc1d4 100644
--- a/pjsip/include/pjsip/sip_module.h
+++ b/pjsip/include/pjsip/sip_module.h
@@ -1,124 +1,146 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_MODULE_H__
-#define __PJSIP_SIP_MODULE_H__
-
-/**
- * @file sip_module.h
- * @brief Module helpers
- */
-#include <pjsip/sip_types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_MOD SIP Modules
- * @ingroup PJSIP
- * @{
- */
-
-/**
- * Module registration structure, which is passed by the module to the
- * endpoint during the module registration process. This structure enables
- * the endpoint to query the module capability and to further communicate
- * with the module.
- */
-struct pjsip_module
-{
-    /**
-     * Module name.
-     */
-    pj_str_t name;
-
-    /**
-     * Flag to indicate the type of interfaces supported by the module.
-     */
-    pj_uint32_t flag;
-
-    /**
-     * Integer number to identify module initialization and start order with
-     * regard to other modules. Higher number will make the module gets
-     * initialized later.
-     */
-    pj_uint32_t priority;
-
-    /**
-     * Opaque data which can be used by a module to identify a resource within
-     * the module itself.
-     */
-    void *mod_data;
-
-    /**
-     * Number of methods supported by this module.
-     */
-    int method_cnt;
-
-    /**
-     * Array of methods supported by this module.
-     */
-    const pjsip_method *methods[8];
-
-    /**
-     * Pointer to function to be called to initialize the module.
-     *
-     * @param endpt	The endpoint instance.
-     * @param mod	The module.
-     * @param id	The unique module ID assigned to this module.
-     *
-     * @return		Module should return zero when initialization succeed.
-     */
-    pj_status_t (*init_module)(pjsip_endpoint *endpt,
-			       struct pjsip_module *mod, pj_uint32_t id);
-
-    /**
-     * Pointer to function to be called to start the module.
-     *
-     * @param mod	The module.
-     *
-     * @return		Module should return zero to indicate success.
-     */
-    pj_status_t (*start_module)(struct pjsip_module *mod);
-
-    /**
-     * Pointer to function to be called to deinitialize the module before
-     * it is unloaded.
-     *
-     * @param mod	The module.
-     *
-     * @return		Module should return zero to indicate success.
-     */
-    pj_status_t (*deinit_module)(struct pjsip_module *mod);
-
-    /**
-     * Pointer to function to receive transaction related events.
-     * If the module doesn't wish to receive such notification, this member
-     * must be set to NULL.
-     *
-     * @param mod	The module.
-     * @param event	The transaction event.
-     */
-    void (*tsx_handler)(struct pjsip_module *mod, pjsip_event *event);
-};
-
-
-/**
- * Prototype of function to register static modules (eg modules that are
- * linked staticly with the application). This function must be implemented 
- * by any applications that use PJSIP library.
- *
- * @param count	    [input/output] On input, it contains the maximum number of
- *		    elements in the array. On output, the function fills with 
- *		    the number of modules to be registered.
- * @param modules   [output] array of pointer to modules to be registered.
- */
-pj_status_t register_static_modules( pj_size_t *count,
-				     pjsip_module **modules );
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_SIP_MODULE_H__ */
-
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_MODULE_H__

+#define __PJSIP_SIP_MODULE_H__

+

+/**

+ * @file sip_module.h

+ * @brief Module helpers

+ */

+#include <pjsip/sip_types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_MOD SIP Modules

+ * @ingroup PJSIP

+ * @{

+ */

+

+/**

+ * Module registration structure, which is passed by the module to the

+ * endpoint during the module registration process. This structure enables

+ * the endpoint to query the module capability and to further communicate

+ * with the module.

+ */

+struct pjsip_module

+{

+    /**

+     * Module name.

+     */

+    pj_str_t name;

+

+    /**

+     * Flag to indicate the type of interfaces supported by the module.

+     */

+    pj_uint32_t flag;

+

+    /**

+     * Integer number to identify module initialization and start order with

+     * regard to other modules. Higher number will make the module gets

+     * initialized later.

+     */

+    pj_uint32_t priority;

+

+    /**

+     * Opaque data which can be used by a module to identify a resource within

+     * the module itself.

+     */

+    void *mod_data;

+

+    /**

+     * Number of methods supported by this module.

+     */

+    int method_cnt;

+

+    /**

+     * Array of methods supported by this module.

+     */

+    const pjsip_method *methods[8];

+

+    /**

+     * Pointer to function to be called to initialize the module.

+     *

+     * @param endpt	The endpoint instance.

+     * @param mod	The module.

+     * @param id	The unique module ID assigned to this module.

+     *

+     * @return		Module should return zero when initialization succeed.

+     */

+    pj_status_t (*init_module)(pjsip_endpoint *endpt,

+			       struct pjsip_module *mod, pj_uint32_t id);

+

+    /**

+     * Pointer to function to be called to start the module.

+     *

+     * @param mod	The module.

+     *

+     * @return		Module should return zero to indicate success.

+     */

+    pj_status_t (*start_module)(struct pjsip_module *mod);

+

+    /**

+     * Pointer to function to be called to deinitialize the module before

+     * it is unloaded.

+     *

+     * @param mod	The module.

+     *

+     * @return		Module should return zero to indicate success.

+     */

+    pj_status_t (*deinit_module)(struct pjsip_module *mod);

+

+    /**

+     * Pointer to function to receive transaction related events.

+     * If the module doesn't wish to receive such notification, this member

+     * must be set to NULL.

+     *

+     * @param mod	The module.

+     * @param event	The transaction event.

+     */

+    void (*tsx_handler)(struct pjsip_module *mod, pjsip_event *event);

+};

+

+

+/**

+ * Prototype of function to register static modules (eg modules that are

+ * linked staticly with the application). This function must be implemented 

+ * by any applications that use PJSIP library.

+ *

+ * @param count	    [input/output] On input, it contains the maximum number of

+ *		    elements in the array. On output, the function fills with 

+ *		    the number of modules to be registered.

+ * @param modules   [output] array of pointer to modules to be registered.

+ */

+pj_status_t register_static_modules( pj_size_t *count,

+				     pjsip_module **modules );

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_SIP_MODULE_H__ */

+

diff --git a/pjsip/include/pjsip/sip_msg.h b/pjsip/include/pjsip/sip_msg.h
index ed9450b..6b78462 100644
--- a/pjsip/include/pjsip/sip_msg.h
+++ b/pjsip/include/pjsip/sip_msg.h
@@ -1,1511 +1,1533 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_MSG_H__
-#define __PJSIP_SIP_MSG_H__
-
-/**
- * @file sip_msg.h
- * @brief SIP Message Structure.
- */
-
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_uri.h>
-#include <pj/list.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_MSG SIP Message Structure
- * @ingroup PJSIP
- * @{
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_METHOD Methods
- * @brief Method names and manipulation.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * This enumeration declares SIP methods as described by RFC3261. Additional
- * methods do exist, and they are described by corresponding RFCs for the SIP
- * extentensions. Since they won't alter the characteristic of the processing
- * of the message, they don't need to be explicitly mentioned here.
- */
-typedef enum pjsip_method_e
-{
-    /** INVITE method, for establishing dialogs. */
-    PJSIP_INVITE_METHOD,
-
-    /** CANCEL method, for cancelling request. */
-    PJSIP_CANCEL_METHOD,
-
-    /** ACK method, for acknowledging final response to INVITE. */
-    PJSIP_ACK_METHOD,
-
-    /** BYE method, for terminating dialog. */
-    PJSIP_BYE_METHOD,
-
-    /** REGISTER method. */
-    PJSIP_REGISTER_METHOD,
-
-    /** OPTIONS method, for querying remote capabilities. */
-    PJSIP_OPTIONS_METHOD,
-
-    /** Other method, which means that the method name itself will be stored
-        elsewhere. */
-    PJSIP_OTHER_METHOD,
-
-} pjsip_method_e;
-
-
-
-/**
- * This structure represents a SIP method.
- * Application must always use either #pjsip_method_init or #pjsip_method_set
- * to make sure that method name is initialized correctly. This way, the name
- * member will always contain a valid method string regardless whether the ID
- * is recognized or not.
- */
-typedef struct pjsip_method
-{
-    pjsip_method_e id;	    /**< Method ID, from \a pjsip_method_e. */
-    pj_str_t	   name;    /**< Method name, which will always contain the 
-			         method string. */
-} pjsip_method;
-
-
-/** 
- * Initialize the method structure from a string. 
- * This function will check whether the method is a known method then set
- * both the id and name accordingly.
- *
- * @param m	The method to initialize.
- * @param pool	Pool where memory allocation will be allocated from, if required.
- * @param str	The method string.
- */
-PJ_DECL(void) pjsip_method_init( pjsip_method *m, 
-				 pj_pool_t *pool, 
-				 const pj_str_t *str);
-
-/** 
- * Initialize the method structure from a string, without cloning the string.
- * See #pjsip_method_init.
- *
- * @param m	The method structure to be initialized.
- * @param str	The method string.
- */
-PJ_DECL(void) pjsip_method_init_np( pjsip_method *m,
-				    pj_str_t *str);
-
-/** 
- * Set the method with the predefined method ID. 
- * This function will also set the name member of the structure to the correct
- * string according to the method.
- *
- * @param m	The method structure.
- * @param id	The method ID.
- */
-PJ_DECL(void) pjsip_method_set( pjsip_method *m, pjsip_method_e id );
-
-
-/** 
- * Copy one method structure to another. If the method is of the known methods,
- * then memory allocation is not required.
- *
- * @param pool	    Pool to allocate memory from, if required.
- * @param method    The destination method to copy to.
- * @param rhs	    The source method to copy from.
- */
-PJ_DECL(void) pjsip_method_copy( pj_pool_t *pool,
-				 pjsip_method *method,
-				 const pjsip_method *rhs );
-
-/** 
- * Compare one method with another, and conveniently determine whether the 
- * first method is equal, less than, or greater than the second method.
- *
- * @param m1	The first method.
- * @param m2	The second method.
- *
- * @return	Zero if equal, otherwise will return -1 if less or +1 if greater.
- */
-PJ_DECL(int) pjsip_method_cmp( const pjsip_method *m1, const pjsip_method *m2);
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/** 
- * @defgroup PJSIP_MSG_HDR Header Fields General Structure.
- * @brief General Header Fields Structure.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * Header types, as defined by RFC3261.
- */
-typedef enum pjsip_hdr_e
-{
-    /*
-     * These are the headers documented in RFC3261. Headers not documented
-     * there must have type PJSIP_H_OTHER, and the header type itself is 
-     * recorded in the header name string.
-     *
-     * DO NOT CHANGE THE VALUE/ORDER OF THE HEADER IDs!!!.
-     */
-    PJSIP_H_ACCEPT,
-    PJSIP_H_ACCEPT_ENCODING_UNIMP,
-    PJSIP_H_ACCEPT_LANGUAGE_UNIMP,
-    PJSIP_H_ALERT_INFO_UNIMP,
-    PJSIP_H_ALLOW,
-    PJSIP_H_AUTHENTICATION_INFO_UNIMP,
-    PJSIP_H_AUTHORIZATION,
-    PJSIP_H_CALL_ID,
-    PJSIP_H_CALL_INFO_UNIMP,
-    PJSIP_H_CONTACT,
-    PJSIP_H_CONTENT_DISPOSITION_UNIMP,
-    PJSIP_H_CONTENT_ENCODING_UNIMP,
-    PJSIP_H_CONTENT_LANGUAGE_UNIMP,
-    PJSIP_H_CONTENT_LENGTH,
-    PJSIP_H_CONTENT_TYPE,
-    PJSIP_H_CSEQ,
-    PJSIP_H_DATE_UNIMP,
-    PJSIP_H_ERROR_INFO_UNIMP,
-    PJSIP_H_EXPIRES,
-    PJSIP_H_FROM,
-    PJSIP_H_IN_REPLY_TO_UNIMP,
-    PJSIP_H_MAX_FORWARDS,
-    PJSIP_H_MIME_VERSION_UNIMP,
-    PJSIP_H_MIN_EXPIRES,
-    PJSIP_H_ORGANIZATION_UNIMP,
-    PJSIP_H_PRIORITY_UNIMP,
-    PJSIP_H_PROXY_AUTHENTICATE,
-    PJSIP_H_PROXY_AUTHORIZATION,
-    PJSIP_H_PROXY_REQUIRE_UNIMP,
-    PJSIP_H_RECORD_ROUTE,
-    PJSIP_H_REPLY_TO_UNIMP,
-    PJSIP_H_REQUIRE,
-    PJSIP_H_RETRY_AFTER,
-    PJSIP_H_ROUTE,
-    PJSIP_H_SERVER_UNIMP,
-    PJSIP_H_SUBJECT_UNIMP,
-    PJSIP_H_SUPPORTED,
-    PJSIP_H_TIMESTAMP_UNIMP,
-    PJSIP_H_TO,
-    PJSIP_H_UNSUPPORTED,
-    PJSIP_H_USER_AGENT_UNIMP,
-    PJSIP_H_VIA,
-    PJSIP_H_WARNING_UNIMP,
-    PJSIP_H_WWW_AUTHENTICATE,
-
-    PJSIP_H_OTHER,
-
-} pjsip_hdr_e;
-
-/**
- * This structure provides the pointer to basic functions that are needed
- * for generic header operations. All header fields will have pointer to
- * this structure, so that they can be manipulated uniformly.
- */
-typedef struct pjsip_hdr_vptr
-{
-    /** 
-     * Function to clone the header. 
-     *
-     * @param pool  Memory pool to allocate the new header.
-     * @param hdr   Header to clone.
-     *
-     * @return A new instance of the header.
-     */
-    void *(*clone)(pj_pool_t *pool, const void *hdr);
-
-    /** 
-     * Pointer to function to shallow clone the header. 
-     * Shallow cloning will just make a memory copy of the original header,
-     * thus all pointers in original header will be kept intact. Because the
-     * function does not need to perform deep copy, the operation should be
-     * faster, but the application must make sure that the original header
-     * is still valid throughout the lifetime of new header.
-     *
-     * @param pool  Memory pool to allocate the new header.
-     * @param hdr   The header to clone.
-     */
-    void *(*shallow_clone)(pj_pool_t *pool, const void *hdr);
-
-    /** Pointer to function to print the header to the specified buffer.
-     *	Returns the length of string written, or -1 if the remaining buffer
-     *	is not enough to hold the header.
-     *
-     *  @param hdr  The header to print.
-     *  @param buf  The buffer.
-     *  @param len  The size of the buffer.
-     *
-     *  @return	    The size copied to buffer, or -1 if there's not enough space.
-     */
-    int (*print_on)(void *hdr, char *buf, pj_size_t len);
-
-} pjsip_hdr_vptr;
-
-
-/**
- * Generic fields for all SIP headers are declared using this macro, to make
- * sure that all headers will have exactly the same layout in their start of
- * the storage. This behaves like C++ inheritance actually.
- */
-#define PJSIP_DECL_HDR_MEMBER(hdr)   \
-    /** List members. */	\
-    PJ_DECL_LIST_MEMBER(hdr);	\
-    /** Header type */		\
-    pjsip_hdr_e	    type;	\
-    /** Header name. */		\
-    pj_str_t	    name;	\
-    /** Header short name version. */	\
-    pj_str_t	    sname;		\
-    /** Virtual function table. */	\
-    pjsip_hdr_vptr *vptr
-
-
-/**
- * Generic SIP header structure, for generic manipulation for headers in the
- * message. All header fields can be typecasted to this type.
- */
-struct pjsip_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_hdr);
-};
-
-
-/**
- * This generic function will clone any header, by calling "clone" function
- * in header's virtual function table.
- *
- * @param pool	    The pool to allocate memory from.
- * @param hdr	    The header to clone.
- *
- * @return	    A new instance copied from the original header.
- */
-PJ_DECL(void*) pjsip_hdr_clone( pj_pool_t *pool, const void *hdr );
-
-
-/**
- * This generic function will clone any header, by calling "shallow_clone" 
- * function in header's virtual function table.
- *
- * @param pool	    The pool to allocate memory from.
- * @param hdr	    The header to clone.
- *
- * @return	    A new instance copied from the original header.
- */
-PJ_DECL(void*) pjsip_hdr_shallow_clone( pj_pool_t *pool, const void *hdr );
-
-/**
- * This generic function will print any header, by calling "print" 
- * function in header's virtual function table.
- *
- * @param hdr  The header to print.
- * @param buf  The buffer.
- * @param len  The size of the buffer.
- *
- * @return	The size copied to buffer, or -1 if there's not enough space.
- */
-PJ_DECL(int) pjsip_hdr_print_on( void *hdr, char *buf, pj_size_t len);
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_LINE Request and Status Line.
- * @brief Request and status line structures and manipulation.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * This structure describes SIP request line.
- */
-typedef struct pjsip_request_line 
-{
-    pjsip_method    method; /**< Method for this request line. */
-    pjsip_uri *uri;    /**< URI for this request line. */
-} pjsip_request_line;
-
-
-/**
- * This structure describes SIP status line.
- */
-typedef struct pjsip_status_line 
-{
-    int		code;	    /**< Status code. */
-    pj_str_t	reason;	    /**< Reason string. */
-} pjsip_status_line;
-
-
-/**
- * This enumeration lists standard SIP status codes according to RFC 3261.
- * In addition, it also declares new status class 7xx for errors generated
- * by the stack. This status class however should not get transmitted on the 
- * wire.
- */
-typedef enum pjsip_status_code
-{
-    PJSIP_SC_TRYING = 100,
-    PJSIP_SC_RINGING = 180,
-    PJSIP_SC_CALL_BEING_FORWARDED = 181,
-    PJSIP_SC_QUEUED = 182,
-    PJSIP_SC_PROGRESS = 183,
-
-    PJSIP_SC_OK = 200,
-
-    PJSIP_SC_MULTIPLE_CHOICES = 300,
-    PJSIP_SC_MOVED_PERMANENTLY = 301,
-    PJSIP_SC_MOVED_TEMPORARILY = 302,
-    PJSIP_SC_USE_PROXY = 305,
-    PJSIP_SC_ALTERNATIVE_SERVICE = 380,
-
-    PJSIP_SC_BAD_REQUEST = 400,
-    PJSIP_SC_UNAUTHORIZED = 401,
-    PJSIP_SC_PAYMENT_REQUIRED = 402,
-    PJSIP_SC_FORBIDDEN = 403,
-    PJSIP_SC_NOT_FOUND = 404,
-    PJSIP_SC_METHOD_NOT_ALLOWED = 405,
-    PJSIP_SC_NOT_ACCEPTABLE = 406,
-    PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED = 407,
-    PJSIP_SC_REQUEST_TIMEOUT = 408,
-    PJSIP_SC_GONE = 410,
-    PJSIP_SC_REQUEST_ENTITY_TOO_LARGE = 413,
-    PJSIP_SC_REQUEST_URI_TOO_LONG = 414,
-    PJSIP_SC_UNSUPPORTED_MEDIA_TYPE = 415,
-    PJSIP_SC_UNSUPPORTED_URI_SCHEME = 416,
-    PJSIP_SC_BAD_EXTENSION = 420,
-    PJSIP_SC_EXTENSION_REQUIRED = 421,
-    PJSIP_SC_INTERVAL_TOO_BRIEF = 423,
-    PJSIP_SC_TEMPORARILY_UNAVAILABLE = 480,
-    PJSIP_SC_CALL_TSX_DOES_NOT_EXIST = 481,
-    PJSIP_SC_LOOP_DETECTED = 482,
-    PJSIP_SC_TOO_MANY_HOPS = 483,
-    PJSIP_SC_ADDRESS_INCOMPLETE = 484,
-    PJSIP_AC_AMBIGUOUS = 485,
-    PJSIP_SC_BUSY_HERE = 486,
-    PJSIP_SC_REQUEST_TERMINATED = 487,
-    PJSIP_SC_NOT_ACCEPTABLE_HERE = 488,
-    PJSIP_SC_REQUEST_PENDING = 491,
-    PJSIP_SC_UNDECIPHERABLE = 493,
-
-    PJSIP_SC_INTERNAL_SERVER_ERROR = 500,
-    PJSIP_SC_NOT_IMPLEMENTED = 501,
-    PJSIP_SC_BAD_GATEWAY = 502,
-    PJSIP_SC_SERVICE_UNAVAILABLE = 503,
-    PJSIP_SC_SERVER_TIMEOUT = 504,
-    PJSIP_SC_VERSION_NOT_SUPPORTED = 505,
-    PJSIP_SC_MESSAGE_TOO_LARGE = 513,
-
-    PJSIP_SC_BUSY_EVERYWHERE = 600,
-    PJSIP_SC_DECLINE = 603,
-    PJSIP_SC_DOES_NOT_EXIST_ANYWHERE = 604,
-    PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE = 606,
-
-    PJSIP_SC_TSX_TIMEOUT = 701,
-    PJSIP_SC_TSX_RESOLVE_ERROR = 702,
-    PJSIP_SC_TSX_TRANSPORT_ERROR = 703,
-
-} pjsip_status_code;
-
-/**
- * Get the default status text for the status code.
- *
- * @param status_code	    SIP Status Code
- *
- * @return		    textual message for the status code.
- */ 
-PJ_DECL(const pj_str_t*) pjsip_get_status_text(int status_code);
-
-/**
- * This macro returns non-zero (TRUE) if the specified status_code is
- * in the same class as the code_class.
- *
- * @param status_code	The status code.
- * @param code_class	The status code in the class (for example 100, 200).
- */
-#define PJSIP_IS_STATUS_IN_CLASS(status_code, code_class)    \
-	    (status_code/100 == code_class/100)
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @addtogroup PJSIP_MSG_MEDIA Media Type
- * @brief Media type definitions and manipulations.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * This structure describes SIP media type, as used for example in 
- * Accept and Content-Type header..
- */
-typedef struct pjsip_media_type
-{
-    pj_str_t type;	    /**< Media type. */
-    pj_str_t subtype;	    /**< Media subtype. */
-    pj_str_t param;	    /**< Media type parameters (concatenated). */
-} pjsip_media_type;
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @addtogroup PJSIP_MSG_BODY Message Body
- * @brief SIP message body structures and manipulation.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * Generic abstraction to message body.
- * When an incoming message is parsed (pjsip_parse_msg()), the parser fills in
- * all members with the appropriate value. The 'data' and 'len' member will
- * describe portion of incoming packet which denotes the message body.
- * When application needs to attach message body to outgoing SIP message, it
- * must fill in all members of this structure. 
- */
-typedef struct pjsip_msg_body
-{
-    /** MIME content type. 
-     *  For incoming messages, the parser will fill in this member with the
-     *  content type found in Content-Type header.
-     *
-     *  For outgoing messages, application must fill in this member with
-     *  appropriate value, because the stack will generate Content-Type header
-     *  based on the value specified here.
-     */
-    pjsip_media_type content_type;
-
-    /** Pointer to buffer which holds the message body data. 
-     *  For incoming messages, the parser will fill in this member with the
-     *  pointer to the body string.
-     *
-     *  When sending outgoing message, this member doesn't need to point to the
-     *  actual message body string. It can be assigned with arbitrary pointer,
-     *  because the value will only need to be understood by the print_body()
-     *  function. The stack itself will not try to interpret this value, but
-     *  instead will always call the print_body() whenever it needs to get the
-     *  actual body string.
-     */
-    void *data;
-
-    /** The length of the data. 
-     *  For incoming messages, the parser will fill in this member with the
-     *  actual length of message body.
-     *
-     *  When sending outgoing message, again just like the "data" member, the
-     *  "len" member doesn't need to point to the actual length of the body 
-     *  string.
-     */
-    unsigned len;
-
-    /** Pointer to function to print this message body. 
-     *  Application must set a proper function here when sending outgoing 
-     *  message.
-     *
-     *  @param msg_body	    This structure itself.
-     *  @param buf	    The buffer.
-     *  @param size	    The buffer size.
-     *
-     *  @return		    The length of the string printed, or -1 if there is
-     *			    not enough space in the buffer to print the whole
-     *			    message body.
-     */
-    int (*print_body)(struct pjsip_msg_body *msg_body, 
-		      char *buf, pj_size_t size);
-
-} pjsip_msg_body;
-
-/**
- * General purpose function to textual data in a SIP body. Attach this function
- * in a SIP message body only if the data in pjsip_msg_body is a textual 
- * message ready to be embedded in a SIP message. If the data in the message
- * body is not a textual body, then application must supply a custom function
- * to print that body.
- *
- * @param msg_body	The message body.
- * @param buf		Buffer to copy the message body to.
- * @param size		The size of the buffer.
- *
- * @return		The length copied to the buffer, or -1.
- */
-PJ_DECL(int) pjsip_print_text_body( pjsip_msg_body *msg_body, 
-				    char *buf, pj_size_t size);
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_MSG Message Structure
- * @brief Message structure and operations.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * Message type (request or response).
- */
-typedef enum pjsip_msg_type_e
-{
-    PJSIP_REQUEST_MSG,	    /**< Indicates request message. */
-    PJSIP_RESPONSE_MSG,	    /**< Indicates response message. */
-} pjsip_msg_type_e;
-
-
-/**
- * This structure describes a SIP message.
- */
-struct pjsip_msg
-{
-    /** Message type (ie request or response). */
-    pjsip_msg_type_e  type;
-
-    /** The first line of the message can be either request line for request
-     *	messages, or status line for response messages. It is represented here
-     *  as a union.
-     */
-    union
-    {
-	/** Request Line. */
-	struct pjsip_request_line   req;
-
-	/** Status Line. */
-	struct pjsip_status_line    status;
-    } line;
-
-    /** List of message headers. */
-    pjsip_hdr hdr;
-
-    /** Pointer to message body, or NULL if no message body is attached to
-     *	this mesage. 
-     */
-    pjsip_msg_body *body;
-};
-
-
-/** 
- * Create new request or response message.
- *
- * @param pool	    The pool.
- * @param type	    Message type.
- * @return	    New message, or THROW exception if failed.
- */
-PJ_DECL(pjsip_msg*)  pjsip_msg_create( pj_pool_t *pool, pjsip_msg_type_e type);
-
-/** 
- * Find a header in the message by the header type.
- *
- * @param msg	    The message.
- * @param type	    The header type to find.
- * @param start	    The first header field where the search should begin.
- *		    If NULL is specified, then the search will begin from the
- *		    first header, otherwise the search will begin at the
- *		    specified header.
- *
- * @return	    The header field, or NULL if no header with the specified 
- *		    type is found.
- */
-PJ_DECL(void*)  pjsip_msg_find_hdr( pjsip_msg *msg, 
-				    pjsip_hdr_e type, void *start);
-
-/** 
- * Find a header in the message by its name.
- *
- * @param msg	    The message.
- * @param name	    The header name to find.
- * @param start	    The first header field where the search should begin.
- *		    If NULL is specified, then the search will begin from the
- *		    first header, otherwise the search will begin at the
- *		    specified header.
- *
- * @return	    The header field, or NULL if no header with the specified 
- *		    type is found.
- */
-PJ_DECL(void*)  pjsip_msg_find_hdr_by_name( pjsip_msg *msg, 
-					    const pj_str_t *name, void *start);
-
-/** 
- * Find and remove a header in the message. 
- *
- * @param msg	    The message.
- * @param hdr	    The header type to find.
- * @param start	    The first header field where the search should begin,
- *		    or NULL to search from the first header in the message.
- *
- * @return	    The header field, or NULL if not found.
- */
-PJ_DECL(void*)  pjsip_msg_find_remove_hdr( pjsip_msg *msg, 
-					   pjsip_hdr_e hdr, void *start);
-
-/** 
- * Add a header to the message, putting it last in the header list.
- *
- * @param msg	    The message.
- * @param hdr	    The header to add.
- *
- * @bug Once the header is put in a list (or message), it can not be put in 
- *      other list (or message). Otherwise Real Bad Thing will happen.
- */
-PJ_IDECL(void) pjsip_msg_add_hdr( pjsip_msg *msg, pjsip_hdr *hdr );
-
-/** 
- * Add header field to the message, putting it in the front of the header list.
- *
- * @param msg	The message.
- * @param hdr	The header to add.
- *
- * @bug Once the header is put in a list (or message), it can not be put in 
- *      other list (or message). Otherwise Real Bad Thing will happen.
- */
-PJ_IDECL(void) pjsip_msg_insert_first_hdr( pjsip_msg *msg, pjsip_hdr *hdr );
-
-/** 
- * Print the message to the specified buffer. 
- *
- * @param msg	The message to print.
- * @param buf	The buffer
- * @param size	The size of the buffer.
- *
- * @return	The length of the printed characters (in bytes), or NEGATIVE
- *		value if the message is too large for the specified buffer.
- */
-PJ_DECL(pj_ssize_t) pjsip_msg_print(pjsip_msg *msg, char *buf, pj_size_t size);
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @addtogroup PJSIP_MSG_HDR_GEN Header Field: Generic
- * @brief Generic header field which contains header name and value.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * Generic SIP header, which contains hname and a string hvalue.
- * Note that this header is not supposed to be used as 'base' class for headers.
- */
-typedef struct pjsip_generic_string_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_string_hdr); /**< Standard header field. */
-    pj_str_t hvalue;				    /**< hvalue */
-} pjsip_generic_string_hdr;
-
-
-/**
- * Create a new instance of generic header. A generic header can have an
- * arbitrary header name.
- *
- * @param pool	    The pool.
- * @param hname	    The header name to be assigned to the header, or NULL to
- *		    assign the header name with some string.
- *
- * @return	    The header, or THROW exception.
- */
-PJ_DECL(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool, 
-						      const pj_str_t *hname );
-
-/**
- * Create a generic header along with the text content.
- *
- * @param pool	    The pool.
- * @param hname	    The header name.
- * @param hvalue    The header text content.
- *
- * @return	    The header instance.
- */
-PJ_DECL(pjsip_generic_string_hdr*) 
-pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,
-					   const pj_str_t *hname,
-					   const pj_str_t *hvalue);
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @addtogroup PJSIP_MSG_HDR_GEN_INT Header Field: Generic Integer
- * @brief Generic header field which contains header name and value.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * Generic SIP header, which contains hname and a string hvalue.
- */
-typedef struct pjsip_generic_int_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_int_hdr); /**< Standard header field. */
-    pj_int32_t ivalue;				    /**< ivalue */
-} pjsip_generic_int_hdr;
-
-
-/**
- * Create a new instance of generic header. A generic header can have an
- * arbitrary header name.
- *
- * @param pool	    The pool.
- * @param hname	    The header name to be assigned to the header, or NULL to
- *		    assign the header name with some string.
- *
- * @return	    The header, or THROW exception.
- */
-PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool, 
-						      const pj_str_t *hname );
-
-/**
- * Create a generic header along with the value.
- *
- * @param pool	    The pool.
- * @param hname	    The header name.
- * @param value     The header value content.
- *
- * @return	    The header instance.
- */
-PJ_DECL(pjsip_generic_int_hdr*) 
-pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,
-					 const pj_str_t *hname,
-					 int value);
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_GENERIC_LIST Header Field: Generic string list.
- * @brief Header with list of strings separated with comma
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/** Maximum elements in the header array. */
-#define PJSIP_GENERIC_ARRAY_MAX_COUNT	32
-
-typedef struct pjsip_generic_array_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_array_hdr);
-    unsigned	count;					/**< Number of elements. */
-    pj_str_t	values[PJSIP_GENERIC_ARRAY_MAX_COUNT];	/**< Elements.		 */
-} pjsip_generic_array_hdr;
-
-/**
- * Create generic array header.
- *
- * @param pool	    Pool to allocate memory from.
- *
- * @return	    New generic array header.
- */
-PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_create(pj_pool_t *pool,
-							     const pj_str_t *hnames);
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_ACCEPT Header Field: Accept
- * @brief Accept header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-/** Accept header. */
-typedef pjsip_generic_array_hdr pjsip_accept_hdr;
-
-/** Maximum fields in Accept header. */
-#define PJSIP_MAX_ACCEPT_COUNT	PJSIP_GENERIC_ARRAY_MAX_COUNT
-
-/**
- * Create new Accept header instance.
- *
- * @param pool	    The pool.
- *
- * @return	    New Accept header instance.
- */
-PJ_DECL(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool);
-
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_ALLOW Header Field: Allow
- * @brief Allow header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-typedef pjsip_generic_array_hdr pjsip_allow_hdr;
-
-/**
- * Create new Allow header instance.
- *
- * @param pool	    The pool.
- *
- * @return	    New Allow header instance.
- */
-PJ_DECL(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool);
-
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_CID Header Field: Call-ID
- * @brief Call-ID header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-/**
- * Call-ID header.
- */
-typedef struct pjsip_cid_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_cid_hdr);
-    pj_str_t id;	    /**< Call-ID string. */
-} pjsip_cid_hdr;
-
-
-/**
- * Create new Call-ID header.
- *
- * @param pool	The pool.
- *
- * @return	new Call-ID header.
- */
-PJ_DECL(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool );
-
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_CLEN Header Field: Content-Length
- * @brief Content-Length header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-/**
- * Content-Length header.
- */
-typedef struct pjsip_clen_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_clen_hdr);
-    int len;	/**< Content length. */
-} pjsip_clen_hdr;
-
-/**
- * Create new Content-Length header.
- *
- * @param pool	the pool.
- * @return	A new Content-Length header instance.
- */
-PJ_DECL(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool );
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_CSEQ Header Field: CSeq
- * @brief CSeq header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-/**
- * CSeq header.
- */
-typedef struct pjsip_cseq_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_cseq_hdr);
-    int		    cseq;	/**< CSeq number. */
-    pjsip_method    method;	/**< CSeq method. */
-} pjsip_cseq_hdr;
-
-
-/** Create new  CSeq header. 
- *
- *  @param pool	The pool.
- *  @return A new CSeq header instance.
- */
-PJ_DECL(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool );
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_CONTACT Header Field: Contact
- * @brief Contact header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-/**
- * Contact header.
- * In this library, contact header only contains single URI. If a message has
- * multiple URI in the Contact header, the URI will be put in separate Contact
- * headers.
- */
-typedef struct pjsip_contact_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_contact_hdr);
-    int		    star;	    /**< The contact contains only a '*' character */
-    pjsip_uri *uri;	    /**< URI in the contact. */
-    int		    q1000;	    /**< The "q" value times 1000 (to avoid float) */
-    pj_int32_t	    expires;	    /**< Expires parameter, otherwise -1 if not present. */
-    pj_str_t	    other_param;    /**< Other parameters, concatenated in a single string. */
-} pjsip_contact_hdr;
-
-
-/**
- * Create a new Contact header.
- *
- * @param pool	The pool.
- * @return	A new instance of Contact header.
- */
-PJ_DECL(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool );
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_CTYPE Header Field: Content-Type
- * @brief Content-Type header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-/**
- * Content-Type.
- */
-typedef struct pjsip_ctype_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_ctype_hdr);
-    pjsip_media_type media; /**< Media type. */
-} pjsip_ctype_hdr;
-
-
-/**
- * Create a nwe Content Type header.
- *
- * @param pool	The pool.
- * @return	A new Content-Type header.
- */
-PJ_DECL(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool );
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_EXPIRES Header Field: Expires
- * @brief Expires header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-/** Expires header. */
-typedef pjsip_generic_int_hdr pjsip_expires_hdr;
-
-/**
- * Create a new Expires header.
- *
- * @param pool	The pool.
- * @return	A new Expires header.
- */
-PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool );
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_FROMTO Header Field: From/To
- * @brief From and To header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-/**
- * To or From header.
- */
-typedef struct pjsip_fromto_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_fromto_hdr);
-    pjsip_uri  *uri;	    /**< URI in From/To header. */
-    pj_str_t	     tag;	    /**< Header "tag" parameter. */
-    pj_str_t	     other_param;   /**< Other params, concatenated as a single string. */
-} pjsip_fromto_hdr;
-
-/** Alias for From header. */
-typedef pjsip_fromto_hdr pjsip_from_hdr;
-
-/** Alias for To header. */
-typedef pjsip_fromto_hdr pjsip_to_hdr;
-
-/**
- * Create a From header.
- *
- * @param pool	The pool.
- * @return	New instance of From header.
- */
-PJ_DECL(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool );
-
-/**
- * Create a To header.
- *
- * @param pool	The pool.
- * @return	New instance of To header.
- */
-PJ_DECL(pjsip_to_hdr*)   pjsip_to_hdr_create( pj_pool_t *pool );
-
-/**
- * Convert the header to a From header.
- *
- * @param pool	The pool.
- * @return	"From" header.
- */
-PJ_DECL(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr );
-
-/**
- * Convert the header to a To header.
- *
- * @param pool	The pool.
- * @return	"To" header.
- */
-PJ_DECL(pjsip_to_hdr*)   pjsip_fromto_set_to( pjsip_fromto_hdr *hdr );
-
-/**
- * @}
- */
-
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_MAX_FORWARDS Header Field: Max-Forwards
- * @brief Max-Forwards header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-typedef pjsip_generic_int_hdr pjsip_max_forwards_hdr;
-
-/**
- * Create new Max-Forwards header instance.
- *
- * @param pool	    The pool.
- *
- * @return	    New Max-Forwards header instance.
- */
-PJ_DECL(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool);
-
-
-/**
- * @}
- */
-
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_MIN_EXPIRES Header Field: Min-Expires
- * @brief Min-Expires header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-typedef pjsip_generic_int_hdr pjsip_min_expires_hdr;
-
-/**
- * Create new Max-Forwards header instance.
- *
- * @param pool	    The pool.
- *
- * @return	    New Max-Forwards header instance.
- */
-PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool);
-
-
-/**
- * @}
- */
-
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_ROUTING Header Field: Record-Route/Route
- * @brief Record-Route and Route header fields.
- * @ingroup PJSIP_MSG
- * @{
- */
-/**
- * Record-Route and Route headers.
- */
-typedef struct pjsip_routing_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_routing_hdr);  /**< Generic header fields. */
-    pjsip_name_addr  name_addr;	  /**< The URL in the Route/Record-Route header. */
-    pj_str_t	     other_param; /** Other parameter. */
-} pjsip_routing_hdr;
-
-/** Alias for Record-Route header. */
-typedef pjsip_routing_hdr pjsip_rr_hdr;
-
-/** Alias for Route header. */
-typedef pjsip_routing_hdr pjsip_route_hdr;
-
-
-/** 
- * Create new Record-Route header from the pool. 
- *
- * @param pool	The pool.
- * @return	A new instance of Record-Route header.
- */
-PJ_DECL(pjsip_rr_hdr*)	    pjsip_rr_hdr_create( pj_pool_t *pool );
-
-/** 
- * Create new Route header from the pool. 
- *
- * @param pool	The pool.
- * @return	A new instance of "Route" header.
- */
-PJ_DECL(pjsip_route_hdr*)   pjsip_route_hdr_create( pj_pool_t *pool );
-
-/** 
- * Convert generic routing header to Record-Route header. 
- *
- * @param r	The generic routing header, or a "Routing" header.
- * @return	Record-Route header.
- */
-PJ_DECL(pjsip_rr_hdr*)	    pjsip_routing_hdr_set_rr( pjsip_routing_hdr *r );
-
-/** 
- * Convert generic routing header to "Route" header. 
- *
- * @param r	The generic routing header, or a "Record-Route" header.
- * @return	"Route" header.
- */
-PJ_DECL(pjsip_route_hdr*)   pjsip_routing_hdr_set_route( pjsip_routing_hdr *r );
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_REQUIRE Header Field: Require
- * @brief Require header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-typedef pjsip_generic_array_hdr pjsip_require_hdr;
-
-/**
- * Create new Require header instance.
- *
- * @param pool	    The pool.
- *
- * @return	    New Require header instance.
- */
-PJ_DECL(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool);
-
-
-/**
- * @}
- */
-
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_RETRY_AFTER Header Field: Retry-After
- * @brief Retry-After header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-typedef pjsip_generic_int_hdr pjsip_retry_after_hdr;
-
-/**
- * Create new Retry-After header instance.
- *
- * @param pool	    The pool.
- *
- * @return	    New Retry-After header instance.
- */
-PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool);
-
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_SUPPORTED Header Field: Supported
- * @brief Supported header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-typedef pjsip_generic_array_hdr pjsip_supported_hdr;
-
-/**
- * Create new Supported header instance.
- *
- * @param pool	    The pool.
- *
- * @return	    New Supported header instance.
- */
-PJ_DECL(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool);
-
-
-/**
- * @}
- */
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_UNSUPPORTED Header Field: Unsupported
- * @brief Unsupported header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-typedef pjsip_generic_array_hdr pjsip_unsupported_hdr;
-
-/**
- * Create new Unsupported header instance.
- *
- * @param pool	    The pool.
- *
- * @return	    New Unsupported header instance.
- */
-PJ_DECL(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool);
-
-
-/**
- * @}
- */
-
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_VIA Header Field: Via
- * @brief Via header field.
- * @ingroup PJSIP_MSG
- * @{
- */
-/**
- * SIP Via header.
- * In this implementation, Via header can only have one element in each header.
- * If a message arrives with multiple elements in a single Via, then they will
- * be split up into multiple Via headers.
- */
-typedef struct pjsip_via_hdr
-{
-    PJSIP_DECL_HDR_MEMBER(struct pjsip_via_hdr);
-    pj_str_t	     transport;	    /**< Transport type. */
-    pjsip_host_port  sent_by;	    /**< Host and optional port */
-    int		     ttl_param;	    /**< TTL parameter, or -1 if it's not specified. */
-    int		     rport_param;   /**< "rport" parameter, 0 to specify without
-					 port number, -1 means doesn't exist. */
-    pj_str_t	     maddr_param;   /**< "maddr" parameter. */
-    pj_str_t	     recvd_param;   /**< "received" parameter. */
-    pj_str_t	     branch_param;  /**< "branch" parameter. */
-    pj_str_t	     other_param;   /**< Other parameters, concatenated as single string. */
-    pj_str_t	     comment;	    /**< Comment. */
-} pjsip_via_hdr;
-
-/**
- * Create a new Via header.
- *
- * @param pool	    The pool.
- * @return	    A new "Via" header instance.
- */
-PJ_DECL(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool );
-
-/**
- * @}
- */
-
-/**
- * @bug Once a header is put in the message, the header CAN NOT be put in
- *      other list. Solution:
- *	- always clone header in the message.
- *	- create a list node for each header in the message.
- */
-
-
-///////////////////////////////////////////////////////////////////////////////
-/**
- * @defgroup PJSIP_MSG_HDR_UNIMP Unimplemented Header Fields
- * @brief Unimplemented header fields.
- * @ingroup PJSIP_MSG
- * @{
- */
-/** Accept-Encoding header. */
-typedef pjsip_generic_string_hdr pjsip_accept_encoding_hdr;
-
-/** Create Accept-Encoding header. */
-#define pjsip_accept_encoding_hdr_create pjsip_generic_string_hdr_create
-
-/** Accept-Language header. */
-typedef pjsip_generic_string_hdr pjsip_accept_lang_hdr;
-
-/** Create Accept-Language header. */
-#define pjsip_accept_lang_hdr_create pjsip_generic_string_hdr_create
-
-/** Alert-Info header. */
-typedef pjsip_generic_string_hdr pjsip_alert_info_hdr;
-
-/** Create Alert-Info header. */
-#define pjsip_alert_info_hdr_create pjsip_generic_string_hdr_create
-
-/** Authentication-Info header. */
-typedef pjsip_generic_string_hdr pjsip_auth_info_hdr;
-
-/** Create Authentication-Info header. */
-#define pjsip_auth_info_hdr_create pjsip_generic_string_hdr_create
-
-/** Call-Info header. */
-typedef pjsip_generic_string_hdr pjsip_call_info_hdr;
-
-/** Create Call-Info header. */
-#define pjsip_call_info_hdr_create pjsip_generic_string_hdr_create
-
-/** Content-Disposition header. */
-typedef pjsip_generic_string_hdr pjsip_content_disposition_hdr;
-
-/** Create Content-Disposition header. */
-#define pjsip_content_disposition_hdr_create pjsip_generic_string_hdr_create
-
-/** Content-Encoding header. */
-typedef pjsip_generic_string_hdr pjsip_content_encoding_hdr;
-
-/** Create Content-Encoding header. */
-#define pjsip_content_encoding_hdr_create pjsip_generic_string_hdr_create
-
-/** Content-Language header. */
-typedef pjsip_generic_string_hdr pjsip_content_lang_hdr;
-
-/** Create Content-Language header. */
-#define pjsip_content_lang_hdr_create pjsip_generic_string_hdr_create
-
-/** Date header. */
-typedef pjsip_generic_string_hdr pjsip_date_hdr;
-
-/** Create Date header. */
-#define pjsip_date_hdr_create pjsip_generic_string_hdr_create
-
-/** Error-Info header. */
-typedef pjsip_generic_string_hdr pjsip_err_info_hdr;
-
-/** Create Error-Info header. */
-#define pjsip_err_info_hdr_create pjsip_generic_string_hdr_create
-
-/** In-Reply-To header. */
-typedef pjsip_generic_string_hdr pjsip_in_reply_to_hdr;
-
-/** Create In-Reply-To header. */
-#define pjsip_in_reply_to_hdr_create pjsip_generic_string_hdr_create
-
-/** MIME-Version header. */
-typedef pjsip_generic_string_hdr pjsip_mime_version_hdr;
-
-/** Create MIME-Version header. */
-#define pjsip_mime_version_hdr_create pjsip_generic_string_hdr_create
-
-/** Organization header. */
-typedef pjsip_generic_string_hdr pjsip_organization_hdr;
-
-/** Create Organization header. */
-#define pjsip_organization_hdr_create pjsip_genric_string_hdr_create
-
-/** Priority header. */
-typedef pjsip_generic_string_hdr pjsip_priority_hdr;
-
-/** Create Priority header. */
-#define pjsip_priority_hdr_create pjsip_generic_string_hdr_create
-
-/** Proxy-Require header. */
-typedef pjsip_generic_string_hdr pjsip_proxy_require_hdr;
-
-/** Reply-To header. */
-typedef pjsip_generic_string_hdr pjsip_reply_to_hdr;
-
-/** Create Reply-To header. */
-#define pjsip_reply_to_hdr_create pjsip_generic_string_hdr_create
-
-/** Server header. */
-typedef pjsip_generic_string_hdr pjsip_server_hdr;
-
-/** Create Server header. */
-#define pjsip_server_hdr_create pjsip_generic_string_hdr_create
-
-/** Subject header. */
-typedef pjsip_generic_string_hdr pjsip_subject_hdr;
-
-/** Create Subject header. */
-#define pjsip_subject_hdr_create pjsip_generic_string_hdr_create
-
-/** Timestamp header. */
-typedef pjsip_generic_string_hdr pjsip_timestamp_hdr;
-
-/** Create Timestamp header. */
-#define pjsip_timestamp_hdr_create pjsip_generic_string_hdr_create
-
-/** User-Agent header. */
-typedef pjsip_generic_string_hdr pjsip_user_agent_hdr;
-
-/** Create User-Agent header. */
-#define pjsip_user_agent_hdr_create pjsip_generic_string_hdr_create
-
-/** Warning header. */
-typedef pjsip_generic_string_hdr pjsip_warning_hdr;
-
-/** Create Warning header. */
-#define pjsip_warning_hdr_create pjsip_generic_string_hdr_create
-
-/**
- * @}
- */
-
-/**
- * @}  // PJSIP_MSG
- */
-
-/*
- * Include inline definitions.
- */
-#if PJ_FUNCTIONS_ARE_INLINED
-#  include <pjsip/sip_msg_i.h>
-#endif
-
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_SIP_MSG_H__ */
-
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_MSG_H__

+#define __PJSIP_SIP_MSG_H__

+

+/**

+ * @file sip_msg.h

+ * @brief SIP Message Structure.

+ */

+

+#include <pjsip/sip_types.h>

+#include <pjsip/sip_uri.h>

+#include <pj/list.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_MSG SIP Message Structure

+ * @ingroup PJSIP

+ * @{

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_METHOD Methods

+ * @brief Method names and manipulation.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * This enumeration declares SIP methods as described by RFC3261. Additional

+ * methods do exist, and they are described by corresponding RFCs for the SIP

+ * extentensions. Since they won't alter the characteristic of the processing

+ * of the message, they don't need to be explicitly mentioned here.

+ */

+typedef enum pjsip_method_e

+{

+    /** INVITE method, for establishing dialogs. */

+    PJSIP_INVITE_METHOD,

+

+    /** CANCEL method, for cancelling request. */

+    PJSIP_CANCEL_METHOD,

+

+    /** ACK method, for acknowledging final response to INVITE. */

+    PJSIP_ACK_METHOD,

+

+    /** BYE method, for terminating dialog. */

+    PJSIP_BYE_METHOD,

+

+    /** REGISTER method. */

+    PJSIP_REGISTER_METHOD,

+

+    /** OPTIONS method, for querying remote capabilities. */

+    PJSIP_OPTIONS_METHOD,

+

+    /** Other method, which means that the method name itself will be stored

+        elsewhere. */

+    PJSIP_OTHER_METHOD,

+

+} pjsip_method_e;

+

+

+

+/**

+ * This structure represents a SIP method.

+ * Application must always use either #pjsip_method_init or #pjsip_method_set

+ * to make sure that method name is initialized correctly. This way, the name

+ * member will always contain a valid method string regardless whether the ID

+ * is recognized or not.

+ */

+typedef struct pjsip_method

+{

+    pjsip_method_e id;	    /**< Method ID, from \a pjsip_method_e. */

+    pj_str_t	   name;    /**< Method name, which will always contain the 

+			         method string. */

+} pjsip_method;

+

+

+/** 

+ * Initialize the method structure from a string. 

+ * This function will check whether the method is a known method then set

+ * both the id and name accordingly.

+ *

+ * @param m	The method to initialize.

+ * @param pool	Pool where memory allocation will be allocated from, if required.

+ * @param str	The method string.

+ */

+PJ_DECL(void) pjsip_method_init( pjsip_method *m, 

+				 pj_pool_t *pool, 

+				 const pj_str_t *str);

+

+/** 

+ * Initialize the method structure from a string, without cloning the string.

+ * See #pjsip_method_init.

+ *

+ * @param m	The method structure to be initialized.

+ * @param str	The method string.

+ */

+PJ_DECL(void) pjsip_method_init_np( pjsip_method *m,

+				    pj_str_t *str);

+

+/** 

+ * Set the method with the predefined method ID. 

+ * This function will also set the name member of the structure to the correct

+ * string according to the method.

+ *

+ * @param m	The method structure.

+ * @param id	The method ID.

+ */

+PJ_DECL(void) pjsip_method_set( pjsip_method *m, pjsip_method_e id );

+

+

+/** 

+ * Copy one method structure to another. If the method is of the known methods,

+ * then memory allocation is not required.

+ *

+ * @param pool	    Pool to allocate memory from, if required.

+ * @param method    The destination method to copy to.

+ * @param rhs	    The source method to copy from.

+ */

+PJ_DECL(void) pjsip_method_copy( pj_pool_t *pool,

+				 pjsip_method *method,

+				 const pjsip_method *rhs );

+

+/** 

+ * Compare one method with another, and conveniently determine whether the 

+ * first method is equal, less than, or greater than the second method.

+ *

+ * @param m1	The first method.

+ * @param m2	The second method.

+ *

+ * @return	Zero if equal, otherwise will return -1 if less or +1 if greater.

+ */

+PJ_DECL(int) pjsip_method_cmp( const pjsip_method *m1, const pjsip_method *m2);

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/** 

+ * @defgroup PJSIP_MSG_HDR Header Fields General Structure.

+ * @brief General Header Fields Structure.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * Header types, as defined by RFC3261.

+ */

+typedef enum pjsip_hdr_e

+{

+    /*

+     * These are the headers documented in RFC3261. Headers not documented

+     * there must have type PJSIP_H_OTHER, and the header type itself is 

+     * recorded in the header name string.

+     *

+     * DO NOT CHANGE THE VALUE/ORDER OF THE HEADER IDs!!!.

+     */

+    PJSIP_H_ACCEPT,

+    PJSIP_H_ACCEPT_ENCODING_UNIMP,

+    PJSIP_H_ACCEPT_LANGUAGE_UNIMP,

+    PJSIP_H_ALERT_INFO_UNIMP,

+    PJSIP_H_ALLOW,

+    PJSIP_H_AUTHENTICATION_INFO_UNIMP,

+    PJSIP_H_AUTHORIZATION,

+    PJSIP_H_CALL_ID,

+    PJSIP_H_CALL_INFO_UNIMP,

+    PJSIP_H_CONTACT,

+    PJSIP_H_CONTENT_DISPOSITION_UNIMP,

+    PJSIP_H_CONTENT_ENCODING_UNIMP,

+    PJSIP_H_CONTENT_LANGUAGE_UNIMP,

+    PJSIP_H_CONTENT_LENGTH,

+    PJSIP_H_CONTENT_TYPE,

+    PJSIP_H_CSEQ,

+    PJSIP_H_DATE_UNIMP,

+    PJSIP_H_ERROR_INFO_UNIMP,

+    PJSIP_H_EXPIRES,

+    PJSIP_H_FROM,

+    PJSIP_H_IN_REPLY_TO_UNIMP,

+    PJSIP_H_MAX_FORWARDS,

+    PJSIP_H_MIME_VERSION_UNIMP,

+    PJSIP_H_MIN_EXPIRES,

+    PJSIP_H_ORGANIZATION_UNIMP,

+    PJSIP_H_PRIORITY_UNIMP,

+    PJSIP_H_PROXY_AUTHENTICATE,

+    PJSIP_H_PROXY_AUTHORIZATION,

+    PJSIP_H_PROXY_REQUIRE_UNIMP,

+    PJSIP_H_RECORD_ROUTE,

+    PJSIP_H_REPLY_TO_UNIMP,

+    PJSIP_H_REQUIRE,

+    PJSIP_H_RETRY_AFTER,

+    PJSIP_H_ROUTE,

+    PJSIP_H_SERVER_UNIMP,

+    PJSIP_H_SUBJECT_UNIMP,

+    PJSIP_H_SUPPORTED,

+    PJSIP_H_TIMESTAMP_UNIMP,

+    PJSIP_H_TO,

+    PJSIP_H_UNSUPPORTED,

+    PJSIP_H_USER_AGENT_UNIMP,

+    PJSIP_H_VIA,

+    PJSIP_H_WARNING_UNIMP,

+    PJSIP_H_WWW_AUTHENTICATE,

+

+    PJSIP_H_OTHER,

+

+} pjsip_hdr_e;

+

+/**

+ * This structure provides the pointer to basic functions that are needed

+ * for generic header operations. All header fields will have pointer to

+ * this structure, so that they can be manipulated uniformly.

+ */

+typedef struct pjsip_hdr_vptr

+{

+    /** 

+     * Function to clone the header. 

+     *

+     * @param pool  Memory pool to allocate the new header.

+     * @param hdr   Header to clone.

+     *

+     * @return A new instance of the header.

+     */

+    void *(*clone)(pj_pool_t *pool, const void *hdr);

+

+    /** 

+     * Pointer to function to shallow clone the header. 

+     * Shallow cloning will just make a memory copy of the original header,

+     * thus all pointers in original header will be kept intact. Because the

+     * function does not need to perform deep copy, the operation should be

+     * faster, but the application must make sure that the original header

+     * is still valid throughout the lifetime of new header.

+     *

+     * @param pool  Memory pool to allocate the new header.

+     * @param hdr   The header to clone.

+     */

+    void *(*shallow_clone)(pj_pool_t *pool, const void *hdr);

+

+    /** Pointer to function to print the header to the specified buffer.

+     *	Returns the length of string written, or -1 if the remaining buffer

+     *	is not enough to hold the header.

+     *

+     *  @param hdr  The header to print.

+     *  @param buf  The buffer.

+     *  @param len  The size of the buffer.

+     *

+     *  @return	    The size copied to buffer, or -1 if there's not enough space.

+     */

+    int (*print_on)(void *hdr, char *buf, pj_size_t len);

+

+} pjsip_hdr_vptr;

+

+

+/**

+ * Generic fields for all SIP headers are declared using this macro, to make

+ * sure that all headers will have exactly the same layout in their start of

+ * the storage. This behaves like C++ inheritance actually.

+ */

+#define PJSIP_DECL_HDR_MEMBER(hdr)   \

+    /** List members. */	\

+    PJ_DECL_LIST_MEMBER(hdr);	\

+    /** Header type */		\

+    pjsip_hdr_e	    type;	\

+    /** Header name. */		\

+    pj_str_t	    name;	\

+    /** Header short name version. */	\

+    pj_str_t	    sname;		\

+    /** Virtual function table. */	\

+    pjsip_hdr_vptr *vptr

+

+

+/**

+ * Generic SIP header structure, for generic manipulation for headers in the

+ * message. All header fields can be typecasted to this type.

+ */

+struct pjsip_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_hdr);

+};

+

+

+/**

+ * This generic function will clone any header, by calling "clone" function

+ * in header's virtual function table.

+ *

+ * @param pool	    The pool to allocate memory from.

+ * @param hdr	    The header to clone.

+ *

+ * @return	    A new instance copied from the original header.

+ */

+PJ_DECL(void*) pjsip_hdr_clone( pj_pool_t *pool, const void *hdr );

+

+

+/**

+ * This generic function will clone any header, by calling "shallow_clone" 

+ * function in header's virtual function table.

+ *

+ * @param pool	    The pool to allocate memory from.

+ * @param hdr	    The header to clone.

+ *

+ * @return	    A new instance copied from the original header.

+ */

+PJ_DECL(void*) pjsip_hdr_shallow_clone( pj_pool_t *pool, const void *hdr );

+

+/**

+ * This generic function will print any header, by calling "print" 

+ * function in header's virtual function table.

+ *

+ * @param hdr  The header to print.

+ * @param buf  The buffer.

+ * @param len  The size of the buffer.

+ *

+ * @return	The size copied to buffer, or -1 if there's not enough space.

+ */

+PJ_DECL(int) pjsip_hdr_print_on( void *hdr, char *buf, pj_size_t len);

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_LINE Request and Status Line.

+ * @brief Request and status line structures and manipulation.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * This structure describes SIP request line.

+ */

+typedef struct pjsip_request_line 

+{

+    pjsip_method    method; /**< Method for this request line. */

+    pjsip_uri *uri;    /**< URI for this request line. */

+} pjsip_request_line;

+

+

+/**

+ * This structure describes SIP status line.

+ */

+typedef struct pjsip_status_line 

+{

+    int		code;	    /**< Status code. */

+    pj_str_t	reason;	    /**< Reason string. */

+} pjsip_status_line;

+

+

+/**

+ * This enumeration lists standard SIP status codes according to RFC 3261.

+ * In addition, it also declares new status class 7xx for errors generated

+ * by the stack. This status class however should not get transmitted on the 

+ * wire.

+ */

+typedef enum pjsip_status_code

+{

+    PJSIP_SC_TRYING = 100,

+    PJSIP_SC_RINGING = 180,

+    PJSIP_SC_CALL_BEING_FORWARDED = 181,

+    PJSIP_SC_QUEUED = 182,

+    PJSIP_SC_PROGRESS = 183,

+

+    PJSIP_SC_OK = 200,

+

+    PJSIP_SC_MULTIPLE_CHOICES = 300,

+    PJSIP_SC_MOVED_PERMANENTLY = 301,

+    PJSIP_SC_MOVED_TEMPORARILY = 302,

+    PJSIP_SC_USE_PROXY = 305,

+    PJSIP_SC_ALTERNATIVE_SERVICE = 380,

+

+    PJSIP_SC_BAD_REQUEST = 400,

+    PJSIP_SC_UNAUTHORIZED = 401,

+    PJSIP_SC_PAYMENT_REQUIRED = 402,

+    PJSIP_SC_FORBIDDEN = 403,

+    PJSIP_SC_NOT_FOUND = 404,

+    PJSIP_SC_METHOD_NOT_ALLOWED = 405,

+    PJSIP_SC_NOT_ACCEPTABLE = 406,

+    PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED = 407,

+    PJSIP_SC_REQUEST_TIMEOUT = 408,

+    PJSIP_SC_GONE = 410,

+    PJSIP_SC_REQUEST_ENTITY_TOO_LARGE = 413,

+    PJSIP_SC_REQUEST_URI_TOO_LONG = 414,

+    PJSIP_SC_UNSUPPORTED_MEDIA_TYPE = 415,

+    PJSIP_SC_UNSUPPORTED_URI_SCHEME = 416,

+    PJSIP_SC_BAD_EXTENSION = 420,

+    PJSIP_SC_EXTENSION_REQUIRED = 421,

+    PJSIP_SC_INTERVAL_TOO_BRIEF = 423,

+    PJSIP_SC_TEMPORARILY_UNAVAILABLE = 480,

+    PJSIP_SC_CALL_TSX_DOES_NOT_EXIST = 481,

+    PJSIP_SC_LOOP_DETECTED = 482,

+    PJSIP_SC_TOO_MANY_HOPS = 483,

+    PJSIP_SC_ADDRESS_INCOMPLETE = 484,

+    PJSIP_AC_AMBIGUOUS = 485,

+    PJSIP_SC_BUSY_HERE = 486,

+    PJSIP_SC_REQUEST_TERMINATED = 487,

+    PJSIP_SC_NOT_ACCEPTABLE_HERE = 488,

+    PJSIP_SC_REQUEST_PENDING = 491,

+    PJSIP_SC_UNDECIPHERABLE = 493,

+

+    PJSIP_SC_INTERNAL_SERVER_ERROR = 500,

+    PJSIP_SC_NOT_IMPLEMENTED = 501,

+    PJSIP_SC_BAD_GATEWAY = 502,

+    PJSIP_SC_SERVICE_UNAVAILABLE = 503,

+    PJSIP_SC_SERVER_TIMEOUT = 504,

+    PJSIP_SC_VERSION_NOT_SUPPORTED = 505,

+    PJSIP_SC_MESSAGE_TOO_LARGE = 513,

+

+    PJSIP_SC_BUSY_EVERYWHERE = 600,

+    PJSIP_SC_DECLINE = 603,

+    PJSIP_SC_DOES_NOT_EXIST_ANYWHERE = 604,

+    PJSIP_SC_NOT_ACCEPTABLE_ANYWHERE = 606,

+

+    PJSIP_SC_TSX_TIMEOUT = 701,

+    PJSIP_SC_TSX_RESOLVE_ERROR = 702,

+    PJSIP_SC_TSX_TRANSPORT_ERROR = 703,

+

+} pjsip_status_code;

+

+/**

+ * Get the default status text for the status code.

+ *

+ * @param status_code	    SIP Status Code

+ *

+ * @return		    textual message for the status code.

+ */ 

+PJ_DECL(const pj_str_t*) pjsip_get_status_text(int status_code);

+

+/**

+ * This macro returns non-zero (TRUE) if the specified status_code is

+ * in the same class as the code_class.

+ *

+ * @param status_code	The status code.

+ * @param code_class	The status code in the class (for example 100, 200).

+ */

+#define PJSIP_IS_STATUS_IN_CLASS(status_code, code_class)    \

+	    (status_code/100 == code_class/100)

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @addtogroup PJSIP_MSG_MEDIA Media Type

+ * @brief Media type definitions and manipulations.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * This structure describes SIP media type, as used for example in 

+ * Accept and Content-Type header..

+ */

+typedef struct pjsip_media_type

+{

+    pj_str_t type;	    /**< Media type. */

+    pj_str_t subtype;	    /**< Media subtype. */

+    pj_str_t param;	    /**< Media type parameters (concatenated). */

+} pjsip_media_type;

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @addtogroup PJSIP_MSG_BODY Message Body

+ * @brief SIP message body structures and manipulation.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * Generic abstraction to message body.

+ * When an incoming message is parsed (pjsip_parse_msg()), the parser fills in

+ * all members with the appropriate value. The 'data' and 'len' member will

+ * describe portion of incoming packet which denotes the message body.

+ * When application needs to attach message body to outgoing SIP message, it

+ * must fill in all members of this structure. 

+ */

+typedef struct pjsip_msg_body

+{

+    /** MIME content type. 

+     *  For incoming messages, the parser will fill in this member with the

+     *  content type found in Content-Type header.

+     *

+     *  For outgoing messages, application must fill in this member with

+     *  appropriate value, because the stack will generate Content-Type header

+     *  based on the value specified here.

+     */

+    pjsip_media_type content_type;

+

+    /** Pointer to buffer which holds the message body data. 

+     *  For incoming messages, the parser will fill in this member with the

+     *  pointer to the body string.

+     *

+     *  When sending outgoing message, this member doesn't need to point to the

+     *  actual message body string. It can be assigned with arbitrary pointer,

+     *  because the value will only need to be understood by the print_body()

+     *  function. The stack itself will not try to interpret this value, but

+     *  instead will always call the print_body() whenever it needs to get the

+     *  actual body string.

+     */

+    void *data;

+

+    /** The length of the data. 

+     *  For incoming messages, the parser will fill in this member with the

+     *  actual length of message body.

+     *

+     *  When sending outgoing message, again just like the "data" member, the

+     *  "len" member doesn't need to point to the actual length of the body 

+     *  string.

+     */

+    unsigned len;

+

+    /** Pointer to function to print this message body. 

+     *  Application must set a proper function here when sending outgoing 

+     *  message.

+     *

+     *  @param msg_body	    This structure itself.

+     *  @param buf	    The buffer.

+     *  @param size	    The buffer size.

+     *

+     *  @return		    The length of the string printed, or -1 if there is

+     *			    not enough space in the buffer to print the whole

+     *			    message body.

+     */

+    int (*print_body)(struct pjsip_msg_body *msg_body, 

+		      char *buf, pj_size_t size);

+

+} pjsip_msg_body;

+

+/**

+ * General purpose function to textual data in a SIP body. Attach this function

+ * in a SIP message body only if the data in pjsip_msg_body is a textual 

+ * message ready to be embedded in a SIP message. If the data in the message

+ * body is not a textual body, then application must supply a custom function

+ * to print that body.

+ *

+ * @param msg_body	The message body.

+ * @param buf		Buffer to copy the message body to.

+ * @param size		The size of the buffer.

+ *

+ * @return		The length copied to the buffer, or -1.

+ */

+PJ_DECL(int) pjsip_print_text_body( pjsip_msg_body *msg_body, 

+				    char *buf, pj_size_t size);

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_MSG Message Structure

+ * @brief Message structure and operations.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * Message type (request or response).

+ */

+typedef enum pjsip_msg_type_e

+{

+    PJSIP_REQUEST_MSG,	    /**< Indicates request message. */

+    PJSIP_RESPONSE_MSG,	    /**< Indicates response message. */

+} pjsip_msg_type_e;

+

+

+/**

+ * This structure describes a SIP message.

+ */

+struct pjsip_msg

+{

+    /** Message type (ie request or response). */

+    pjsip_msg_type_e  type;

+

+    /** The first line of the message can be either request line for request

+     *	messages, or status line for response messages. It is represented here

+     *  as a union.

+     */

+    union

+    {

+	/** Request Line. */

+	struct pjsip_request_line   req;

+

+	/** Status Line. */

+	struct pjsip_status_line    status;

+    } line;

+

+    /** List of message headers. */

+    pjsip_hdr hdr;

+

+    /** Pointer to message body, or NULL if no message body is attached to

+     *	this mesage. 

+     */

+    pjsip_msg_body *body;

+};

+

+

+/** 

+ * Create new request or response message.

+ *

+ * @param pool	    The pool.

+ * @param type	    Message type.

+ * @return	    New message, or THROW exception if failed.

+ */

+PJ_DECL(pjsip_msg*)  pjsip_msg_create( pj_pool_t *pool, pjsip_msg_type_e type);

+

+/** 

+ * Find a header in the message by the header type.

+ *

+ * @param msg	    The message.

+ * @param type	    The header type to find.

+ * @param start	    The first header field where the search should begin.

+ *		    If NULL is specified, then the search will begin from the

+ *		    first header, otherwise the search will begin at the

+ *		    specified header.

+ *

+ * @return	    The header field, or NULL if no header with the specified 

+ *		    type is found.

+ */

+PJ_DECL(void*)  pjsip_msg_find_hdr( pjsip_msg *msg, 

+				    pjsip_hdr_e type, void *start);

+

+/** 

+ * Find a header in the message by its name.

+ *

+ * @param msg	    The message.

+ * @param name	    The header name to find.

+ * @param start	    The first header field where the search should begin.

+ *		    If NULL is specified, then the search will begin from the

+ *		    first header, otherwise the search will begin at the

+ *		    specified header.

+ *

+ * @return	    The header field, or NULL if no header with the specified 

+ *		    type is found.

+ */

+PJ_DECL(void*)  pjsip_msg_find_hdr_by_name( pjsip_msg *msg, 

+					    const pj_str_t *name, void *start);

+

+/** 

+ * Find and remove a header in the message. 

+ *

+ * @param msg	    The message.

+ * @param hdr	    The header type to find.

+ * @param start	    The first header field where the search should begin,

+ *		    or NULL to search from the first header in the message.

+ *

+ * @return	    The header field, or NULL if not found.

+ */

+PJ_DECL(void*)  pjsip_msg_find_remove_hdr( pjsip_msg *msg, 

+					   pjsip_hdr_e hdr, void *start);

+

+/** 

+ * Add a header to the message, putting it last in the header list.

+ *

+ * @param msg	    The message.

+ * @param hdr	    The header to add.

+ *

+ * @bug Once the header is put in a list (or message), it can not be put in 

+ *      other list (or message). Otherwise Real Bad Thing will happen.

+ */

+PJ_IDECL(void) pjsip_msg_add_hdr( pjsip_msg *msg, pjsip_hdr *hdr );

+

+/** 

+ * Add header field to the message, putting it in the front of the header list.

+ *

+ * @param msg	The message.

+ * @param hdr	The header to add.

+ *

+ * @bug Once the header is put in a list (or message), it can not be put in 

+ *      other list (or message). Otherwise Real Bad Thing will happen.

+ */

+PJ_IDECL(void) pjsip_msg_insert_first_hdr( pjsip_msg *msg, pjsip_hdr *hdr );

+

+/** 

+ * Print the message to the specified buffer. 

+ *

+ * @param msg	The message to print.

+ * @param buf	The buffer

+ * @param size	The size of the buffer.

+ *

+ * @return	The length of the printed characters (in bytes), or NEGATIVE

+ *		value if the message is too large for the specified buffer.

+ */

+PJ_DECL(pj_ssize_t) pjsip_msg_print(pjsip_msg *msg, char *buf, pj_size_t size);

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @addtogroup PJSIP_MSG_HDR_GEN Header Field: Generic

+ * @brief Generic header field which contains header name and value.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * Generic SIP header, which contains hname and a string hvalue.

+ * Note that this header is not supposed to be used as 'base' class for headers.

+ */

+typedef struct pjsip_generic_string_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_string_hdr); /**< Standard header field. */

+    pj_str_t hvalue;				    /**< hvalue */

+} pjsip_generic_string_hdr;

+

+

+/**

+ * Create a new instance of generic header. A generic header can have an

+ * arbitrary header name.

+ *

+ * @param pool	    The pool.

+ * @param hname	    The header name to be assigned to the header, or NULL to

+ *		    assign the header name with some string.

+ *

+ * @return	    The header, or THROW exception.

+ */

+PJ_DECL(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool, 

+						      const pj_str_t *hname );

+

+/**

+ * Create a generic header along with the text content.

+ *

+ * @param pool	    The pool.

+ * @param hname	    The header name.

+ * @param hvalue    The header text content.

+ *

+ * @return	    The header instance.

+ */

+PJ_DECL(pjsip_generic_string_hdr*) 

+pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,

+					   const pj_str_t *hname,

+					   const pj_str_t *hvalue);

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @addtogroup PJSIP_MSG_HDR_GEN_INT Header Field: Generic Integer

+ * @brief Generic header field which contains header name and value.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * Generic SIP header, which contains hname and a string hvalue.

+ */

+typedef struct pjsip_generic_int_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_int_hdr); /**< Standard header field. */

+    pj_int32_t ivalue;				    /**< ivalue */

+} pjsip_generic_int_hdr;

+

+

+/**

+ * Create a new instance of generic header. A generic header can have an

+ * arbitrary header name.

+ *

+ * @param pool	    The pool.

+ * @param hname	    The header name to be assigned to the header, or NULL to

+ *		    assign the header name with some string.

+ *

+ * @return	    The header, or THROW exception.

+ */

+PJ_DECL(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool, 

+						      const pj_str_t *hname );

+

+/**

+ * Create a generic header along with the value.

+ *

+ * @param pool	    The pool.

+ * @param hname	    The header name.

+ * @param value     The header value content.

+ *

+ * @return	    The header instance.

+ */

+PJ_DECL(pjsip_generic_int_hdr*) 

+pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,

+					 const pj_str_t *hname,

+					 int value);

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_GENERIC_LIST Header Field: Generic string list.

+ * @brief Header with list of strings separated with comma

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/** Maximum elements in the header array. */

+#define PJSIP_GENERIC_ARRAY_MAX_COUNT	32

+

+typedef struct pjsip_generic_array_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_generic_array_hdr);

+    unsigned	count;					/**< Number of elements. */

+    pj_str_t	values[PJSIP_GENERIC_ARRAY_MAX_COUNT];	/**< Elements.		 */

+} pjsip_generic_array_hdr;

+

+/**

+ * Create generic array header.

+ *

+ * @param pool	    Pool to allocate memory from.

+ *

+ * @return	    New generic array header.

+ */

+PJ_DECL(pjsip_generic_array_hdr*) pjsip_generic_array_create(pj_pool_t *pool,

+							     const pj_str_t *hnames);

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_ACCEPT Header Field: Accept

+ * @brief Accept header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/** Accept header. */

+typedef pjsip_generic_array_hdr pjsip_accept_hdr;

+

+/** Maximum fields in Accept header. */

+#define PJSIP_MAX_ACCEPT_COUNT	PJSIP_GENERIC_ARRAY_MAX_COUNT

+

+/**

+ * Create new Accept header instance.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    New Accept header instance.

+ */

+PJ_DECL(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_ALLOW Header Field: Allow

+ * @brief Allow header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+typedef pjsip_generic_array_hdr pjsip_allow_hdr;

+

+/**

+ * Create new Allow header instance.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    New Allow header instance.

+ */

+PJ_DECL(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_CID Header Field: Call-ID

+ * @brief Call-ID header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/**

+ * Call-ID header.

+ */

+typedef struct pjsip_cid_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_cid_hdr);

+    pj_str_t id;	    /**< Call-ID string. */

+} pjsip_cid_hdr;

+

+

+/**

+ * Create new Call-ID header.

+ *

+ * @param pool	The pool.

+ *

+ * @return	new Call-ID header.

+ */

+PJ_DECL(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool );

+

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_CLEN Header Field: Content-Length

+ * @brief Content-Length header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/**

+ * Content-Length header.

+ */

+typedef struct pjsip_clen_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_clen_hdr);

+    int len;	/**< Content length. */

+} pjsip_clen_hdr;

+

+/**

+ * Create new Content-Length header.

+ *

+ * @param pool	the pool.

+ * @return	A new Content-Length header instance.

+ */

+PJ_DECL(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool );

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_CSEQ Header Field: CSeq

+ * @brief CSeq header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/**

+ * CSeq header.

+ */

+typedef struct pjsip_cseq_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_cseq_hdr);

+    int		    cseq;	/**< CSeq number. */

+    pjsip_method    method;	/**< CSeq method. */

+} pjsip_cseq_hdr;

+

+

+/** Create new  CSeq header. 

+ *

+ *  @param pool	The pool.

+ *  @return A new CSeq header instance.

+ */

+PJ_DECL(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool );

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_CONTACT Header Field: Contact

+ * @brief Contact header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/**

+ * Contact header.

+ * In this library, contact header only contains single URI. If a message has

+ * multiple URI in the Contact header, the URI will be put in separate Contact

+ * headers.

+ */

+typedef struct pjsip_contact_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_contact_hdr);

+    int		    star;	    /**< The contact contains only a '*' character */

+    pjsip_uri *uri;	    /**< URI in the contact. */

+    int		    q1000;	    /**< The "q" value times 1000 (to avoid float) */

+    pj_int32_t	    expires;	    /**< Expires parameter, otherwise -1 if not present. */

+    pj_str_t	    other_param;    /**< Other parameters, concatenated in a single string. */

+} pjsip_contact_hdr;

+

+

+/**

+ * Create a new Contact header.

+ *

+ * @param pool	The pool.

+ * @return	A new instance of Contact header.

+ */

+PJ_DECL(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool );

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_CTYPE Header Field: Content-Type

+ * @brief Content-Type header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/**

+ * Content-Type.

+ */

+typedef struct pjsip_ctype_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_ctype_hdr);

+    pjsip_media_type media; /**< Media type. */

+} pjsip_ctype_hdr;

+

+

+/**

+ * Create a nwe Content Type header.

+ *

+ * @param pool	The pool.

+ * @return	A new Content-Type header.

+ */

+PJ_DECL(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool );

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_EXPIRES Header Field: Expires

+ * @brief Expires header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/** Expires header. */

+typedef pjsip_generic_int_hdr pjsip_expires_hdr;

+

+/**

+ * Create a new Expires header.

+ *

+ * @param pool	The pool.

+ * @return	A new Expires header.

+ */

+PJ_DECL(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool );

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_FROMTO Header Field: From/To

+ * @brief From and To header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/**

+ * To or From header.

+ */

+typedef struct pjsip_fromto_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_fromto_hdr);

+    pjsip_uri  *uri;	    /**< URI in From/To header. */

+    pj_str_t	     tag;	    /**< Header "tag" parameter. */

+    pj_str_t	     other_param;   /**< Other params, concatenated as a single string. */

+} pjsip_fromto_hdr;

+

+/** Alias for From header. */

+typedef pjsip_fromto_hdr pjsip_from_hdr;

+

+/** Alias for To header. */

+typedef pjsip_fromto_hdr pjsip_to_hdr;

+

+/**

+ * Create a From header.

+ *

+ * @param pool	The pool.

+ * @return	New instance of From header.

+ */

+PJ_DECL(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool );

+

+/**

+ * Create a To header.

+ *

+ * @param pool	The pool.

+ * @return	New instance of To header.

+ */

+PJ_DECL(pjsip_to_hdr*)   pjsip_to_hdr_create( pj_pool_t *pool );

+

+/**

+ * Convert the header to a From header.

+ *

+ * @param pool	The pool.

+ * @return	"From" header.

+ */

+PJ_DECL(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr );

+

+/**

+ * Convert the header to a To header.

+ *

+ * @param pool	The pool.

+ * @return	"To" header.

+ */

+PJ_DECL(pjsip_to_hdr*)   pjsip_fromto_set_to( pjsip_fromto_hdr *hdr );

+

+/**

+ * @}

+ */

+

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_MAX_FORWARDS Header Field: Max-Forwards

+ * @brief Max-Forwards header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+typedef pjsip_generic_int_hdr pjsip_max_forwards_hdr;

+

+/**

+ * Create new Max-Forwards header instance.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    New Max-Forwards header instance.

+ */

+PJ_DECL(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * @}

+ */

+

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_MIN_EXPIRES Header Field: Min-Expires

+ * @brief Min-Expires header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+typedef pjsip_generic_int_hdr pjsip_min_expires_hdr;

+

+/**

+ * Create new Max-Forwards header instance.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    New Max-Forwards header instance.

+ */

+PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * @}

+ */

+

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_ROUTING Header Field: Record-Route/Route

+ * @brief Record-Route and Route header fields.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/**

+ * Record-Route and Route headers.

+ */

+typedef struct pjsip_routing_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_routing_hdr);  /**< Generic header fields. */

+    pjsip_name_addr  name_addr;	  /**< The URL in the Route/Record-Route header. */

+    pj_str_t	     other_param; /** Other parameter. */

+} pjsip_routing_hdr;

+

+/** Alias for Record-Route header. */

+typedef pjsip_routing_hdr pjsip_rr_hdr;

+

+/** Alias for Route header. */

+typedef pjsip_routing_hdr pjsip_route_hdr;

+

+

+/** 

+ * Create new Record-Route header from the pool. 

+ *

+ * @param pool	The pool.

+ * @return	A new instance of Record-Route header.

+ */

+PJ_DECL(pjsip_rr_hdr*)	    pjsip_rr_hdr_create( pj_pool_t *pool );

+

+/** 

+ * Create new Route header from the pool. 

+ *

+ * @param pool	The pool.

+ * @return	A new instance of "Route" header.

+ */

+PJ_DECL(pjsip_route_hdr*)   pjsip_route_hdr_create( pj_pool_t *pool );

+

+/** 

+ * Convert generic routing header to Record-Route header. 

+ *

+ * @param r	The generic routing header, or a "Routing" header.

+ * @return	Record-Route header.

+ */

+PJ_DECL(pjsip_rr_hdr*)	    pjsip_routing_hdr_set_rr( pjsip_routing_hdr *r );

+

+/** 

+ * Convert generic routing header to "Route" header. 

+ *

+ * @param r	The generic routing header, or a "Record-Route" header.

+ * @return	"Route" header.

+ */

+PJ_DECL(pjsip_route_hdr*)   pjsip_routing_hdr_set_route( pjsip_routing_hdr *r );

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_REQUIRE Header Field: Require

+ * @brief Require header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+typedef pjsip_generic_array_hdr pjsip_require_hdr;

+

+/**

+ * Create new Require header instance.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    New Require header instance.

+ */

+PJ_DECL(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * @}

+ */

+

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_RETRY_AFTER Header Field: Retry-After

+ * @brief Retry-After header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+typedef pjsip_generic_int_hdr pjsip_retry_after_hdr;

+

+/**

+ * Create new Retry-After header instance.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    New Retry-After header instance.

+ */

+PJ_DECL(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_SUPPORTED Header Field: Supported

+ * @brief Supported header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+typedef pjsip_generic_array_hdr pjsip_supported_hdr;

+

+/**

+ * Create new Supported header instance.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    New Supported header instance.

+ */

+PJ_DECL(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * @}

+ */

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_UNSUPPORTED Header Field: Unsupported

+ * @brief Unsupported header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+typedef pjsip_generic_array_hdr pjsip_unsupported_hdr;

+

+/**

+ * Create new Unsupported header instance.

+ *

+ * @param pool	    The pool.

+ *

+ * @return	    New Unsupported header instance.

+ */

+PJ_DECL(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool);

+

+

+/**

+ * @}

+ */

+

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_VIA Header Field: Via

+ * @brief Via header field.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/**

+ * SIP Via header.

+ * In this implementation, Via header can only have one element in each header.

+ * If a message arrives with multiple elements in a single Via, then they will

+ * be split up into multiple Via headers.

+ */

+typedef struct pjsip_via_hdr

+{

+    PJSIP_DECL_HDR_MEMBER(struct pjsip_via_hdr);

+    pj_str_t	     transport;	    /**< Transport type. */

+    pjsip_host_port  sent_by;	    /**< Host and optional port */

+    int		     ttl_param;	    /**< TTL parameter, or -1 if it's not specified. */

+    int		     rport_param;   /**< "rport" parameter, 0 to specify without

+					 port number, -1 means doesn't exist. */

+    pj_str_t	     maddr_param;   /**< "maddr" parameter. */

+    pj_str_t	     recvd_param;   /**< "received" parameter. */

+    pj_str_t	     branch_param;  /**< "branch" parameter. */

+    pj_str_t	     other_param;   /**< Other parameters, concatenated as single string. */

+    pj_str_t	     comment;	    /**< Comment. */

+} pjsip_via_hdr;

+

+/**

+ * Create a new Via header.

+ *

+ * @param pool	    The pool.

+ * @return	    A new "Via" header instance.

+ */

+PJ_DECL(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool );

+

+/**

+ * @}

+ */

+

+/**

+ * @bug Once a header is put in the message, the header CAN NOT be put in

+ *      other list. Solution:

+ *	- always clone header in the message.

+ *	- create a list node for each header in the message.

+ */

+

+

+///////////////////////////////////////////////////////////////////////////////

+/**

+ * @defgroup PJSIP_MSG_HDR_UNIMP Unimplemented Header Fields

+ * @brief Unimplemented header fields.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+/** Accept-Encoding header. */

+typedef pjsip_generic_string_hdr pjsip_accept_encoding_hdr;

+

+/** Create Accept-Encoding header. */

+#define pjsip_accept_encoding_hdr_create pjsip_generic_string_hdr_create

+

+/** Accept-Language header. */

+typedef pjsip_generic_string_hdr pjsip_accept_lang_hdr;

+

+/** Create Accept-Language header. */

+#define pjsip_accept_lang_hdr_create pjsip_generic_string_hdr_create

+

+/** Alert-Info header. */

+typedef pjsip_generic_string_hdr pjsip_alert_info_hdr;

+

+/** Create Alert-Info header. */

+#define pjsip_alert_info_hdr_create pjsip_generic_string_hdr_create

+

+/** Authentication-Info header. */

+typedef pjsip_generic_string_hdr pjsip_auth_info_hdr;

+

+/** Create Authentication-Info header. */

+#define pjsip_auth_info_hdr_create pjsip_generic_string_hdr_create

+

+/** Call-Info header. */

+typedef pjsip_generic_string_hdr pjsip_call_info_hdr;

+

+/** Create Call-Info header. */

+#define pjsip_call_info_hdr_create pjsip_generic_string_hdr_create

+

+/** Content-Disposition header. */

+typedef pjsip_generic_string_hdr pjsip_content_disposition_hdr;

+

+/** Create Content-Disposition header. */

+#define pjsip_content_disposition_hdr_create pjsip_generic_string_hdr_create

+

+/** Content-Encoding header. */

+typedef pjsip_generic_string_hdr pjsip_content_encoding_hdr;

+

+/** Create Content-Encoding header. */

+#define pjsip_content_encoding_hdr_create pjsip_generic_string_hdr_create

+

+/** Content-Language header. */

+typedef pjsip_generic_string_hdr pjsip_content_lang_hdr;

+

+/** Create Content-Language header. */

+#define pjsip_content_lang_hdr_create pjsip_generic_string_hdr_create

+

+/** Date header. */

+typedef pjsip_generic_string_hdr pjsip_date_hdr;

+

+/** Create Date header. */

+#define pjsip_date_hdr_create pjsip_generic_string_hdr_create

+

+/** Error-Info header. */

+typedef pjsip_generic_string_hdr pjsip_err_info_hdr;

+

+/** Create Error-Info header. */

+#define pjsip_err_info_hdr_create pjsip_generic_string_hdr_create

+

+/** In-Reply-To header. */

+typedef pjsip_generic_string_hdr pjsip_in_reply_to_hdr;

+

+/** Create In-Reply-To header. */

+#define pjsip_in_reply_to_hdr_create pjsip_generic_string_hdr_create

+

+/** MIME-Version header. */

+typedef pjsip_generic_string_hdr pjsip_mime_version_hdr;

+

+/** Create MIME-Version header. */

+#define pjsip_mime_version_hdr_create pjsip_generic_string_hdr_create

+

+/** Organization header. */

+typedef pjsip_generic_string_hdr pjsip_organization_hdr;

+

+/** Create Organization header. */

+#define pjsip_organization_hdr_create pjsip_genric_string_hdr_create

+

+/** Priority header. */

+typedef pjsip_generic_string_hdr pjsip_priority_hdr;

+

+/** Create Priority header. */

+#define pjsip_priority_hdr_create pjsip_generic_string_hdr_create

+

+/** Proxy-Require header. */

+typedef pjsip_generic_string_hdr pjsip_proxy_require_hdr;

+

+/** Reply-To header. */

+typedef pjsip_generic_string_hdr pjsip_reply_to_hdr;

+

+/** Create Reply-To header. */

+#define pjsip_reply_to_hdr_create pjsip_generic_string_hdr_create

+

+/** Server header. */

+typedef pjsip_generic_string_hdr pjsip_server_hdr;

+

+/** Create Server header. */

+#define pjsip_server_hdr_create pjsip_generic_string_hdr_create

+

+/** Subject header. */

+typedef pjsip_generic_string_hdr pjsip_subject_hdr;

+

+/** Create Subject header. */

+#define pjsip_subject_hdr_create pjsip_generic_string_hdr_create

+

+/** Timestamp header. */

+typedef pjsip_generic_string_hdr pjsip_timestamp_hdr;

+

+/** Create Timestamp header. */

+#define pjsip_timestamp_hdr_create pjsip_generic_string_hdr_create

+

+/** User-Agent header. */

+typedef pjsip_generic_string_hdr pjsip_user_agent_hdr;

+

+/** Create User-Agent header. */

+#define pjsip_user_agent_hdr_create pjsip_generic_string_hdr_create

+

+/** Warning header. */

+typedef pjsip_generic_string_hdr pjsip_warning_hdr;

+

+/** Create Warning header. */

+#define pjsip_warning_hdr_create pjsip_generic_string_hdr_create

+

+/**

+ * @}

+ */

+

+/**

+ * @}  // PJSIP_MSG

+ */

+

+/*

+ * Include inline definitions.

+ */

+#if PJ_FUNCTIONS_ARE_INLINED

+#  include <pjsip/sip_msg_i.h>

+#endif

+

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_SIP_MSG_H__ */

+

diff --git a/pjsip/include/pjsip/sip_msg_i.h b/pjsip/include/pjsip/sip_msg_i.h
index 7aa5095..11a584f 100644
--- a/pjsip/include/pjsip/sip_msg_i.h
+++ b/pjsip/include/pjsip/sip_msg_i.h
@@ -1,14 +1,36 @@
-/* $Id$
- *
- */
-
-PJ_IDEF(void) pjsip_msg_add_hdr( pjsip_msg *msg, pjsip_hdr *hdr )
-{
-    pj_list_insert_before(&msg->hdr, hdr);
-}
-
-PJ_IDEF(void) pjsip_msg_insert_first_hdr( pjsip_msg *msg, pjsip_hdr *hdr )
-{
-    pj_list_insert_after(&msg->hdr, hdr);
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+

+PJ_IDEF(void) pjsip_msg_add_hdr( pjsip_msg *msg, pjsip_hdr *hdr )

+{

+    pj_list_insert_before(&msg->hdr, hdr);

+}

+

+PJ_IDEF(void) pjsip_msg_insert_first_hdr( pjsip_msg *msg, pjsip_hdr *hdr )

+{

+    pj_list_insert_after(&msg->hdr, hdr);

+}

+

diff --git a/pjsip/include/pjsip/sip_parser.h b/pjsip/include/pjsip/sip_parser.h
index 5ae2f80..fd5ae37 100644
--- a/pjsip/include/pjsip/sip_parser.h
+++ b/pjsip/include/pjsip/sip_parser.h
@@ -1,62 +1,84 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_PARSER_H__
-#define __PJSIP_SIP_PARSER_H__
-
-/**
- * @file sip_parser.h
- * @brief SIP Message Parser
- */
-
-#include <pjsip/sip_types.h>
-#include <pjlib-util/scanner.h>
-#include <pj/list.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_PARSER SIP Message Parser
- * @ingroup PJSIP
- * @{
- */
-
-/**
- * URI Parsing options.
- */
-enum
-{
-    /** If this option is specified, function #pjsip_parse_uri will return
-     *  the URI object as pjsip_name_addr instead of the corresponding
-     *  URI object.
-     */
-    PJSIP_PARSE_URI_AS_NAMEADDR = 1,
-
-    /** If this option is specified, function #pjsip_parse_uri and other
-     *  internal functions that this function calls will parse URI according
-     *  to convention for parsing From/To header. For example, when the URI
-     *  is not enclosed in brackets ("<" and ">"), all parameters will not
-     *  be stored to the URI (it will be stored to the header).
-     */
-    PJSIP_PARSE_URI_IN_FROM_TO_HDR = 2,
-};
-
-/**
- * Parser syntax error exception value.
- */
-#define PJSIP_SYN_ERR_EXCEPTION	1
-
-/**
- * This structure is used to get error reporting from parser.
- */
-typedef struct pjsip_parser_err_report
-{
-    PJ_DECL_LIST_MEMBER(struct pjsip_parser_err_report);
-    int		exception_code;	/**< Error exception (e.g. PJSIP_SYN_ERR_EXCEPTION) */
-    int		line;		/**< Line number. */
-    int		col;		/**< Column number. */
-    pj_str_t	hname;		/**< Header name, if any. */
-} pjsip_parser_err_report;
-
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_PARSER_H__

+#define __PJSIP_SIP_PARSER_H__

+

+/**

+ * @file sip_parser.h

+ * @brief SIP Message Parser

+ */

+

+#include <pjsip/sip_types.h>

+#include <pjlib-util/scanner.h>

+#include <pj/list.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_PARSER SIP Message Parser

+ * @ingroup PJSIP

+ * @{

+ */

+

+/**

+ * URI Parsing options.

+ */

+enum

+{

+    /** If this option is specified, function #pjsip_parse_uri will return

+     *  the URI object as pjsip_name_addr instead of the corresponding

+     *  URI object.

+     */

+    PJSIP_PARSE_URI_AS_NAMEADDR = 1,

+

+    /** If this option is specified, function #pjsip_parse_uri and other

+     *  internal functions that this function calls will parse URI according

+     *  to convention for parsing From/To header. For example, when the URI

+     *  is not enclosed in brackets ("<" and ">"), all parameters will not

+     *  be stored to the URI (it will be stored to the header).

+     */

+    PJSIP_PARSE_URI_IN_FROM_TO_HDR = 2,

+};

+

+/**

+ * Parser syntax error exception value.

+ */

+#define PJSIP_SYN_ERR_EXCEPTION	1

+

+/**

+ * This structure is used to get error reporting from parser.

+ */

+typedef struct pjsip_parser_err_report

+{

+    PJ_DECL_LIST_MEMBER(struct pjsip_parser_err_report);

+    int		exception_code;	/**< Error exception (e.g. PJSIP_SYN_ERR_EXCEPTION) */

+    int		line;		/**< Line number. */

+    int		col;		/**< Column number. */

+    pj_str_t	hname;		/**< Header name, if any. */

+} pjsip_parser_err_report;

+

 

 /**

  * Parsing context, the default argument for parsing functions.

@@ -68,130 +90,130 @@
     pjsip_rx_data   *rdata;     /**< Optional rdata.    */

 } pjsip_parse_ctx;

 

-
-/**
- * Type of function to parse header. The parsing function must follow these
- * specification:
- *   - It must not modify the input text.
- *   - The hname and HCOLON has been parsed prior to invoking the handler.
- *   - It returns the header instance on success.
- *   - For error reporting, it must throw PJSIP_SYN_ERR_EXCEPTION exception 
- *     instead of just returning NULL. 
- *     When exception is thrown, the return value is ignored.
- *   - It must read the header separator after finished reading the header
- *     body. The separator types are described below, and if they don't exist,
- *     exception must be thrown. Header separator can be a:
- *	- newline, such as when the header is part of a SIP message.
- *	- ampersand, such as when the header is part of an URI.
- *	- for the last header, these separator is optional since parsing
- *        can be terminated when seeing EOF.
- */
-typedef pjsip_hdr* (pjsip_parse_hdr_func)(pjsip_parse_ctx *context);
-
-/**
- * Type of function to parse URI scheme.
- * Most of the specification of header parser handler (pjsip_parse_hdr_func)
- * also applies here (except the separator part).
- */
-typedef void* (pjsip_parse_uri_func)(pj_scanner *scanner, pj_pool_t *pool);
-
-/**
- * Register header parser handler. The parser handler MUST follow the 
- * specification of header parser handler function. New registration 
- * overwrites previous registration with the same name.
- *
- * @param hname		The header name.
- * @param hshortname	The short header name or NULL.
- * @param fptr		The pointer to function to parser the header.
- *
- * @return		PJ_SUCCESS if success, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_register_hdr_parser( const char *hname,
-						const char *hshortname,
-						pjsip_parse_hdr_func *fptr);
-
-/**
- * Unregister previously registered header parser handler.
- * All the arguments MUST exactly equal to the value specified upon 
- * registration of the handler.
- *
- * @param hname		The header name registered.
- * @param hshortname	The short header name registered, or NULL.
- *
- * @return		zero if unregistration was successfull.
- */
-PJ_DECL(pj_status_t) pjsip_unregister_hdr_parser( const char *hname,
-						  const char *hshortname,
-						  pjsip_parse_hdr_func *fptr);
-
-/**
- * Register URI scheme parser handler.
- *
- * @param scheme	The URI scheme registered.
- * @param func		The URI parser function.
- *
- * @return		zero on success.
- */
-PJ_DECL(pj_status_t) pjsip_register_uri_parser( const char *scheme,
-					        pjsip_parse_uri_func *func);
-
-/**
- * Unregister URI scheme parser handler.
- * All the arguments MUST exactly equal to the value specified upon 
- * registration of the handler.
- *
- * @param scheme	The URI scheme as registered previously.
- * @param func		The function handler as registered previously.
- *
- * @return		zero if the registration was successfull.
- */
-PJ_DECL(pj_status_t) pjsip_unregister_uri_parser( const char *scheme,
-						  pjsip_parse_uri_func *func);
-
-/**
- * Parse an URI in the input and return the correct instance of URI.
- *
- * @param pool		The pool to get memory allocations.
- * @param buf		The input buffer, which size must be at least (size+1)
- *			because the function will temporarily put NULL 
- *			termination at the end of the buffer during parsing.
- * @param size		The length of the string (not counting NULL terminator).
- * @param options	If no options are given (value is zero), the object 
- *			returned is dependent on the syntax of the URI, 
- *			eg. basic SIP URL, TEL URL, or name address. 
- *			If option PJSIP_PARSE_URI_AS_NAMEADDR is given,
- *			then the returned object is always name address object,
- *			with the relevant URI object contained in the name 
- *			address object.
- * @return		The URI or NULL when failed. No exception is thrown by 
- *			this function (or any public parser functions).
- */
-PJ_DECL(pjsip_uri*) pjsip_parse_uri( pj_pool_t *pool, 
-				     char *buf, pj_size_t size,
-				     unsigned option);
-
-/**
- * Parse a packet buffer and build a full SIP message from the packet. This
- * function parses all parts of the message, including request/status line,
- * all headers, and the message body. The message body however is only 
- * treated as a text block, ie. the function will not try to parse the content
- * of the body.
- *
- * @param pool		The pool to allocate memory.
- * @param buf		The input buffer, which size must be at least (size+1)
- *			because the function will temporarily put NULL 
- *			termination at the end of the buffer during parsing.
- * @param size		The length of the string (not counting NULL terminator).
- * @param err_list	If this parameter is not NULL, then the parser will
- *			put error messages during parsing in this list.
- *
- * @return		The message or NULL when failed. No exception is thrown
- *			by this function (or any public parser functions).
- */
-PJ_DECL(pjsip_msg *) pjsip_parse_msg( pj_pool_t *pool, 
-				      char *buf, pj_size_t size,
-				      pjsip_parser_err_report *err_list);
-
+

+/**

+ * Type of function to parse header. The parsing function must follow these

+ * specification:

+ *   - It must not modify the input text.

+ *   - The hname and HCOLON has been parsed prior to invoking the handler.

+ *   - It returns the header instance on success.

+ *   - For error reporting, it must throw PJSIP_SYN_ERR_EXCEPTION exception 

+ *     instead of just returning NULL. 

+ *     When exception is thrown, the return value is ignored.

+ *   - It must read the header separator after finished reading the header

+ *     body. The separator types are described below, and if they don't exist,

+ *     exception must be thrown. Header separator can be a:

+ *	- newline, such as when the header is part of a SIP message.

+ *	- ampersand, such as when the header is part of an URI.

+ *	- for the last header, these separator is optional since parsing

+ *        can be terminated when seeing EOF.

+ */

+typedef pjsip_hdr* (pjsip_parse_hdr_func)(pjsip_parse_ctx *context);

+

+/**

+ * Type of function to parse URI scheme.

+ * Most of the specification of header parser handler (pjsip_parse_hdr_func)

+ * also applies here (except the separator part).

+ */

+typedef void* (pjsip_parse_uri_func)(pj_scanner *scanner, pj_pool_t *pool);

+

+/**

+ * Register header parser handler. The parser handler MUST follow the 

+ * specification of header parser handler function. New registration 

+ * overwrites previous registration with the same name.

+ *

+ * @param hname		The header name.

+ * @param hshortname	The short header name or NULL.

+ * @param fptr		The pointer to function to parser the header.

+ *

+ * @return		PJ_SUCCESS if success, or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pjsip_register_hdr_parser( const char *hname,

+						const char *hshortname,

+						pjsip_parse_hdr_func *fptr);

+

+/**

+ * Unregister previously registered header parser handler.

+ * All the arguments MUST exactly equal to the value specified upon 

+ * registration of the handler.

+ *

+ * @param hname		The header name registered.

+ * @param hshortname	The short header name registered, or NULL.

+ *

+ * @return		zero if unregistration was successfull.

+ */

+PJ_DECL(pj_status_t) pjsip_unregister_hdr_parser( const char *hname,

+						  const char *hshortname,

+						  pjsip_parse_hdr_func *fptr);

+

+/**

+ * Register URI scheme parser handler.

+ *

+ * @param scheme	The URI scheme registered.

+ * @param func		The URI parser function.

+ *

+ * @return		zero on success.

+ */

+PJ_DECL(pj_status_t) pjsip_register_uri_parser( const char *scheme,

+					        pjsip_parse_uri_func *func);

+

+/**

+ * Unregister URI scheme parser handler.

+ * All the arguments MUST exactly equal to the value specified upon 

+ * registration of the handler.

+ *

+ * @param scheme	The URI scheme as registered previously.

+ * @param func		The function handler as registered previously.

+ *

+ * @return		zero if the registration was successfull.

+ */

+PJ_DECL(pj_status_t) pjsip_unregister_uri_parser( const char *scheme,

+						  pjsip_parse_uri_func *func);

+

+/**

+ * Parse an URI in the input and return the correct instance of URI.

+ *

+ * @param pool		The pool to get memory allocations.

+ * @param buf		The input buffer, which size must be at least (size+1)

+ *			because the function will temporarily put NULL 

+ *			termination at the end of the buffer during parsing.

+ * @param size		The length of the string (not counting NULL terminator).

+ * @param options	If no options are given (value is zero), the object 

+ *			returned is dependent on the syntax of the URI, 

+ *			eg. basic SIP URL, TEL URL, or name address. 

+ *			If option PJSIP_PARSE_URI_AS_NAMEADDR is given,

+ *			then the returned object is always name address object,

+ *			with the relevant URI object contained in the name 

+ *			address object.

+ * @return		The URI or NULL when failed. No exception is thrown by 

+ *			this function (or any public parser functions).

+ */

+PJ_DECL(pjsip_uri*) pjsip_parse_uri( pj_pool_t *pool, 

+				     char *buf, pj_size_t size,

+				     unsigned option);

+

+/**

+ * Parse a packet buffer and build a full SIP message from the packet. This

+ * function parses all parts of the message, including request/status line,

+ * all headers, and the message body. The message body however is only 

+ * treated as a text block, ie. the function will not try to parse the content

+ * of the body.

+ *

+ * @param pool		The pool to allocate memory.

+ * @param buf		The input buffer, which size must be at least (size+1)

+ *			because the function will temporarily put NULL 

+ *			termination at the end of the buffer during parsing.

+ * @param size		The length of the string (not counting NULL terminator).

+ * @param err_list	If this parameter is not NULL, then the parser will

+ *			put error messages during parsing in this list.

+ *

+ * @return		The message or NULL when failed. No exception is thrown

+ *			by this function (or any public parser functions).

+ */

+PJ_DECL(pjsip_msg *) pjsip_parse_msg( pj_pool_t *pool, 

+				      char *buf, pj_size_t size,

+				      pjsip_parser_err_report *err_list);

+

 

 /**

  * Parse a packet buffer and build a rdata. The resulting message will be

@@ -213,123 +235,123 @@
  */

 PJ_DECL(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size,

                                         pjsip_rx_data *rdata );

-
-/**
- * Check incoming packet to see if a (probably) valid SIP message has been 
- * received.
- *
- * @param buf		The input buffer, which must be NULL terminated.
- * @param size		The buffer size.
- * @param msg_size	[out] If message is valid, this parameter will contain
- *			the size of the SIP message (including body, if any).
- *
- * @return		PJ_SUCCESS if a message is found, or an error code.
- */
+

+/**

+ * Check incoming packet to see if a (probably) valid SIP message has been 

+ * received.

+ *

+ * @param buf		The input buffer, which must be NULL terminated.

+ * @param size		The buffer size.

+ * @param msg_size	[out] If message is valid, this parameter will contain

+ *			the size of the SIP message (including body, if any).

+ *

+ * @return		PJ_SUCCESS if a message is found, or an error code.

+ */

 PJ_DECL(pj_status_t) pjsip_find_msg(const char *buf, 

-                                    pj_size_t size, 
+                                    pj_size_t size, 

 				    pj_bool_t is_datagram, 

-                                    pj_size_t *msg_size);
-
-/**
- * Parse the content of a header and return the header instance.
- * This function parses the content of a header (ie. part after colon) according
- * to the expected name, and will return the correct instance of header.
- *
- * @param pool		Pool to allocate memory for the header.
- * @param hname		Header name which is used to find the correct function
- *			to parse the header.
- * @param line		Header content, which size must be at least size+1.
- * @param size		The length of the string (not counting NULL terminator,
- *			if any).
- * @param parsed_len	If the value is not NULL, then upon return the function
- *			will fill the pointer with the length of the string
- *			that has been parsed. This is usefull for two purposes,
- *			one is when the string may contain more than one header
- *			lines, and two when an error happen the value can
- *			pinpoint the location of the error in the buffer.
- *
- * @return		The instance of the header if parsing was successfull,
- *			or otherwise a NULL pointer will be returned.
- */
-PJ_DECL(void*) pjsip_parse_hdr( pj_pool_t *pool, const pj_str_t *hname,
-				char *line, pj_size_t size,
-				int *parsed_len);
-
-/**
- * Parse header line(s). Multiple headers can be parsed by this function.
- * When there are multiple headers, the headers MUST be separated by either
- * a newline (as in SIP message) or ampersand mark (as in URI). This separator
- * however is optional for the last header.
- *
- * @param pool the pool.
- * @param buf the input text to parse.
- * @param size the text length.
- * @param hlist the header list to store the parsed headers. This list must
- *              have been initialized before calling this function.
- * @return zero if successfull, or -1 if error is encountered. Upon error,
- *              the \a hlist argument MAY contain successfully parsed headers.
- */
-PJ_DECL(pj_status_t) pjsip_parse_headers( pj_pool_t *pool,
-					  char *input, pj_size_t size,
-					  pj_list *hlist );
-
-
-/*
- * Various specification used in parsing, exported here as extern for other
- * parsers.
- */
-extern
-pj_cis_t	pjsip_HOST_SPEC,	    /* For scanning host part. */
-		pjsip_DIGIT_SPEC,	    /* Decimal digits */
-		pjsip_ALPHA_SPEC,	    /* Alpha (A-Z, a-z) */
-		pjsip_ALNUM_SPEC,	    /* Decimal + Alpha. */
-		pjsip_TOKEN_SPEC,	    /* Token. */
-		pjsip_HEX_SPEC,		    /* Hexadecimal digits. */
-		pjsip_PARAM_CHAR_SPEC,	    /* For scanning pname (or pvalue when it's not quoted.) */
-		pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */
-		pjsip_PASSWD_SPEC,	    /* Password. */
-		pjsip_USER_SPEC,	    /* User */
-		pjsip_NEWLINE_OR_EOF_SPEC,  /* For eating up header.*/
-		pjsip_DISPLAY_SCAN_SPEC;    /* Used when searching for display name in URL. */
-
-/*
- * Various string constants.
- */
-extern const pj_str_t pjsip_USER_STR,
-		      pjsip_METHOD_STR,
-		      pjsip_TRANSPORT_STR,
-		      pjsip_MADDR_STR,
-		      pjsip_LR_STR,
-		      pjsip_SIP_STR,
-		      pjsip_SIPS_STR,
-		      pjsip_TEL_STR,
-		      pjsip_BRANCH_STR,
-		      pjsip_TTL_STR,
-		      pjsip_PNAME_STR,
-		      pjsip_Q_STR,
-		      pjsip_EXPIRES_STR,
-		      pjsip_TAG_STR;
-
-/*
- * Parser utilities.
- */
-enum
-{
-    PJSIP_PARSE_REMOVE_QUOTE = 1,
-};
-
-void pjsip_parse_param_imp(  pj_scanner *scanner,
-			     pj_str_t *pname, pj_str_t *pvalue,
-			     unsigned opt);
-void pjsip_concat_param_imp( pj_str_t *param, pj_pool_t *pool, 
-			 const pj_str_t *pname, const pj_str_t *pvalue, int sepchar);
-void pjsip_parse_end_hdr_imp ( pj_scanner *scanner );
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_SIP_PARSER_H__ */
-
+                                    pj_size_t *msg_size);

+

+/**

+ * Parse the content of a header and return the header instance.

+ * This function parses the content of a header (ie. part after colon) according

+ * to the expected name, and will return the correct instance of header.

+ *

+ * @param pool		Pool to allocate memory for the header.

+ * @param hname		Header name which is used to find the correct function

+ *			to parse the header.

+ * @param line		Header content, which size must be at least size+1.

+ * @param size		The length of the string (not counting NULL terminator,

+ *			if any).

+ * @param parsed_len	If the value is not NULL, then upon return the function

+ *			will fill the pointer with the length of the string

+ *			that has been parsed. This is usefull for two purposes,

+ *			one is when the string may contain more than one header

+ *			lines, and two when an error happen the value can

+ *			pinpoint the location of the error in the buffer.

+ *

+ * @return		The instance of the header if parsing was successfull,

+ *			or otherwise a NULL pointer will be returned.

+ */

+PJ_DECL(void*) pjsip_parse_hdr( pj_pool_t *pool, const pj_str_t *hname,

+				char *line, pj_size_t size,

+				int *parsed_len);

+

+/**

+ * Parse header line(s). Multiple headers can be parsed by this function.

+ * When there are multiple headers, the headers MUST be separated by either

+ * a newline (as in SIP message) or ampersand mark (as in URI). This separator

+ * however is optional for the last header.

+ *

+ * @param pool the pool.

+ * @param buf the input text to parse.

+ * @param size the text length.

+ * @param hlist the header list to store the parsed headers. This list must

+ *              have been initialized before calling this function.

+ * @return zero if successfull, or -1 if error is encountered. Upon error,

+ *              the \a hlist argument MAY contain successfully parsed headers.

+ */

+PJ_DECL(pj_status_t) pjsip_parse_headers( pj_pool_t *pool,

+					  char *input, pj_size_t size,

+					  pj_list *hlist );

+

+

+/*

+ * Various specification used in parsing, exported here as extern for other

+ * parsers.

+ */

+extern

+pj_cis_t	pjsip_HOST_SPEC,	    /* For scanning host part. */

+		pjsip_DIGIT_SPEC,	    /* Decimal digits */

+		pjsip_ALPHA_SPEC,	    /* Alpha (A-Z, a-z) */

+		pjsip_ALNUM_SPEC,	    /* Decimal + Alpha. */

+		pjsip_TOKEN_SPEC,	    /* Token. */

+		pjsip_HEX_SPEC,		    /* Hexadecimal digits. */

+		pjsip_PARAM_CHAR_SPEC,	    /* For scanning pname (or pvalue when it's not quoted.) */

+		pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */

+		pjsip_PASSWD_SPEC,	    /* Password. */

+		pjsip_USER_SPEC,	    /* User */

+		pjsip_NEWLINE_OR_EOF_SPEC,  /* For eating up header.*/

+		pjsip_DISPLAY_SCAN_SPEC;    /* Used when searching for display name in URL. */

+

+/*

+ * Various string constants.

+ */

+extern const pj_str_t pjsip_USER_STR,

+		      pjsip_METHOD_STR,

+		      pjsip_TRANSPORT_STR,

+		      pjsip_MADDR_STR,

+		      pjsip_LR_STR,

+		      pjsip_SIP_STR,

+		      pjsip_SIPS_STR,

+		      pjsip_TEL_STR,

+		      pjsip_BRANCH_STR,

+		      pjsip_TTL_STR,

+		      pjsip_PNAME_STR,

+		      pjsip_Q_STR,

+		      pjsip_EXPIRES_STR,

+		      pjsip_TAG_STR;

+

+/*

+ * Parser utilities.

+ */

+enum

+{

+    PJSIP_PARSE_REMOVE_QUOTE = 1,

+};

+

+void pjsip_parse_param_imp(  pj_scanner *scanner,

+			     pj_str_t *pname, pj_str_t *pvalue,

+			     unsigned opt);

+void pjsip_concat_param_imp( pj_str_t *param, pj_pool_t *pool, 

+			 const pj_str_t *pname, const pj_str_t *pvalue, int sepchar);

+void pjsip_parse_end_hdr_imp ( pj_scanner *scanner );

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_SIP_PARSER_H__ */

+

diff --git a/pjsip/include/pjsip/sip_private.h b/pjsip/include/pjsip/sip_private.h
index b266135..813b76b 100644
--- a/pjsip/include/pjsip/sip_private.h
+++ b/pjsip/include/pjsip/sip_private.h
@@ -1,85 +1,107 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_PRIVATE_H__
-#define __PJSIP_SIP_PRIVATE_H__
-
-/**
- * @file sip_private.h
- * @brief Private structures and functions for PJSIP Library.
- */ 
-
-#include <pjsip/sip_types.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_PRIVATE Private structures and functions (PJSIP internals)
- * @ingroup PJSIP
- * @{
- */
-
-
-/** 
- * Create a new transport manager.
- * @param pool The pool
- * @param endpt The endpoint
- * @param cb Callback to be called to receive messages from transport.
- */
-PJ_DECL(pj_status_t) pjsip_transport_mgr_create( pj_pool_t *pool,
-						 pjsip_endpoint *endpt,
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_PRIVATE_H__

+#define __PJSIP_SIP_PRIVATE_H__

+

+/**

+ * @file sip_private.h

+ * @brief Private structures and functions for PJSIP Library.

+ */ 

+

+#include <pjsip/sip_types.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_PRIVATE Private structures and functions (PJSIP internals)

+ * @ingroup PJSIP

+ * @{

+ */

+

+

+/** 

+ * Create a new transport manager.

+ * @param pool The pool

+ * @param endpt The endpoint

+ * @param cb Callback to be called to receive messages from transport.

+ */

+PJ_DECL(pj_status_t) pjsip_transport_mgr_create( pj_pool_t *pool,

+						 pjsip_endpoint *endpt,

 						 void (*cb)(pjsip_endpoint *,

 							    pjsip_rx_data *),

-						 pjsip_transport_mgr **);
-
-
-/**
- * Destroy transport manager and release all transports.
- * @param mgr Transport manager to be destroyed.
- */
-PJ_DECL(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr );
-
-/**
- * Poll for transport events.
- * Incoming messages will be parsed by the transport manager, and the callback
- * will be called for each of this message.
- * @param endpt The endpoint.
- * @param timeout Timeout value, or NULL to wait forever.
- */
-PJ_DECL(int) pjsip_transport_mgr_handle_events( pjsip_transport_mgr *mgr,
-					        const pj_time_val *timeout );
-
-/**
- * Get the pointer to the first transport iterator.
- * @param mgr The transport manager.
- * @param it  The iterator used for iterating the hash element.
- * @return the iterator to the first transport, or NULL.
- */
-PJ_DECL(pj_hash_iterator_t*) pjsip_transport_first( pjsip_transport_mgr *mgr,
-						    pj_hash_iterator_t *it );
-
-
-/**
- * Get the next transport iterator.
- * @param itr the iterator to the transport.
- * @return the iterator pointed to the next transport, or NULL.
- */
-PJ_DECL(pj_hash_iterator_t*) pjsip_transport_next( pjsip_transport_mgr *mgr,
-						   pj_hash_iterator_t *itr );
-
-/**
- * Get the value of transport iterator.
- * @param mgr the transport manager.
- * @param itr the transport iterator.
- * @return the transport associated with the iterator.
- */
-PJ_DECL(pjsip_transport_t*) pjsip_transport_this( pjsip_transport_mgr *mgr,
-						  pj_hash_iterator_t *itr );
-
-/** 
- * @}
- */
-
-PJ_END_DECL
-
-#endif /* __PJSIP_PRIVATE_I_H__ */
-
+						 pjsip_transport_mgr **);

+

+

+/**

+ * Destroy transport manager and release all transports.

+ * @param mgr Transport manager to be destroyed.

+ */

+PJ_DECL(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr );

+

+/**

+ * Poll for transport events.

+ * Incoming messages will be parsed by the transport manager, and the callback

+ * will be called for each of this message.

+ * @param endpt The endpoint.

+ * @param timeout Timeout value, or NULL to wait forever.

+ */

+PJ_DECL(int) pjsip_transport_mgr_handle_events( pjsip_transport_mgr *mgr,

+					        const pj_time_val *timeout );

+

+/**

+ * Get the pointer to the first transport iterator.

+ * @param mgr The transport manager.

+ * @param it  The iterator used for iterating the hash element.

+ * @return the iterator to the first transport, or NULL.

+ */

+PJ_DECL(pj_hash_iterator_t*) pjsip_transport_first( pjsip_transport_mgr *mgr,

+						    pj_hash_iterator_t *it );

+

+

+/**

+ * Get the next transport iterator.

+ * @param itr the iterator to the transport.

+ * @return the iterator pointed to the next transport, or NULL.

+ */

+PJ_DECL(pj_hash_iterator_t*) pjsip_transport_next( pjsip_transport_mgr *mgr,

+						   pj_hash_iterator_t *itr );

+

+/**

+ * Get the value of transport iterator.

+ * @param mgr the transport manager.

+ * @param itr the transport iterator.

+ * @return the transport associated with the iterator.

+ */

+PJ_DECL(pjsip_transport_t*) pjsip_transport_this( pjsip_transport_mgr *mgr,

+						  pj_hash_iterator_t *itr );

+

+/** 

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif /* __PJSIP_PRIVATE_I_H__ */

+

diff --git a/pjsip/include/pjsip/sip_resolve.h b/pjsip/include/pjsip/sip_resolve.h
index 5464db9..15e09bb 100644
--- a/pjsip/include/pjsip/sip_resolve.h
+++ b/pjsip/include/pjsip/sip_resolve.h
@@ -1,104 +1,126 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_RESOLVE_H__
-#define __PJSIP_SIP_RESOLVE_H__
-
-/**
- * @file sip_resolve.h
- * @brief 
- * This module contains the mechanism to resolve server address as specified by
- * RFC 3263 - Locating SIP Servers
- */
-
-#include <pjsip/sip_types.h>
-#include <pj/sock.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_RESOLVE SIP Server Resolver
- * @ingroup PJSIP
- * @{
- */
-
-/** 
- * Maximum number of addresses returned by the resolver. 
- */
-#define PJSIP_MAX_RESOLVED_ADDRESSES	8
-
-typedef struct pjsip_server_addresses pjsip_server_addresses;
-
-/**
- * The server addresses returned by the resolver.
- */
-struct pjsip_server_addresses
-{
-    /** Number of address records. */
-    unsigned	count;
-
-    /** Address records. */
-    struct
-    {
-	/** Preferable transport to be used to contact this address. */
-	pjsip_transport_type_e	type;
-
-	/** The server's address. */
-	pj_sockaddr_in		addr;
-
-    } entry[PJSIP_MAX_RESOLVED_ADDRESSES];
-
-};
-
-/**
- * The type of callback function to be called when resolver finishes the job.
- *
- * @param status    The status of the operation, which is zero on success.
- * @param token	    The token that was associated with the job when application
- *		    call the resolve function.
- * @param addr	    The addresses resolved by the operation.
- */
-typedef void pjsip_resolver_callback(pj_status_t status,
-				     void *token,
-				     const struct pjsip_server_addresses *addr);
-
-/**
- * Create resolver engine.
- *
- * @param pool	The Pool.
- * @return	The resolver engine.
- */
-PJ_DECL(pjsip_resolver_t*) pjsip_resolver_create(pj_pool_t *pool);
-
-/**
- * Destroy resolver engine.
- *
- * @param resolver The resolver.
- */
-PJ_DECL(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver);
-
-/**
- * Asynchronously resolve a SIP target host or domain according to rule 
- * specified in RFC 3263 (Locating SIP Servers). When the resolving operation
- * has completed, the callback will be called.
- *
- * Note: at the moment we don't have implementation of RFC 3263 yet!
- *
- * @param resolver	The resolver engine.
- * @param pool		The pool to allocate resolver job.
- * @param target	The target specification to be resolved.
- * @param token		A user defined token to be passed back to callback function.
- * @param cb		The callback function.
- */
-PJ_DECL(void) pjsip_resolve( pjsip_resolver_t *resolver,
-			     pj_pool_t *pool,
-			     pjsip_host_port *target,
-			     void *token,
-			     pjsip_resolver_callback *cb);
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_SIP_RESOLVE_H__ */
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_RESOLVE_H__

+#define __PJSIP_SIP_RESOLVE_H__

+

+/**

+ * @file sip_resolve.h

+ * @brief 

+ * This module contains the mechanism to resolve server address as specified by

+ * RFC 3263 - Locating SIP Servers

+ */

+

+#include <pjsip/sip_types.h>

+#include <pj/sock.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_RESOLVE SIP Server Resolver

+ * @ingroup PJSIP

+ * @{

+ */

+

+/** 

+ * Maximum number of addresses returned by the resolver. 

+ */

+#define PJSIP_MAX_RESOLVED_ADDRESSES	8

+

+typedef struct pjsip_server_addresses pjsip_server_addresses;

+

+/**

+ * The server addresses returned by the resolver.

+ */

+struct pjsip_server_addresses

+{

+    /** Number of address records. */

+    unsigned	count;

+

+    /** Address records. */

+    struct

+    {

+	/** Preferable transport to be used to contact this address. */

+	pjsip_transport_type_e	type;

+

+	/** The server's address. */

+	pj_sockaddr_in		addr;

+

+    } entry[PJSIP_MAX_RESOLVED_ADDRESSES];

+

+};

+

+/**

+ * The type of callback function to be called when resolver finishes the job.

+ *

+ * @param status    The status of the operation, which is zero on success.

+ * @param token	    The token that was associated with the job when application

+ *		    call the resolve function.

+ * @param addr	    The addresses resolved by the operation.

+ */

+typedef void pjsip_resolver_callback(pj_status_t status,

+				     void *token,

+				     const struct pjsip_server_addresses *addr);

+

+/**

+ * Create resolver engine.

+ *

+ * @param pool	The Pool.

+ * @return	The resolver engine.

+ */

+PJ_DECL(pjsip_resolver_t*) pjsip_resolver_create(pj_pool_t *pool);

+

+/**

+ * Destroy resolver engine.

+ *

+ * @param resolver The resolver.

+ */

+PJ_DECL(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver);

+

+/**

+ * Asynchronously resolve a SIP target host or domain according to rule 

+ * specified in RFC 3263 (Locating SIP Servers). When the resolving operation

+ * has completed, the callback will be called.

+ *

+ * Note: at the moment we don't have implementation of RFC 3263 yet!

+ *

+ * @param resolver	The resolver engine.

+ * @param pool		The pool to allocate resolver job.

+ * @param target	The target specification to be resolved.

+ * @param token		A user defined token to be passed back to callback function.

+ * @param cb		The callback function.

+ */

+PJ_DECL(void) pjsip_resolve( pjsip_resolver_t *resolver,

+			     pj_pool_t *pool,

+			     pjsip_host_port *target,

+			     void *token,

+			     pjsip_resolver_callback *cb);

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_SIP_RESOLVE_H__ */

diff --git a/pjsip/include/pjsip/sip_transaction.h b/pjsip/include/pjsip/sip_transaction.h
index cdb1123..2b7c364 100644
--- a/pjsip/include/pjsip/sip_transaction.h
+++ b/pjsip/include/pjsip/sip_transaction.h
@@ -1,63 +1,85 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_TRANSACTION_H__
-#define __PJSIP_SIP_TRANSACTION_H__
-
-/**
- * @file sip_transaction.h
- * @brief SIP Transaction
- */
-
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_resolve.h>
-#include <pj/timer.h>
-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_TRANSACT SIP Transaction
- * @ingroup PJSIP
- * @{
- */
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_TRANSACTION_H__

+#define __PJSIP_SIP_TRANSACTION_H__

 

-/* Forward decl. */
-struct pjsip_transaction;
-
-
-/**
- * Transaction state.
- */
-typedef enum pjsip_tsx_state_e
-{
-    PJSIP_TSX_STATE_NULL,
-    PJSIP_TSX_STATE_CALLING,
-    PJSIP_TSX_STATE_TRYING,
-    PJSIP_TSX_STATE_PROCEEDING,
-    PJSIP_TSX_STATE_COMPLETED,
-    PJSIP_TSX_STATE_CONFIRMED,
-    PJSIP_TSX_STATE_TERMINATED,
-    PJSIP_TSX_STATE_DESTROYED,
-    PJSIP_TSX_STATE_MAX,
-} pjsip_tsx_state_e;
-
-
-/**
- * State of the transport in the transaction.
- * The transport is progressing independently of the transaction.
- */
-typedef enum pjsip_tsx_transport_state_e
-{
-    PJSIP_TSX_TRANSPORT_STATE_NULL,
-    PJSIP_TSX_TRANSPORT_STATE_RESOLVING,
-    PJSIP_TSX_TRANSPORT_STATE_CONNECTING,
-    PJSIP_TSX_TRANSPORT_STATE_FINAL,
-} pjsip_tsx_transport_state_e;
-
-
-/**
- * Transaction state.
- */
-struct pjsip_transaction
+/**

+ * @file sip_transaction.h

+ * @brief SIP Transaction

+ */

+

+#include <pjsip/sip_msg.h>

+#include <pjsip/sip_resolve.h>

+#include <pj/timer.h>

+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_TRANSACT SIP Transaction

+ * @ingroup PJSIP

+ * @{

+ */

+

+/* Forward decl. */

+struct pjsip_transaction;

+

+

+/**

+ * Transaction state.

+ */

+typedef enum pjsip_tsx_state_e

+{

+    PJSIP_TSX_STATE_NULL,

+    PJSIP_TSX_STATE_CALLING,

+    PJSIP_TSX_STATE_TRYING,

+    PJSIP_TSX_STATE_PROCEEDING,

+    PJSIP_TSX_STATE_COMPLETED,

+    PJSIP_TSX_STATE_CONFIRMED,

+    PJSIP_TSX_STATE_TERMINATED,

+    PJSIP_TSX_STATE_DESTROYED,

+    PJSIP_TSX_STATE_MAX,

+} pjsip_tsx_state_e;

+

+

+/**

+ * State of the transport in the transaction.

+ * The transport is progressing independently of the transaction.

+ */

+typedef enum pjsip_tsx_transport_state_e

+{

+    PJSIP_TSX_TRANSPORT_STATE_NULL,

+    PJSIP_TSX_TRANSPORT_STATE_RESOLVING,

+    PJSIP_TSX_TRANSPORT_STATE_CONNECTING,

+    PJSIP_TSX_TRANSPORT_STATE_FINAL,

+} pjsip_tsx_transport_state_e;

+

+

+/**

+ * Transaction state.

+ */

+struct pjsip_transaction

 {

     /*

      * Administrivia

@@ -85,17 +107,17 @@
     int				handle_ack;     /**< Should we handle ACK?  */

 

     /** Handler according to current state. */

-    pj_status_t (*state_handler)(struct pjsip_transaction *, pjsip_event *);
+    pj_status_t (*state_handler)(struct pjsip_transaction *, pjsip_event *);

 

     /*

      * Transport.

-     */
+     */

     pjsip_tsx_transport_state_e	transport_state;/**< Transport's state.     */

     pjsip_host_port		dest_name;      /**< Destination address.   */

     pjsip_server_addresses	remote_addr;    /**< Addresses resolved.    */

     int				current_addr;   /**< Address currently used. */

 

-    pjsip_transport_t	       *transport;      /**< Transport to use.      */
+    pjsip_transport_t	       *transport;      /**< Transport to use.      */

 

     /*

      * Messages and timer.

@@ -104,16 +126,16 @@
     int				has_unsent_msg; /**< Non-zero if tsx need to 

                                                      transmit msg once resolver

                                                      completes.             */

-    int				retransmit_count;/**< Retransmission count. */
+    int				retransmit_count;/**< Retransmission count. */

     pj_timer_entry		retransmit_timer;/**< Retransmit timer.     */

     pj_timer_entry		timeout_timer;  /**< Timeout timer.         */

 

-    /** Module specific data. */
-    void		       *module_data[PJSIP_MAX_MODULE];
-};
-
-
-/** 
+    /** Module specific data. */

+    void		       *module_data[PJSIP_MAX_MODULE];

+};

+

+

+/** 

  * Init transaction as UAC from the specified transmit data (\c tdata).

  * The transmit data must have a valid \c Request-Line and \c CSeq header.

  * If \c Route headers are present, it will be used to calculate remote

@@ -129,110 +151,110 @@
  * At the end of the function, the transaction will start resolving the

  * addresses of remote server to contact. Transport will be acquired as soon

  * as the resolving job completes.

- *
- * @param tsx       The transaction.
+ *

+ * @param tsx       The transaction.

  * @param tdata     The transmit data.

- *
- * @return          PJ_SUCCESS if successfull.
- */
-PJ_DECL(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, 
-					 pjsip_tx_data *tdata);
-
-/**
+ *

+ * @return          PJ_SUCCESS if successfull.

+ */

+PJ_DECL(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, 

+					 pjsip_tx_data *tdata);

+

+/**

  * Init transaction as UAS.

- *
- * @param tsx       The transaction to be initialized.
+ *

+ * @param tsx       The transaction to be initialized.

  * @param rdata     The received incoming request.

- *
- * @return PJ_SUCCESS if successfull.
- */
-PJ_DECL(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx,
-					 pjsip_rx_data *rdata);
-
-/**
+ *

+ * @return PJ_SUCCESS if successfull.

+ */

+PJ_DECL(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx,

+					 pjsip_rx_data *rdata);

+

+/**

  * Process incoming message for this transaction.

- *
- * @param tsx       The transaction.
- * @param rdata     The incoming message.
- */
-PJ_DECL(void) pjsip_tsx_on_rx_msg( pjsip_transaction *tsx,
-				   pjsip_rx_data *rdata);
-
-/**
+ *

+ * @param tsx       The transaction.

+ * @param rdata     The incoming message.

+ */

+PJ_DECL(void) pjsip_tsx_on_rx_msg( pjsip_transaction *tsx,

+				   pjsip_rx_data *rdata);

+

+/**

  * Transmit message with this transaction.

- *
- * @param tsx       The transaction.
- * @param tdata     The outgoing message.
- */
-PJ_DECL(void) pjsip_tsx_on_tx_msg( pjsip_transaction *tsx,
-				   pjsip_tx_data *tdata);
-
-
-/**
- * Transmit ACK message for 2xx/INVITE with this transaction. The ACK for
- * non-2xx/INVITE is automatically sent by the transaction.
- * This operation is only valid if the transaction is configured to handle ACK
- * (tsx->handle_ack is non-zero). If this attribute is not set, then the
- * transaction will comply with RFC-3261, i.e. it will set itself to 
+ *

+ * @param tsx       The transaction.

+ * @param tdata     The outgoing message.

+ */

+PJ_DECL(void) pjsip_tsx_on_tx_msg( pjsip_transaction *tsx,

+				   pjsip_tx_data *tdata);

+

+

+/**

+ * Transmit ACK message for 2xx/INVITE with this transaction. The ACK for

+ * non-2xx/INVITE is automatically sent by the transaction.

+ * This operation is only valid if the transaction is configured to handle ACK

+ * (tsx->handle_ack is non-zero). If this attribute is not set, then the

+ * transaction will comply with RFC-3261, i.e. it will set itself to 

  * TERMINATED state when it receives 2xx/INVITE.

- *
- * @param tsx       The transaction.
- * @param tdata     The ACK request.
- */
-PJ_DECL(void) pjsip_tsx_on_tx_ack( pjsip_transaction *tsx,
-				   pjsip_tx_data *tdata);
-
-/**
+ *

+ * @param tsx       The transaction.

+ * @param tdata     The ACK request.

+ */

+PJ_DECL(void) pjsip_tsx_on_tx_ack( pjsip_transaction *tsx,

+				   pjsip_tx_data *tdata);

+

+/**

  * Force terminate transaction.

- *
- * @param tsx       The transaction.
- * @param code      The status code to report.
- */
-PJ_DECL(void) pjsip_tsx_terminate( pjsip_transaction *tsx,
-				   int code );
-
-/**
- * Create transaction key, which is used to match incoming requests 
+ *

+ * @param tsx       The transaction.

+ * @param code      The status code to report.

+ */

+PJ_DECL(void) pjsip_tsx_terminate( pjsip_transaction *tsx,

+				   int code );

+

+/**

+ * Create transaction key, which is used to match incoming requests 

  * or response (retransmissions) against transactions.

- *
- * @param pool      The pool
- * @param key       Output key.
- * @param role      The role of the transaction.
- * @param method    The method to be put as a key. 
+ *

+ * @param pool      The pool

+ * @param key       Output key.

+ * @param role      The role of the transaction.

+ * @param method    The method to be put as a key. 

  * @param rdata     The received data to calculate.

  *

  * @return          PJ_SUCCESS or the appropriate error code.

- */
-PJ_DECL(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool,
-				           pj_str_t *key,
-				           pjsip_role_e role,
-				           const pjsip_method *method,
-				           const pjsip_rx_data *rdata );
+ */

+PJ_DECL(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool,

+				           pj_str_t *key,

+				           pjsip_role_e role,

+				           const pjsip_method *method,

+				           const pjsip_rx_data *rdata );

 

-
-/**
- * @}
- */
-
-/*
- * Internal.
- */
-
-/*
- * Get the string name for the state.
- */
-PJ_DECL(const char *) pjsip_tsx_state_str(pjsip_tsx_state_e state);
-
-/*
- * Get the role name.
- */
-PJ_DECL(const char *) pjsip_role_name(pjsip_role_e role);
-
-
-/* Thread Local Storage ID for transaction lock (initialized by endpoint) */
-extern long pjsip_tsx_lock_tls_id;
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_TRANSACT_H__ */
-
+

+/**

+ * @}

+ */

+

+/*

+ * Internal.

+ */

+

+/*

+ * Get the string name for the state.

+ */

+PJ_DECL(const char *) pjsip_tsx_state_str(pjsip_tsx_state_e state);

+

+/*

+ * Get the role name.

+ */

+PJ_DECL(const char *) pjsip_role_name(pjsip_role_e role);

+

+

+/* Thread Local Storage ID for transaction lock (initialized by endpoint) */

+extern long pjsip_tsx_lock_tls_id;

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_TRANSACT_H__ */

+

diff --git a/pjsip/include/pjsip/sip_transport.h b/pjsip/include/pjsip/sip_transport.h
index dd3baea..abe71bf 100644
--- a/pjsip/include/pjsip/sip_transport.h
+++ b/pjsip/include/pjsip/sip_transport.h
@@ -1,89 +1,111 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_TRANSPORT_H__
-#define __PJSIP_SIP_TRANSPORT_H__
-
-/**
- * @file sip_transport.h
- * @brief SIP Transport
- */
-
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_parser.h>
-#include <pj/sock.h>
-#include <pj/list.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_TRANSPORT_H__

+#define __PJSIP_SIP_TRANSPORT_H__

+

+/**

+ * @file sip_transport.h

+ * @brief SIP Transport

+ */

+

+#include <pjsip/sip_msg.h>

+#include <pjsip/sip_parser.h>

+#include <pj/sock.h>

+#include <pj/list.h>

 #include <pj/ioqueue.h>

-
-PJ_BEGIN_DECL
-
-/**
- * @defgroup PJSIP_TRANSPORT SIP Transport
- * @ingroup PJSIP
- *
- * This is the low-level transport layer. Application normally won't need to 
- * use this function, but instead can use transaction or higher layer API to
- * send and receive messages.
- *
- * @{
- */
-
-/**
- * Incoming message buffer.
- * This structure keep all the information regarding the received message. This
- * buffer lifetime is only very short, normally after the transaction has been
- * called, this buffer will be deleted/recycled. So care must be taken when
- * allocating storage from the pool of this buffer.
- */
-struct pjsip_rx_data
-{
-    //PJ_DECL_LIST_MEMBER(struct pjsip_rx_data);
-
-    /** Memory pool for this buffer. */
-    pj_pool_t		*pool;
+

+PJ_BEGIN_DECL

+

+/**

+ * @defgroup PJSIP_TRANSPORT SIP Transport

+ * @ingroup PJSIP

+ *

+ * This is the low-level transport layer. Application normally won't need to 

+ * use this function, but instead can use transaction or higher layer API to

+ * send and receive messages.

+ *

+ * @{

+ */

+

+/**

+ * Incoming message buffer.

+ * This structure keep all the information regarding the received message. This

+ * buffer lifetime is only very short, normally after the transaction has been

+ * called, this buffer will be deleted/recycled. So care must be taken when

+ * allocating storage from the pool of this buffer.

+ */

+struct pjsip_rx_data

+{

+    //PJ_DECL_LIST_MEMBER(struct pjsip_rx_data);

+

+    /** Memory pool for this buffer. */

+    pj_pool_t		*pool;

 

     /** Ioqueue op key. */

     pj_ioqueue_op_key_t	 op_key;

-
-    /** Time when the message was received. */
-    pj_time_val		 timestamp;
-
-    /** The packet buffer. */
-    char		 packet[PJSIP_MAX_PKT_LEN];
-
-    /** The length of the packet received. */
-    int			 len;
-
-    /** The source address from which the packet was received. */
-    pj_sockaddr_in	 addr;
-
-    /** The length of the source address. */
-    int			 addr_len;
-
-    /** The transport object which received this packet. */
-    pjsip_transport_t	*transport;
-
-    /** The parsed message, if any. */
-    pjsip_msg		*msg;
-
-    /** This the transaction key generated from the message. This key is only
-     *  available after the rdata has reached the endpoint. 
-     */
-    pj_str_t		 key;
-
-    /** The Call-ID header as found in the message. */
-    pj_str_t		 call_id;
-
-    /** The From header as found in the message. */
-    pjsip_from_hdr	*from;
-
-    /** The To header as found in the message. */
-    pjsip_to_hdr	*to;
-
-    /** The topmost Via header as found in the message. */
-    pjsip_via_hdr	*via;
-
-    /** The CSeq header as found in the message. */
-    pjsip_cseq_hdr	*cseq;
+

+    /** Time when the message was received. */

+    pj_time_val		 timestamp;

+

+    /** The packet buffer. */

+    char		 packet[PJSIP_MAX_PKT_LEN];

+

+    /** The length of the packet received. */

+    int			 len;

+

+    /** The source address from which the packet was received. */

+    pj_sockaddr_in	 addr;

+

+    /** The length of the source address. */

+    int			 addr_len;

+

+    /** The transport object which received this packet. */

+    pjsip_transport_t	*transport;

+

+    /** The parsed message, if any. */

+    pjsip_msg		*msg;

+

+    /** This the transaction key generated from the message. This key is only

+     *  available after the rdata has reached the endpoint. 

+     */

+    pj_str_t		 key;

+

+    /** The Call-ID header as found in the message. */

+    pj_str_t		 call_id;

+

+    /** The From header as found in the message. */

+    pjsip_from_hdr	*from;

+

+    /** The To header as found in the message. */

+    pjsip_to_hdr	*to;

+

+    /** The topmost Via header as found in the message. */

+    pjsip_via_hdr	*via;

+

+    /** The CSeq header as found in the message. */

+    pjsip_cseq_hdr	*cseq;

 

     /** Max forwards header. */

     pjsip_max_forwards_hdr *max_fwd;

@@ -103,378 +125,378 @@
     /** The first Require header. */

     pjsip_require_hdr   *require;

 

-    /** The list of error generated by the parser when parsing this message. */
-    pjsip_parser_err_report parse_err;
-};
-
-
-/**
- * Data structure for sending outgoing message. Application normally creates
- * this buffer by calling #pjsip_endpt_create_tdata.
- *
- * The lifetime of this buffer is controlled by the reference counter in this
- * structure, which is manipulated by calling #pjsip_tx_data_add_ref and
- * #pjsip_tx_data_dec_ref. When the reference counter has reached zero, then
- * this buffer will be destroyed.
- *
- * A transaction object normally will add reference counter to this buffer
- * when application calls #pjsip_tsx_on_tx_msg, because it needs to keep the
- * message for retransmission. The transaction will release the reference
- * counter once its state has reached final state.
- */
-struct pjsip_tx_data
-{
-    PJ_DECL_LIST_MEMBER(struct pjsip_tx_data);
-
-    /** Memory pool for this buffer. */
-    pj_pool_t		*pool;
-
-    /** A name to identify this buffer. */
-    char		 obj_name[PJ_MAX_OBJ_NAME];
-
-    /** For response message, this contains the reference to timestamp when 
-     *  the original request message was received. The value of this field
-     *  is set when application creates response message to a request by
-     *  calling #pjsip_endpt_create_response.
-     */
-    pj_time_val		 rx_timestamp;
-
-    /** The transport manager for this buffer. */
-    pjsip_transport_mgr *mgr;
+    /** The list of error generated by the parser when parsing this message. */

+    pjsip_parser_err_report parse_err;

+};

+

+

+/**

+ * Data structure for sending outgoing message. Application normally creates

+ * this buffer by calling #pjsip_endpt_create_tdata.

+ *

+ * The lifetime of this buffer is controlled by the reference counter in this

+ * structure, which is manipulated by calling #pjsip_tx_data_add_ref and

+ * #pjsip_tx_data_dec_ref. When the reference counter has reached zero, then

+ * this buffer will be destroyed.

+ *

+ * A transaction object normally will add reference counter to this buffer

+ * when application calls #pjsip_tsx_on_tx_msg, because it needs to keep the

+ * message for retransmission. The transaction will release the reference

+ * counter once its state has reached final state.

+ */

+struct pjsip_tx_data

+{

+    PJ_DECL_LIST_MEMBER(struct pjsip_tx_data);

+

+    /** Memory pool for this buffer. */

+    pj_pool_t		*pool;

+

+    /** A name to identify this buffer. */

+    char		 obj_name[PJ_MAX_OBJ_NAME];

+

+    /** For response message, this contains the reference to timestamp when 

+     *  the original request message was received. The value of this field

+     *  is set when application creates response message to a request by

+     *  calling #pjsip_endpt_create_response.

+     */

+    pj_time_val		 rx_timestamp;

+

+    /** The transport manager for this buffer. */

+    pjsip_transport_mgr *mgr;

 

     /** Ioqueue asynchronous operation key. */

     pj_ioqueue_op_key_t	 op_key;

-
-    /** The message in this buffer. */
-    pjsip_msg 		*msg;
-
-    /** Buffer to the printed text representation of the message. When the
-     *  content of this buffer is set, then the transport will send the content
-     *  of this buffer instead of re-printing the message structure. If the
-     *  message structure has changed, then application must invalidate this
-     *  buffer by calling #pjsip_tx_data_invalidate_msg.
-     */
-    pjsip_buffer	 buf;
-
-    /** Reference counter. */
-    pj_atomic_t		*ref_cnt;
-};
-
-
-/**
- * Add reference counter to the transmit buffer. The reference counter controls
- * the life time of the buffer, ie. when the counter reaches zero, then it 
- * will be destroyed.
- *
- * @param tdata	    The transmit buffer.
- */
-PJ_DECL(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata );
-
-/**
- * Decrement reference counter of the transmit buffer.
- * When the transmit buffer is no longer used, it will be destroyed.
- *
- * @param tdata	    The transmit buffer data.
- */
-PJ_DECL(void) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata );
-
-/**
- * Invalidate the print buffer to force message to be re-printed. Call
- * when the message has changed after it has been printed to buffer. The
- * message is printed to buffer normally by transport when it is about to be 
- * sent to the wire. Subsequent sending of the message will not cause
- * the message to be re-printed, unless application invalidates the buffer
- * by calling this function.
- *
- * @param tdata	    The transmit buffer.
- */
-PJ_DECL(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata );
-
-
-/**
- * Flags for SIP transports.
- */
-enum pjsip_transport_flags_e
-{
-    PJSIP_TRANSPORT_RELIABLE	    = 1,    /**< Transport is reliable. */
-    PJSIP_TRANSPORT_SECURE	    = 2,    /**< Transport is secure. */
-    PJSIP_TRANSPORT_IOQUEUE_BUSY    = 4,    /**< WTH?? */
-};
-
-/**
- * Get the transport type from the transport name.
- *
- * @param name	    Transport name, such as "TCP", or "UDP".
- *
- * @return	    The transport type, or PJSIP_TRANSPORT_UNSPECIFIED if 
- *		    the name is not recognized as the name of supported 
- *		    transport.
- */
-PJ_DECL(pjsip_transport_type_e) 
-pjsip_transport_get_type_from_name(const pj_str_t *name);
-
-/**
- * Get the transport type for the specified flags.
- *
- * @param flag	    The transport flag.
- *
- * @return	    Transport type.
- */
-PJ_DECL(pjsip_transport_type_e) 
-pjsip_transport_get_type_from_flag(unsigned flag);
-
-/**
- * Get the default SIP port number for the specified type.
- *
- * @param type	    Transport type.
- *
- * @return	    The port number, which is the default SIP port number for
- *		    the specified type.
- */
-PJ_DECL(int) 
-pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type);
-
-
-/**
- * Add reference to transport.
- * Transactions or dialogs that uses a particular transport must call this 
- * function to indicate that the transport is being used, thus preventing the
- * transport from being closed.
- *
- * @param transport	The transport.
- */
-PJ_DECL(void) 
-pjsip_transport_add_ref( pjsip_transport_t *transport );
-
-/**
- * Decrease reference to transport.
- * When the transport reference counter becomes zero, a timer will be started
- * and when this timer expires and the reference counter is still zero, the
- * transport will be released.
- *
- * @param transport	The transport
- */
-PJ_DECL(void) 
-pjsip_transport_dec_ref( pjsip_transport_t *transport );
-
-
-/**
- * Macro to check whether the transport is reliable.
- *
- * @param transport	The transport
- *
- * @return		non-zero (not necessarily 1) if transport is reliable.
- */
-#define PJSIP_TRANSPORT_IS_RELIABLE(transport)	\
-	(pjsip_transport_get_flag(transport) & PJSIP_TRANSPORT_RELIABLE)
-
-
-/**
- * Macro to check whether the transport is secure.
- *
- * @param transport	The transport
- *
- * @return		non-zero (not necessarily one) if transport is secure.
- */
-#define PJSIP_TRANSPORT_IS_SECURE(transport)	\
-	(pjsip_transport_get_flag(transport) & PJSIP_TRANSPORT_SECURE)
-
-/**
- * Get the transport type.
- *
- * @param tr		The transport.
- *
- * @return		Transport type.
- */
-PJ_DECL(pjsip_transport_type_e) 
-pjsip_transport_get_type( const pjsip_transport_t * tr);
-
-/**
- * Get the transport type name (ie "UDP", or "TCP").
- *
- * @param tr		The transport.
- * @return		The string type.
- */
-PJ_DECL(const char *) 
-pjsip_transport_get_type_name( const pjsip_transport_t * tr);
-
-/**
- * Get the transport's object name.
- *
- * @param tr		The transport.
- * @return		The object name.
- */
-PJ_DECL(const char*) 
-pjsip_transport_get_obj_name( const pjsip_transport_t *tr );
-
-/**
- * Get the transport's reference counter.
- *
- * @param tr		The transport.
- * @return		The reference count value.
- */
-PJ_DECL(int) 
-pjsip_transport_get_ref_cnt( const pjsip_transport_t *tr );
-
-/**
- * Get transport flag.
- *
- * @param tr		The transport.
- * @return		Transport flag.
- */
-PJ_DECL(unsigned) 
-pjsip_transport_get_flag( const pjsip_transport_t * tr );
-
-/**
- * Get the local address of the transport, ie. the address which the socket
- * is bound.
- *
- * @param tr		The transport.
- * @return		The address.
- */
-PJ_DECL(const pj_sockaddr_in *) 
-pjsip_transport_get_local_addr( pjsip_transport_t * tr );
-
-/**
- * Get the address name of the transport. Address name can be an arbitrary
- * address assigned to a transport. This is usefull for example when STUN
- * is used, then the address name of an UDP transport can specify the public
- * address of the transport. When the address name is not set, then value
- * will be equal to the local/bound address. Application should normally
- * prefer to use the address name instead of the local address.
- *
- * @param tr		The transport.
- * @return		The address name.
- */
-PJ_DECL(const pj_sockaddr_in*) 
-pjsip_transport_get_addr_name (pjsip_transport_t *tr);
-
-/**
- * Get the remote address of the transport. Not all transports will have 
- * a valid remote address. UDP transports, for example, will likely to have
- * zero has their remote address, because UDP transport can be used to send
- * and receive messages from multiple destinations.
- *
- * @param tr		The transport.
- * @return		The address.
- */
-PJ_DECL(const pj_sockaddr_in *) 
-pjsip_transport_get_remote_addr( const pjsip_transport_t * tr );
-
-/**
- * Send a SIP message using the specified transport, to the address specified
- * in the outgoing data. This function is only usefull for application when it
- * wants to handle the message statelessly, because otherwise it should create
- * a transaction and let the transaction handles the transmission of the 
- * message.
- *
- * This function will send the message immediately, so application must be
- * sure that the transport is ready to do so before calling this function.
- *
- * @param tr		The transport to send the message.
- * @param tdata		The outgoing message buffer.
+

+    /** The message in this buffer. */

+    pjsip_msg 		*msg;

+

+    /** Buffer to the printed text representation of the message. When the

+     *  content of this buffer is set, then the transport will send the content

+     *  of this buffer instead of re-printing the message structure. If the

+     *  message structure has changed, then application must invalidate this

+     *  buffer by calling #pjsip_tx_data_invalidate_msg.

+     */

+    pjsip_buffer	 buf;

+

+    /** Reference counter. */

+    pj_atomic_t		*ref_cnt;

+};

+

+

+/**

+ * Add reference counter to the transmit buffer. The reference counter controls

+ * the life time of the buffer, ie. when the counter reaches zero, then it 

+ * will be destroyed.

+ *

+ * @param tdata	    The transmit buffer.

+ */

+PJ_DECL(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata );

+

+/**

+ * Decrement reference counter of the transmit buffer.

+ * When the transmit buffer is no longer used, it will be destroyed.

+ *

+ * @param tdata	    The transmit buffer data.

+ */

+PJ_DECL(void) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata );

+

+/**

+ * Invalidate the print buffer to force message to be re-printed. Call

+ * when the message has changed after it has been printed to buffer. The

+ * message is printed to buffer normally by transport when it is about to be 

+ * sent to the wire. Subsequent sending of the message will not cause

+ * the message to be re-printed, unless application invalidates the buffer

+ * by calling this function.

+ *

+ * @param tdata	    The transmit buffer.

+ */

+PJ_DECL(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata );

+

+

+/**

+ * Flags for SIP transports.

+ */

+enum pjsip_transport_flags_e

+{

+    PJSIP_TRANSPORT_RELIABLE	    = 1,    /**< Transport is reliable. */

+    PJSIP_TRANSPORT_SECURE	    = 2,    /**< Transport is secure. */

+    PJSIP_TRANSPORT_IOQUEUE_BUSY    = 4,    /**< WTH?? */

+};

+

+/**

+ * Get the transport type from the transport name.

+ *

+ * @param name	    Transport name, such as "TCP", or "UDP".

+ *

+ * @return	    The transport type, or PJSIP_TRANSPORT_UNSPECIFIED if 

+ *		    the name is not recognized as the name of supported 

+ *		    transport.

+ */

+PJ_DECL(pjsip_transport_type_e) 

+pjsip_transport_get_type_from_name(const pj_str_t *name);

+

+/**

+ * Get the transport type for the specified flags.

+ *

+ * @param flag	    The transport flag.

+ *

+ * @return	    Transport type.

+ */

+PJ_DECL(pjsip_transport_type_e) 

+pjsip_transport_get_type_from_flag(unsigned flag);

+

+/**

+ * Get the default SIP port number for the specified type.

+ *

+ * @param type	    Transport type.

+ *

+ * @return	    The port number, which is the default SIP port number for

+ *		    the specified type.

+ */

+PJ_DECL(int) 

+pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type);

+

+

+/**

+ * Add reference to transport.

+ * Transactions or dialogs that uses a particular transport must call this 

+ * function to indicate that the transport is being used, thus preventing the

+ * transport from being closed.

+ *

+ * @param transport	The transport.

+ */

+PJ_DECL(void) 

+pjsip_transport_add_ref( pjsip_transport_t *transport );

+

+/**

+ * Decrease reference to transport.

+ * When the transport reference counter becomes zero, a timer will be started

+ * and when this timer expires and the reference counter is still zero, the

+ * transport will be released.

+ *

+ * @param transport	The transport

+ */

+PJ_DECL(void) 

+pjsip_transport_dec_ref( pjsip_transport_t *transport );

+

+

+/**

+ * Macro to check whether the transport is reliable.

+ *

+ * @param transport	The transport

+ *

+ * @return		non-zero (not necessarily 1) if transport is reliable.

+ */

+#define PJSIP_TRANSPORT_IS_RELIABLE(transport)	\

+	(pjsip_transport_get_flag(transport) & PJSIP_TRANSPORT_RELIABLE)

+

+

+/**

+ * Macro to check whether the transport is secure.

+ *

+ * @param transport	The transport

+ *

+ * @return		non-zero (not necessarily one) if transport is secure.

+ */

+#define PJSIP_TRANSPORT_IS_SECURE(transport)	\

+	(pjsip_transport_get_flag(transport) & PJSIP_TRANSPORT_SECURE)

+

+/**

+ * Get the transport type.

+ *

+ * @param tr		The transport.

+ *

+ * @return		Transport type.

+ */

+PJ_DECL(pjsip_transport_type_e) 

+pjsip_transport_get_type( const pjsip_transport_t * tr);

+

+/**

+ * Get the transport type name (ie "UDP", or "TCP").

+ *

+ * @param tr		The transport.

+ * @return		The string type.

+ */

+PJ_DECL(const char *) 

+pjsip_transport_get_type_name( const pjsip_transport_t * tr);

+

+/**

+ * Get the transport's object name.

+ *

+ * @param tr		The transport.

+ * @return		The object name.

+ */

+PJ_DECL(const char*) 

+pjsip_transport_get_obj_name( const pjsip_transport_t *tr );

+

+/**

+ * Get the transport's reference counter.

+ *

+ * @param tr		The transport.

+ * @return		The reference count value.

+ */

+PJ_DECL(int) 

+pjsip_transport_get_ref_cnt( const pjsip_transport_t *tr );

+

+/**

+ * Get transport flag.

+ *

+ * @param tr		The transport.

+ * @return		Transport flag.

+ */

+PJ_DECL(unsigned) 

+pjsip_transport_get_flag( const pjsip_transport_t * tr );

+

+/**

+ * Get the local address of the transport, ie. the address which the socket

+ * is bound.

+ *

+ * @param tr		The transport.

+ * @return		The address.

+ */

+PJ_DECL(const pj_sockaddr_in *) 

+pjsip_transport_get_local_addr( pjsip_transport_t * tr );

+

+/**

+ * Get the address name of the transport. Address name can be an arbitrary

+ * address assigned to a transport. This is usefull for example when STUN

+ * is used, then the address name of an UDP transport can specify the public

+ * address of the transport. When the address name is not set, then value

+ * will be equal to the local/bound address. Application should normally

+ * prefer to use the address name instead of the local address.

+ *

+ * @param tr		The transport.

+ * @return		The address name.

+ */

+PJ_DECL(const pj_sockaddr_in*) 

+pjsip_transport_get_addr_name (pjsip_transport_t *tr);

+

+/**

+ * Get the remote address of the transport. Not all transports will have 

+ * a valid remote address. UDP transports, for example, will likely to have

+ * zero has their remote address, because UDP transport can be used to send

+ * and receive messages from multiple destinations.

+ *

+ * @param tr		The transport.

+ * @return		The address.

+ */

+PJ_DECL(const pj_sockaddr_in *) 

+pjsip_transport_get_remote_addr( const pjsip_transport_t * tr );

+

+/**

+ * Send a SIP message using the specified transport, to the address specified

+ * in the outgoing data. This function is only usefull for application when it

+ * wants to handle the message statelessly, because otherwise it should create

+ * a transaction and let the transaction handles the transmission of the 

+ * message.

+ *

+ * This function will send the message immediately, so application must be

+ * sure that the transport is ready to do so before calling this function.

+ *

+ * @param tr		The transport to send the message.

+ * @param tdata		The outgoing message buffer.

  * @param addr		The remote address.

  * @param sent          If not null, it will be filled up with the length of

- *                      data sent.
- *
- * @return		PJ_SUCCESS on success, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjsip_transport_send_msg( pjsip_transport_t *tr, 
-					       pjsip_tx_data *tdata,
+ *                      data sent.

+ *

+ * @return		PJ_SUCCESS on success, or the appropriate error code.

+ */

+PJ_DECL(pj_status_t) pjsip_transport_send_msg( pjsip_transport_t *tr, 

+					       pjsip_tx_data *tdata,

 					       const pj_sockaddr_in *addr,

-					       pj_ssize_t *sent);
-
-
-/**
- * @}
- */
-
-/*
- * PRIVATE FUNCTIONS!!!
- *
- * These functions are normally to be used by endpoint. Application should
- * use the variant provided by the endpoint instance.
- *
- * Application normally wouldn't be able to call these functions because it
- * has no reference of the transport manager (the instance of the transport
- * manager is hidden by endpoint!).
- */
-
-/*
- * Create a new transmit buffer.
- *
- * @param mgr		The transport manager.
- * @return		The transmit buffer data, or NULL on error.
- */
+					       pj_ssize_t *sent);

+

+

+/**

+ * @}

+ */

+

+/*

+ * PRIVATE FUNCTIONS!!!

+ *

+ * These functions are normally to be used by endpoint. Application should

+ * use the variant provided by the endpoint instance.

+ *

+ * Application normally wouldn't be able to call these functions because it

+ * has no reference of the transport manager (the instance of the transport

+ * manager is hidden by endpoint!).

+ */

+

+/*

+ * Create a new transmit buffer.

+ *

+ * @param mgr		The transport manager.

+ * @return		The transmit buffer data, or NULL on error.

+ */

 pj_status_t pjsip_tx_data_create( pjsip_transport_mgr *mgr,

-                                  pjsip_tx_data **tdata );
-
-
-/**
- * Create listener.
- *
- * @param mgr		The transport manager.
- * @param type		Transport type.
- * @param local_addr	The address to bind.
- * @param addr_name	If not null, sets the address name. If NULL, 
- *			then the local address will be used.
- *
- * @return		PJ_SUCCESS if listener was successfully created.
- */
-PJ_DECL(pj_status_t) pjsip_create_listener( pjsip_transport_mgr *mgr,
-					    pjsip_transport_type_e type,
-					    pj_sockaddr_in *local_addr,
-					    const pj_sockaddr_in *addr_name);
-
-
-/**
- * Create UDP listener.
- *
- * @param mgr		The transport manager.
- * @param sock		The UDP socket.
- * @param addr_name	If not null, sets the address name. If NULL, 
- *			then the local address will be used.
- *
- * @return		PJ_SUCCESS if listener was successfully created.
- */
-PJ_DECL(pj_status_t) pjsip_create_udp_listener( pjsip_transport_mgr *mgr,
-						pj_sock_t sock,
-						const pj_sockaddr_in *addr_name);
-
-/** 
- * Type of function to receive asynchronous transport completion for
- * pjsip_transport_get() operation.
- *
- * @param tr		The transport.
- * @param token		Token registered previously.
- * @param status	Status of operation.
- */
-typedef void pjsip_transport_completion_callback(pjsip_transport_t *tr, 
-						 void *token, 
-						 pj_status_t status);
-
-/**
- * Find transport to be used to send message to remote destination. If no
- * suitable transport is found, a new one will be created. If transport
- * can not be available immediately (for example, an outgoing TCP connec()),
- * then the caller will be notified later via the callback.
- *
- * @param mgr		The transport manager.
- * @param pool		Pool to allocate asychronous job (if required).
- * @param type		The transport type.
- * @param remote	The remote address.
- * @param token		The token that will be passed to the callback.
- * @param cb		The callback to be called to report the completion of 
- *			the operation.
- */
-PJ_DECL(void) pjsip_transport_get( pjsip_transport_mgr *mgr,
-				   pj_pool_t *pool,
-				   pjsip_transport_type_e type,
-				   const pj_sockaddr_in *remote,
-				   void *token,
-				   pjsip_transport_completion_callback *cb);
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_SIP_TRANSPORT_H__ */
-
+                                  pjsip_tx_data **tdata );

+

+

+/**

+ * Create listener.

+ *

+ * @param mgr		The transport manager.

+ * @param type		Transport type.

+ * @param local_addr	The address to bind.

+ * @param addr_name	If not null, sets the address name. If NULL, 

+ *			then the local address will be used.

+ *

+ * @return		PJ_SUCCESS if listener was successfully created.

+ */

+PJ_DECL(pj_status_t) pjsip_create_listener( pjsip_transport_mgr *mgr,

+					    pjsip_transport_type_e type,

+					    pj_sockaddr_in *local_addr,

+					    const pj_sockaddr_in *addr_name);

+

+

+/**

+ * Create UDP listener.

+ *

+ * @param mgr		The transport manager.

+ * @param sock		The UDP socket.

+ * @param addr_name	If not null, sets the address name. If NULL, 

+ *			then the local address will be used.

+ *

+ * @return		PJ_SUCCESS if listener was successfully created.

+ */

+PJ_DECL(pj_status_t) pjsip_create_udp_listener( pjsip_transport_mgr *mgr,

+						pj_sock_t sock,

+						const pj_sockaddr_in *addr_name);

+

+/** 

+ * Type of function to receive asynchronous transport completion for

+ * pjsip_transport_get() operation.

+ *

+ * @param tr		The transport.

+ * @param token		Token registered previously.

+ * @param status	Status of operation.

+ */

+typedef void pjsip_transport_completion_callback(pjsip_transport_t *tr, 

+						 void *token, 

+						 pj_status_t status);

+

+/**

+ * Find transport to be used to send message to remote destination. If no

+ * suitable transport is found, a new one will be created. If transport

+ * can not be available immediately (for example, an outgoing TCP connec()),

+ * then the caller will be notified later via the callback.

+ *

+ * @param mgr		The transport manager.

+ * @param pool		Pool to allocate asychronous job (if required).

+ * @param type		The transport type.

+ * @param remote	The remote address.

+ * @param token		The token that will be passed to the callback.

+ * @param cb		The callback to be called to report the completion of 

+ *			the operation.

+ */

+PJ_DECL(void) pjsip_transport_get( pjsip_transport_mgr *mgr,

+				   pj_pool_t *pool,

+				   pjsip_transport_type_e type,

+				   const pj_sockaddr_in *remote,

+				   void *token,

+				   pjsip_transport_completion_callback *cb);

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_SIP_TRANSPORT_H__ */

+

diff --git a/pjsip/include/pjsip/sip_types.h b/pjsip/include/pjsip/sip_types.h
index 64f5f3a..0ba3a47 100644
--- a/pjsip/include/pjsip/sip_types.h
+++ b/pjsip/include/pjsip/sip_types.h
@@ -1,141 +1,163 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_TYPES_H__
-#define __PJSIP_SIP_TYPES_H__
-
-#include <pjsip/sip_config.h>
-#include <pj/types.h>
-
-/**
- * Opaque data structure for transports (sip_transport.h).
- */
-typedef struct pjsip_transport_t pjsip_transport_t;
-
-/**
- * Opaque data type for transport manager (sip_transport.h).
- */
-typedef struct pjsip_transport_mgr pjsip_transport_mgr;
-
-/**
- * Transport types.
- */
-typedef enum pjsip_transport_type_e
-{
-    /** Unspecified. */
-    PJSIP_TRANSPORT_UNSPECIFIED,
-
-    /** UDP. */
-    PJSIP_TRANSPORT_UDP,
-
-#if PJ_HAS_TCP
-    /** TCP. */
-    PJSIP_TRANSPORT_TCP,
-
-    /** TLS. */
-    PJSIP_TRANSPORT_TLS,
-
-    /** SCTP. */
-    PJSIP_TRANSPORT_SCTP,
-#endif
-
-} pjsip_transport_type_e;
-
-
-/**
- * Forward declaration for endpoint (sip_endpoint.h).
- */
-typedef struct pjsip_endpoint pjsip_endpoint;
-
-/**
- * Forward declaration for transactions (sip_transaction.h).
- */
-typedef struct pjsip_transaction pjsip_transaction;
-
-/**
- * Forward declaration for events (sip_event.h).
- */
-typedef struct pjsip_event pjsip_event;
-
-/**
- * Forward declaration for transmit data/buffer (sip_transport.h).
- */
-typedef struct pjsip_tx_data pjsip_tx_data;
-
-/**
- * Forward declaration for receive data/buffer (sip_transport.h).
- */
-typedef struct pjsip_rx_data pjsip_rx_data;
-
-/**
- * Forward declaration for message (sip_msg.h).
- */
-typedef struct pjsip_msg pjsip_msg;
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_TYPES_H__

+#define __PJSIP_SIP_TYPES_H__

+

+#include <pjsip/sip_config.h>

+#include <pj/types.h>

+

+/**

+ * Opaque data structure for transports (sip_transport.h).

+ */

+typedef struct pjsip_transport_t pjsip_transport_t;

+

+/**

+ * Opaque data type for transport manager (sip_transport.h).

+ */

+typedef struct pjsip_transport_mgr pjsip_transport_mgr;

+

+/**

+ * Transport types.

+ */

+typedef enum pjsip_transport_type_e

+{

+    /** Unspecified. */

+    PJSIP_TRANSPORT_UNSPECIFIED,

+

+    /** UDP. */

+    PJSIP_TRANSPORT_UDP,

+

+#if PJ_HAS_TCP

+    /** TCP. */

+    PJSIP_TRANSPORT_TCP,

+

+    /** TLS. */

+    PJSIP_TRANSPORT_TLS,

+

+    /** SCTP. */

+    PJSIP_TRANSPORT_SCTP,

+#endif

+

+} pjsip_transport_type_e;

+

+

+/**

+ * Forward declaration for endpoint (sip_endpoint.h).

+ */

+typedef struct pjsip_endpoint pjsip_endpoint;

+

+/**

+ * Forward declaration for transactions (sip_transaction.h).

+ */

+typedef struct pjsip_transaction pjsip_transaction;

+

+/**

+ * Forward declaration for events (sip_event.h).

+ */

+typedef struct pjsip_event pjsip_event;

+

+/**

+ * Forward declaration for transmit data/buffer (sip_transport.h).

+ */

+typedef struct pjsip_tx_data pjsip_tx_data;

+

+/**

+ * Forward declaration for receive data/buffer (sip_transport.h).

+ */

+typedef struct pjsip_rx_data pjsip_rx_data;

+

+/**

+ * Forward declaration for message (sip_msg.h).

+ */

+typedef struct pjsip_msg pjsip_msg;

 

 /**

  * Forward declaration for header field (sip_msg.h).

  */

 typedef struct pjsip_hdr pjsip_hdr;

-
-/**
- * Forward declaration for URI (sip_uri.h).
- */
-typedef struct pjsip_uri pjsip_uri;
-
-/**
- * Opaque data type for the resolver engine (sip_resolve.h).
- */
-typedef struct pjsip_resolver_t pjsip_resolver_t;
-
-/**
- * Forward declaration for credential.
- */
-typedef struct pjsip_cred_info pjsip_cred_info;
-
-
-/**
- * Forward declaration for module (sip_module.h).
- */
-typedef struct pjsip_module pjsip_module;
-
-/**
- * Transaction role.
- */
-typedef enum pjsip_role_e
-{
-    PJSIP_ROLE_UAC,	/**< Transaction role is UAC. */
-    PJSIP_ROLE_UAS,	/**< Transaction role is UAS. */
-} pjsip_role_e;
-
-
-/**
- * General purpose buffer.
- */
-typedef struct pjsip_buffer
-{
-    /** The start of the buffer. */
-    char *start;
-
-    /** Pointer to current end of the buffer, which also indicates the position
-        of subsequent buffer write.
-     */
-    char *cur;
-
-    /** The absolute end of the buffer. */
-    char *end;
-
-} pjsip_buffer;
-
-
-/**
- * General host:port pair, used for example as Via sent-by.
- */
-typedef struct pjsip_host_port
-{
-    unsigned flag;	/**< Flags of pjsip_transport_flags_e (not used in Via). */
-    unsigned type;	/**< Transport type (pjsip_transport_type_e), or zero. */
-    pj_str_t host;	/**< Host part. */
-    int	     port;	/**< Port number. */
-} pjsip_host_port;
+

+/**

+ * Forward declaration for URI (sip_uri.h).

+ */

+typedef struct pjsip_uri pjsip_uri;

+

+/**

+ * Opaque data type for the resolver engine (sip_resolve.h).

+ */

+typedef struct pjsip_resolver_t pjsip_resolver_t;

+

+/**

+ * Forward declaration for credential.

+ */

+typedef struct pjsip_cred_info pjsip_cred_info;

+

+

+/**

+ * Forward declaration for module (sip_module.h).

+ */

+typedef struct pjsip_module pjsip_module;

+

+/**

+ * Transaction role.

+ */

+typedef enum pjsip_role_e

+{

+    PJSIP_ROLE_UAC,	/**< Transaction role is UAC. */

+    PJSIP_ROLE_UAS,	/**< Transaction role is UAS. */

+} pjsip_role_e;

+

+

+/**

+ * General purpose buffer.

+ */

+typedef struct pjsip_buffer

+{

+    /** The start of the buffer. */

+    char *start;

+

+    /** Pointer to current end of the buffer, which also indicates the position

+        of subsequent buffer write.

+     */

+    char *cur;

+

+    /** The absolute end of the buffer. */

+    char *end;

+

+} pjsip_buffer;

+

+

+/**

+ * General host:port pair, used for example as Via sent-by.

+ */

+typedef struct pjsip_host_port

+{

+    unsigned flag;	/**< Flags of pjsip_transport_flags_e (not used in Via). */

+    unsigned type;	/**< Transport type (pjsip_transport_type_e), or zero. */

+    pj_str_t host;	/**< Host part. */

+    int	     port;	/**< Port number. */

+} pjsip_host_port;

 

 

 /**

@@ -156,6 +178,6 @@
  * Attributes to inform that the function may throw exceptions.

  */

 #define PJSIP_THROW_SPEC(list)

-
-#endif	/* __PJSIP_SIP_TYPES_H__ */
-
+

+#endif	/* __PJSIP_SIP_TYPES_H__ */

+

diff --git a/pjsip/include/pjsip/sip_uri.h b/pjsip/include/pjsip/sip_uri.h
index 8d72d0a..24b2edd 100644
--- a/pjsip/include/pjsip/sip_uri.h
+++ b/pjsip/include/pjsip/sip_uri.h
@@ -1,294 +1,316 @@
-/* $Id$
- */
-#ifndef __PJSIP_SIP_URI_H__
-#define __PJSIP_SIP_URI_H__
-
-/**
- * @file sip_uri.h
- * @brief SIP URL Structures and Manipulations
- */
-
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_config.h>
-
-PJ_BEGIN_DECL
-
-
-/**
- * @defgroup PJSIP_URL URL Structures
- * @brief SIP Url, tel: Url, and generic URI.
- * @ingroup PJSIP_MSG
- * @{
- */
-
-/**
- * URI context.
- */
-typedef enum pjsip_uri_context_e
-{
-    PJSIP_URI_IN_REQ_URI,	/**< The URI is in Request URI. */
-    PJSIP_URI_IN_FROMTO_HDR,	/**< The URI is in From/To header. */
-    PJSIP_URI_IN_CONTACT_HDR,	/**< The URI is in Contact header. */
-    PJSIP_URI_IN_ROUTING_HDR,	/**< The URI is in Route/Record-Route header. */
-    PJSIP_URI_IN_OTHER,		/**< Other context (web page, business card, etc.) */
-} pjsip_uri_context_e;
-
-/**
- * URI 'virtual' function table.
- * All types of URI in this library (such as sip:, sips:, tel:, and name-addr) 
- * will have pointer to this table as their first struct member. This table
- * provides polimorphic behaviour to the URI.
- */
-typedef struct pjsip_uri_vptr
-{
-    /** 
-     * Get URI scheme. 
-     * @param uri the URI (self).
-     * @return the URI scheme.
-     */
-    const pj_str_t* (*p_get_scheme)(const void *uri);
-
-    /**
-     * Get the URI object contained by this URI, or the URI itself if
-     * it doesn't contain another URI.
-     * @param uri the URI (self).
-     */
-    void* (*p_get_uri)(void *uri);
-
-    /**
-     * Print URI components to the buffer, following the rule of which 
-     * components are allowed for the context.
-     * @param context the context where the URI will be placed.
-     * @param uri the URI (self).
-     * @param buf the buffer.
-     * @param size the size of the buffer.
-     * @return the length printed.
-     */
-    int	(*p_print)(pjsip_uri_context_e context,
-		   const void *uri, 
-		   char *buf, pj_size_t size);
-
-    /** 
-     * Compare two URIs according to the context.
-     * @param context the context.
-     * @param uri1 the first URI (self).
-     * @param uri2 the second URI.
-     * @return zero if equal.
-     */
-    int	(*p_compare)(pjsip_uri_context_e context, 
-		     const void *uri1, const void *uri2);
-
-    /** 
-     * Clone URI. 
-     * @param pool the pool.
-     * @param the URI to clone (self).
-     * @return new URI.
-     */
-    void *(*p_clone)(pj_pool_t *pool, const void *uri);
-
-} pjsip_uri_vptr;
-
-
-/**
- * The declaration of 'base class' for all URI scheme.
- */
-struct pjsip_uri
-{
-    /** All URIs must have URI virtual function table as their first member. */
-    pjsip_uri_vptr *vptr;
-};
-
-/**
- * This macro checks that the URL is a "sip:" or "sips:" URL.
- * @param url The URL (pointer to)
- * @return non-zero if TRUE.
- */
-#define PJSIP_URI_SCHEME_IS_SIP(url)	\
-    (pj_strnicmp2(pjsip_uri_get_scheme(url), "sip", 3)==0)
-
-/**
- * This macro checks that the URL is a "sips:" URL (not SIP).
- * @param url The URL (pointer to)
- * @return non-zero if TRUE.
- */
-#define PJSIP_URI_SCHEME_IS_SIPS(url)	\
-    (pj_strnicmp2(pjsip_uri_get_scheme(url), "sips", 4)==0)
-
-/**
- * This macro checks that the URL is a "tel:" URL.
- * @param url The URL (pointer to)
- * @return non-zero if TRUE.
- */
-#define PJSIP_URI_SCHEME_IS_TEL(url)	\
-    (pj_strnicmp2(pjsip_uri_get_scheme(url), "tel", 3)==0)
-
-
-
-/**
- * SIP and SIPS URL scheme.
- */
-typedef struct pjsip_url
-{
-    pjsip_uri_vptr *vptr;		/**< Pointer to virtual function table.*/
-    pj_str_t	    user;		/**< Optional user part. */
-    pj_str_t	    passwd;		/**< Optional password part. */
-    pj_str_t	    host;		/**< Host part, always exists. */
-    int		    port;		/**< Optional port number, or zero. */
-    pj_str_t	    user_param;		/**< Optional user parameter */
-    pj_str_t	    method_param;	/**< Optional method parameter. */
-    pj_str_t	    transport_param;	/**< Optional transport parameter. */
-    int		    ttl_param;		/**< Optional TTL param, or -1. */
-    int		    lr_param;		/**< Optional loose routing param, or zero */
-    pj_str_t	    maddr_param;	/**< Optional maddr param */
-    pj_str_t	    other_param;	/**< Other parameters grouped together. */
-    pj_str_t	    header_param;	/**< Optional header parameter. */
-} pjsip_url;
-
-
-/**
- * SIP name-addr, which typically appear in From, To, and Contact header.
- * The SIP name-addr contains a generic URI and a display name.
- */
-typedef struct pjsip_name_addr
-{
-    /** Pointer to virtual function table. */
-    pjsip_uri_vptr  *vptr;
-
-    /** Optional display name. */
-    pj_str_t	     display;
-
-    /** URI part. */
-    pjsip_uri	    *uri;
-
-} pjsip_name_addr;
-
-
-/**
- * Generic function to get the URI scheme.
- * @param uri	    the URI object.
- * @return	    the URI scheme.
- */
-PJ_INLINE(const pj_str_t*) pjsip_uri_get_scheme(const void *uri)
-{
-    return (*((pjsip_uri*)uri)->vptr->p_get_scheme)(uri);
-}
-
-/**
- * Generic function to get the URI object contained by this URI, or the URI 
- * itself if it doesn't contain another URI.
- *
- * @param uri	    the URI.
- * @return	    the URI.
- */
-PJ_INLINE(void*) pjsip_uri_get_uri(void *uri)
-{
-    return (*((pjsip_uri*)uri)->vptr->p_get_uri)(uri);
-}
-
-/**
- * Generic function to compare two URIs.
- *
- * @param context   Comparison context.
- * @param uri1	    The first URI.
- * @param uri2	    The second URI.
- * @return	    Zero if equal.
- */
-PJ_INLINE(int) pjsip_uri_cmp(pjsip_uri_context_e context, 
-			     const void *uri1, const void *uri2)
-{
-    return (*((const pjsip_uri*)uri1)->vptr->p_compare)(context, uri1, uri2);
-}
-
-/**
- * Generic function to print an URI object.
- *
- * @param context   Print context.
- * @param uri	    The URI to print.
- * @param buf	    The buffer.
- * @param size	    Size of the buffer.
- * @return	    Length printed.
- */
-PJ_INLINE(int) pjsip_uri_print(pjsip_uri_context_e context,
-			       const void *uri,
-			       char *buf, pj_size_t size)
-{
-    return (*((const pjsip_uri*)uri)->vptr->p_print)(context, uri, buf, size);
-}
-
-/**
- * Generic function to clone an URI object.
- *
- * @param pool	    Pool.
- * @param uri	    URI to clone.
- * @return	    New URI.
- */
-PJ_INLINE(void*) pjsip_uri_clone( pj_pool_t *pool, const void *uri )
-{
-    return (*((const pjsip_uri*)uri)->vptr->p_clone)(pool, uri);
-}
-
-
-/**
- * Create new SIP URL and initialize all fields with zero or NULL.
- * @param pool	    The pool.
- * @param secure    Tlag to indicate whether secure transport should be used.
- * @return SIP URL.
- */
-PJ_DECL(pjsip_url*) pjsip_url_create( pj_pool_t *pool, int secure );
-
-/**
- * Create new SIPS URL and initialize all fields with zero or NULL.
- * @param pool	    The pool.
- * @return	    SIPS URL.
- */
-PJ_DECL(pjsip_url*) pjsips_url_create( pj_pool_t *pool );
-
-/**
- * Initialize SIP URL (all fields are set to NULL or zero).
- * @param url	    The URL.
- */
-PJ_DECL(void)  pjsip_url_init(pjsip_url *url, int secure);
-
-/**
- * Perform full assignment to the SIP URL.
- * @param pool	    The pool.
- * @param url	    Destination URL.
- * @param rhs	    The source URL.
- */
-PJ_DECL(void)  pjsip_url_assign(pj_pool_t *pool, pjsip_url *url, const pjsip_url *rhs);
-
-/**
- * Create new instance of name address and initialize all fields with zero or
- * NULL.
- * @param pool	    The pool.
- * @return	    New SIP name address.
- */
-PJ_DECL(pjsip_name_addr*) pjsip_name_addr_create(pj_pool_t *pool);
-
-/**
- * Initialize with default value.
- * @param name_addr The name address.
- */
-PJ_DECL(void) pjsip_name_addr_init(pjsip_name_addr *name_addr);
-
-/**
- * Perform full assignment to the name address.
- * @param pool	    The pool.
- * @param addr	    The destination name address.
- * @param rhs	    The source name address.
- */
-PJ_DECL(void)  pjsip_name_addr_assign(pj_pool_t *pool, 
-				      pjsip_name_addr *addr, 
-				      const pjsip_name_addr *rhs);
-
-
-
-
-/**
- * @}
- */
-
-PJ_END_DECL
-
-#endif	/* __PJSIP_URL_H__ */
-
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_SIP_URI_H__

+#define __PJSIP_SIP_URI_H__

+

+/**

+ * @file sip_uri.h

+ * @brief SIP URL Structures and Manipulations

+ */

+

+#include <pjsip/sip_types.h>

+#include <pjsip/sip_config.h>

+

+PJ_BEGIN_DECL

+

+

+/**

+ * @defgroup PJSIP_URL URL Structures

+ * @brief SIP Url, tel: Url, and generic URI.

+ * @ingroup PJSIP_MSG

+ * @{

+ */

+

+/**

+ * URI context.

+ */

+typedef enum pjsip_uri_context_e

+{

+    PJSIP_URI_IN_REQ_URI,	/**< The URI is in Request URI. */

+    PJSIP_URI_IN_FROMTO_HDR,	/**< The URI is in From/To header. */

+    PJSIP_URI_IN_CONTACT_HDR,	/**< The URI is in Contact header. */

+    PJSIP_URI_IN_ROUTING_HDR,	/**< The URI is in Route/Record-Route header. */

+    PJSIP_URI_IN_OTHER,		/**< Other context (web page, business card, etc.) */

+} pjsip_uri_context_e;

+

+/**

+ * URI 'virtual' function table.

+ * All types of URI in this library (such as sip:, sips:, tel:, and name-addr) 

+ * will have pointer to this table as their first struct member. This table

+ * provides polimorphic behaviour to the URI.

+ */

+typedef struct pjsip_uri_vptr

+{

+    /** 

+     * Get URI scheme. 

+     * @param uri the URI (self).

+     * @return the URI scheme.

+     */

+    const pj_str_t* (*p_get_scheme)(const void *uri);

+

+    /**

+     * Get the URI object contained by this URI, or the URI itself if

+     * it doesn't contain another URI.

+     * @param uri the URI (self).

+     */

+    void* (*p_get_uri)(void *uri);

+

+    /**

+     * Print URI components to the buffer, following the rule of which 

+     * components are allowed for the context.

+     * @param context the context where the URI will be placed.

+     * @param uri the URI (self).

+     * @param buf the buffer.

+     * @param size the size of the buffer.

+     * @return the length printed.

+     */

+    int	(*p_print)(pjsip_uri_context_e context,

+		   const void *uri, 

+		   char *buf, pj_size_t size);

+

+    /** 

+     * Compare two URIs according to the context.

+     * @param context the context.

+     * @param uri1 the first URI (self).

+     * @param uri2 the second URI.

+     * @return zero if equal.

+     */

+    int	(*p_compare)(pjsip_uri_context_e context, 

+		     const void *uri1, const void *uri2);

+

+    /** 

+     * Clone URI. 

+     * @param pool the pool.

+     * @param the URI to clone (self).

+     * @return new URI.

+     */

+    void *(*p_clone)(pj_pool_t *pool, const void *uri);

+

+} pjsip_uri_vptr;

+

+

+/**

+ * The declaration of 'base class' for all URI scheme.

+ */

+struct pjsip_uri

+{

+    /** All URIs must have URI virtual function table as their first member. */

+    pjsip_uri_vptr *vptr;

+};

+

+/**

+ * This macro checks that the URL is a "sip:" or "sips:" URL.

+ * @param url The URL (pointer to)

+ * @return non-zero if TRUE.

+ */

+#define PJSIP_URI_SCHEME_IS_SIP(url)	\

+    (pj_strnicmp2(pjsip_uri_get_scheme(url), "sip", 3)==0)

+

+/**

+ * This macro checks that the URL is a "sips:" URL (not SIP).

+ * @param url The URL (pointer to)

+ * @return non-zero if TRUE.

+ */

+#define PJSIP_URI_SCHEME_IS_SIPS(url)	\

+    (pj_strnicmp2(pjsip_uri_get_scheme(url), "sips", 4)==0)

+

+/**

+ * This macro checks that the URL is a "tel:" URL.

+ * @param url The URL (pointer to)

+ * @return non-zero if TRUE.

+ */

+#define PJSIP_URI_SCHEME_IS_TEL(url)	\

+    (pj_strnicmp2(pjsip_uri_get_scheme(url), "tel", 3)==0)

+

+

+

+/**

+ * SIP and SIPS URL scheme.

+ */

+typedef struct pjsip_url

+{

+    pjsip_uri_vptr *vptr;		/**< Pointer to virtual function table.*/

+    pj_str_t	    user;		/**< Optional user part. */

+    pj_str_t	    passwd;		/**< Optional password part. */

+    pj_str_t	    host;		/**< Host part, always exists. */

+    int		    port;		/**< Optional port number, or zero. */

+    pj_str_t	    user_param;		/**< Optional user parameter */

+    pj_str_t	    method_param;	/**< Optional method parameter. */

+    pj_str_t	    transport_param;	/**< Optional transport parameter. */

+    int		    ttl_param;		/**< Optional TTL param, or -1. */

+    int		    lr_param;		/**< Optional loose routing param, or zero */

+    pj_str_t	    maddr_param;	/**< Optional maddr param */

+    pj_str_t	    other_param;	/**< Other parameters grouped together. */

+    pj_str_t	    header_param;	/**< Optional header parameter. */

+} pjsip_url;

+

+

+/**

+ * SIP name-addr, which typically appear in From, To, and Contact header.

+ * The SIP name-addr contains a generic URI and a display name.

+ */

+typedef struct pjsip_name_addr

+{

+    /** Pointer to virtual function table. */

+    pjsip_uri_vptr  *vptr;

+

+    /** Optional display name. */

+    pj_str_t	     display;

+

+    /** URI part. */

+    pjsip_uri	    *uri;

+

+} pjsip_name_addr;

+

+

+/**

+ * Generic function to get the URI scheme.

+ * @param uri	    the URI object.

+ * @return	    the URI scheme.

+ */

+PJ_INLINE(const pj_str_t*) pjsip_uri_get_scheme(const void *uri)

+{

+    return (*((pjsip_uri*)uri)->vptr->p_get_scheme)(uri);

+}

+

+/**

+ * Generic function to get the URI object contained by this URI, or the URI 

+ * itself if it doesn't contain another URI.

+ *

+ * @param uri	    the URI.

+ * @return	    the URI.

+ */

+PJ_INLINE(void*) pjsip_uri_get_uri(void *uri)

+{

+    return (*((pjsip_uri*)uri)->vptr->p_get_uri)(uri);

+}

+

+/**

+ * Generic function to compare two URIs.

+ *

+ * @param context   Comparison context.

+ * @param uri1	    The first URI.

+ * @param uri2	    The second URI.

+ * @return	    Zero if equal.

+ */

+PJ_INLINE(int) pjsip_uri_cmp(pjsip_uri_context_e context, 

+			     const void *uri1, const void *uri2)

+{

+    return (*((const pjsip_uri*)uri1)->vptr->p_compare)(context, uri1, uri2);

+}

+

+/**

+ * Generic function to print an URI object.

+ *

+ * @param context   Print context.

+ * @param uri	    The URI to print.

+ * @param buf	    The buffer.

+ * @param size	    Size of the buffer.

+ * @return	    Length printed.

+ */

+PJ_INLINE(int) pjsip_uri_print(pjsip_uri_context_e context,

+			       const void *uri,

+			       char *buf, pj_size_t size)

+{

+    return (*((const pjsip_uri*)uri)->vptr->p_print)(context, uri, buf, size);

+}

+

+/**

+ * Generic function to clone an URI object.

+ *

+ * @param pool	    Pool.

+ * @param uri	    URI to clone.

+ * @return	    New URI.

+ */

+PJ_INLINE(void*) pjsip_uri_clone( pj_pool_t *pool, const void *uri )

+{

+    return (*((const pjsip_uri*)uri)->vptr->p_clone)(pool, uri);

+}

+

+

+/**

+ * Create new SIP URL and initialize all fields with zero or NULL.

+ * @param pool	    The pool.

+ * @param secure    Tlag to indicate whether secure transport should be used.

+ * @return SIP URL.

+ */

+PJ_DECL(pjsip_url*) pjsip_url_create( pj_pool_t *pool, int secure );

+

+/**

+ * Create new SIPS URL and initialize all fields with zero or NULL.

+ * @param pool	    The pool.

+ * @return	    SIPS URL.

+ */

+PJ_DECL(pjsip_url*) pjsips_url_create( pj_pool_t *pool );

+

+/**

+ * Initialize SIP URL (all fields are set to NULL or zero).

+ * @param url	    The URL.

+ */

+PJ_DECL(void)  pjsip_url_init(pjsip_url *url, int secure);

+

+/**

+ * Perform full assignment to the SIP URL.

+ * @param pool	    The pool.

+ * @param url	    Destination URL.

+ * @param rhs	    The source URL.

+ */

+PJ_DECL(void)  pjsip_url_assign(pj_pool_t *pool, pjsip_url *url, const pjsip_url *rhs);

+

+/**

+ * Create new instance of name address and initialize all fields with zero or

+ * NULL.

+ * @param pool	    The pool.

+ * @return	    New SIP name address.

+ */

+PJ_DECL(pjsip_name_addr*) pjsip_name_addr_create(pj_pool_t *pool);

+

+/**

+ * Initialize with default value.

+ * @param name_addr The name address.

+ */

+PJ_DECL(void) pjsip_name_addr_init(pjsip_name_addr *name_addr);

+

+/**

+ * Perform full assignment to the name address.

+ * @param pool	    The pool.

+ * @param addr	    The destination name address.

+ * @param rhs	    The source name address.

+ */

+PJ_DECL(void)  pjsip_name_addr_assign(pj_pool_t *pool, 

+				      pjsip_name_addr *addr, 

+				      const pjsip_name_addr *rhs);

+

+

+

+

+/**

+ * @}

+ */

+

+PJ_END_DECL

+

+#endif	/* __PJSIP_URL_H__ */

+

diff --git a/pjsip/include/pjsip_auth.h b/pjsip/include/pjsip_auth.h
index 9c0d33b..a538bb9 100644
--- a/pjsip/include/pjsip_auth.h
+++ b/pjsip/include/pjsip_auth.h
@@ -1,22 +1,44 @@
-/* $Id$
- *
- */
-#ifndef __PJSIP_AUTH_H__
-#define __PJSIP_AUTH_H__
-
-/**
- * @defgroup PJSIP_AUTH SIP Authorization module
- */
-
-/**
- * @file pjsip_auth.h
- * @brief SIP Authorization Module.
- */
-
-
-#include <pjsip_auth/sip_auth.h>
-#include <pjsip_auth/sip_auth_msg.h>
-#include <pjsip_auth/sip_auth_parser.h>
-
-#endif	/* __PJSIP_AUTH_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_AUTH_H__

+#define __PJSIP_AUTH_H__

+

+/**

+ * @defgroup PJSIP_AUTH SIP Authorization module

+ */

+

+/**

+ * @file pjsip_auth.h

+ * @brief SIP Authorization Module.

+ */

+

+

+#include <pjsip_auth/sip_auth.h>

+#include <pjsip_auth/sip_auth_msg.h>

+#include <pjsip_auth/sip_auth_parser.h>

+

+#endif	/* __PJSIP_AUTH_H__ */

+

diff --git a/pjsip/include/pjsip_core.h b/pjsip/include/pjsip_core.h
index 96b3948..8b4f6b9 100644
--- a/pjsip/include/pjsip_core.h
+++ b/pjsip/include/pjsip_core.h
@@ -1,20 +1,42 @@
-/* $Id$
- */
-#ifndef __PJSIP_CORE_H__
-#define __PJSIP_CORE_H__
-
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_misc.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_parser.h>
-#include <pjsip/sip_resolve.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_auth.h>
-
-#endif	/* __PJSIP_CORE_H__ */
-
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#ifndef __PJSIP_CORE_H__

+#define __PJSIP_CORE_H__

+

+#include <pjsip/sip_types.h>

+#include <pjsip/sip_endpoint.h>

+#include <pjsip/sip_event.h>

+#include <pjsip/sip_misc.h>

+#include <pjsip/sip_module.h>

+#include <pjsip/sip_msg.h>

+#include <pjsip/sip_parser.h>

+#include <pjsip/sip_resolve.h>

+#include <pjsip/sip_transaction.h>

+#include <pjsip/sip_transport.h>

+#include <pjsip/sip_uri.h>

+#include <pjsip/sip_auth.h>

+

+#endif	/* __PJSIP_CORE_H__ */

+

diff --git a/pjsip/include/pjsip_simple.h b/pjsip/include/pjsip_simple.h
index 3ede039..15c2001 100644
--- a/pjsip/include/pjsip_simple.h
+++ b/pjsip/include/pjsip_simple.h
@@ -1,26 +1,48 @@
-/* $Id$
- *
- */
-
-/**
- * @defgroup PJSIP_SIMPLE SIP Event, Instant Messaging and Presence Extension (SIMPLE)
- */
-
-/**
- * @file pjsip_simple.h
- * @brief SIP SIMPLE Extension
- */
-
-/*
- * Include this header file to get all functionalities for SIMPLE extension
- * (SIP for Instant Messaging and Presence Leveraging Extension).
- */
-#ifndef __PJSIP_SIMPLE_H__
-#define __PJSIP_SIMPLE_H__
-
-#include <pjsip_simple/messaging.h>
-#include <pjsip_simple/event_notify.h>
-#include <pjsip_simple/pidf.h>
-#include <pjsip_simple/presence.h>
-
-#endif	/* __PJSIP_SIMPLE_H__ */
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+

+/**

+ * @defgroup PJSIP_SIMPLE SIP Event, Instant Messaging and Presence Extension (SIMPLE)

+ */

+

+/**

+ * @file pjsip_simple.h

+ * @brief SIP SIMPLE Extension

+ */

+

+/*

+ * Include this header file to get all functionalities for SIMPLE extension

+ * (SIP for Instant Messaging and Presence Leveraging Extension).

+ */

+#ifndef __PJSIP_SIMPLE_H__

+#define __PJSIP_SIMPLE_H__

+

+#include <pjsip_simple/messaging.h>

+#include <pjsip_simple/event_notify.h>

+#include <pjsip_simple/pidf.h>

+#include <pjsip_simple/presence.h>

+

+#endif	/* __PJSIP_SIMPLE_H__ */

diff --git a/pjsip/include/pjsip_ua.h b/pjsip/include/pjsip_ua.h
index 883faa5..a8facd2 100644
--- a/pjsip/include/pjsip_ua.h
+++ b/pjsip/include/pjsip_ua.h
@@ -1,13 +1,35 @@
-/* $Id$
- *
- */
-
-#ifndef __PJSIP_UA_H__
-#define __PJSIP_UA_H__
-
-#include <pjsip_mod_ua/sip_dialog.h>
-#include <pjsip_mod_ua/sip_reg.h>
-#include <pjsip_mod_ua/sip_ua.h>
-
-#endif	/* __PJSIP_UA_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+

+#ifndef __PJSIP_UA_H__

+#define __PJSIP_UA_H__

+

+#include <pjsip_mod_ua/sip_dialog.h>

+#include <pjsip_mod_ua/sip_reg.h>

+#include <pjsip_mod_ua/sip_ua.h>

+

+#endif	/* __PJSIP_UA_H__ */

+

diff --git a/pjsip/src/pjsip-simple/event_notify.c b/pjsip/src/pjsip-simple/event_notify.c
index 24aa68a..42d8503 100644
--- a/pjsip/src/pjsip-simple/event_notify.c
+++ b/pjsip/src/pjsip-simple/event_notify.c
@@ -1,1629 +1,1651 @@
-/* $Id$
- *
- */
-#include <pjsip_simple/event_notify.h>
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_misc.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_event.h>
-#include <pj/pool.h>
-#include <pj/timer.h>
-#include <pj/string.h>
-#include <pj/hash.h>
-#include <pj/os.h>
-#include <pj/except.h>
-#include <pj/log.h>
-#include <pj/guid.h>
-
-#define THIS_FILE		"event_sub"
-
-/* String names for state. 
- * The names here should be compliant with sub_state names in RFC3265.
- */
-static const pj_str_t state[] = {
-    { "null", 4 }, 
-    { "active", 6 },
-    { "pending", 7 },
-    { "terminated", 10 },
-    { "unknown", 7 }
-};
-
-/* Timer IDs */
-#define TIMER_ID_REFRESH	1
-#define TIMER_ID_UAS_EXPIRY	2
-
-/* Static configuration. */
-#define SECONDS_BEFORE_EXPIRY	10
-#define MGR_POOL_SIZE		512
-#define MGR_POOL_INC		0
-#define SUB_POOL_SIZE		2048
-#define SUB_POOL_INC		0
-#define HASH_TABLE_SIZE		32
-
-/* Static vars. */
-static int mod_id;
-static const pjsip_method SUBSCRIBE = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 9}};
-static const pjsip_method NOTIFY = { PJSIP_OTHER_METHOD, { "NOTIFY", 6}};
-
-typedef struct package
-{
-    PJ_DECL_LIST_MEMBER(struct package)
-    pj_str_t		    event;
-    int			    accept_cnt;
-    pj_str_t		   *accept;
-    pjsip_event_sub_pkg_cb  cb;
-} package;
-
-/* Event subscription manager singleton instance. */
-static struct pjsip_event_sub_mgr
-{
-    pj_pool_t		    *pool;
-    pj_hash_table_t	    *ht;
-    pjsip_endpoint	    *endpt;
-    pj_mutex_t		    *mutex;
-    pjsip_allow_events_hdr  *allow_events;
-    package		     pkg_list;
-} mgr;
-
-/* Fordward declarations for static functions. */
-static pj_status_t	mod_init(pjsip_endpoint *, pjsip_module *, pj_uint32_t);
-static pj_status_t	mod_deinit(pjsip_module*);
-static void		tsx_handler(pjsip_module*, pjsip_event*);
-static pjsip_event_sub *find_sub(pjsip_rx_data *);
-static void		on_subscribe_request(pjsip_transaction*, pjsip_rx_data*);
-static void		on_subscribe_response(void *, pjsip_event*);
-static void		on_notify_request(pjsip_transaction *, pjsip_rx_data*);
-static void		on_notify_response(void *, pjsip_event *);
-static void		refresh_timer_cb(pj_timer_heap_t*, pj_timer_entry*);
-static void		uas_expire_timer_cb(pj_timer_heap_t*, pj_timer_entry*);
-static pj_status_t	send_sub_refresh( pjsip_event_sub *sub );
-
-/* Module descriptor. */
-static pjsip_module event_sub_module = 
-{
-    {"EventSub", 8},			/* Name.		*/
-    0,					/* Flag			*/
-    128,				/* Priority		*/
-    &mgr,				/* User data.		*/
-    2,					/* Number of methods supported . */
-    { &SUBSCRIBE, &NOTIFY },		/* Array of methods */
-    &mod_init,				/* init_module()	*/
-    NULL,				/* start_module()	*/
-    &mod_deinit,			/* deinit_module()	*/
-    &tsx_handler,			/* tsx_handler()	*/
-};
-
-/*
- * Module initialization.
- * This will be called by endpoint when it initializes all modules.
- */
-static pj_status_t mod_init( pjsip_endpoint *endpt,
-			     struct pjsip_module *mod, pj_uint32_t id )
-{
-    pj_pool_t *pool;
-
-    pool = pjsip_endpt_create_pool(endpt, "esubmgr", MGR_POOL_SIZE, MGR_POOL_INC);
-    if (!pool)
-	return -1;
-
-    /* Manager initialization: create hash table and mutex. */
-    mgr.pool = pool;
-    mgr.endpt = endpt;
-    mgr.ht = pj_hash_create(pool, HASH_TABLE_SIZE);
-    if (!mgr.ht)
-	return -1;
-
-    mgr.mutex = pj_mutex_create(pool, "esubmgr", PJ_MUTEX_SIMPLE);
-    if (!mgr.mutex)
-	return -1;
-
-    /* Attach manager to module. */
-    mod->mod_data = &mgr;
-
-    /* Init package list. */
-    pj_list_init(&mgr.pkg_list);
-
-    /* Init Allow-Events header. */
-    mgr.allow_events = pjsip_allow_events_hdr_create(mgr.pool);
-
-    /* Save the module ID. */
-    mod_id = id;
-
-    pjsip_event_notify_init_parser();
-    return 0;
-}
-
-/*
- * Module deinitialization.
- * Called by endpoint.
- */
-static pj_status_t mod_deinit( struct pjsip_module *mod )
-{
-    pj_mutex_lock(mgr.mutex);
-    pj_mutex_destroy(mgr.mutex);
-    pjsip_endpt_destroy_pool(mgr.endpt, mgr.pool);
-    return 0;
-}
-
-/*
- * This public function is called by application to register callback.
- * In exchange, the instance of the module is returned.
- */
-PJ_DEF(pjsip_module*) pjsip_event_sub_get_module(void)
-{
-    return &event_sub_module;
-}
-
-/*
- * Register event package.
- */
-PJ_DEF(pj_status_t) pjsip_event_sub_register_pkg( const pj_str_t *event,
-						  int accept_cnt,
-						  const pj_str_t accept[],
-						  const pjsip_event_sub_pkg_cb *cb )
-{
-    package *pkg;
-    int i;
-
-    pj_mutex_lock(mgr.mutex);
-
-    /* Create and register new package. */
-    pkg = pj_pool_alloc(mgr.pool, sizeof(*pkg));
-    pj_strdup(mgr.pool, &pkg->event, event);
-    pj_list_insert_before(&mgr.pkg_list, pkg);
-
-    /* Save Accept specification. */
-    pkg->accept_cnt = accept_cnt;
-    pkg->accept = pj_pool_alloc(mgr.pool, accept_cnt*sizeof(pj_str_t));
-    for (i=0; i<accept_cnt; ++i) {
-	pj_strdup(mgr.pool, &pkg->accept[i], &accept[i]);
-    }
-
-    /* Copy callback. */
-    pj_memcpy(&pkg->cb, cb, sizeof(*cb));
-
-    /* Update Allow-Events header. */
-    pj_assert(mgr.allow_events->event_cnt < PJSIP_MAX_ALLOW_EVENTS);
-    mgr.allow_events->events[mgr.allow_events->event_cnt++] = pkg->event;
-
-    pj_mutex_unlock(mgr.mutex);
-    return 0;
-}
-
-/*
- * Create subscription key (for hash table).
- */
-static void create_subscriber_key( pj_str_t *key, pj_pool_t *pool,
-				   pjsip_role_e role, 
-				   const pj_str_t *call_id, const pj_str_t *from_tag)
-{
-    char *p;
-
-    p = key->ptr = pj_pool_alloc(pool, call_id->slen + from_tag->slen + 3);
-    *p++ = (role == PJSIP_ROLE_UAS ? 'S' : 'C');
-    *p++ = '$';
-    pj_memcpy(p, call_id->ptr, call_id->slen);
-    p += call_id->slen;
-    *p++ = '$';
-    pj_memcpy(p, from_tag->ptr, from_tag->slen);
-    p += from_tag->slen;
-
-    key->slen = p - key->ptr;
-}
-
-
-/*
- * Create UAC subscription.
- */
-PJ_DEF(pjsip_event_sub*) pjsip_event_sub_create( pjsip_endpoint *endpt,
-						 const pj_str_t *from,
-						 const pj_str_t *to,
-						 const pj_str_t *event,
-						 int expires,
-						 int accept_cnt,
-						 const pj_str_t accept[],
-						 void *user_data,
-						 const pjsip_event_sub_cb *cb)
-{
-    pjsip_tx_data *tdata;
-    pj_pool_t *pool;
-    const pjsip_hdr *hdr;
-    pjsip_event_sub *sub;
-    PJ_USE_EXCEPTION;
-
-    PJ_LOG(5,(THIS_FILE, "Creating event subscription %.*s to %.*s",
-			 event->slen, event->ptr, to->slen, to->ptr));
-
-    /* Create pool for the event subscription. */
-    pool = pjsip_endpt_create_pool(endpt, "esub", SUB_POOL_SIZE, SUB_POOL_INC);
-    if (!pool) {
-	return NULL;
-    }
-
-    /* Init subscription. */
-    sub = pj_pool_calloc(pool, 1, sizeof(*sub));
-    sub->pool = pool;
-    sub->endpt = endpt;
-    sub->role = PJSIP_ROLE_UAC;
-    sub->state = PJSIP_EVENT_SUB_STATE_PENDING;
-    sub->state_str = state[sub->state];
-    sub->user_data = user_data;
-    sub->timer.id = 0;
-    sub->default_interval = expires;
-    pj_memcpy(&sub->cb, cb, sizeof(*cb));
-    pj_list_init(&sub->auth_sess);
-    pj_list_init(&sub->route_set);
-    sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE);
-    if (!sub->mutex) {
-	pjsip_endpt_destroy_pool(endpt, pool);
-	return NULL;
-    }
-
-    /* The easiest way to parse the parameters is to create a dummy request! */
-    tdata = pjsip_endpt_create_request( endpt, &SUBSCRIBE, to, from, to, from,
-					NULL, -1, NULL);
-    if (!tdata) {
-	pj_mutex_destroy(sub->mutex);
-	pjsip_endpt_destroy_pool(endpt, pool);
-	return NULL;
-    }
-
-    /* 
-     * Duplicate headers in the request to our structure. 
-     */
-    PJ_TRY {
-	int i;
-
-	/* From */
-	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL);
-	pj_assert(hdr != NULL);
-	sub->from = pjsip_hdr_clone(pool, hdr);
-        
-	/* To */
-	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL);
-	pj_assert(hdr != NULL);
-	sub->to = pjsip_hdr_clone(pool, hdr);
-
-	/* Contact. */
-	sub->contact = pjsip_contact_hdr_create(pool);
-	sub->contact->uri = sub->from->uri;
-
-	/* Call-ID */
-	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CALL_ID, NULL);
-	pj_assert(hdr != NULL);
-	sub->call_id = pjsip_hdr_clone(pool, hdr);
-
-	/* CSeq */
-	sub->cseq = pj_rand() % 0xFFFF;
-
-	/* Event. */
-	sub->event = pjsip_event_hdr_create(sub->pool);
-	pj_strdup(pool, &sub->event->event_type, event);
-
-	/* Expires. */
-	sub->uac_expires = pjsip_expires_hdr_create(pool);
-	sub->uac_expires->ivalue = expires;
-
-	/* Accept. */
-	sub->local_accept = pjsip_accept_hdr_create(pool);
-	for (i=0; i<accept_cnt && i < PJSIP_MAX_ACCEPT_COUNT; ++i) {
-	    sub->local_accept->count++;
-	    pj_strdup(sub->pool, &sub->local_accept->values[i], &accept[i]);
-	}
-
-	/* Register to hash table. */
-	create_subscriber_key( &sub->key, pool, PJSIP_ROLE_UAC, 
-			       &sub->call_id->id, &sub->from->tag);
-	pj_mutex_lock( mgr.mutex );
-	pj_hash_set( pool, mgr.ht, sub->key.ptr, sub->key.slen, sub);
-	pj_mutex_unlock( mgr.mutex );
-
-    }
-    PJ_DEFAULT {
-	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): caught exception %d during init", 
-			     sub, state[sub->state].ptr, PJ_GET_EXCEPTION()));
-
-	pjsip_tx_data_dec_ref(tdata);
-	pj_mutex_destroy(sub->mutex);
-	pjsip_endpt_destroy_pool(endpt, sub->pool);
-	return NULL;
-    }
-    PJ_END;
-
-    /* All set, delete temporary transmit data as we don't need it. */
-    pjsip_tx_data_dec_ref(tdata);
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): client created, target=%.*s, event=%.*s",
-			 sub, state[sub->state].ptr,
-			 to->slen, to->ptr, event->slen, event->ptr));
-
-    return sub;
-}
-
-/*
- * Set credentials.
- */
-PJ_DEF(pj_status_t) pjsip_event_sub_set_credentials( pjsip_event_sub *sub,
-						     int count,
-						     const pjsip_cred_info cred[])
-{
-    pj_mutex_lock(sub->mutex);
-    if (count > 0) {
-	sub->cred_info = pj_pool_alloc(sub->pool, count*sizeof(pjsip_cred_info));
-	pj_memcpy( sub->cred_info, cred, count*sizeof(pjsip_cred_info));
-    }
-    sub->cred_cnt = count;
-    pj_mutex_unlock(sub->mutex);
-    return 0;
-}
-
-/*
- * Set route-set.
- */
-PJ_DEF(pj_status_t) pjsip_event_sub_set_route_set( pjsip_event_sub *sub,
-						   const pjsip_route_hdr *route_set )
-{
-    const pjsip_route_hdr *hdr;
-
-    pj_mutex_lock(sub->mutex);
-
-    /* Clear existing route set. */
-    pj_list_init(&sub->route_set);
-
-    /* Duplicate route headers. */
-    hdr = route_set->next;
-    while (hdr != route_set) {
-	pjsip_route_hdr *new_hdr = pjsip_hdr_clone(sub->pool, hdr);
-	pj_list_insert_before(&sub->route_set, new_hdr);
-	hdr = hdr->next;
-    }
-
-    pj_mutex_unlock(sub->mutex);
-
-    return 0;
-}
-
-/*
- * Send subscribe request.
- */
-PJ_DEF(pj_status_t) pjsip_event_sub_subscribe( pjsip_event_sub *sub )
-{
-    pj_status_t status;
-
-    pj_mutex_lock(sub->mutex);
-    status = send_sub_refresh(sub);
-    pj_mutex_unlock(sub->mutex);
-
-    return status;
-}
-
-/*
- * Destroy subscription.
- * If there are pending transactions, then this will just set the flag.
- */
-PJ_DEF(pj_status_t) pjsip_event_sub_destroy(pjsip_event_sub *sub)
-{
-    pj_assert(sub != NULL);
-    if (sub == NULL)
-	return -1;
-
-    /* Application must terminate the subscription first. */
-    pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_NULL ||
-	      sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED);
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): about to be destroyed", 
-			 sub, state[sub->state].ptr));
-
-    pj_mutex_lock(mgr.mutex);
-    pj_mutex_lock(sub->mutex);
-
-    /* Set delete flag. */
-    sub->delete_flag = 1;
-
-    /* Unregister timer, if any. */
-    if (sub->timer.id != 0) {
-	pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);
-	sub->timer.id = 0;
-    }
-
-    if (sub->pending_tsx > 0) {
-	pj_mutex_unlock(sub->mutex);
-	pj_mutex_unlock(mgr.mutex);
-	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): has %d pending, will destroy later",
-			     sub, state[sub->state].ptr,
-			     sub->pending_tsx));
-	return 1;
-    }
-
-    /* Unregister from hash table. */
-    pj_hash_set(sub->pool, mgr.ht, sub->key.ptr, sub->key.slen, NULL);
-
-    /* Destroy. */
-    pj_mutex_destroy(sub->mutex);
-    pjsip_endpt_destroy_pool(sub->endpt, sub->pool);
-
-    pj_mutex_unlock(mgr.mutex);
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p: destroyed", sub));
-    return 0;
-}
-
-/* Change state. */
-static void sub_set_state( pjsip_event_sub *sub, int new_state)
-{
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): changed state to %s",
-	      sub, state[sub->state].ptr, state[new_state].ptr));
-    sub->state = new_state;
-    sub->state_str = state[new_state];
-}
-
-/*
- * Refresh subscription.
- */
-static pj_status_t send_sub_refresh( pjsip_event_sub *sub )
-{
-    pjsip_tx_data *tdata;
-    pj_status_t status;
-    const pjsip_route_hdr *route;
-
-    pj_assert(sub->role == PJSIP_ROLE_UAC);
-    pj_assert(sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED);
-    if (sub->role != PJSIP_ROLE_UAC || 
-	sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED)
-    {
-	return -1;
-    }
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refreshing subscription", 
-			 sub, state[sub->state].ptr));
-
-    /* Create request. */
-    tdata = pjsip_endpt_create_request_from_hdr( sub->endpt, 
-						 &SUBSCRIBE,
-						 sub->to->uri,
-						 sub->from, sub->to, 
-						 sub->contact, sub->call_id,
-						 sub->cseq++,
-						 NULL);
-
-    if (!tdata) {
-	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refresh: unable to create tx data!",
-			     sub, state[sub->state].ptr));
-	return -1;
-    }
-
-    pjsip_msg_add_hdr( tdata->msg, 
-		       pjsip_hdr_shallow_clone(tdata->pool, sub->event));
-    pjsip_msg_add_hdr( tdata->msg, 
-		       pjsip_hdr_shallow_clone(tdata->pool, sub->uac_expires));
-    pjsip_msg_add_hdr( tdata->msg, 
-		       pjsip_hdr_shallow_clone(tdata->pool, sub->local_accept));
-    pjsip_msg_add_hdr( tdata->msg, 
-		       pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events));
-
-    /* Authentication */
-    pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess,
-			 sub->cred_cnt, sub->cred_info);
-
-    /* Route set. */
-    route = sub->route_set.next;
-    while (route != &sub->route_set) {
-	pj_list_insert_before( &tdata->msg->hdr,
-			       pjsip_hdr_shallow_clone(tdata->pool, route));
-	route = route->next;
-    }
-
-    /* Send */
-    status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, 
-				       &on_subscribe_response);
-    if (status == 0) {
-	sub->pending_tsx++;
-    } else {
-	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): FAILED to refresh subscription!", 
-			     sub, state[sub->state].ptr));
-    }
-
-    return status;
-}
-
-/*
- * Stop subscription.
- */
-PJ_DEF(pj_status_t) pjsip_event_sub_unsubscribe( pjsip_event_sub *sub )
-{
-    pjsip_tx_data *tdata;
-    const pjsip_route_hdr *route;
-    pj_status_t status;
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): unsubscribing...", 
-			 sub, state[sub->state].ptr));
-
-    /* Lock subscription. */
-    pj_mutex_lock(sub->mutex);
-
-    pj_assert(sub->role == PJSIP_ROLE_UAC);
-
-    /* Kill refresh timer, if any. */
-    if (sub->timer.id != 0) {
-	sub->timer.id = 0;
-	pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);
-    }
-
-    /* Create request. */
-    tdata = pjsip_endpt_create_request_from_hdr( sub->endpt, 
-						 &SUBSCRIBE,
-						 sub->to->uri,
-						 sub->from, sub->to, 
-						 sub->contact, sub->call_id,
-						 sub->cseq++,
-						 NULL);
-
-    if (!tdata) {
-	pj_mutex_unlock(sub->mutex);
-	return -1;
-    }
-
-    /* Add headers to request. */
-    pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->event));
-    sub->uac_expires->ivalue = 0;
-    pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->uac_expires));
-
-    /* Add authentication. */
-    pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess,
-			 sub->cred_cnt, sub->cred_info);
-
-
-    /* Route set. */
-    route = sub->route_set.next;
-    while (route != &sub->route_set) {
-	pj_list_insert_before( &tdata->msg->hdr,
-			       pjsip_hdr_shallow_clone(tdata->pool, route));
-	route = route->next;
-    }
-
-    /* Prevent timer from refreshing itself. */
-    sub->default_interval = 0;
-
-    /* Set state. */
-    sub_set_state( sub, PJSIP_EVENT_SUB_STATE_TERMINATED );
-
-    /* Send the request. */
-    status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, 
-				       &on_subscribe_response);
-    if (status == 0) {
-	sub->pending_tsx++;
-    }
-
-    pj_mutex_unlock(sub->mutex);
-
-    if (status != 0) {
-	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): FAILED to unsubscribe!", 
-			     sub, state[sub->state].ptr));
-    }
-
-    return status;
-}
-
-/*
- * Send notify.
- */
-PJ_DEF(pj_status_t) pjsip_event_sub_notify(pjsip_event_sub *sub,
-					   pjsip_event_sub_state new_state,
-					   const pj_str_t *reason,
-					   pjsip_msg_body *body)
-{
-    pjsip_tx_data *tdata;
-    pjsip_sub_state_hdr *ss_hdr;
-    const pjsip_route_hdr *route;
-    pj_time_val now;
-    pj_status_t status;
-    pjsip_event_sub_state old_state = sub->state;
-
-    pj_gettimeofday(&now);
-
-    pj_assert(sub->role == PJSIP_ROLE_UAS);
-    if (sub->role != PJSIP_ROLE_UAS)
-	return -1;
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sending NOTIFY", 
-			 sub, state[new_state].ptr));
-
-    /* Lock subscription. */
-    pj_mutex_lock(sub->mutex);
-
-    /* Can not send NOTIFY if current state is NULL. We can accept TERMINATED. */
-    if (sub->state==PJSIP_EVENT_SUB_STATE_NULL) {
-	pj_assert(0);
-	pj_mutex_unlock(sub->mutex);
-	return -1;
-    }
-
-    /* Update state no matter what. */
-    sub_set_state(sub, new_state);
-
-    /* Create transmit data. */
-    tdata = pjsip_endpt_create_request_from_hdr( sub->endpt,
-						 &NOTIFY,
-						 sub->to->uri,
-						 sub->from, sub->to,
-						 sub->contact, sub->call_id,
-						 sub->cseq++,
-						 NULL);
-    if (!tdata) {
-	pj_mutex_unlock(sub->mutex);
-	return -1;
-    }
-
-    /* Add Event header. */
-    pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->event));
-
-    /* Add Subscription-State header. */
-    ss_hdr = pjsip_sub_state_hdr_create(tdata->pool);
-    ss_hdr->sub_state = state[new_state];
-    ss_hdr->expires_param = sub->expiry_time.sec - now.sec;
-    if (ss_hdr->expires_param < 0)
-	ss_hdr->expires_param = 0;
-    if (reason)
-	pj_strdup(tdata->pool, &ss_hdr->reason_param, reason);
-    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)ss_hdr);
-
-    /* Add Allow-Events header. */
-    pjsip_msg_add_hdr( tdata->msg, 
-		       pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events));
-
-    /* Add authentication */
-    pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess,
-			 sub->cred_cnt, sub->cred_info);
-
-    /* Route set. */
-    route = sub->route_set.next;
-    while (route != &sub->route_set) {
-	pj_list_insert_before( &tdata->msg->hdr,
-			       pjsip_hdr_shallow_clone(tdata->pool, route));
-	route = route->next;
-    }
-
-    /* Attach body. */
-    tdata->msg->body = body;
-
-    /* That's it, send! */
-    status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, &on_notify_response);
-    if (status == 0)
-	sub->pending_tsx++;
-
-    /* If terminated notify application. */
-    if (new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) {
-	if (sub->cb.on_sub_terminated) {
-	    sub->pending_tsx++;
-	    (*sub->cb.on_sub_terminated)(sub, reason);
-	    sub->pending_tsx--;
-	}
-    }
-
-    /* Unlock subscription. */
-    pj_mutex_unlock(sub->mutex);
-
-    if (status != 0) {
-	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): failed to send NOTIFY", 
-			     sub, state[sub->state].ptr));
-    }
-
-    if (sub->delete_flag && sub->pending_tsx <= 0) {
-	pjsip_event_sub_destroy(sub);
-    }
-    return status;
-}
-
-
-/* If this timer callback is called, it means subscriber hasn't refreshed its
- * subscription on-time. Set the state to terminated. This will also send
- * NOTIFY with Subscription-State set to terminated.
- */
-static void uas_expire_timer_cb( pj_timer_heap_t *timer_heap, pj_timer_entry *entry)
-{
-    pjsip_event_sub *sub = entry->user_data;
-    pj_str_t reason = { "timeout", 7 };
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): UAS subscription expired!", 
-			 sub, state[sub->state].ptr));
-
-    pj_mutex_lock(sub->mutex);
-    sub->timer.id = 0;
-
-    if (sub->cb.on_sub_terminated && sub->state!=PJSIP_EVENT_SUB_STATE_TERMINATED) {
-	/* Notify application, but prevent app from destroying the sub. */
-	++sub->pending_tsx;
-	(*sub->cb.on_sub_terminated)(sub, &reason);
-	--sub->pending_tsx;
-    }
-    //pjsip_event_sub_notify( sub, PJSIP_EVENT_SUB_STATE_TERMINATED, 
-    //			    &reason, NULL);
-    pj_mutex_unlock(sub->mutex);
-
-}
-
-/* Schedule notifier expiration. */
-static void sub_schedule_uas_expire( pjsip_event_sub *sub, int sec_delay)
-{
-    pj_time_val delay = { 0, 0 };
-    pj_parsed_time pt;
-
-    if (sub->timer.id != 0)
-	pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);
-
-    pj_gettimeofday(&sub->expiry_time);
-    sub->expiry_time.sec += sec_delay;
-
-    sub->timer.id = TIMER_ID_UAS_EXPIRY;
-    sub->timer.user_data = sub;
-    sub->timer.cb = &uas_expire_timer_cb;
-    delay.sec = sec_delay;
-    pjsip_endpt_schedule_timer( sub->endpt, &sub->timer, &delay);
-
-    pj_time_decode(&sub->expiry_time, &pt);
-    PJ_LOG(4,(THIS_FILE, 
-	      "event_sub%p (%s)(UAS): will expire at %02d:%02d:%02d (in %d secs)",
-	      sub, state[sub->state].ptr, pt.hour, pt.min, pt.sec, sec_delay));
-}
-
-/* This timer is called for UAC to refresh the subscription. */
-static void refresh_timer_cb( pj_timer_heap_t *timer_heap, pj_timer_entry *entry)
-{
-    pjsip_event_sub *sub = entry->user_data;
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refresh subscription timer", 
-			 sub, state[sub->state].ptr));
-
-    pj_mutex_lock(sub->mutex);
-    sub->timer.id = 0;
-    send_sub_refresh(sub);
-    pj_mutex_unlock(sub->mutex);
-}
-
-
-/* This will update the UAC's refresh schedule. */
-static void update_next_refresh(pjsip_event_sub *sub, int interval)
-{
-    pj_time_val delay = {0, 0};
-    pj_parsed_time pt;
-
-    if (interval < SECONDS_BEFORE_EXPIRY) {
-	PJ_LOG(4,(THIS_FILE, 
-		  "event_sub%p (%s): expiration delay too short (%d sec)! updated.",
-		  sub, state[sub->state].ptr, interval));
-	interval = SECONDS_BEFORE_EXPIRY;
-    }
-
-    if (sub->timer.id != 0)
-	pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);
-
-    sub->timer.id = TIMER_ID_REFRESH;
-    sub->timer.user_data = sub;
-    sub->timer.cb = &refresh_timer_cb;
-    pj_gettimeofday(&sub->expiry_time);
-    delay.sec = interval - SECONDS_BEFORE_EXPIRY;
-    sub->expiry_time.sec += delay.sec;
-
-    pj_time_decode(&sub->expiry_time, &pt);
-    PJ_LOG(4,(THIS_FILE, 
-	      "event_sub%p (%s): will send SUBSCRIBE at %02d:%02d:%02d (in %d secs)",
-	      sub, state[sub->state].ptr, 
-	      pt.hour, pt.min, pt.sec,
-	      delay.sec));
-
-    pjsip_endpt_schedule_timer( sub->endpt, &sub->timer, &delay );
-}
-
-
-/* Find subscription in the hash table. 
- * If found, lock the subscription before returning to caller.
- */
-static pjsip_event_sub *find_sub(pjsip_rx_data *rdata)
-{
-    pj_str_t key;
-    pjsip_role_e role;
-    pjsip_event_sub *sub;
-    pjsip_method *method = &rdata->msg->line.req.method;
-    pj_str_t *tag;
-
-    if (rdata->msg->type == PJSIP_REQUEST_MSG) {
-	if (pjsip_method_cmp(method, &SUBSCRIBE)==0) {
-	    role = PJSIP_ROLE_UAS;
-	    tag = &rdata->to_tag;
-	} else {
-	    pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0);
-	    role = PJSIP_ROLE_UAC;
-	    tag = &rdata->to_tag;
-	}
-    } else {
-	if (pjsip_method_cmp(&rdata->cseq->method, &SUBSCRIBE)==0) {
-	    role = PJSIP_ROLE_UAC;
-	    tag = &rdata->from_tag;
-	} else {
-	    pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0);
-	    role = PJSIP_ROLE_UAS;
-	    tag = &rdata->from_tag;
-	}
-    }
-    create_subscriber_key( &key, rdata->pool, role, &rdata->call_id, tag);
-
-    pj_mutex_lock(mgr.mutex);
-    sub = pj_hash_get(mgr.ht, key.ptr, key.slen);
-    if (sub)
-	pj_mutex_lock(sub->mutex);
-    pj_mutex_unlock(mgr.mutex);
-
-    return sub;
-}
-
-
-/* This function is called when we receive SUBSCRIBE request message 
- * to refresh existing subscription.
- */
-static void on_received_sub_refresh( pjsip_event_sub *sub, 
-				     pjsip_transaction *tsx, pjsip_rx_data *rdata)
-{
-    pjsip_event_hdr *e;
-    pjsip_expires_hdr *expires;
-    pj_str_t hname;
-    int status = 200;
-    pj_str_t reason_phrase = { NULL, 0 };
-    int new_state = sub->state;
-    int old_state = sub->state;
-    int new_interval = 0;
-    pjsip_tx_data *tdata;
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received target refresh", 
-			 sub, state[sub->state].ptr));
-
-    /* Check that the event matches. */
-    hname = pj_str("Event");
-    e = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL);
-    if (!e) {
-	status = 400;
-	reason_phrase = pj_str("Missing Event header");
-	goto send_response;
-    }
-    if (pj_stricmp(&e->event_type, &sub->event->event_type) != 0 ||
-	pj_stricmp(&e->id_param, &sub->event->id_param) != 0)
-    {
-	status = 481;
-	reason_phrase = pj_str("Subscription does not exist");
-	goto send_response;
-    }
-
-    /* Check server state. */
-    if (sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED) {
-	status = 481;
-	reason_phrase = pj_str("Subscription does not exist");
-	goto send_response;
-    }
-
-    /* Check expires header. */
-    expires = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_EXPIRES, NULL);
-    if (!expires) {
-	/*
-	status = 400;
-	reason_phrase = pj_str("Missing Expires header");
-	goto send_response;
-	*/
-	new_interval = sub->default_interval;
-    } else {
-	/* Check that interval is not too short. 
-	 * Note that expires time may be zero (for unsubscription).
-	 */
-	new_interval = expires->ivalue;
-	if (new_interval != 0 && new_interval < SECONDS_BEFORE_EXPIRY) {
-	    status = PJSIP_SC_INTERVAL_TOO_BRIEF;
-	    goto send_response;
-	}
-    }
-
-    /* Update interval. */
-    sub->default_interval = new_interval;
-    pj_gettimeofday(&sub->expiry_time);
-    sub->expiry_time.sec += new_interval;
-
-    /* Update timer only if this is not unsubscription. */
-    if (new_interval > 0) {
-	sub->default_interval = new_interval;
-	sub_schedule_uas_expire( sub, new_interval );
-
-	/* Call callback. */
-	if (sub->cb.on_received_refresh) {
-	    sub->pending_tsx++;
-	    (*sub->cb.on_received_refresh)(sub, rdata);
-	    sub->pending_tsx--;
-	}
-    }
-
-send_response:
-    tdata = pjsip_endpt_create_response( sub->endpt, rdata, status);
-    if (tdata) {
-	if (reason_phrase.slen)
-	    tdata->msg->line.status.reason = reason_phrase;
-
-	/* Add Expires header. */
-	expires = pjsip_expires_hdr_create(tdata->pool);
-	expires->ivalue = sub->default_interval;
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires);
-
-	if (PJSIP_IS_STATUS_IN_CLASS(status,200)) {
-	    pjsip_msg_add_hdr(tdata->msg, 
-			      pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events));
-	}
-	/* Send down to transaction. */
-	pjsip_tsx_on_tx_msg(tsx, tdata);
-    }
-
-    if (sub->default_interval==0 || !PJSIP_IS_STATUS_IN_CLASS(status,200)) {
-	/* Notify application if sub is terminated. */
-	new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;
-	sub_set_state(sub, new_state);
-	if (new_state!=old_state && sub->cb.on_sub_terminated) {
-	    pj_str_t reason = {"", 0};
-	    if (reason_phrase.slen) reason = reason_phrase;
-	    else reason = *pjsip_get_status_text(status);
-
-	    sub->pending_tsx++;
-	    (*sub->cb.on_sub_terminated)(sub, &reason);
-	    sub->pending_tsx--;
-	}
-    }
-
-    pj_mutex_unlock(sub->mutex);
-
-    /* Prefer to call log when we're not holding the mutex. */
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sent refresh response %s, status=%d", 
-			 sub, state[sub->state].ptr,
-			 (tdata ? tdata->obj_name : "null"), status));
-
-    /* Check if application has requested deletion. */
-    if (sub->delete_flag && sub->pending_tsx <= 0) {
-	pjsip_event_sub_destroy(sub);
-    }
-
-}
-
-
-/* This function is called when we receive SUBSCRIBE request message for 
- * a new subscription.
- */
-static void on_new_subscription( pjsip_transaction *tsx, pjsip_rx_data *rdata )
-{
-    package *pkg;
-    pj_pool_t *pool;
-    pjsip_event_sub *sub = NULL;
-    pj_str_t hname;
-    int status = 200;
-    pj_str_t reason = { NULL, 0 };
-    pjsip_tx_data *tdata;
-    pjsip_expires_hdr *expires;
-    pjsip_accept_hdr *accept;
-    pjsip_event_hdr *evhdr;
-
-    /* Get the Event header. */
-    hname = pj_str("Event");
-    evhdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL);
-    if (!evhdr) {
-	status = 400;
-	reason = pj_str("No Event header in request");
-	goto send_response;
-    }
-
-    /* Find corresponding package. 
-     * We don't lock the manager's mutex since we assume the package list
-     * won't change once the application is running!
-     */
-    pkg = mgr.pkg_list.next;
-    while (pkg != &mgr.pkg_list) {
-	if (pj_stricmp(&pkg->event, &evhdr->event_type) == 0)
-	    break;
-	pkg = pkg->next;
-    }
-
-    if (pkg == &mgr.pkg_list) {
-	/* Event type is not supported by any packages! */
-	status = 489;
-	reason = pj_str("Bad Event");
-	goto send_response;
-    }
-
-    /* First check that the Accept specification matches the 
-     * package's Accept types.
-     */
-    accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL);
-    if (accept) {
-	unsigned i;
-	pj_str_t *content_type = NULL;
-
-	for (i=0; i<accept->count && !content_type; ++i) {
-	    int j;
-	    for (j=0; j<pkg->accept_cnt; ++j) {
-		if (pj_stricmp(&accept->values[i], &pkg->accept[j])==0) {
-		    content_type = &pkg->accept[j];
-		    break;
-		}
-	    }
-	}
-
-	if (!content_type) {
-	    status = PJSIP_SC_NOT_ACCEPTABLE_HERE;
-	    goto send_response;
-	}
-    }
-
-    /* Check whether the package wants to accept the subscription. */
-    pj_assert(pkg->cb.on_query_subscribe != NULL);
-    (*pkg->cb.on_query_subscribe)(rdata, &status);
-    if (!PJSIP_IS_STATUS_IN_CLASS(status,200))
-	goto send_response;
-
-    /* Create new subscription record. */
-    pool = pjsip_endpt_create_pool(tsx->endpt, "esub", 
-				   SUB_POOL_SIZE, SUB_POOL_INC);
-    if (!pool) {
-	status = 500;
-	goto send_response;
-    }
-    sub = pj_pool_calloc(pool, 1, sizeof(*sub));
-    sub->pool = pool;
-    sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE);
-    if (!sub->mutex) {
-	status = 500;
-	goto send_response;
-    }
-
-    PJ_LOG(4,(THIS_FILE, "event_sub%p: notifier is created.", sub));
-
-    /* Start locking mutex. */
-    pj_mutex_lock(sub->mutex);
-
-    /* Init UAS subscription */
-    sub->endpt = tsx->endpt;
-    sub->role = PJSIP_ROLE_UAS;
-    sub->state = PJSIP_EVENT_SUB_STATE_PENDING;
-    sub->state_str = state[sub->state];
-    pj_list_init(&sub->auth_sess);
-    pj_list_init(&sub->route_set);
-    sub->from = pjsip_hdr_clone(pool, rdata->to);
-    pjsip_fromto_set_from(sub->from);
-    if (sub->from->tag.slen == 0) {
-	pj_create_unique_string(pool, &sub->from->tag);
-	rdata->to->tag = sub->from->tag;
-    }
-    sub->to = pjsip_hdr_clone(pool, rdata->from);
-    pjsip_fromto_set_to(sub->to);
-    sub->contact = pjsip_contact_hdr_create(pool);
-    sub->contact->uri = sub->from->uri;
-    sub->call_id = pjsip_cid_hdr_create(pool);
-    pj_strdup(pool, &sub->call_id->id, &rdata->call_id);
-    sub->cseq = pj_rand() % 0xFFFF;
-    
-    expires = pjsip_msg_find_hdr( rdata->msg, PJSIP_H_EXPIRES, NULL);
-    if (expires) {
-	sub->default_interval = expires->ivalue;
-	if (sub->default_interval > 0 && 
-	    sub->default_interval < SECONDS_BEFORE_EXPIRY) 
-	{
-	    status = 423; /* Interval too short. */
-	    goto send_response;
-	}
-    } else {
-	sub->default_interval = 600;
-    }
-
-    /* Clone Event header. */
-    sub->event = pjsip_hdr_clone(pool, evhdr);
-
-    /* Register to hash table. */
-    create_subscriber_key(&sub->key, pool, PJSIP_ROLE_UAS, &sub->call_id->id,
-			  &sub->from->tag);
-    pj_mutex_lock(mgr.mutex);
-    pj_hash_set(pool, mgr.ht, sub->key.ptr, sub->key.slen, sub);
-    pj_mutex_unlock(mgr.mutex);
-
-    /* Set timer where subscription will expire only when expires<>0. 
-     * Subscriber may send new subscription with expires==0.
-     */
-    if (sub->default_interval != 0) {
-	sub_schedule_uas_expire( sub, sub->default_interval-SECONDS_BEFORE_EXPIRY);
-    }
-
-    /* Notify application. */
-    if (pkg->cb.on_subscribe) {
-	pjsip_event_sub_cb *cb = NULL;
-	sub->pending_tsx++;
-	(*pkg->cb.on_subscribe)(sub, rdata, &cb, &sub->default_interval);
-	sub->pending_tsx--;
-	if (cb == NULL)
-	    pj_memset(&sub->cb, 0, sizeof(*cb));
-	else
-	    pj_memcpy(&sub->cb, cb, sizeof(*cb));
-    }
-
-
-send_response:
-    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s)(UAS): status=%d", 
-			  sub, state[sub->state].ptr, status));
-
-    tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status);
-    if (tdata) {
-	if (reason.slen) {
-	    /* Customize reason text. */
-	    tdata->msg->line.status.reason = reason;
-	}
-	if (PJSIP_IS_STATUS_IN_CLASS(status,200)) {
-	    /* Add Expires header. */
-	    pjsip_expires_hdr *hdr;
-
-	    hdr = pjsip_expires_hdr_create(tdata->pool);
-	    hdr->ivalue = sub->default_interval;
-	    pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr );
-	}
-	if (status == 423) {
-	    /* Add Min-Expires header. */
-	    pjsip_min_expires_hdr *hdr;
-
-	    hdr = pjsip_min_expires_hdr_create(tdata->pool);
-	    hdr->ivalue = SECONDS_BEFORE_EXPIRY;
-	    pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr);
-	}
-	if (status == 489 || 
-	    status==PJSIP_SC_NOT_ACCEPTABLE_HERE ||
-	    PJSIP_IS_STATUS_IN_CLASS(status,200)) 
-	{
-	    /* Add Allow-Events header. */
-	    pjsip_hdr *hdr;
-	    hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events);
-	    pjsip_msg_add_hdr(tdata->msg, hdr);
-
-	    /* Should add Accept header?. */
-	}
-
-	pjsip_tsx_on_tx_msg(tsx, tdata);
-    }
-
-    /* If received new subscription with expires=0, terminate. */
-    if (sub && sub->default_interval == 0) {
-	pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED);
-	if (sub->cb.on_sub_terminated) {
-	    pj_str_t reason = { "timeout", 7 };
-	    (*sub->cb.on_sub_terminated)(sub, &reason);
-	}
-    }
-
-    if (!PJSIP_IS_STATUS_IN_CLASS(status,200) || (sub && sub->delete_flag)) {
-	if (sub && sub->mutex) {
-	    pjsip_event_sub_destroy(sub);
-	} else if (sub) {
-	    pjsip_endpt_destroy_pool(tsx->endpt, sub->pool);
-	}
-    } else {
-	pj_assert(status >= 200);
-	pj_mutex_unlock(sub->mutex);
-    }
-}
-
-/* This is the main callback when SUBSCRIBE request is received. */
-static void on_subscribe_request(pjsip_transaction *tsx, pjsip_rx_data *rdata)
-{
-    pjsip_event_sub *sub = find_sub(rdata);
-
-    if (sub)
-	on_received_sub_refresh(sub, tsx, rdata);
-    else
-	on_new_subscription(tsx, rdata);
-}
-
-
-/* This callback is called when response to SUBSCRIBE is received. */
-static void on_subscribe_response(void *token, pjsip_event *event)
-{
-    pjsip_event_sub *sub = token;
-    pjsip_transaction *tsx = event->obj.tsx;
-    int new_state, old_state = sub->state;
-
-    pj_assert(tsx->status_code >= 200);
-    if (tsx->status_code < 200)
-	return;
-
-    pj_assert(sub->role == PJSIP_ROLE_UAC);
-
-    /* Lock mutex. */
-    pj_mutex_lock(sub->mutex);
-
-    /* If request failed with 401/407 error, silently retry the request. */
-    if (tsx->status_code==401 || tsx->status_code==407) {
-	pjsip_tx_data *tdata;
-	tdata = pjsip_auth_reinit_req(sub->endpt,
-				      sub->pool, &sub->auth_sess,
-				      sub->cred_cnt, sub->cred_info,
-				      tsx->last_tx, event->src.rdata );
-	if (tdata) {
-	    int status;
-	    pjsip_cseq_hdr *cseq;
-	    cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
-	    cseq->cseq = sub->cseq++;
-	    status = pjsip_endpt_send_request( sub->endpt, tdata, 
-					       -1, sub, 
-					       &on_subscribe_response);
-	    if (status == 0) {
-		pj_mutex_unlock(sub->mutex);
-		return;
-	    }
-	}
-    }
-
-    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code,200)) {
-	/* Update To tag. */
-	if (sub->to->tag.slen == 0)
-	    pj_strdup(sub->pool, &sub->to->tag, &event->src.rdata->to_tag);
-
-	new_state = sub->state;
-
-    } else if (tsx->status_code == 481) {
-	new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;
-
-    } else if (tsx->status_code >= 300) {
-	/* RFC 3265 Section 3.1.4.2:
-         * If a SUBSCRIBE request to refresh a subscription fails 
-	 * with a non-481 response, the original subscription is still 
-	 * considered valid for the duration of original exires.
-	 *
-	 * Note:
-	 * Since we normally send SUBSCRIBE for refreshing the subscription,
-	 * it means the subscription already expired anyway. So we terminate
-	 * the subscription now.
-	 */
-	if (sub->state != PJSIP_EVENT_SUB_STATE_ACTIVE) {
-	    new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;
-	} else {
-	    /* Use this to be compliant with Section 3.1.4.2
-	      new_state = sub->state;
-	     */
-	    new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;
-	}
-    } else {
-	pj_assert(0);
-	new_state = sub->state;
-    }
-
-    if (new_state != sub->state && sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) {
-	sub_set_state(sub, new_state);
-    }
-
-    if (sub->state == PJSIP_EVENT_SUB_STATE_ACTIVE ||
-	sub->state == PJSIP_EVENT_SUB_STATE_PENDING)
-    {
-	/*
-	 * Register timer for next subscription refresh, but only when
-	 * we're not unsubscribing. Also update default_interval and Expires
-	 * header.
-	 */
-	if (sub->default_interval > 0 && !sub->delete_flag) {
-	    pjsip_expires_hdr *exp = NULL;
-	    
-	    /* Could be transaction timeout. */
-	    if (event->src_type == PJSIP_EVENT_RX_MSG) {
-		exp = pjsip_msg_find_hdr(event->src.rdata->msg,
-					 PJSIP_H_EXPIRES, NULL);
-	    }
-
-	    if (exp) {
-		int delay = exp->ivalue;
-		if (delay > 0) {
-		    pj_time_val new_expiry;
-		    pj_gettimeofday(&new_expiry);
-		    new_expiry.sec += delay;
-		    if (sub->timer.id==0 || 
-			new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2) 
-		    {
-		    //if (delay > 0 && delay < sub->default_interval) {
-			sub->default_interval = delay;
-			sub->uac_expires->ivalue = delay;
-			update_next_refresh(sub, delay);
-		    }
-		}
-	    }
-	}
-    }
-
-    /* Call callback. */
-    if (!sub->delete_flag) {
-	if (sub->cb.on_received_sub_response) {
-	    (*sub->cb.on_received_sub_response)(sub, event);
-	}
-    }
-
-    /* Notify application if we're terminated. */
-    if (new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) {
-	if (sub->cb.on_sub_terminated) {
-	    pj_str_t reason;
-	    if (event->src_type == PJSIP_EVENT_RX_MSG)
-		reason = event->src.rdata->msg->line.status.reason;
-	    else
-		reason = *pjsip_get_status_text(tsx->status_code);
-
-	    (*sub->cb.on_sub_terminated)(sub, &reason);
-	}
-    }
-
-    /* Decrement pending tsx count. */
-    --sub->pending_tsx;
-    pj_assert(sub->pending_tsx >= 0);
-
-    if (sub->delete_flag && sub->pending_tsx <= 0) {
-	pjsip_event_sub_destroy(sub);
-    } else {
-	pj_mutex_unlock(sub->mutex);
-    }
-
-    /* DO NOT ACCESS sub FROM NOW ON! IT MIGHT HAVE BEEN DELETED */
-}
-
-/*
- * This callback called when we receive incoming NOTIFY request.
- */
-static void on_notify_request(pjsip_transaction *tsx, pjsip_rx_data *rdata)
-{
-    pjsip_event_sub *sub;
-    pjsip_tx_data *tdata;
-    int status = 200;
-    int old_state;
-    pj_str_t reason = { NULL, 0 };
-    pj_str_t reason_phrase = { NULL, 0 };
-    int new_state = PJSIP_EVENT_SUB_STATE_NULL;
-
-    /* Find subscription based on Call-ID and From tag. 
-     * This will also automatically lock the subscription, if it's found.
-     */
-    sub = find_sub(rdata);
-    if (!sub) {
-	/* RFC 3265: Section 3.2 Description of NOTIFY Behavior:
-	 * Answer with 481 Subscription does not exist.
-	 */
-	PJ_LOG(4,(THIS_FILE, "Unable to find subscription for incoming NOTIFY!"));
-	status = 481;
-	reason_phrase = pj_str("Subscription does not exist");
-
-    } else {
-	pj_assert(sub->role == PJSIP_ROLE_UAC);
-	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received NOTIFY", 
-			     sub, state[sub->state].ptr));
-
-    }
-
-    new_state = old_state = sub->state;
-
-    /* RFC 3265: Section 3.2.1
-     * Check that the Event header match the subscription. 
-     */
-    if (status == 200) {
-	pjsip_event_hdr *hdr;
-	pj_str_t hname = { "Event", 5 };
-
-	hdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL);
-	if (!hdr) {
-	    status = PJSIP_SC_BAD_REQUEST;
-	    reason_phrase = pj_str("No Event header found");
-	} else if (pj_stricmp(&hdr->event_type, &sub->event->event_type) != 0 ||
-		   pj_stricmp(&hdr->id_param, &sub->event->id_param) != 0) 
-	{
-	    status = 481;
-	    reason_phrase = pj_str("Subscription does not exist");
-	}
-    }
-
-    /* Update subscription state and timer. */
-    if (status == 200) {
-	pjsip_sub_state_hdr *hdr;
-	const pj_str_t hname = { "Subscription-State", 18 };
-	const pj_str_t state_active = { "active", 6 },
-		       state_pending = { "pending", 7},
-		       state_terminated = { "terminated", 10 };
-
-	hdr = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL);
-	if (!hdr) {
-	    status = PJSIP_SC_BAD_REQUEST;
-	    reason_phrase = pj_str("No Subscription-State header found");
-	    goto process;
-	} 
-
-	/*
-	 * Update subscription state.
-	 */
-	if (pj_stricmp(&hdr->sub_state, &state_active) == 0) {
-	    if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED)
-		new_state = PJSIP_EVENT_SUB_STATE_ACTIVE;
-	} else if (pj_stricmp(&hdr->sub_state, &state_pending) == 0) {
-	    if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED)
-		new_state = PJSIP_EVENT_SUB_STATE_PENDING;
-	} else if (pj_stricmp(&hdr->sub_state, &state_terminated) == 0) {
-	    new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;
-	} else {
-	    new_state = PJSIP_EVENT_SUB_STATE_UNKNOWN;
-	}
-
-	reason = hdr->reason_param;
-
-	if (new_state != sub->state && new_state != PJSIP_EVENT_SUB_STATE_NULL &&
-	    sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) 
-	{
-	    sub_set_state(sub, new_state);
-	    if (new_state == PJSIP_EVENT_SUB_STATE_UNKNOWN) {
-		pj_strdup_with_null(sub->pool, &sub->state_str, &hdr->sub_state);
-	    } else {
-		sub->state_str = state[new_state];
-	    }
-	}
-
-	/*
-	 * Update timeout timer in required, just in case notifier changed the 
-         * expiration to shorter time.
-	 * Section 3.2.2: the expires param can only shorten the interval.
-	 */
-	if ((sub->state==PJSIP_EVENT_SUB_STATE_ACTIVE || 
-	     sub->state==PJSIP_EVENT_SUB_STATE_PENDING) && hdr->expires_param > 0) 
-	{
-	    pj_time_val now, new_expiry;
-
-	    pj_gettimeofday(&now);
-	    new_expiry.sec = now.sec + hdr->expires_param;
-	    if (sub->timer.id==0 || 
-		new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2) 
-	    {
-		update_next_refresh(sub, hdr->expires_param);
-	    }
-	}
-    }
-
-process:
-    /* Note: here we sub MAY BE NULL! */
-
-    /* Send response to NOTIFY */
-    tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status );
-    if (tdata) {
-	if (reason_phrase.slen)
-	    tdata->msg->line.status.reason = reason_phrase;
-
-	if (PJSIP_IS_STATUS_IN_CLASS(status,200)) {
-	    pjsip_hdr *hdr;
-	    hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events);
-	    pjsip_msg_add_hdr( tdata->msg, hdr);
-	}
-
-	pjsip_tsx_on_tx_msg(tsx, tdata);
-    }
-
-    /* Call NOTIFY callback, if any. */
-    if (sub && PJSIP_IS_STATUS_IN_CLASS(status,200) && sub->cb.on_received_notify) {
-	sub->pending_tsx++;
-	(*sub->cb.on_received_notify)(sub, rdata);
-	sub->pending_tsx--;
-    }
-
-    /* Check if subscription is terminated and call callback. */
-    if (sub && new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) {
-	if (sub->cb.on_sub_terminated) {
-	    sub->pending_tsx++;
-	    (*sub->cb.on_sub_terminated)(sub, &reason);
-	    sub->pending_tsx--;
-	}
-    }
-
-    /* Check if application has requested deletion. */
-    if (sub && sub->delete_flag && sub->pending_tsx <= 0) {
-	pjsip_event_sub_destroy(sub);
-    } else if (sub) {
-	pj_mutex_unlock(sub->mutex);
-    }
-}
-
-/* This callback is called when we received NOTIFY response. */
-static void on_notify_response(void *token, pjsip_event *event)
-{
-    pjsip_event_sub *sub = token;
-    pjsip_event_sub_state old_state = sub->state;
-    pjsip_transaction *tsx = event->obj.tsx;
-
-    /* Lock the subscription. */
-    pj_mutex_lock(sub->mutex);
-
-    pj_assert(sub->role == PJSIP_ROLE_UAS);
-
-    /* If request failed with authorization failure, silently retry. */
-    if (tsx->status_code==401 || tsx->status_code==407) {
-	pjsip_tx_data *tdata;
-	tdata = pjsip_auth_reinit_req(sub->endpt,
-				      sub->pool, &sub->auth_sess,
-				      sub->cred_cnt, sub->cred_info,
-				      tsx->last_tx, event->src.rdata );
-	if (tdata) {
-	    int status;
-	    pjsip_cseq_hdr *cseq;
-	    cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
-	    cseq->cseq = sub->cseq++;
-	    status = pjsip_endpt_send_request( sub->endpt, tdata, 
-					       -1, sub, 
-					       &on_notify_response);
-	    if (status == 0) {
-		pj_mutex_unlock(sub->mutex);
-		return;
-	    }
-	}
-    }
-
-    /* Notify application. */
-    if (sub->cb.on_received_notify_response)
-	(*sub->cb.on_received_notify_response)(sub, event);
-
-    /* Check for response 481. */
-    if (event->obj.tsx->status_code == 481) {
-	/* Remote says that the subscription does not exist! 
-	 * Terminate subscription!
-	 */
-	sub_set_state(sub, PJSIP_EVENT_SUB_STATE_TERMINATED);
-	if (sub->timer.id) {
-	    pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);
-	    sub->timer.id = 0;
-	}
-
-	PJ_LOG(4, (THIS_FILE, 
-		   "event_sub%p (%s): got 481 response to NOTIFY. Terminating...",
-		   sub, state[sub->state].ptr));
-
-	/* Notify app. */
-	if (sub->state!=old_state && sub->cb.on_sub_terminated) 
-	    (*sub->cb.on_sub_terminated)(sub, &event->src.rdata->msg->line.status.reason);
-    }
-
-    /* Decrement pending transaction count. */
-    --sub->pending_tsx;
-    pj_assert(sub->pending_tsx >= 0);
-
-    /* Check that the subscription is marked for deletion. */
-    if (sub->delete_flag && sub->pending_tsx <= 0) {
-	pjsip_event_sub_destroy(sub);
-    } else {
-	pj_mutex_unlock(sub->mutex);
-    }
-
-    /* DO NOT ACCESS sub, IT MIGHT HAVE BEEN DESTROYED! */
-}
-
-
-/* This is the transaction handler for incoming SUBSCRIBE and NOTIFY 
- * requests. 
- */
-static void tsx_handler( struct pjsip_module *mod, pjsip_event *event )
-{
-    pjsip_msg *msg;
-    pjsip_rx_data *rdata;
-
-    /* Only want incoming message events. */
-    if (event->src_type != PJSIP_EVENT_RX_MSG)
-	return;
-
-    rdata = event->src.rdata;
-    msg = rdata->msg;
-
-    /* Only want to process request messages. */
-    if (msg->type != PJSIP_REQUEST_MSG)
-	return;
-
-    /* Only want the first notification. */
-    if (event->obj.tsx && event->obj.tsx->status_code >= 100)
-	return;
-
-    if (pjsip_method_cmp(&msg->line.req.method, &SUBSCRIBE)==0) {
-	/* Process incoming SUBSCRIBE request. */
-	on_subscribe_request( event->obj.tsx, rdata );
-    } else if (pjsip_method_cmp(&msg->line.req.method, &NOTIFY)==0) {
-	/* Process incoming NOTIFY request. */
-	on_notify_request( event->obj.tsx, rdata );
-    }
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip_simple/event_notify.h>

+#include <pjsip/sip_msg.h>

+#include <pjsip/sip_misc.h>

+#include <pjsip/sip_endpoint.h>

+#include <pjsip/sip_module.h>

+#include <pjsip/sip_transaction.h>

+#include <pjsip/sip_event.h>

+#include <pj/pool.h>

+#include <pj/timer.h>

+#include <pj/string.h>

+#include <pj/hash.h>

+#include <pj/os.h>

+#include <pj/except.h>

+#include <pj/log.h>

+#include <pj/guid.h>

+

+#define THIS_FILE		"event_sub"

+

+/* String names for state. 

+ * The names here should be compliant with sub_state names in RFC3265.

+ */

+static const pj_str_t state[] = {

+    { "null", 4 }, 

+    { "active", 6 },

+    { "pending", 7 },

+    { "terminated", 10 },

+    { "unknown", 7 }

+};

+

+/* Timer IDs */

+#define TIMER_ID_REFRESH	1

+#define TIMER_ID_UAS_EXPIRY	2

+

+/* Static configuration. */

+#define SECONDS_BEFORE_EXPIRY	10

+#define MGR_POOL_SIZE		512

+#define MGR_POOL_INC		0

+#define SUB_POOL_SIZE		2048

+#define SUB_POOL_INC		0

+#define HASH_TABLE_SIZE		32

+

+/* Static vars. */

+static int mod_id;

+static const pjsip_method SUBSCRIBE = { PJSIP_OTHER_METHOD, {"SUBSCRIBE", 9}};

+static const pjsip_method NOTIFY = { PJSIP_OTHER_METHOD, { "NOTIFY", 6}};

+

+typedef struct package

+{

+    PJ_DECL_LIST_MEMBER(struct package)

+    pj_str_t		    event;

+    int			    accept_cnt;

+    pj_str_t		   *accept;

+    pjsip_event_sub_pkg_cb  cb;

+} package;

+

+/* Event subscription manager singleton instance. */

+static struct pjsip_event_sub_mgr

+{

+    pj_pool_t		    *pool;

+    pj_hash_table_t	    *ht;

+    pjsip_endpoint	    *endpt;

+    pj_mutex_t		    *mutex;

+    pjsip_allow_events_hdr  *allow_events;

+    package		     pkg_list;

+} mgr;

+

+/* Fordward declarations for static functions. */

+static pj_status_t	mod_init(pjsip_endpoint *, pjsip_module *, pj_uint32_t);

+static pj_status_t	mod_deinit(pjsip_module*);

+static void		tsx_handler(pjsip_module*, pjsip_event*);

+static pjsip_event_sub *find_sub(pjsip_rx_data *);

+static void		on_subscribe_request(pjsip_transaction*, pjsip_rx_data*);

+static void		on_subscribe_response(void *, pjsip_event*);

+static void		on_notify_request(pjsip_transaction *, pjsip_rx_data*);

+static void		on_notify_response(void *, pjsip_event *);

+static void		refresh_timer_cb(pj_timer_heap_t*, pj_timer_entry*);

+static void		uas_expire_timer_cb(pj_timer_heap_t*, pj_timer_entry*);

+static pj_status_t	send_sub_refresh( pjsip_event_sub *sub );

+

+/* Module descriptor. */

+static pjsip_module event_sub_module = 

+{

+    {"EventSub", 8},			/* Name.		*/

+    0,					/* Flag			*/

+    128,				/* Priority		*/

+    &mgr,				/* User data.		*/

+    2,					/* Number of methods supported . */

+    { &SUBSCRIBE, &NOTIFY },		/* Array of methods */

+    &mod_init,				/* init_module()	*/

+    NULL,				/* start_module()	*/

+    &mod_deinit,			/* deinit_module()	*/

+    &tsx_handler,			/* tsx_handler()	*/

+};

+

+/*

+ * Module initialization.

+ * This will be called by endpoint when it initializes all modules.

+ */

+static pj_status_t mod_init( pjsip_endpoint *endpt,

+			     struct pjsip_module *mod, pj_uint32_t id )

+{

+    pj_pool_t *pool;

+

+    pool = pjsip_endpt_create_pool(endpt, "esubmgr", MGR_POOL_SIZE, MGR_POOL_INC);

+    if (!pool)

+	return -1;

+

+    /* Manager initialization: create hash table and mutex. */

+    mgr.pool = pool;

+    mgr.endpt = endpt;

+    mgr.ht = pj_hash_create(pool, HASH_TABLE_SIZE);

+    if (!mgr.ht)

+	return -1;

+

+    mgr.mutex = pj_mutex_create(pool, "esubmgr", PJ_MUTEX_SIMPLE);

+    if (!mgr.mutex)

+	return -1;

+

+    /* Attach manager to module. */

+    mod->mod_data = &mgr;

+

+    /* Init package list. */

+    pj_list_init(&mgr.pkg_list);

+

+    /* Init Allow-Events header. */

+    mgr.allow_events = pjsip_allow_events_hdr_create(mgr.pool);

+

+    /* Save the module ID. */

+    mod_id = id;

+

+    pjsip_event_notify_init_parser();

+    return 0;

+}

+

+/*

+ * Module deinitialization.

+ * Called by endpoint.

+ */

+static pj_status_t mod_deinit( struct pjsip_module *mod )

+{

+    pj_mutex_lock(mgr.mutex);

+    pj_mutex_destroy(mgr.mutex);

+    pjsip_endpt_destroy_pool(mgr.endpt, mgr.pool);

+    return 0;

+}

+

+/*

+ * This public function is called by application to register callback.

+ * In exchange, the instance of the module is returned.

+ */

+PJ_DEF(pjsip_module*) pjsip_event_sub_get_module(void)

+{

+    return &event_sub_module;

+}

+

+/*

+ * Register event package.

+ */

+PJ_DEF(pj_status_t) pjsip_event_sub_register_pkg( const pj_str_t *event,

+						  int accept_cnt,

+						  const pj_str_t accept[],

+						  const pjsip_event_sub_pkg_cb *cb )

+{

+    package *pkg;

+    int i;

+

+    pj_mutex_lock(mgr.mutex);

+

+    /* Create and register new package. */

+    pkg = pj_pool_alloc(mgr.pool, sizeof(*pkg));

+    pj_strdup(mgr.pool, &pkg->event, event);

+    pj_list_insert_before(&mgr.pkg_list, pkg);

+

+    /* Save Accept specification. */

+    pkg->accept_cnt = accept_cnt;

+    pkg->accept = pj_pool_alloc(mgr.pool, accept_cnt*sizeof(pj_str_t));

+    for (i=0; i<accept_cnt; ++i) {

+	pj_strdup(mgr.pool, &pkg->accept[i], &accept[i]);

+    }

+

+    /* Copy callback. */

+    pj_memcpy(&pkg->cb, cb, sizeof(*cb));

+

+    /* Update Allow-Events header. */

+    pj_assert(mgr.allow_events->event_cnt < PJSIP_MAX_ALLOW_EVENTS);

+    mgr.allow_events->events[mgr.allow_events->event_cnt++] = pkg->event;

+

+    pj_mutex_unlock(mgr.mutex);

+    return 0;

+}

+

+/*

+ * Create subscription key (for hash table).

+ */

+static void create_subscriber_key( pj_str_t *key, pj_pool_t *pool,

+				   pjsip_role_e role, 

+				   const pj_str_t *call_id, const pj_str_t *from_tag)

+{

+    char *p;

+

+    p = key->ptr = pj_pool_alloc(pool, call_id->slen + from_tag->slen + 3);

+    *p++ = (role == PJSIP_ROLE_UAS ? 'S' : 'C');

+    *p++ = '$';

+    pj_memcpy(p, call_id->ptr, call_id->slen);

+    p += call_id->slen;

+    *p++ = '$';

+    pj_memcpy(p, from_tag->ptr, from_tag->slen);

+    p += from_tag->slen;

+

+    key->slen = p - key->ptr;

+}

+

+

+/*

+ * Create UAC subscription.

+ */

+PJ_DEF(pjsip_event_sub*) pjsip_event_sub_create( pjsip_endpoint *endpt,

+						 const pj_str_t *from,

+						 const pj_str_t *to,

+						 const pj_str_t *event,

+						 int expires,

+						 int accept_cnt,

+						 const pj_str_t accept[],

+						 void *user_data,

+						 const pjsip_event_sub_cb *cb)

+{

+    pjsip_tx_data *tdata;

+    pj_pool_t *pool;

+    const pjsip_hdr *hdr;

+    pjsip_event_sub *sub;

+    PJ_USE_EXCEPTION;

+

+    PJ_LOG(5,(THIS_FILE, "Creating event subscription %.*s to %.*s",

+			 event->slen, event->ptr, to->slen, to->ptr));

+

+    /* Create pool for the event subscription. */

+    pool = pjsip_endpt_create_pool(endpt, "esub", SUB_POOL_SIZE, SUB_POOL_INC);

+    if (!pool) {

+	return NULL;

+    }

+

+    /* Init subscription. */

+    sub = pj_pool_calloc(pool, 1, sizeof(*sub));

+    sub->pool = pool;

+    sub->endpt = endpt;

+    sub->role = PJSIP_ROLE_UAC;

+    sub->state = PJSIP_EVENT_SUB_STATE_PENDING;

+    sub->state_str = state[sub->state];

+    sub->user_data = user_data;

+    sub->timer.id = 0;

+    sub->default_interval = expires;

+    pj_memcpy(&sub->cb, cb, sizeof(*cb));

+    pj_list_init(&sub->auth_sess);

+    pj_list_init(&sub->route_set);

+    sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE);

+    if (!sub->mutex) {

+	pjsip_endpt_destroy_pool(endpt, pool);

+	return NULL;

+    }

+

+    /* The easiest way to parse the parameters is to create a dummy request! */

+    tdata = pjsip_endpt_create_request( endpt, &SUBSCRIBE, to, from, to, from,

+					NULL, -1, NULL);

+    if (!tdata) {

+	pj_mutex_destroy(sub->mutex);

+	pjsip_endpt_destroy_pool(endpt, pool);

+	return NULL;

+    }

+

+    /* 

+     * Duplicate headers in the request to our structure. 

+     */

+    PJ_TRY {

+	int i;

+

+	/* From */

+	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_FROM, NULL);

+	pj_assert(hdr != NULL);

+	sub->from = pjsip_hdr_clone(pool, hdr);

+        

+	/* To */

+	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL);

+	pj_assert(hdr != NULL);

+	sub->to = pjsip_hdr_clone(pool, hdr);

+

+	/* Contact. */

+	sub->contact = pjsip_contact_hdr_create(pool);

+	sub->contact->uri = sub->from->uri;

+

+	/* Call-ID */

+	hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CALL_ID, NULL);

+	pj_assert(hdr != NULL);

+	sub->call_id = pjsip_hdr_clone(pool, hdr);

+

+	/* CSeq */

+	sub->cseq = pj_rand() % 0xFFFF;

+

+	/* Event. */

+	sub->event = pjsip_event_hdr_create(sub->pool);

+	pj_strdup(pool, &sub->event->event_type, event);

+

+	/* Expires. */

+	sub->uac_expires = pjsip_expires_hdr_create(pool);

+	sub->uac_expires->ivalue = expires;

+

+	/* Accept. */

+	sub->local_accept = pjsip_accept_hdr_create(pool);

+	for (i=0; i<accept_cnt && i < PJSIP_MAX_ACCEPT_COUNT; ++i) {

+	    sub->local_accept->count++;

+	    pj_strdup(sub->pool, &sub->local_accept->values[i], &accept[i]);

+	}

+

+	/* Register to hash table. */

+	create_subscriber_key( &sub->key, pool, PJSIP_ROLE_UAC, 

+			       &sub->call_id->id, &sub->from->tag);

+	pj_mutex_lock( mgr.mutex );

+	pj_hash_set( pool, mgr.ht, sub->key.ptr, sub->key.slen, sub);

+	pj_mutex_unlock( mgr.mutex );

+

+    }

+    PJ_DEFAULT {

+	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): caught exception %d during init", 

+			     sub, state[sub->state].ptr, PJ_GET_EXCEPTION()));

+

+	pjsip_tx_data_dec_ref(tdata);

+	pj_mutex_destroy(sub->mutex);

+	pjsip_endpt_destroy_pool(endpt, sub->pool);

+	return NULL;

+    }

+    PJ_END;

+

+    /* All set, delete temporary transmit data as we don't need it. */

+    pjsip_tx_data_dec_ref(tdata);

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): client created, target=%.*s, event=%.*s",

+			 sub, state[sub->state].ptr,

+			 to->slen, to->ptr, event->slen, event->ptr));

+

+    return sub;

+}

+

+/*

+ * Set credentials.

+ */

+PJ_DEF(pj_status_t) pjsip_event_sub_set_credentials( pjsip_event_sub *sub,

+						     int count,

+						     const pjsip_cred_info cred[])

+{

+    pj_mutex_lock(sub->mutex);

+    if (count > 0) {

+	sub->cred_info = pj_pool_alloc(sub->pool, count*sizeof(pjsip_cred_info));

+	pj_memcpy( sub->cred_info, cred, count*sizeof(pjsip_cred_info));

+    }

+    sub->cred_cnt = count;

+    pj_mutex_unlock(sub->mutex);

+    return 0;

+}

+

+/*

+ * Set route-set.

+ */

+PJ_DEF(pj_status_t) pjsip_event_sub_set_route_set( pjsip_event_sub *sub,

+						   const pjsip_route_hdr *route_set )

+{

+    const pjsip_route_hdr *hdr;

+

+    pj_mutex_lock(sub->mutex);

+

+    /* Clear existing route set. */

+    pj_list_init(&sub->route_set);

+

+    /* Duplicate route headers. */

+    hdr = route_set->next;

+    while (hdr != route_set) {

+	pjsip_route_hdr *new_hdr = pjsip_hdr_clone(sub->pool, hdr);

+	pj_list_insert_before(&sub->route_set, new_hdr);

+	hdr = hdr->next;

+    }

+

+    pj_mutex_unlock(sub->mutex);

+

+    return 0;

+}

+

+/*

+ * Send subscribe request.

+ */

+PJ_DEF(pj_status_t) pjsip_event_sub_subscribe( pjsip_event_sub *sub )

+{

+    pj_status_t status;

+

+    pj_mutex_lock(sub->mutex);

+    status = send_sub_refresh(sub);

+    pj_mutex_unlock(sub->mutex);

+

+    return status;

+}

+

+/*

+ * Destroy subscription.

+ * If there are pending transactions, then this will just set the flag.

+ */

+PJ_DEF(pj_status_t) pjsip_event_sub_destroy(pjsip_event_sub *sub)

+{

+    pj_assert(sub != NULL);

+    if (sub == NULL)

+	return -1;

+

+    /* Application must terminate the subscription first. */

+    pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_NULL ||

+	      sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED);

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): about to be destroyed", 

+			 sub, state[sub->state].ptr));

+

+    pj_mutex_lock(mgr.mutex);

+    pj_mutex_lock(sub->mutex);

+

+    /* Set delete flag. */

+    sub->delete_flag = 1;

+

+    /* Unregister timer, if any. */

+    if (sub->timer.id != 0) {

+	pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);

+	sub->timer.id = 0;

+    }

+

+    if (sub->pending_tsx > 0) {

+	pj_mutex_unlock(sub->mutex);

+	pj_mutex_unlock(mgr.mutex);

+	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): has %d pending, will destroy later",

+			     sub, state[sub->state].ptr,

+			     sub->pending_tsx));

+	return 1;

+    }

+

+    /* Unregister from hash table. */

+    pj_hash_set(sub->pool, mgr.ht, sub->key.ptr, sub->key.slen, NULL);

+

+    /* Destroy. */

+    pj_mutex_destroy(sub->mutex);

+    pjsip_endpt_destroy_pool(sub->endpt, sub->pool);

+

+    pj_mutex_unlock(mgr.mutex);

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p: destroyed", sub));

+    return 0;

+}

+

+/* Change state. */

+static void sub_set_state( pjsip_event_sub *sub, int new_state)

+{

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): changed state to %s",

+	      sub, state[sub->state].ptr, state[new_state].ptr));

+    sub->state = new_state;

+    sub->state_str = state[new_state];

+}

+

+/*

+ * Refresh subscription.

+ */

+static pj_status_t send_sub_refresh( pjsip_event_sub *sub )

+{

+    pjsip_tx_data *tdata;

+    pj_status_t status;

+    const pjsip_route_hdr *route;

+

+    pj_assert(sub->role == PJSIP_ROLE_UAC);

+    pj_assert(sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED);

+    if (sub->role != PJSIP_ROLE_UAC || 

+	sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED)

+    {

+	return -1;

+    }

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refreshing subscription", 

+			 sub, state[sub->state].ptr));

+

+    /* Create request. */

+    tdata = pjsip_endpt_create_request_from_hdr( sub->endpt, 

+						 &SUBSCRIBE,

+						 sub->to->uri,

+						 sub->from, sub->to, 

+						 sub->contact, sub->call_id,

+						 sub->cseq++,

+						 NULL);

+

+    if (!tdata) {

+	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refresh: unable to create tx data!",

+			     sub, state[sub->state].ptr));

+	return -1;

+    }

+

+    pjsip_msg_add_hdr( tdata->msg, 

+		       pjsip_hdr_shallow_clone(tdata->pool, sub->event));

+    pjsip_msg_add_hdr( tdata->msg, 

+		       pjsip_hdr_shallow_clone(tdata->pool, sub->uac_expires));

+    pjsip_msg_add_hdr( tdata->msg, 

+		       pjsip_hdr_shallow_clone(tdata->pool, sub->local_accept));

+    pjsip_msg_add_hdr( tdata->msg, 

+		       pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events));

+

+    /* Authentication */

+    pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess,

+			 sub->cred_cnt, sub->cred_info);

+

+    /* Route set. */

+    route = sub->route_set.next;

+    while (route != &sub->route_set) {

+	pj_list_insert_before( &tdata->msg->hdr,

+			       pjsip_hdr_shallow_clone(tdata->pool, route));

+	route = route->next;

+    }

+

+    /* Send */

+    status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, 

+				       &on_subscribe_response);

+    if (status == 0) {

+	sub->pending_tsx++;

+    } else {

+	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): FAILED to refresh subscription!", 

+			     sub, state[sub->state].ptr));

+    }

+

+    return status;

+}

+

+/*

+ * Stop subscription.

+ */

+PJ_DEF(pj_status_t) pjsip_event_sub_unsubscribe( pjsip_event_sub *sub )

+{

+    pjsip_tx_data *tdata;

+    const pjsip_route_hdr *route;

+    pj_status_t status;

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): unsubscribing...", 

+			 sub, state[sub->state].ptr));

+

+    /* Lock subscription. */

+    pj_mutex_lock(sub->mutex);

+

+    pj_assert(sub->role == PJSIP_ROLE_UAC);

+

+    /* Kill refresh timer, if any. */

+    if (sub->timer.id != 0) {

+	sub->timer.id = 0;

+	pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);

+    }

+

+    /* Create request. */

+    tdata = pjsip_endpt_create_request_from_hdr( sub->endpt, 

+						 &SUBSCRIBE,

+						 sub->to->uri,

+						 sub->from, sub->to, 

+						 sub->contact, sub->call_id,

+						 sub->cseq++,

+						 NULL);

+

+    if (!tdata) {

+	pj_mutex_unlock(sub->mutex);

+	return -1;

+    }

+

+    /* Add headers to request. */

+    pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->event));

+    sub->uac_expires->ivalue = 0;

+    pjsip_msg_add_hdr( tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->uac_expires));

+

+    /* Add authentication. */

+    pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess,

+			 sub->cred_cnt, sub->cred_info);

+

+

+    /* Route set. */

+    route = sub->route_set.next;

+    while (route != &sub->route_set) {

+	pj_list_insert_before( &tdata->msg->hdr,

+			       pjsip_hdr_shallow_clone(tdata->pool, route));

+	route = route->next;

+    }

+

+    /* Prevent timer from refreshing itself. */

+    sub->default_interval = 0;

+

+    /* Set state. */

+    sub_set_state( sub, PJSIP_EVENT_SUB_STATE_TERMINATED );

+

+    /* Send the request. */

+    status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, 

+				       &on_subscribe_response);

+    if (status == 0) {

+	sub->pending_tsx++;

+    }

+

+    pj_mutex_unlock(sub->mutex);

+

+    if (status != 0) {

+	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): FAILED to unsubscribe!", 

+			     sub, state[sub->state].ptr));

+    }

+

+    return status;

+}

+

+/*

+ * Send notify.

+ */

+PJ_DEF(pj_status_t) pjsip_event_sub_notify(pjsip_event_sub *sub,

+					   pjsip_event_sub_state new_state,

+					   const pj_str_t *reason,

+					   pjsip_msg_body *body)

+{

+    pjsip_tx_data *tdata;

+    pjsip_sub_state_hdr *ss_hdr;

+    const pjsip_route_hdr *route;

+    pj_time_val now;

+    pj_status_t status;

+    pjsip_event_sub_state old_state = sub->state;

+

+    pj_gettimeofday(&now);

+

+    pj_assert(sub->role == PJSIP_ROLE_UAS);

+    if (sub->role != PJSIP_ROLE_UAS)

+	return -1;

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sending NOTIFY", 

+			 sub, state[new_state].ptr));

+

+    /* Lock subscription. */

+    pj_mutex_lock(sub->mutex);

+

+    /* Can not send NOTIFY if current state is NULL. We can accept TERMINATED. */

+    if (sub->state==PJSIP_EVENT_SUB_STATE_NULL) {

+	pj_assert(0);

+	pj_mutex_unlock(sub->mutex);

+	return -1;

+    }

+

+    /* Update state no matter what. */

+    sub_set_state(sub, new_state);

+

+    /* Create transmit data. */

+    tdata = pjsip_endpt_create_request_from_hdr( sub->endpt,

+						 &NOTIFY,

+						 sub->to->uri,

+						 sub->from, sub->to,

+						 sub->contact, sub->call_id,

+						 sub->cseq++,

+						 NULL);

+    if (!tdata) {

+	pj_mutex_unlock(sub->mutex);

+	return -1;

+    }

+

+    /* Add Event header. */

+    pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, sub->event));

+

+    /* Add Subscription-State header. */

+    ss_hdr = pjsip_sub_state_hdr_create(tdata->pool);

+    ss_hdr->sub_state = state[new_state];

+    ss_hdr->expires_param = sub->expiry_time.sec - now.sec;

+    if (ss_hdr->expires_param < 0)

+	ss_hdr->expires_param = 0;

+    if (reason)

+	pj_strdup(tdata->pool, &ss_hdr->reason_param, reason);

+    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)ss_hdr);

+

+    /* Add Allow-Events header. */

+    pjsip_msg_add_hdr( tdata->msg, 

+		       pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events));

+

+    /* Add authentication */

+    pjsip_auth_init_req( sub->pool, tdata, &sub->auth_sess,

+			 sub->cred_cnt, sub->cred_info);

+

+    /* Route set. */

+    route = sub->route_set.next;

+    while (route != &sub->route_set) {

+	pj_list_insert_before( &tdata->msg->hdr,

+			       pjsip_hdr_shallow_clone(tdata->pool, route));

+	route = route->next;

+    }

+

+    /* Attach body. */

+    tdata->msg->body = body;

+

+    /* That's it, send! */

+    status = pjsip_endpt_send_request( sub->endpt, tdata, -1, sub, &on_notify_response);

+    if (status == 0)

+	sub->pending_tsx++;

+

+    /* If terminated notify application. */

+    if (new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) {

+	if (sub->cb.on_sub_terminated) {

+	    sub->pending_tsx++;

+	    (*sub->cb.on_sub_terminated)(sub, reason);

+	    sub->pending_tsx--;

+	}

+    }

+

+    /* Unlock subscription. */

+    pj_mutex_unlock(sub->mutex);

+

+    if (status != 0) {

+	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): failed to send NOTIFY", 

+			     sub, state[sub->state].ptr));

+    }

+

+    if (sub->delete_flag && sub->pending_tsx <= 0) {

+	pjsip_event_sub_destroy(sub);

+    }

+    return status;

+}

+

+

+/* If this timer callback is called, it means subscriber hasn't refreshed its

+ * subscription on-time. Set the state to terminated. This will also send

+ * NOTIFY with Subscription-State set to terminated.

+ */

+static void uas_expire_timer_cb( pj_timer_heap_t *timer_heap, pj_timer_entry *entry)

+{

+    pjsip_event_sub *sub = entry->user_data;

+    pj_str_t reason = { "timeout", 7 };

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): UAS subscription expired!", 

+			 sub, state[sub->state].ptr));

+

+    pj_mutex_lock(sub->mutex);

+    sub->timer.id = 0;

+

+    if (sub->cb.on_sub_terminated && sub->state!=PJSIP_EVENT_SUB_STATE_TERMINATED) {

+	/* Notify application, but prevent app from destroying the sub. */

+	++sub->pending_tsx;

+	(*sub->cb.on_sub_terminated)(sub, &reason);

+	--sub->pending_tsx;

+    }

+    //pjsip_event_sub_notify( sub, PJSIP_EVENT_SUB_STATE_TERMINATED, 

+    //			    &reason, NULL);

+    pj_mutex_unlock(sub->mutex);

+

+}

+

+/* Schedule notifier expiration. */

+static void sub_schedule_uas_expire( pjsip_event_sub *sub, int sec_delay)

+{

+    pj_time_val delay = { 0, 0 };

+    pj_parsed_time pt;

+

+    if (sub->timer.id != 0)

+	pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);

+

+    pj_gettimeofday(&sub->expiry_time);

+    sub->expiry_time.sec += sec_delay;

+

+    sub->timer.id = TIMER_ID_UAS_EXPIRY;

+    sub->timer.user_data = sub;

+    sub->timer.cb = &uas_expire_timer_cb;

+    delay.sec = sec_delay;

+    pjsip_endpt_schedule_timer( sub->endpt, &sub->timer, &delay);

+

+    pj_time_decode(&sub->expiry_time, &pt);

+    PJ_LOG(4,(THIS_FILE, 

+	      "event_sub%p (%s)(UAS): will expire at %02d:%02d:%02d (in %d secs)",

+	      sub, state[sub->state].ptr, pt.hour, pt.min, pt.sec, sec_delay));

+}

+

+/* This timer is called for UAC to refresh the subscription. */

+static void refresh_timer_cb( pj_timer_heap_t *timer_heap, pj_timer_entry *entry)

+{

+    pjsip_event_sub *sub = entry->user_data;

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): refresh subscription timer", 

+			 sub, state[sub->state].ptr));

+

+    pj_mutex_lock(sub->mutex);

+    sub->timer.id = 0;

+    send_sub_refresh(sub);

+    pj_mutex_unlock(sub->mutex);

+}

+

+

+/* This will update the UAC's refresh schedule. */

+static void update_next_refresh(pjsip_event_sub *sub, int interval)

+{

+    pj_time_val delay = {0, 0};

+    pj_parsed_time pt;

+

+    if (interval < SECONDS_BEFORE_EXPIRY) {

+	PJ_LOG(4,(THIS_FILE, 

+		  "event_sub%p (%s): expiration delay too short (%d sec)! updated.",

+		  sub, state[sub->state].ptr, interval));

+	interval = SECONDS_BEFORE_EXPIRY;

+    }

+

+    if (sub->timer.id != 0)

+	pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);

+

+    sub->timer.id = TIMER_ID_REFRESH;

+    sub->timer.user_data = sub;

+    sub->timer.cb = &refresh_timer_cb;

+    pj_gettimeofday(&sub->expiry_time);

+    delay.sec = interval - SECONDS_BEFORE_EXPIRY;

+    sub->expiry_time.sec += delay.sec;

+

+    pj_time_decode(&sub->expiry_time, &pt);

+    PJ_LOG(4,(THIS_FILE, 

+	      "event_sub%p (%s): will send SUBSCRIBE at %02d:%02d:%02d (in %d secs)",

+	      sub, state[sub->state].ptr, 

+	      pt.hour, pt.min, pt.sec,

+	      delay.sec));

+

+    pjsip_endpt_schedule_timer( sub->endpt, &sub->timer, &delay );

+}

+

+

+/* Find subscription in the hash table. 

+ * If found, lock the subscription before returning to caller.

+ */

+static pjsip_event_sub *find_sub(pjsip_rx_data *rdata)

+{

+    pj_str_t key;

+    pjsip_role_e role;

+    pjsip_event_sub *sub;

+    pjsip_method *method = &rdata->msg->line.req.method;

+    pj_str_t *tag;

+

+    if (rdata->msg->type == PJSIP_REQUEST_MSG) {

+	if (pjsip_method_cmp(method, &SUBSCRIBE)==0) {

+	    role = PJSIP_ROLE_UAS;

+	    tag = &rdata->to_tag;

+	} else {

+	    pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0);

+	    role = PJSIP_ROLE_UAC;

+	    tag = &rdata->to_tag;

+	}

+    } else {

+	if (pjsip_method_cmp(&rdata->cseq->method, &SUBSCRIBE)==0) {

+	    role = PJSIP_ROLE_UAC;

+	    tag = &rdata->from_tag;

+	} else {

+	    pj_assert(pjsip_method_cmp(method, &NOTIFY) == 0);

+	    role = PJSIP_ROLE_UAS;

+	    tag = &rdata->from_tag;

+	}

+    }

+    create_subscriber_key( &key, rdata->pool, role, &rdata->call_id, tag);

+

+    pj_mutex_lock(mgr.mutex);

+    sub = pj_hash_get(mgr.ht, key.ptr, key.slen);

+    if (sub)

+	pj_mutex_lock(sub->mutex);

+    pj_mutex_unlock(mgr.mutex);

+

+    return sub;

+}

+

+

+/* This function is called when we receive SUBSCRIBE request message 

+ * to refresh existing subscription.

+ */

+static void on_received_sub_refresh( pjsip_event_sub *sub, 

+				     pjsip_transaction *tsx, pjsip_rx_data *rdata)

+{

+    pjsip_event_hdr *e;

+    pjsip_expires_hdr *expires;

+    pj_str_t hname;

+    int status = 200;

+    pj_str_t reason_phrase = { NULL, 0 };

+    int new_state = sub->state;

+    int old_state = sub->state;

+    int new_interval = 0;

+    pjsip_tx_data *tdata;

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received target refresh", 

+			 sub, state[sub->state].ptr));

+

+    /* Check that the event matches. */

+    hname = pj_str("Event");

+    e = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL);

+    if (!e) {

+	status = 400;

+	reason_phrase = pj_str("Missing Event header");

+	goto send_response;

+    }

+    if (pj_stricmp(&e->event_type, &sub->event->event_type) != 0 ||

+	pj_stricmp(&e->id_param, &sub->event->id_param) != 0)

+    {

+	status = 481;

+	reason_phrase = pj_str("Subscription does not exist");

+	goto send_response;

+    }

+

+    /* Check server state. */

+    if (sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED) {

+	status = 481;

+	reason_phrase = pj_str("Subscription does not exist");

+	goto send_response;

+    }

+

+    /* Check expires header. */

+    expires = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_EXPIRES, NULL);

+    if (!expires) {

+	/*

+	status = 400;

+	reason_phrase = pj_str("Missing Expires header");

+	goto send_response;

+	*/

+	new_interval = sub->default_interval;

+    } else {

+	/* Check that interval is not too short. 

+	 * Note that expires time may be zero (for unsubscription).

+	 */

+	new_interval = expires->ivalue;

+	if (new_interval != 0 && new_interval < SECONDS_BEFORE_EXPIRY) {

+	    status = PJSIP_SC_INTERVAL_TOO_BRIEF;

+	    goto send_response;

+	}

+    }

+

+    /* Update interval. */

+    sub->default_interval = new_interval;

+    pj_gettimeofday(&sub->expiry_time);

+    sub->expiry_time.sec += new_interval;

+

+    /* Update timer only if this is not unsubscription. */

+    if (new_interval > 0) {

+	sub->default_interval = new_interval;

+	sub_schedule_uas_expire( sub, new_interval );

+

+	/* Call callback. */

+	if (sub->cb.on_received_refresh) {

+	    sub->pending_tsx++;

+	    (*sub->cb.on_received_refresh)(sub, rdata);

+	    sub->pending_tsx--;

+	}

+    }

+

+send_response:

+    tdata = pjsip_endpt_create_response( sub->endpt, rdata, status);

+    if (tdata) {

+	if (reason_phrase.slen)

+	    tdata->msg->line.status.reason = reason_phrase;

+

+	/* Add Expires header. */

+	expires = pjsip_expires_hdr_create(tdata->pool);

+	expires->ivalue = sub->default_interval;

+	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires);

+

+	if (PJSIP_IS_STATUS_IN_CLASS(status,200)) {

+	    pjsip_msg_add_hdr(tdata->msg, 

+			      pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events));

+	}

+	/* Send down to transaction. */

+	pjsip_tsx_on_tx_msg(tsx, tdata);

+    }

+

+    if (sub->default_interval==0 || !PJSIP_IS_STATUS_IN_CLASS(status,200)) {

+	/* Notify application if sub is terminated. */

+	new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;

+	sub_set_state(sub, new_state);

+	if (new_state!=old_state && sub->cb.on_sub_terminated) {

+	    pj_str_t reason = {"", 0};

+	    if (reason_phrase.slen) reason = reason_phrase;

+	    else reason = *pjsip_get_status_text(status);

+

+	    sub->pending_tsx++;

+	    (*sub->cb.on_sub_terminated)(sub, &reason);

+	    sub->pending_tsx--;

+	}

+    }

+

+    pj_mutex_unlock(sub->mutex);

+

+    /* Prefer to call log when we're not holding the mutex. */

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sent refresh response %s, status=%d", 

+			 sub, state[sub->state].ptr,

+			 (tdata ? tdata->obj_name : "null"), status));

+

+    /* Check if application has requested deletion. */

+    if (sub->delete_flag && sub->pending_tsx <= 0) {

+	pjsip_event_sub_destroy(sub);

+    }

+

+}

+

+

+/* This function is called when we receive SUBSCRIBE request message for 

+ * a new subscription.

+ */

+static void on_new_subscription( pjsip_transaction *tsx, pjsip_rx_data *rdata )

+{

+    package *pkg;

+    pj_pool_t *pool;

+    pjsip_event_sub *sub = NULL;

+    pj_str_t hname;

+    int status = 200;

+    pj_str_t reason = { NULL, 0 };

+    pjsip_tx_data *tdata;

+    pjsip_expires_hdr *expires;

+    pjsip_accept_hdr *accept;

+    pjsip_event_hdr *evhdr;

+

+    /* Get the Event header. */

+    hname = pj_str("Event");

+    evhdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL);

+    if (!evhdr) {

+	status = 400;

+	reason = pj_str("No Event header in request");

+	goto send_response;

+    }

+

+    /* Find corresponding package. 

+     * We don't lock the manager's mutex since we assume the package list

+     * won't change once the application is running!

+     */

+    pkg = mgr.pkg_list.next;

+    while (pkg != &mgr.pkg_list) {

+	if (pj_stricmp(&pkg->event, &evhdr->event_type) == 0)

+	    break;

+	pkg = pkg->next;

+    }

+

+    if (pkg == &mgr.pkg_list) {

+	/* Event type is not supported by any packages! */

+	status = 489;

+	reason = pj_str("Bad Event");

+	goto send_response;

+    }

+

+    /* First check that the Accept specification matches the 

+     * package's Accept types.

+     */

+    accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL);

+    if (accept) {

+	unsigned i;

+	pj_str_t *content_type = NULL;

+

+	for (i=0; i<accept->count && !content_type; ++i) {

+	    int j;

+	    for (j=0; j<pkg->accept_cnt; ++j) {

+		if (pj_stricmp(&accept->values[i], &pkg->accept[j])==0) {

+		    content_type = &pkg->accept[j];

+		    break;

+		}

+	    }

+	}

+

+	if (!content_type) {

+	    status = PJSIP_SC_NOT_ACCEPTABLE_HERE;

+	    goto send_response;

+	}

+    }

+

+    /* Check whether the package wants to accept the subscription. */

+    pj_assert(pkg->cb.on_query_subscribe != NULL);

+    (*pkg->cb.on_query_subscribe)(rdata, &status);

+    if (!PJSIP_IS_STATUS_IN_CLASS(status,200))

+	goto send_response;

+

+    /* Create new subscription record. */

+    pool = pjsip_endpt_create_pool(tsx->endpt, "esub", 

+				   SUB_POOL_SIZE, SUB_POOL_INC);

+    if (!pool) {

+	status = 500;

+	goto send_response;

+    }

+    sub = pj_pool_calloc(pool, 1, sizeof(*sub));

+    sub->pool = pool;

+    sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE);

+    if (!sub->mutex) {

+	status = 500;

+	goto send_response;

+    }

+

+    PJ_LOG(4,(THIS_FILE, "event_sub%p: notifier is created.", sub));

+

+    /* Start locking mutex. */

+    pj_mutex_lock(sub->mutex);

+

+    /* Init UAS subscription */

+    sub->endpt = tsx->endpt;

+    sub->role = PJSIP_ROLE_UAS;

+    sub->state = PJSIP_EVENT_SUB_STATE_PENDING;

+    sub->state_str = state[sub->state];

+    pj_list_init(&sub->auth_sess);

+    pj_list_init(&sub->route_set);

+    sub->from = pjsip_hdr_clone(pool, rdata->to);

+    pjsip_fromto_set_from(sub->from);

+    if (sub->from->tag.slen == 0) {

+	pj_create_unique_string(pool, &sub->from->tag);

+	rdata->to->tag = sub->from->tag;

+    }

+    sub->to = pjsip_hdr_clone(pool, rdata->from);

+    pjsip_fromto_set_to(sub->to);

+    sub->contact = pjsip_contact_hdr_create(pool);

+    sub->contact->uri = sub->from->uri;

+    sub->call_id = pjsip_cid_hdr_create(pool);

+    pj_strdup(pool, &sub->call_id->id, &rdata->call_id);

+    sub->cseq = pj_rand() % 0xFFFF;

+    

+    expires = pjsip_msg_find_hdr( rdata->msg, PJSIP_H_EXPIRES, NULL);

+    if (expires) {

+	sub->default_interval = expires->ivalue;

+	if (sub->default_interval > 0 && 

+	    sub->default_interval < SECONDS_BEFORE_EXPIRY) 

+	{

+	    status = 423; /* Interval too short. */

+	    goto send_response;

+	}

+    } else {

+	sub->default_interval = 600;

+    }

+

+    /* Clone Event header. */

+    sub->event = pjsip_hdr_clone(pool, evhdr);

+

+    /* Register to hash table. */

+    create_subscriber_key(&sub->key, pool, PJSIP_ROLE_UAS, &sub->call_id->id,

+			  &sub->from->tag);

+    pj_mutex_lock(mgr.mutex);

+    pj_hash_set(pool, mgr.ht, sub->key.ptr, sub->key.slen, sub);

+    pj_mutex_unlock(mgr.mutex);

+

+    /* Set timer where subscription will expire only when expires<>0. 

+     * Subscriber may send new subscription with expires==0.

+     */

+    if (sub->default_interval != 0) {

+	sub_schedule_uas_expire( sub, sub->default_interval-SECONDS_BEFORE_EXPIRY);

+    }

+

+    /* Notify application. */

+    if (pkg->cb.on_subscribe) {

+	pjsip_event_sub_cb *cb = NULL;

+	sub->pending_tsx++;

+	(*pkg->cb.on_subscribe)(sub, rdata, &cb, &sub->default_interval);

+	sub->pending_tsx--;

+	if (cb == NULL)

+	    pj_memset(&sub->cb, 0, sizeof(*cb));

+	else

+	    pj_memcpy(&sub->cb, cb, sizeof(*cb));

+    }

+

+

+send_response:

+    PJ_LOG(4,(THIS_FILE, "event_sub%p (%s)(UAS): status=%d", 

+			  sub, state[sub->state].ptr, status));

+

+    tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status);

+    if (tdata) {

+	if (reason.slen) {

+	    /* Customize reason text. */

+	    tdata->msg->line.status.reason = reason;

+	}

+	if (PJSIP_IS_STATUS_IN_CLASS(status,200)) {

+	    /* Add Expires header. */

+	    pjsip_expires_hdr *hdr;

+

+	    hdr = pjsip_expires_hdr_create(tdata->pool);

+	    hdr->ivalue = sub->default_interval;

+	    pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr );

+	}

+	if (status == 423) {

+	    /* Add Min-Expires header. */

+	    pjsip_min_expires_hdr *hdr;

+

+	    hdr = pjsip_min_expires_hdr_create(tdata->pool);

+	    hdr->ivalue = SECONDS_BEFORE_EXPIRY;

+	    pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr);

+	}

+	if (status == 489 || 

+	    status==PJSIP_SC_NOT_ACCEPTABLE_HERE ||

+	    PJSIP_IS_STATUS_IN_CLASS(status,200)) 

+	{

+	    /* Add Allow-Events header. */

+	    pjsip_hdr *hdr;

+	    hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events);

+	    pjsip_msg_add_hdr(tdata->msg, hdr);

+

+	    /* Should add Accept header?. */

+	}

+

+	pjsip_tsx_on_tx_msg(tsx, tdata);

+    }

+

+    /* If received new subscription with expires=0, terminate. */

+    if (sub && sub->default_interval == 0) {

+	pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED);

+	if (sub->cb.on_sub_terminated) {

+	    pj_str_t reason = { "timeout", 7 };

+	    (*sub->cb.on_sub_terminated)(sub, &reason);

+	}

+    }

+

+    if (!PJSIP_IS_STATUS_IN_CLASS(status,200) || (sub && sub->delete_flag)) {

+	if (sub && sub->mutex) {

+	    pjsip_event_sub_destroy(sub);

+	} else if (sub) {

+	    pjsip_endpt_destroy_pool(tsx->endpt, sub->pool);

+	}

+    } else {

+	pj_assert(status >= 200);

+	pj_mutex_unlock(sub->mutex);

+    }

+}

+

+/* This is the main callback when SUBSCRIBE request is received. */

+static void on_subscribe_request(pjsip_transaction *tsx, pjsip_rx_data *rdata)

+{

+    pjsip_event_sub *sub = find_sub(rdata);

+

+    if (sub)

+	on_received_sub_refresh(sub, tsx, rdata);

+    else

+	on_new_subscription(tsx, rdata);

+}

+

+

+/* This callback is called when response to SUBSCRIBE is received. */

+static void on_subscribe_response(void *token, pjsip_event *event)

+{

+    pjsip_event_sub *sub = token;

+    pjsip_transaction *tsx = event->obj.tsx;

+    int new_state, old_state = sub->state;

+

+    pj_assert(tsx->status_code >= 200);

+    if (tsx->status_code < 200)

+	return;

+

+    pj_assert(sub->role == PJSIP_ROLE_UAC);

+

+    /* Lock mutex. */

+    pj_mutex_lock(sub->mutex);

+

+    /* If request failed with 401/407 error, silently retry the request. */

+    if (tsx->status_code==401 || tsx->status_code==407) {

+	pjsip_tx_data *tdata;

+	tdata = pjsip_auth_reinit_req(sub->endpt,

+				      sub->pool, &sub->auth_sess,

+				      sub->cred_cnt, sub->cred_info,

+				      tsx->last_tx, event->src.rdata );

+	if (tdata) {

+	    int status;

+	    pjsip_cseq_hdr *cseq;

+	    cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);

+	    cseq->cseq = sub->cseq++;

+	    status = pjsip_endpt_send_request( sub->endpt, tdata, 

+					       -1, sub, 

+					       &on_subscribe_response);

+	    if (status == 0) {

+		pj_mutex_unlock(sub->mutex);

+		return;

+	    }

+	}

+    }

+

+    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code,200)) {

+	/* Update To tag. */

+	if (sub->to->tag.slen == 0)

+	    pj_strdup(sub->pool, &sub->to->tag, &event->src.rdata->to_tag);

+

+	new_state = sub->state;

+

+    } else if (tsx->status_code == 481) {

+	new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;

+

+    } else if (tsx->status_code >= 300) {

+	/* RFC 3265 Section 3.1.4.2:

+         * If a SUBSCRIBE request to refresh a subscription fails 

+	 * with a non-481 response, the original subscription is still 

+	 * considered valid for the duration of original exires.

+	 *

+	 * Note:

+	 * Since we normally send SUBSCRIBE for refreshing the subscription,

+	 * it means the subscription already expired anyway. So we terminate

+	 * the subscription now.

+	 */

+	if (sub->state != PJSIP_EVENT_SUB_STATE_ACTIVE) {

+	    new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;

+	} else {

+	    /* Use this to be compliant with Section 3.1.4.2

+	      new_state = sub->state;

+	     */

+	    new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;

+	}

+    } else {

+	pj_assert(0);

+	new_state = sub->state;

+    }

+

+    if (new_state != sub->state && sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) {

+	sub_set_state(sub, new_state);

+    }

+

+    if (sub->state == PJSIP_EVENT_SUB_STATE_ACTIVE ||

+	sub->state == PJSIP_EVENT_SUB_STATE_PENDING)

+    {

+	/*

+	 * Register timer for next subscription refresh, but only when

+	 * we're not unsubscribing. Also update default_interval and Expires

+	 * header.

+	 */

+	if (sub->default_interval > 0 && !sub->delete_flag) {

+	    pjsip_expires_hdr *exp = NULL;

+	    

+	    /* Could be transaction timeout. */

+	    if (event->src_type == PJSIP_EVENT_RX_MSG) {

+		exp = pjsip_msg_find_hdr(event->src.rdata->msg,

+					 PJSIP_H_EXPIRES, NULL);

+	    }

+

+	    if (exp) {

+		int delay = exp->ivalue;

+		if (delay > 0) {

+		    pj_time_val new_expiry;

+		    pj_gettimeofday(&new_expiry);

+		    new_expiry.sec += delay;

+		    if (sub->timer.id==0 || 

+			new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2) 

+		    {

+		    //if (delay > 0 && delay < sub->default_interval) {

+			sub->default_interval = delay;

+			sub->uac_expires->ivalue = delay;

+			update_next_refresh(sub, delay);

+		    }

+		}

+	    }

+	}

+    }

+

+    /* Call callback. */

+    if (!sub->delete_flag) {

+	if (sub->cb.on_received_sub_response) {

+	    (*sub->cb.on_received_sub_response)(sub, event);

+	}

+    }

+

+    /* Notify application if we're terminated. */

+    if (new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) {

+	if (sub->cb.on_sub_terminated) {

+	    pj_str_t reason;

+	    if (event->src_type == PJSIP_EVENT_RX_MSG)

+		reason = event->src.rdata->msg->line.status.reason;

+	    else

+		reason = *pjsip_get_status_text(tsx->status_code);

+

+	    (*sub->cb.on_sub_terminated)(sub, &reason);

+	}

+    }

+

+    /* Decrement pending tsx count. */

+    --sub->pending_tsx;

+    pj_assert(sub->pending_tsx >= 0);

+

+    if (sub->delete_flag && sub->pending_tsx <= 0) {

+	pjsip_event_sub_destroy(sub);

+    } else {

+	pj_mutex_unlock(sub->mutex);

+    }

+

+    /* DO NOT ACCESS sub FROM NOW ON! IT MIGHT HAVE BEEN DELETED */

+}

+

+/*

+ * This callback called when we receive incoming NOTIFY request.

+ */

+static void on_notify_request(pjsip_transaction *tsx, pjsip_rx_data *rdata)

+{

+    pjsip_event_sub *sub;

+    pjsip_tx_data *tdata;

+    int status = 200;

+    int old_state;

+    pj_str_t reason = { NULL, 0 };

+    pj_str_t reason_phrase = { NULL, 0 };

+    int new_state = PJSIP_EVENT_SUB_STATE_NULL;

+

+    /* Find subscription based on Call-ID and From tag. 

+     * This will also automatically lock the subscription, if it's found.

+     */

+    sub = find_sub(rdata);

+    if (!sub) {

+	/* RFC 3265: Section 3.2 Description of NOTIFY Behavior:

+	 * Answer with 481 Subscription does not exist.

+	 */

+	PJ_LOG(4,(THIS_FILE, "Unable to find subscription for incoming NOTIFY!"));

+	status = 481;

+	reason_phrase = pj_str("Subscription does not exist");

+

+    } else {

+	pj_assert(sub->role == PJSIP_ROLE_UAC);

+	PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received NOTIFY", 

+			     sub, state[sub->state].ptr));

+

+    }

+

+    new_state = old_state = sub->state;

+

+    /* RFC 3265: Section 3.2.1

+     * Check that the Event header match the subscription. 

+     */

+    if (status == 200) {

+	pjsip_event_hdr *hdr;

+	pj_str_t hname = { "Event", 5 };

+

+	hdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL);

+	if (!hdr) {

+	    status = PJSIP_SC_BAD_REQUEST;

+	    reason_phrase = pj_str("No Event header found");

+	} else if (pj_stricmp(&hdr->event_type, &sub->event->event_type) != 0 ||

+		   pj_stricmp(&hdr->id_param, &sub->event->id_param) != 0) 

+	{

+	    status = 481;

+	    reason_phrase = pj_str("Subscription does not exist");

+	}

+    }

+

+    /* Update subscription state and timer. */

+    if (status == 200) {

+	pjsip_sub_state_hdr *hdr;

+	const pj_str_t hname = { "Subscription-State", 18 };

+	const pj_str_t state_active = { "active", 6 },

+		       state_pending = { "pending", 7},

+		       state_terminated = { "terminated", 10 };

+

+	hdr = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL);

+	if (!hdr) {

+	    status = PJSIP_SC_BAD_REQUEST;

+	    reason_phrase = pj_str("No Subscription-State header found");

+	    goto process;

+	} 

+

+	/*

+	 * Update subscription state.

+	 */

+	if (pj_stricmp(&hdr->sub_state, &state_active) == 0) {

+	    if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED)

+		new_state = PJSIP_EVENT_SUB_STATE_ACTIVE;

+	} else if (pj_stricmp(&hdr->sub_state, &state_pending) == 0) {

+	    if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED)

+		new_state = PJSIP_EVENT_SUB_STATE_PENDING;

+	} else if (pj_stricmp(&hdr->sub_state, &state_terminated) == 0) {

+	    new_state = PJSIP_EVENT_SUB_STATE_TERMINATED;

+	} else {

+	    new_state = PJSIP_EVENT_SUB_STATE_UNKNOWN;

+	}

+

+	reason = hdr->reason_param;

+

+	if (new_state != sub->state && new_state != PJSIP_EVENT_SUB_STATE_NULL &&

+	    sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) 

+	{

+	    sub_set_state(sub, new_state);

+	    if (new_state == PJSIP_EVENT_SUB_STATE_UNKNOWN) {

+		pj_strdup_with_null(sub->pool, &sub->state_str, &hdr->sub_state);

+	    } else {

+		sub->state_str = state[new_state];

+	    }

+	}

+

+	/*

+	 * Update timeout timer in required, just in case notifier changed the 

+         * expiration to shorter time.

+	 * Section 3.2.2: the expires param can only shorten the interval.

+	 */

+	if ((sub->state==PJSIP_EVENT_SUB_STATE_ACTIVE || 

+	     sub->state==PJSIP_EVENT_SUB_STATE_PENDING) && hdr->expires_param > 0) 

+	{

+	    pj_time_val now, new_expiry;

+

+	    pj_gettimeofday(&now);

+	    new_expiry.sec = now.sec + hdr->expires_param;

+	    if (sub->timer.id==0 || 

+		new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2) 

+	    {

+		update_next_refresh(sub, hdr->expires_param);

+	    }

+	}

+    }

+

+process:

+    /* Note: here we sub MAY BE NULL! */

+

+    /* Send response to NOTIFY */

+    tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status );

+    if (tdata) {

+	if (reason_phrase.slen)

+	    tdata->msg->line.status.reason = reason_phrase;

+

+	if (PJSIP_IS_STATUS_IN_CLASS(status,200)) {

+	    pjsip_hdr *hdr;

+	    hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events);

+	    pjsip_msg_add_hdr( tdata->msg, hdr);

+	}

+

+	pjsip_tsx_on_tx_msg(tsx, tdata);

+    }

+

+    /* Call NOTIFY callback, if any. */

+    if (sub && PJSIP_IS_STATUS_IN_CLASS(status,200) && sub->cb.on_received_notify) {

+	sub->pending_tsx++;

+	(*sub->cb.on_received_notify)(sub, rdata);

+	sub->pending_tsx--;

+    }

+

+    /* Check if subscription is terminated and call callback. */

+    if (sub && new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) {

+	if (sub->cb.on_sub_terminated) {

+	    sub->pending_tsx++;

+	    (*sub->cb.on_sub_terminated)(sub, &reason);

+	    sub->pending_tsx--;

+	}

+    }

+

+    /* Check if application has requested deletion. */

+    if (sub && sub->delete_flag && sub->pending_tsx <= 0) {

+	pjsip_event_sub_destroy(sub);

+    } else if (sub) {

+	pj_mutex_unlock(sub->mutex);

+    }

+}

+

+/* This callback is called when we received NOTIFY response. */

+static void on_notify_response(void *token, pjsip_event *event)

+{

+    pjsip_event_sub *sub = token;

+    pjsip_event_sub_state old_state = sub->state;

+    pjsip_transaction *tsx = event->obj.tsx;

+

+    /* Lock the subscription. */

+    pj_mutex_lock(sub->mutex);

+

+    pj_assert(sub->role == PJSIP_ROLE_UAS);

+

+    /* If request failed with authorization failure, silently retry. */

+    if (tsx->status_code==401 || tsx->status_code==407) {

+	pjsip_tx_data *tdata;

+	tdata = pjsip_auth_reinit_req(sub->endpt,

+				      sub->pool, &sub->auth_sess,

+				      sub->cred_cnt, sub->cred_info,

+				      tsx->last_tx, event->src.rdata );

+	if (tdata) {

+	    int status;

+	    pjsip_cseq_hdr *cseq;

+	    cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);

+	    cseq->cseq = sub->cseq++;

+	    status = pjsip_endpt_send_request( sub->endpt, tdata, 

+					       -1, sub, 

+					       &on_notify_response);

+	    if (status == 0) {

+		pj_mutex_unlock(sub->mutex);

+		return;

+	    }

+	}

+    }

+

+    /* Notify application. */

+    if (sub->cb.on_received_notify_response)

+	(*sub->cb.on_received_notify_response)(sub, event);

+

+    /* Check for response 481. */

+    if (event->obj.tsx->status_code == 481) {

+	/* Remote says that the subscription does not exist! 

+	 * Terminate subscription!

+	 */

+	sub_set_state(sub, PJSIP_EVENT_SUB_STATE_TERMINATED);

+	if (sub->timer.id) {

+	    pjsip_endpt_cancel_timer(sub->endpt, &sub->timer);

+	    sub->timer.id = 0;

+	}

+

+	PJ_LOG(4, (THIS_FILE, 

+		   "event_sub%p (%s): got 481 response to NOTIFY. Terminating...",

+		   sub, state[sub->state].ptr));

+

+	/* Notify app. */

+	if (sub->state!=old_state && sub->cb.on_sub_terminated) 

+	    (*sub->cb.on_sub_terminated)(sub, &event->src.rdata->msg->line.status.reason);

+    }

+

+    /* Decrement pending transaction count. */

+    --sub->pending_tsx;

+    pj_assert(sub->pending_tsx >= 0);

+

+    /* Check that the subscription is marked for deletion. */

+    if (sub->delete_flag && sub->pending_tsx <= 0) {

+	pjsip_event_sub_destroy(sub);

+    } else {

+	pj_mutex_unlock(sub->mutex);

+    }

+

+    /* DO NOT ACCESS sub, IT MIGHT HAVE BEEN DESTROYED! */

+}

+

+

+/* This is the transaction handler for incoming SUBSCRIBE and NOTIFY 

+ * requests. 

+ */

+static void tsx_handler( struct pjsip_module *mod, pjsip_event *event )

+{

+    pjsip_msg *msg;

+    pjsip_rx_data *rdata;

+

+    /* Only want incoming message events. */

+    if (event->src_type != PJSIP_EVENT_RX_MSG)

+	return;

+

+    rdata = event->src.rdata;

+    msg = rdata->msg;

+

+    /* Only want to process request messages. */

+    if (msg->type != PJSIP_REQUEST_MSG)

+	return;

+

+    /* Only want the first notification. */

+    if (event->obj.tsx && event->obj.tsx->status_code >= 100)

+	return;

+

+    if (pjsip_method_cmp(&msg->line.req.method, &SUBSCRIBE)==0) {

+	/* Process incoming SUBSCRIBE request. */

+	on_subscribe_request( event->obj.tsx, rdata );

+    } else if (pjsip_method_cmp(&msg->line.req.method, &NOTIFY)==0) {

+	/* Process incoming NOTIFY request. */

+	on_notify_request( event->obj.tsx, rdata );

+    }

+}

+

diff --git a/pjsip/src/pjsip-simple/event_notify_msg.c b/pjsip/src/pjsip-simple/event_notify_msg.c
index 9d0f0cd..2b69aef 100644
--- a/pjsip/src/pjsip-simple/event_notify_msg.c
+++ b/pjsip/src/pjsip-simple/event_notify_msg.c
@@ -1,307 +1,329 @@
-/* $Id$
- *
- */
-#include <pjsip_simple/event_notify_msg.h>
-#include <pjsip/print.h>
-#include <pjsip/sip_parser.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/except.h>
-
-static int pjsip_event_hdr_print( pjsip_event_hdr *hdr, 
-				  char *buf, pj_size_t size);
-static pjsip_event_hdr* pjsip_event_hdr_clone( pj_pool_t *pool, 
-					       const pjsip_event_hdr *hdr);
-static pjsip_event_hdr* pjsip_event_hdr_shallow_clone( pj_pool_t *pool,
-						       const pjsip_event_hdr*);
-
-static pjsip_hdr_vptr event_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_event_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_event_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_event_hdr_print,
-};
-
-
-PJ_DEF(pjsip_event_hdr*) pjsip_event_hdr_create(pj_pool_t *pool)
-{
-    pj_str_t event = { "Event", 5 };
-    pjsip_event_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    hdr->type = PJSIP_H_OTHER;
-    hdr->name = hdr->sname = event;
-    hdr->vptr = &event_hdr_vptr;
-    pj_list_init(hdr);
-    return hdr;
-}
-
-static int pjsip_event_hdr_print( pjsip_event_hdr *hdr, 
-				  char *buf, pj_size_t size)
-{
-    char *p = buf;
-    char *endbuf = buf+size;
-    int printed;
-
-    copy_advance(p, hdr->name);
-    *p++ = ':';
-    *p++ = ' ';
-
-    copy_advance(p, hdr->event_type);
-    copy_advance_pair(p, ";id=", 4, hdr->id_param);
-    if (hdr->other_param.slen)
-	copy_advance(p, hdr->other_param);
-    return p - buf;
-}
-
-static pjsip_event_hdr* pjsip_event_hdr_clone( pj_pool_t *pool, 
-					       const pjsip_event_hdr *rhs)
-{
-    pjsip_event_hdr *hdr = pjsip_event_hdr_create(pool);
-    pj_strdup(pool, &hdr->event_type, &rhs->event_type);
-    pj_strdup(pool, &hdr->id_param, &rhs->id_param);
-    pj_strdup(pool, &hdr->other_param, &rhs->other_param);
-    return hdr;
-}
-
-static pjsip_event_hdr* pjsip_event_hdr_shallow_clone( pj_pool_t *pool,
-						       const pjsip_event_hdr *rhs )
-{
-    pjsip_event_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-
-static int pjsip_allow_events_hdr_print(pjsip_allow_events_hdr *hdr, 
-					char *buf, pj_size_t size);
-static pjsip_allow_events_hdr* 
-pjsip_allow_events_hdr_clone(pj_pool_t *pool, 
-			     const pjsip_allow_events_hdr *hdr);
-static pjsip_allow_events_hdr* 
-pjsip_allow_events_hdr_shallow_clone(pj_pool_t *pool,
-				     const pjsip_allow_events_hdr*);
-
-static pjsip_hdr_vptr allow_event_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_allow_events_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_allow_events_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_allow_events_hdr_print,
-};
-
-
-PJ_DEF(pjsip_allow_events_hdr*) pjsip_allow_events_hdr_create(pj_pool_t *pool)
-{
-    pj_str_t allow_events = { "Allow-Events", 12 };
-    pjsip_allow_events_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    hdr->type = PJSIP_H_OTHER;
-    hdr->name = hdr->sname = allow_events;
-    hdr->vptr = &allow_event_hdr_vptr;
-    pj_list_init(hdr);
-    return hdr;
-}
-
-static int pjsip_allow_events_hdr_print(pjsip_allow_events_hdr *hdr, 
-					char *buf, pj_size_t size)
-{
-    char *p = buf;
-    char *endbuf = buf+size;
-    int printed;
-
-    copy_advance(p, hdr->name);
-    *p++ = ':';
-    *p++ = ' ';
-
-    if (hdr->event_cnt > 0) {
-	int i;
-	copy_advance(p, hdr->events[0]);
-	for (i=1; i<hdr->event_cnt; ++i) {
-	    copy_advance_pair(p, ",", 1, hdr->events[i]);
-	}
-    }
-
-    return p - buf;
-}
-
-static pjsip_allow_events_hdr* 
-pjsip_allow_events_hdr_clone(pj_pool_t *pool, 
-			     const pjsip_allow_events_hdr *rhs)
-{
-    int i;
-
-    pjsip_allow_events_hdr *hdr = pjsip_allow_events_hdr_create(pool);
-    hdr->event_cnt = rhs->event_cnt;
-    for (i=0; i<rhs->event_cnt; ++i) {
-	pj_strdup(pool, &hdr->events[i], &rhs->events[i]);
-    }
-    return hdr;
-}
-
-static pjsip_allow_events_hdr* 
-pjsip_allow_events_hdr_shallow_clone(pj_pool_t *pool,
-				     const pjsip_allow_events_hdr *rhs)
-{
-    pjsip_allow_events_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-
-static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, 
-				     char *buf, pj_size_t size);
-static pjsip_sub_state_hdr* 
-pjsip_sub_state_hdr_clone(pj_pool_t *pool, 
-			  const pjsip_sub_state_hdr *hdr);
-static pjsip_sub_state_hdr* 
-pjsip_sub_state_hdr_shallow_clone(pj_pool_t *pool,
-				  const pjsip_sub_state_hdr*);
-
-static pjsip_hdr_vptr sub_state_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_sub_state_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_sub_state_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_sub_state_hdr_print,
-};
-
-
-PJ_DEF(pjsip_sub_state_hdr*) pjsip_sub_state_hdr_create(pj_pool_t *pool)
-{
-    pj_str_t sub_state = { "Subscription-State", 18 };
-    pjsip_sub_state_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    hdr->type = PJSIP_H_OTHER;
-    hdr->name = hdr->sname = sub_state;
-    hdr->vptr = &sub_state_hdr_vptr;
-    hdr->expires_param = -1;
-    hdr->retry_after = -1;
-    pj_list_init(hdr);
-    return hdr;
-}
-
-static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, 
-				     char *buf, pj_size_t size)
-{
-    char *p = buf;
-    char *endbuf = buf+size;
-    int printed;
-
-    copy_advance(p, hdr->name);
-    *p++ = ':';
-    *p++ = ' ';
-
-    copy_advance(p, hdr->sub_state);
-    copy_advance_pair(p, ";reason=", 8, hdr->reason_param);
-    if (hdr->expires_param >= 0) {
-	pj_memcpy(p, ";expires=", 9);
-	p += 9;
-	printed = pj_utoa(hdr->expires_param, p);
-	p += printed;
-    }
-    if (hdr->retry_after >= 0) {
-	pj_memcpy(p, ";retry-after=", 13);
-	p += 9;
-	printed = pj_utoa(hdr->retry_after, p);
-	p += printed;
-    }
-    if (hdr->other_param.slen)
-	copy_advance(p, hdr->other_param);
-
-    return p - buf;
-}
-
-static pjsip_sub_state_hdr* 
-pjsip_sub_state_hdr_clone(pj_pool_t *pool, 
-			  const pjsip_sub_state_hdr *rhs)
-{
-    pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(pool);
-    pj_strdup(pool, &hdr->sub_state, &rhs->sub_state);
-    pj_strdup(pool, &hdr->reason_param, &rhs->reason_param);
-    hdr->retry_after = rhs->retry_after;
-    hdr->expires_param = rhs->expires_param;
-    pj_strdup(pool, &hdr->other_param, &rhs->other_param);
-    return hdr;
-}
-
-static pjsip_sub_state_hdr* 
-pjsip_sub_state_hdr_shallow_clone(pj_pool_t *pool,
-				  const pjsip_sub_state_hdr *rhs)
-{
-    pjsip_sub_state_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-static pjsip_event_hdr *parse_hdr_event(pj_scanner *scanner, 
-					pj_pool_t *pool)
-{
-    pjsip_event_hdr *hdr = pjsip_event_hdr_create(pool);
-    const pj_str_t id_param = { "id", 2 };
-
-    pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->event_type);
-
-    while (*scanner->current == ';') {
-	pj_str_t pname, pvalue;
-	pj_scan_get_char(scanner);
-	pjsip_parse_param_imp(scanner, &pname, &pvalue, 0);
-	if (pj_stricmp(&pname, &id_param)==0) {
-	    hdr->id_param = pvalue;
-	} else {
-	    pjsip_concat_param_imp(&hdr->other_param, pool, &pname, &pvalue, ';');
-	}
-    }
-    pjsip_parse_end_hdr_imp( scanner );
-    return hdr;
-}
-
-static pjsip_allow_events_hdr *parse_hdr_allow_events(pj_scanner *scanner, 
-						      pj_pool_t *pool)
-{
-    pjsip_allow_events_hdr *hdr = pjsip_allow_events_hdr_create(pool);
-
-    pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->events[0]);
-    hdr->event_cnt = 1;
-
-    while (*scanner->current == ',') {
-	pj_scan_get_char(scanner);
-	pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->events[hdr->event_cnt++]);
-	if (hdr->event_cnt == PJSIP_MAX_ALLOW_EVENTS) {
-	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-	}
-    }
-
-    pjsip_parse_end_hdr_imp( scanner );
-    return hdr;
-}
-
-static pjsip_sub_state_hdr *parse_hdr_sub_state(pj_scanner *scanner, 
-						pj_pool_t *pool)
-{
-    pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(pool);
-    const pj_str_t reason = { "reason", 6 },
-		   expires = { "expires", 7 },
-		   retry_after = { "retry-after", 11 };
-    pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->sub_state);
-
-    while (*scanner->current == ';') {
-	pj_str_t pname, pvalue;
-
-	pj_scan_get_char(scanner);
-	pjsip_parse_param_imp(scanner, &pname, &pvalue, 0);
-	if (pj_stricmp(&pname, &reason) == 0) {
-	    hdr->reason_param = pvalue;
-	} else if (pj_stricmp(&pname, &expires) == 0) {
-	    hdr->expires_param = pj_strtoul(&pvalue);
-	} else if (pj_stricmp(&pname, &retry_after) == 0) {
-	    hdr->retry_after = pj_strtoul(&pvalue);
-	} else {
-	    pjsip_concat_param_imp(&hdr->other_param, pool, &pname, &pvalue, ';');
-	}
-    }
-
-    pjsip_parse_end_hdr_imp( scanner );
-    return hdr;
-}
-
-PJ_DEF(void) pjsip_event_notify_init_parser(void)
-{
-    pjsip_register_hdr_parser( "Event", NULL, (pjsip_parse_hdr_func*) &parse_hdr_event);
-    pjsip_register_hdr_parser( "Allow-Events", NULL, (pjsip_parse_hdr_func*) &parse_hdr_allow_events);
-    pjsip_register_hdr_parser( "Subscription-State", NULL, (pjsip_parse_hdr_func*) &parse_hdr_sub_state);
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip_simple/event_notify_msg.h>

+#include <pjsip/print.h>

+#include <pjsip/sip_parser.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/except.h>

+

+static int pjsip_event_hdr_print( pjsip_event_hdr *hdr, 

+				  char *buf, pj_size_t size);

+static pjsip_event_hdr* pjsip_event_hdr_clone( pj_pool_t *pool, 

+					       const pjsip_event_hdr *hdr);

+static pjsip_event_hdr* pjsip_event_hdr_shallow_clone( pj_pool_t *pool,

+						       const pjsip_event_hdr*);

+

+static pjsip_hdr_vptr event_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_event_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_event_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_event_hdr_print,

+};

+

+

+PJ_DEF(pjsip_event_hdr*) pjsip_event_hdr_create(pj_pool_t *pool)

+{

+    pj_str_t event = { "Event", 5 };

+    pjsip_event_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    hdr->type = PJSIP_H_OTHER;

+    hdr->name = hdr->sname = event;

+    hdr->vptr = &event_hdr_vptr;

+    pj_list_init(hdr);

+    return hdr;

+}

+

+static int pjsip_event_hdr_print( pjsip_event_hdr *hdr, 

+				  char *buf, pj_size_t size)

+{

+    char *p = buf;

+    char *endbuf = buf+size;

+    int printed;

+

+    copy_advance(p, hdr->name);

+    *p++ = ':';

+    *p++ = ' ';

+

+    copy_advance(p, hdr->event_type);

+    copy_advance_pair(p, ";id=", 4, hdr->id_param);

+    if (hdr->other_param.slen)

+	copy_advance(p, hdr->other_param);

+    return p - buf;

+}

+

+static pjsip_event_hdr* pjsip_event_hdr_clone( pj_pool_t *pool, 

+					       const pjsip_event_hdr *rhs)

+{

+    pjsip_event_hdr *hdr = pjsip_event_hdr_create(pool);

+    pj_strdup(pool, &hdr->event_type, &rhs->event_type);

+    pj_strdup(pool, &hdr->id_param, &rhs->id_param);

+    pj_strdup(pool, &hdr->other_param, &rhs->other_param);

+    return hdr;

+}

+

+static pjsip_event_hdr* pjsip_event_hdr_shallow_clone( pj_pool_t *pool,

+						       const pjsip_event_hdr *rhs )

+{

+    pjsip_event_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+

+static int pjsip_allow_events_hdr_print(pjsip_allow_events_hdr *hdr, 

+					char *buf, pj_size_t size);

+static pjsip_allow_events_hdr* 

+pjsip_allow_events_hdr_clone(pj_pool_t *pool, 

+			     const pjsip_allow_events_hdr *hdr);

+static pjsip_allow_events_hdr* 

+pjsip_allow_events_hdr_shallow_clone(pj_pool_t *pool,

+				     const pjsip_allow_events_hdr*);

+

+static pjsip_hdr_vptr allow_event_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_allow_events_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_allow_events_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_allow_events_hdr_print,

+};

+

+

+PJ_DEF(pjsip_allow_events_hdr*) pjsip_allow_events_hdr_create(pj_pool_t *pool)

+{

+    pj_str_t allow_events = { "Allow-Events", 12 };

+    pjsip_allow_events_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    hdr->type = PJSIP_H_OTHER;

+    hdr->name = hdr->sname = allow_events;

+    hdr->vptr = &allow_event_hdr_vptr;

+    pj_list_init(hdr);

+    return hdr;

+}

+

+static int pjsip_allow_events_hdr_print(pjsip_allow_events_hdr *hdr, 

+					char *buf, pj_size_t size)

+{

+    char *p = buf;

+    char *endbuf = buf+size;

+    int printed;

+

+    copy_advance(p, hdr->name);

+    *p++ = ':';

+    *p++ = ' ';

+

+    if (hdr->event_cnt > 0) {

+	int i;

+	copy_advance(p, hdr->events[0]);

+	for (i=1; i<hdr->event_cnt; ++i) {

+	    copy_advance_pair(p, ",", 1, hdr->events[i]);

+	}

+    }

+

+    return p - buf;

+}

+

+static pjsip_allow_events_hdr* 

+pjsip_allow_events_hdr_clone(pj_pool_t *pool, 

+			     const pjsip_allow_events_hdr *rhs)

+{

+    int i;

+

+    pjsip_allow_events_hdr *hdr = pjsip_allow_events_hdr_create(pool);

+    hdr->event_cnt = rhs->event_cnt;

+    for (i=0; i<rhs->event_cnt; ++i) {

+	pj_strdup(pool, &hdr->events[i], &rhs->events[i]);

+    }

+    return hdr;

+}

+

+static pjsip_allow_events_hdr* 

+pjsip_allow_events_hdr_shallow_clone(pj_pool_t *pool,

+				     const pjsip_allow_events_hdr *rhs)

+{

+    pjsip_allow_events_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+

+static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, 

+				     char *buf, pj_size_t size);

+static pjsip_sub_state_hdr* 

+pjsip_sub_state_hdr_clone(pj_pool_t *pool, 

+			  const pjsip_sub_state_hdr *hdr);

+static pjsip_sub_state_hdr* 

+pjsip_sub_state_hdr_shallow_clone(pj_pool_t *pool,

+				  const pjsip_sub_state_hdr*);

+

+static pjsip_hdr_vptr sub_state_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_sub_state_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_sub_state_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_sub_state_hdr_print,

+};

+

+

+PJ_DEF(pjsip_sub_state_hdr*) pjsip_sub_state_hdr_create(pj_pool_t *pool)

+{

+    pj_str_t sub_state = { "Subscription-State", 18 };

+    pjsip_sub_state_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    hdr->type = PJSIP_H_OTHER;

+    hdr->name = hdr->sname = sub_state;

+    hdr->vptr = &sub_state_hdr_vptr;

+    hdr->expires_param = -1;

+    hdr->retry_after = -1;

+    pj_list_init(hdr);

+    return hdr;

+}

+

+static int pjsip_sub_state_hdr_print(pjsip_sub_state_hdr *hdr, 

+				     char *buf, pj_size_t size)

+{

+    char *p = buf;

+    char *endbuf = buf+size;

+    int printed;

+

+    copy_advance(p, hdr->name);

+    *p++ = ':';

+    *p++ = ' ';

+

+    copy_advance(p, hdr->sub_state);

+    copy_advance_pair(p, ";reason=", 8, hdr->reason_param);

+    if (hdr->expires_param >= 0) {

+	pj_memcpy(p, ";expires=", 9);

+	p += 9;

+	printed = pj_utoa(hdr->expires_param, p);

+	p += printed;

+    }

+    if (hdr->retry_after >= 0) {

+	pj_memcpy(p, ";retry-after=", 13);

+	p += 9;

+	printed = pj_utoa(hdr->retry_after, p);

+	p += printed;

+    }

+    if (hdr->other_param.slen)

+	copy_advance(p, hdr->other_param);

+

+    return p - buf;

+}

+

+static pjsip_sub_state_hdr* 

+pjsip_sub_state_hdr_clone(pj_pool_t *pool, 

+			  const pjsip_sub_state_hdr *rhs)

+{

+    pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(pool);

+    pj_strdup(pool, &hdr->sub_state, &rhs->sub_state);

+    pj_strdup(pool, &hdr->reason_param, &rhs->reason_param);

+    hdr->retry_after = rhs->retry_after;

+    hdr->expires_param = rhs->expires_param;

+    pj_strdup(pool, &hdr->other_param, &rhs->other_param);

+    return hdr;

+}

+

+static pjsip_sub_state_hdr* 

+pjsip_sub_state_hdr_shallow_clone(pj_pool_t *pool,

+				  const pjsip_sub_state_hdr *rhs)

+{

+    pjsip_sub_state_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+static pjsip_event_hdr *parse_hdr_event(pj_scanner *scanner, 

+					pj_pool_t *pool)

+{

+    pjsip_event_hdr *hdr = pjsip_event_hdr_create(pool);

+    const pj_str_t id_param = { "id", 2 };

+

+    pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->event_type);

+

+    while (*scanner->current == ';') {

+	pj_str_t pname, pvalue;

+	pj_scan_get_char(scanner);

+	pjsip_parse_param_imp(scanner, &pname, &pvalue, 0);

+	if (pj_stricmp(&pname, &id_param)==0) {

+	    hdr->id_param = pvalue;

+	} else {

+	    pjsip_concat_param_imp(&hdr->other_param, pool, &pname, &pvalue, ';');

+	}

+    }

+    pjsip_parse_end_hdr_imp( scanner );

+    return hdr;

+}

+

+static pjsip_allow_events_hdr *parse_hdr_allow_events(pj_scanner *scanner, 

+						      pj_pool_t *pool)

+{

+    pjsip_allow_events_hdr *hdr = pjsip_allow_events_hdr_create(pool);

+

+    pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->events[0]);

+    hdr->event_cnt = 1;

+

+    while (*scanner->current == ',') {

+	pj_scan_get_char(scanner);

+	pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->events[hdr->event_cnt++]);

+	if (hdr->event_cnt == PJSIP_MAX_ALLOW_EVENTS) {

+	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+	}

+    }

+

+    pjsip_parse_end_hdr_imp( scanner );

+    return hdr;

+}

+

+static pjsip_sub_state_hdr *parse_hdr_sub_state(pj_scanner *scanner, 

+						pj_pool_t *pool)

+{

+    pjsip_sub_state_hdr *hdr = pjsip_sub_state_hdr_create(pool);

+    const pj_str_t reason = { "reason", 6 },

+		   expires = { "expires", 7 },

+		   retry_after = { "retry-after", 11 };

+    pj_scan_get(scanner, pjsip_TOKEN_SPEC, &hdr->sub_state);

+

+    while (*scanner->current == ';') {

+	pj_str_t pname, pvalue;

+

+	pj_scan_get_char(scanner);

+	pjsip_parse_param_imp(scanner, &pname, &pvalue, 0);

+	if (pj_stricmp(&pname, &reason) == 0) {

+	    hdr->reason_param = pvalue;

+	} else if (pj_stricmp(&pname, &expires) == 0) {

+	    hdr->expires_param = pj_strtoul(&pvalue);

+	} else if (pj_stricmp(&pname, &retry_after) == 0) {

+	    hdr->retry_after = pj_strtoul(&pvalue);

+	} else {

+	    pjsip_concat_param_imp(&hdr->other_param, pool, &pname, &pvalue, ';');

+	}

+    }

+

+    pjsip_parse_end_hdr_imp( scanner );

+    return hdr;

+}

+

+PJ_DEF(void) pjsip_event_notify_init_parser(void)

+{

+    pjsip_register_hdr_parser( "Event", NULL, (pjsip_parse_hdr_func*) &parse_hdr_event);

+    pjsip_register_hdr_parser( "Allow-Events", NULL, (pjsip_parse_hdr_func*) &parse_hdr_allow_events);

+    pjsip_register_hdr_parser( "Subscription-State", NULL, (pjsip_parse_hdr_func*) &parse_hdr_sub_state);

+}

diff --git a/pjsip/src/pjsip-simple/messaging.c b/pjsip/src/pjsip-simple/messaging.c
index c3992b4..3d08ba2 100644
--- a/pjsip/src/pjsip-simple/messaging.c
+++ b/pjsip/src/pjsip-simple/messaging.c
@@ -1,337 +1,359 @@
-/* $Id$
- *
- */
-#include <pjsip_simple/messaging.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_parser.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_misc.h>
-#include <pj/string.h>
-#include <pj/pool.h>
-#include <pj/guid.h>
-#include <pj/string.h>
-#include <pj/log.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define THIS_FILE   "messaging"
-
-struct messaging_data
-{
-    void		     *token;
-    pjsip_messaging_cb	     cb;
-};
-
-struct pjsip_messaging_session
-{
-    pj_pool_t		*pool;
-    pjsip_endpoint	*endpt;
-    pjsip_from_hdr	*from;
-    pjsip_to_hdr	*to;
-    pjsip_cid_hdr	*call_id;
-    pjsip_cseq_hdr	*cseq;
-};
-
-static int module_id;
-static pjsip_on_new_msg_cb incoming_cb;
-static pjsip_method message_method;
-
-
-/*
- * Set global callback to receive incoming message.
- */
-PJ_DEF(pjsip_on_new_msg_cb) 
-pjsip_messaging_set_incoming_callback(pjsip_on_new_msg_cb cb)
-{
-    pjsip_on_new_msg_cb prev_cb = incoming_cb;
-    incoming_cb = cb;
-    return prev_cb;
-}
-
-
-/*
- * Create an independent message (ie. not associated with a session).
- */
-PJ_DEF(pjsip_tx_data*) 
-pjsip_messaging_create_msg_from_hdr(pjsip_endpoint *endpt, 
-				    const pjsip_uri *target,
-				    const pjsip_from_hdr *param_from,
-				    const pjsip_to_hdr *param_to, 
-				    const pjsip_cid_hdr *param_call_id,
-				    int param_cseq, 
-				    const pj_str_t *param_text)
-{
-    return pjsip_endpt_create_request_from_hdr( endpt, &message_method, 
-						target,
-						param_from, param_to,
-						NULL, param_call_id,
-						param_cseq, param_text );
-}
-
-/*
- * Create independent message from string (instead of from header).
- */
-PJ_DEF(pjsip_tx_data*) 
-pjsip_messaging_create_msg( pjsip_endpoint *endpt, 
-			    const pj_str_t *target,
-			    const pj_str_t *param_from,
-			    const pj_str_t *param_to, 
-			    const pj_str_t *param_call_id,
-			    int param_cseq, 
-			    const pj_str_t *param_text)
-{
-    return pjsip_endpt_create_request( endpt, &message_method, target, 
-				       param_from, param_to, NULL, param_call_id,
-				       param_cseq, param_text);
-}
-
-/*
- * Initiate transaction to send outgoing message.
- */
-PJ_DEF(pj_status_t) 
-pjsip_messaging_send_msg( pjsip_endpoint *endpt, pjsip_tx_data *tdata, 
-			  void *token, pjsip_messaging_cb cb )
-{
-    pjsip_transaction *tsx;
-    struct messaging_data *msg_data;
-
-    /* Create transaction. */
-    tsx = pjsip_endpt_create_tsx(endpt);
-    if (!tsx) {
-	pjsip_tx_data_dec_ref(tdata);
-	return -1;
-    }
-
-    /* Save parameters to messaging data and attach to tsx. */
-    msg_data = pj_pool_calloc(tsx->pool, 1, sizeof(struct messaging_data));
-    msg_data->cb = cb;
-    msg_data->token = token;
-
-    /* Init transaction. */
-    tsx->module_data[module_id] = msg_data;
-    if (pjsip_tsx_init_uac(tsx, tdata) != 0) {
-	pjsip_tx_data_dec_ref(tdata);
-	pjsip_endpt_destroy_tsx(endpt, tsx);
-	return -1;
-    }
-
-    pjsip_endpt_register_tsx(endpt, tsx);
-
-    /* 
-     * Instruct transaction to send message.
-     * Further events will be received via transaction's event.
-     */
-    pjsip_tsx_on_tx_msg(tsx, tdata);
-
-    /* Decrement reference counter. */
-    pjsip_tx_data_dec_ref(tdata);
-    return 0;
-}
-
-
-/*
- * Create 'IM session'.
- */
-PJ_DEF(pjsip_messaging_session*) 
-pjsip_messaging_create_session( pjsip_endpoint *endpt, const pj_str_t *param_from,
-			        const pj_str_t *param_to )
-{
-    pj_pool_t *pool;
-    pjsip_messaging_session *ses;
-    pj_str_t tmp, to;
-
-    pool = pjsip_endpt_create_pool(endpt, "imsess", 1024, 1024);
-    if (!pool)
-	return NULL;
-
-    ses = pj_pool_calloc(pool, 1, sizeof(pjsip_messaging_session));
-    ses->pool = pool;
-    ses->endpt = endpt;
-
-    ses->call_id = pjsip_cid_hdr_create(pool);
-    pj_create_unique_string(pool, &ses->call_id->id);
-
-    ses->cseq = pjsip_cseq_hdr_create(pool);
-    ses->cseq->cseq = pj_rand();
-    ses->cseq->method = message_method;
-
-    ses->from = pjsip_from_hdr_create(pool);
-    pj_strdup_with_null(pool, &tmp, param_from);
-    ses->from->uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (ses->from->uri == NULL) {
-	pjsip_endpt_destroy_pool(endpt, pool);
-	return NULL;
-    }
-    pj_create_unique_string(pool, &ses->from->tag);
-
-    ses->to = pjsip_to_hdr_create(pool);
-    pj_strdup_with_null(pool, &to, param_from);
-    ses->to->uri = pjsip_parse_uri(pool, to.ptr, to.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (ses->to->uri == NULL) {
-	pjsip_endpt_destroy_pool(endpt, pool);
-	return NULL;
-    }
-
-    PJ_LOG(4,(THIS_FILE, "IM session created: recipient=%s", to.ptr));
-    return ses;
-}
-
-
-/*
- * Send IM message using identification from 'IM session'.
- */
-PJ_DEF(pjsip_tx_data*)
-pjsip_messaging_session_create_msg( pjsip_messaging_session *ses, const pj_str_t *text )
-{
-    return pjsip_endpt_create_request_from_hdr( ses->endpt,
-						&message_method,
-						ses->to->uri,
-						ses->from,
-						ses->to,
-						NULL,
-						ses->call_id,
-						ses->cseq->cseq++,
-						text);
-}
-
-
-/*
- * Destroy 'IM session'.
- */
-PJ_DEF(pj_status_t)
-pjsip_messaging_destroy_session( pjsip_messaging_session *ses )
-{
-    /*
-     * NOTE ABOUT POSSIBLE BUG HERE...
-     *
-     * We don't check number of pending transaction before destroying IM
-     * session. As the result, the headers in the txdata of pending transaction
-     * wil be INVALID once the IM session is deleted (because we only
-     * shallo_clone()-ed them).
-     *
-     * This normally should be okay, because once the message is
-     * submitted to transaction, the transaction (or rather the transport)
-     * will 'print' the message to a buffer, and once it is printed, it
-     * won't try to access the original message again. So even when the 
-     * original message has a dangling pointer, we should be safe.
-     *
-     * However, it will cause a problem if:
-     *	- resolving completes asynchronously and with a substantial delay,
-     *	  and before the resolver/transport finished its job the user
-     *	  destroy the IM session.
-     *	- if the transmit data is invalidated after the IM session is
-     *	  destroyed.
-     */
-
-    pjsip_endpt_destroy_pool(ses->endpt, ses->pool);
-    return 0;
-}
-
-
-static pj_status_t messaging_init( pjsip_endpoint *endpt,
-				   struct pjsip_module *mod, pj_uint32_t id )
-{
-    PJ_UNUSED_ARG(endpt)
-    PJ_UNUSED_ARG(mod)
-
-    module_id = id;
-    return 0;
-}
-
-static pj_status_t messaging_start( struct pjsip_module *mod )
-{
-    PJ_UNUSED_ARG(mod)
-    return 0;
-}
-
-static pj_status_t messaging_deinit( struct pjsip_module *mod )
-{
-    PJ_UNUSED_ARG(mod)
-    return 0;
-}
-
-static void messaging_tsx_handler( struct pjsip_module *mod, pjsip_event *event )
-{
-    pjsip_transaction *tsx = event->obj.tsx;
-    struct messaging_data *mod_data;
-
-    PJ_UNUSED_ARG(mod)
-
-    /* Ignore non transaction event */
-    if (event->type != PJSIP_EVENT_TSX_STATE_CHANGED || tsx == NULL)
-	return;
-
-    /* If this is an incoming message, inform application. */
-    if (tsx->role == PJSIP_ROLE_UAS) {
-	int status = 100;
-	pjsip_tx_data *tdata;
-
-	/* Check if we already answered this request. */
-	if (tsx->status_code >= 200)
-	    return;
-
-	/* Only handle MESSAGE requests!. */
-	if (pjsip_method_cmp(&tsx->method, &message_method) != 0)
-	    return;
-
-	/* Call application callback. */
-	if (incoming_cb)
-	    status = (*incoming_cb)(event->src.rdata);
-
-	if (status < 200 || status >= 700)
-	    status = PJSIP_SC_INTERNAL_SERVER_ERROR;
-
-	/* Respond request. */
-	tdata = pjsip_endpt_create_response(tsx->endpt, event->src.rdata, status );
-	if (tdata)
-	    pjsip_tsx_on_tx_msg(tsx, tdata);
-
-	return;
-    }
-
-    /* Ignore if it's not something that came from messaging module. */
-    mod_data = tsx->module_data[ module_id ];
-    if (mod_data == NULL)
-	return;
-
-    /* Ignore non final response. */
-    if (tsx->status_code < 200)
-	return;
-
-    /* Don't want to call the callback more than once. */
-    tsx->module_data[ module_id ] = NULL;
-
-    /* Now call the callback. */
-    if (mod_data->cb) {
-	(*mod_data->cb)(mod_data->token, tsx->status_code);
-    }
-}
-
-static pjsip_module messaging_module = 
-{
-    { "Messaging", 9},	    /* Name.		*/
-    0,			    /* Flag		*/
-    128,		    /* Priority		*/
-    NULL,		    /* User agent instance, initialized by APP.	*/
-    0,			    /* Number of methods supported (will be initialized later). */
-    { 0 },		    /* Array of methods (will be initialized later) */
-    &messaging_init,	    /* init_module()	*/
-    &messaging_start,	    /* start_module()	*/
-    &messaging_deinit,	    /* deinit_module()	*/
-    &messaging_tsx_handler, /* tsx_handler()	*/
-};
-
-PJ_DEF(pjsip_module*) pjsip_messaging_get_module()
-{
-    static pj_str_t method_str = { "MESSAGE", 7 };
-
-    pjsip_method_init_np( &message_method, &method_str);
-
-    messaging_module.method_cnt = 1;
-    messaging_module.methods[0] = &message_method;
-
-    return &messaging_module;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip_simple/messaging.h>

+#include <pjsip/sip_endpoint.h>

+#include <pjsip/sip_parser.h>

+#include <pjsip/sip_transaction.h>

+#include <pjsip/sip_event.h>

+#include <pjsip/sip_module.h>

+#include <pjsip/sip_misc.h>

+#include <pj/string.h>

+#include <pj/pool.h>

+#include <pj/guid.h>

+#include <pj/string.h>

+#include <pj/log.h>

+#include <stdio.h>

+#include <stdlib.h>

+

+#define THIS_FILE   "messaging"

+

+struct messaging_data

+{

+    void		     *token;

+    pjsip_messaging_cb	     cb;

+};

+

+struct pjsip_messaging_session

+{

+    pj_pool_t		*pool;

+    pjsip_endpoint	*endpt;

+    pjsip_from_hdr	*from;

+    pjsip_to_hdr	*to;

+    pjsip_cid_hdr	*call_id;

+    pjsip_cseq_hdr	*cseq;

+};

+

+static int module_id;

+static pjsip_on_new_msg_cb incoming_cb;

+static pjsip_method message_method;

+

+

+/*

+ * Set global callback to receive incoming message.

+ */

+PJ_DEF(pjsip_on_new_msg_cb) 

+pjsip_messaging_set_incoming_callback(pjsip_on_new_msg_cb cb)

+{

+    pjsip_on_new_msg_cb prev_cb = incoming_cb;

+    incoming_cb = cb;

+    return prev_cb;

+}

+

+

+/*

+ * Create an independent message (ie. not associated with a session).

+ */

+PJ_DEF(pjsip_tx_data*) 

+pjsip_messaging_create_msg_from_hdr(pjsip_endpoint *endpt, 

+				    const pjsip_uri *target,

+				    const pjsip_from_hdr *param_from,

+				    const pjsip_to_hdr *param_to, 

+				    const pjsip_cid_hdr *param_call_id,

+				    int param_cseq, 

+				    const pj_str_t *param_text)

+{

+    return pjsip_endpt_create_request_from_hdr( endpt, &message_method, 

+						target,

+						param_from, param_to,

+						NULL, param_call_id,

+						param_cseq, param_text );

+}

+

+/*

+ * Create independent message from string (instead of from header).

+ */

+PJ_DEF(pjsip_tx_data*) 

+pjsip_messaging_create_msg( pjsip_endpoint *endpt, 

+			    const pj_str_t *target,

+			    const pj_str_t *param_from,

+			    const pj_str_t *param_to, 

+			    const pj_str_t *param_call_id,

+			    int param_cseq, 

+			    const pj_str_t *param_text)

+{

+    return pjsip_endpt_create_request( endpt, &message_method, target, 

+				       param_from, param_to, NULL, param_call_id,

+				       param_cseq, param_text);

+}

+

+/*

+ * Initiate transaction to send outgoing message.

+ */

+PJ_DEF(pj_status_t) 

+pjsip_messaging_send_msg( pjsip_endpoint *endpt, pjsip_tx_data *tdata, 

+			  void *token, pjsip_messaging_cb cb )

+{

+    pjsip_transaction *tsx;

+    struct messaging_data *msg_data;

+

+    /* Create transaction. */

+    tsx = pjsip_endpt_create_tsx(endpt);

+    if (!tsx) {

+	pjsip_tx_data_dec_ref(tdata);

+	return -1;

+    }

+

+    /* Save parameters to messaging data and attach to tsx. */

+    msg_data = pj_pool_calloc(tsx->pool, 1, sizeof(struct messaging_data));

+    msg_data->cb = cb;

+    msg_data->token = token;

+

+    /* Init transaction. */

+    tsx->module_data[module_id] = msg_data;

+    if (pjsip_tsx_init_uac(tsx, tdata) != 0) {

+	pjsip_tx_data_dec_ref(tdata);

+	pjsip_endpt_destroy_tsx(endpt, tsx);

+	return -1;

+    }

+

+    pjsip_endpt_register_tsx(endpt, tsx);

+

+    /* 

+     * Instruct transaction to send message.

+     * Further events will be received via transaction's event.

+     */

+    pjsip_tsx_on_tx_msg(tsx, tdata);

+

+    /* Decrement reference counter. */

+    pjsip_tx_data_dec_ref(tdata);

+    return 0;

+}

+

+

+/*

+ * Create 'IM session'.

+ */

+PJ_DEF(pjsip_messaging_session*) 

+pjsip_messaging_create_session( pjsip_endpoint *endpt, const pj_str_t *param_from,

+			        const pj_str_t *param_to )

+{

+    pj_pool_t *pool;

+    pjsip_messaging_session *ses;

+    pj_str_t tmp, to;

+

+    pool = pjsip_endpt_create_pool(endpt, "imsess", 1024, 1024);

+    if (!pool)

+	return NULL;

+

+    ses = pj_pool_calloc(pool, 1, sizeof(pjsip_messaging_session));

+    ses->pool = pool;

+    ses->endpt = endpt;

+

+    ses->call_id = pjsip_cid_hdr_create(pool);

+    pj_create_unique_string(pool, &ses->call_id->id);

+

+    ses->cseq = pjsip_cseq_hdr_create(pool);

+    ses->cseq->cseq = pj_rand();

+    ses->cseq->method = message_method;

+

+    ses->from = pjsip_from_hdr_create(pool);

+    pj_strdup_with_null(pool, &tmp, param_from);

+    ses->from->uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, PJSIP_PARSE_URI_AS_NAMEADDR);

+    if (ses->from->uri == NULL) {

+	pjsip_endpt_destroy_pool(endpt, pool);

+	return NULL;

+    }

+    pj_create_unique_string(pool, &ses->from->tag);

+

+    ses->to = pjsip_to_hdr_create(pool);

+    pj_strdup_with_null(pool, &to, param_from);

+    ses->to->uri = pjsip_parse_uri(pool, to.ptr, to.slen, PJSIP_PARSE_URI_AS_NAMEADDR);

+    if (ses->to->uri == NULL) {

+	pjsip_endpt_destroy_pool(endpt, pool);

+	return NULL;

+    }

+

+    PJ_LOG(4,(THIS_FILE, "IM session created: recipient=%s", to.ptr));

+    return ses;

+}

+

+

+/*

+ * Send IM message using identification from 'IM session'.

+ */

+PJ_DEF(pjsip_tx_data*)

+pjsip_messaging_session_create_msg( pjsip_messaging_session *ses, const pj_str_t *text )

+{

+    return pjsip_endpt_create_request_from_hdr( ses->endpt,

+						&message_method,

+						ses->to->uri,

+						ses->from,

+						ses->to,

+						NULL,

+						ses->call_id,

+						ses->cseq->cseq++,

+						text);

+}

+

+

+/*

+ * Destroy 'IM session'.

+ */

+PJ_DEF(pj_status_t)

+pjsip_messaging_destroy_session( pjsip_messaging_session *ses )

+{

+    /*

+     * NOTE ABOUT POSSIBLE BUG HERE...

+     *

+     * We don't check number of pending transaction before destroying IM

+     * session. As the result, the headers in the txdata of pending transaction

+     * wil be INVALID once the IM session is deleted (because we only

+     * shallo_clone()-ed them).

+     *

+     * This normally should be okay, because once the message is

+     * submitted to transaction, the transaction (or rather the transport)

+     * will 'print' the message to a buffer, and once it is printed, it

+     * won't try to access the original message again. So even when the 

+     * original message has a dangling pointer, we should be safe.

+     *

+     * However, it will cause a problem if:

+     *	- resolving completes asynchronously and with a substantial delay,

+     *	  and before the resolver/transport finished its job the user

+     *	  destroy the IM session.

+     *	- if the transmit data is invalidated after the IM session is

+     *	  destroyed.

+     */

+

+    pjsip_endpt_destroy_pool(ses->endpt, ses->pool);

+    return 0;

+}

+

+

+static pj_status_t messaging_init( pjsip_endpoint *endpt,

+				   struct pjsip_module *mod, pj_uint32_t id )

+{

+    PJ_UNUSED_ARG(endpt)

+    PJ_UNUSED_ARG(mod)

+

+    module_id = id;

+    return 0;

+}

+

+static pj_status_t messaging_start( struct pjsip_module *mod )

+{

+    PJ_UNUSED_ARG(mod)

+    return 0;

+}

+

+static pj_status_t messaging_deinit( struct pjsip_module *mod )

+{

+    PJ_UNUSED_ARG(mod)

+    return 0;

+}

+

+static void messaging_tsx_handler( struct pjsip_module *mod, pjsip_event *event )

+{

+    pjsip_transaction *tsx = event->obj.tsx;

+    struct messaging_data *mod_data;

+

+    PJ_UNUSED_ARG(mod)

+

+    /* Ignore non transaction event */

+    if (event->type != PJSIP_EVENT_TSX_STATE_CHANGED || tsx == NULL)

+	return;

+

+    /* If this is an incoming message, inform application. */

+    if (tsx->role == PJSIP_ROLE_UAS) {

+	int status = 100;

+	pjsip_tx_data *tdata;

+

+	/* Check if we already answered this request. */

+	if (tsx->status_code >= 200)

+	    return;

+

+	/* Only handle MESSAGE requests!. */

+	if (pjsip_method_cmp(&tsx->method, &message_method) != 0)

+	    return;

+

+	/* Call application callback. */

+	if (incoming_cb)

+	    status = (*incoming_cb)(event->src.rdata);

+

+	if (status < 200 || status >= 700)

+	    status = PJSIP_SC_INTERNAL_SERVER_ERROR;

+

+	/* Respond request. */

+	tdata = pjsip_endpt_create_response(tsx->endpt, event->src.rdata, status );

+	if (tdata)

+	    pjsip_tsx_on_tx_msg(tsx, tdata);

+

+	return;

+    }

+

+    /* Ignore if it's not something that came from messaging module. */

+    mod_data = tsx->module_data[ module_id ];

+    if (mod_data == NULL)

+	return;

+

+    /* Ignore non final response. */

+    if (tsx->status_code < 200)

+	return;

+

+    /* Don't want to call the callback more than once. */

+    tsx->module_data[ module_id ] = NULL;

+

+    /* Now call the callback. */

+    if (mod_data->cb) {

+	(*mod_data->cb)(mod_data->token, tsx->status_code);

+    }

+}

+

+static pjsip_module messaging_module = 

+{

+    { "Messaging", 9},	    /* Name.		*/

+    0,			    /* Flag		*/

+    128,		    /* Priority		*/

+    NULL,		    /* User agent instance, initialized by APP.	*/

+    0,			    /* Number of methods supported (will be initialized later). */

+    { 0 },		    /* Array of methods (will be initialized later) */

+    &messaging_init,	    /* init_module()	*/

+    &messaging_start,	    /* start_module()	*/

+    &messaging_deinit,	    /* deinit_module()	*/

+    &messaging_tsx_handler, /* tsx_handler()	*/

+};

+

+PJ_DEF(pjsip_module*) pjsip_messaging_get_module()

+{

+    static pj_str_t method_str = { "MESSAGE", 7 };

+

+    pjsip_method_init_np( &message_method, &method_str);

+

+    messaging_module.method_cnt = 1;

+    messaging_module.methods[0] = &message_method;

+

+    return &messaging_module;

+}

+

diff --git a/pjsip/src/pjsip-simple/pidf.c b/pjsip/src/pjsip-simple/pidf.c
index f1de9c9..0c76b34 100644
--- a/pjsip/src/pjsip-simple/pidf.c
+++ b/pjsip/src/pjsip-simple/pidf.c
@@ -1,335 +1,357 @@
-/* $Id$
- *
- */
-#include <pjsip_simple/pidf.h>
-#include <pj/string.h>
-#include <pj/pool.h>
-
-struct pjpidf_op_desc pjpidf_op = 
-{
-    {
-	&pjpidf_pres_construct,
-	&pjpidf_pres_add_tuple,
-	&pjpidf_pres_get_first_tuple,
-	&pjpidf_pres_get_next_tuple,
-	&pjpidf_pres_find_tuple,
-	&pjpidf_pres_remove_tuple,
-	&pjpidf_pres_add_note,
-	&pjpidf_pres_get_first_note,
-	&pjpidf_pres_get_next_note
-    },
-    {
-	&pjpidf_tuple_construct,
-	&pjpidf_tuple_get_id,
-	&pjpidf_tuple_set_id,
-	&pjpidf_tuple_get_status,
-	&pjpidf_tuple_get_contact,
-	&pjpidf_tuple_set_contact,
-	&pjpidf_tuple_set_contact_prio,
-	&pjpidf_tuple_get_contact_prio,
-	&pjpidf_tuple_add_note,
-	&pjpidf_tuple_get_first_note,
-	&pjpidf_tuple_get_next_note,
-	&pjpidf_tuple_get_timestamp,
-	&pjpidf_tuple_set_timestamp,
-	&pjpidf_tuple_set_timestamp_np
-    },
-    {
-	&pjpidf_status_construct,
-	&pjpidf_status_is_basic_open,
-	&pjpidf_status_set_basic_open
-    }
-};
-
-static pj_str_t PRESENCE = { "presence", 8 };
-static pj_str_t ENTITY = { "entity", 6};
-static pj_str_t	TUPLE = { "tuple", 5 };
-static pj_str_t ID = { "id", 2 };
-static pj_str_t NOTE = { "note", 4 };
-static pj_str_t STATUS = { "status", 6 };
-static pj_str_t CONTACT = { "contact", 7 };
-static pj_str_t PRIORITY = { "priority", 8 };
-static pj_str_t TIMESTAMP = { "timestamp", 9 };
-static pj_str_t BASIC = { "basic", 5 };
-static pj_str_t OPEN = { "open", 4 };
-static pj_str_t CLOSED = { "closed", 6 };
-static pj_str_t EMPTY_STRING = { NULL, 0 };
-
-static void xml_init_node(pj_pool_t *pool, pj_xml_node *node,
-			  pj_str_t *name, const pj_str_t *value)
-{
-    pj_list_init(&node->attr_head);
-    pj_list_init(&node->node_head);
-    node->name = *name;
-    if (value) pj_strdup(pool, &node->content, value);
-    else node->content.ptr=NULL, node->content.slen=0;
-}
-
-static pj_xml_attr* xml_create_attr(pj_pool_t *pool, pj_str_t *name,
-				    const pj_str_t *value)
-{
-    pj_xml_attr *attr = pj_pool_alloc(pool, sizeof(*attr));
-    attr->name = *name;
-    pj_strdup(pool, &attr->value, value);
-    return attr;
-}
-
-/* Presence */
-PJ_DEF(void) pjpidf_pres_construct(pj_pool_t *pool, pjpidf_pres *pres,
-				   const pj_str_t *entity)
-{
-    pj_xml_attr *attr;
-
-    xml_init_node(pool, pres, &PRESENCE, NULL);
-    attr = xml_create_attr(pool, &ENTITY, entity);
-    pj_xml_add_attr(pres, attr);
-}
-
-PJ_DEF(pjpidf_tuple*) pjpidf_pres_add_tuple(pj_pool_t *pool, pjpidf_pres *pres,
-					    const pj_str_t *id)
-{
-    pjpidf_tuple *t = pj_pool_alloc(pool, sizeof(*t));
-    pjpidf_tuple_construct(pool, t, id);
-    pj_xml_add_node(pres, t);
-    return t;
-}
-
-PJ_DEF(pjpidf_tuple*) pjpidf_pres_get_first_tuple(pjpidf_pres *pres)
-{
-    return pj_xml_find_node(pres, &TUPLE);
-}
-
-PJ_DEF(pjpidf_tuple*) pjpidf_pres_get_next_tuple(pjpidf_pres *pres, 
-						 pjpidf_tuple *tuple)
-{
-    return pj_xml_find_next_node(pres, tuple, &TUPLE);
-}
-
-static pj_bool_t find_tuple_by_id(pj_xml_node *node, const void *id)
-{
-    return pj_xml_find_attr(node, &ID, id) != NULL;
-}
-
-PJ_DEF(pjpidf_tuple*) pjpidf_pres_find_tuple(pjpidf_pres *pres, const pj_str_t *id)
-{
-    return pj_xml_find(pres, &TUPLE, id, &find_tuple_by_id);
-}
-
-PJ_DEF(void) pjpidf_pres_remove_tuple(pjpidf_pres *pres, pjpidf_tuple *t)
-{
-    PJ_UNUSED_ARG(pres)
-    pj_list_erase(t);
-}
-
-PJ_DEF(pjpidf_note*) pjpidf_pres_add_note(pj_pool_t *pool, pjpidf_pres *pres, 
-					  const pj_str_t *text)
-{
-    pjpidf_note *note = pj_pool_alloc(pool, sizeof(*note));
-    xml_init_node(pool, note, &NOTE, text);
-    pj_xml_add_node(pres, note);
-    return note;
-}
-
-PJ_DEF(pjpidf_note*) pjpidf_pres_get_first_note(pjpidf_pres *pres)
-{
-    return pj_xml_find_node( pres, &NOTE);
-}
-
-PJ_DEF(pjpidf_note*) pjpidf_pres_get_next_note(pjpidf_pres *t, pjpidf_note *note)
-{
-    return pj_xml_find_next_node(t, note, &NOTE);
-}
-
-
-/* Tuple */
-PJ_DEF(void) pjpidf_tuple_construct(pj_pool_t *pool, pjpidf_tuple *t,
-				    const pj_str_t *id)
-{
-    pj_xml_attr *attr;
-    pjpidf_status *st;
-
-    xml_init_node(pool, t, &TUPLE, NULL);
-    attr = xml_create_attr(pool, &ID, id);
-    pj_xml_add_attr(t, attr);
-    st = pj_pool_alloc(pool, sizeof(*st));
-    pjpidf_status_construct(pool, st);
-    pj_xml_add_node(t, st);
-}
-
-PJ_DEF(const pj_str_t*) pjpidf_tuple_get_id(const pjpidf_tuple *t)
-{
-    const pj_xml_attr *attr = pj_xml_find_attr((pj_xml_node*)t, &ID, NULL);
-    pj_assert(attr);
-    return &attr->value;
-}
-
-PJ_DEF(void) pjpidf_tuple_set_id(pj_pool_t *pool, pjpidf_tuple *t, const pj_str_t *id)
-{
-    pj_xml_attr *attr = pj_xml_find_attr(t, &ID, NULL);
-    pj_assert(attr);
-    pj_strdup(pool, &attr->value, id);
-}
-
-
-PJ_DEF(pjpidf_status*) pjpidf_tuple_get_status(pjpidf_tuple *t)
-{
-    pjpidf_status *st = (pjpidf_status*)pj_xml_find_node(t, &STATUS);
-    pj_assert(st);
-    return st;
-}
-
-
-PJ_DEF(const pj_str_t*) pjpidf_tuple_get_contact(const pjpidf_tuple *t)
-{
-    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)t, &CONTACT);
-    if (!node)
-	return &EMPTY_STRING;
-    return &node->content;
-}
-
-PJ_DEF(void) pjpidf_tuple_set_contact(pj_pool_t *pool, pjpidf_tuple *t, 
-				      const pj_str_t *contact)
-{
-    pj_xml_node *node = pj_xml_find_node(t, &CONTACT);
-    if (!node) {
-	node = pj_pool_alloc(pool, sizeof(*node));
-	xml_init_node(pool, node, &CONTACT, contact);
-	pj_xml_add_node(t, node);
-    } else {
-	pj_strdup(pool, &node->content, contact);
-    }
-}
-
-PJ_DEF(void) pjpidf_tuple_set_contact_prio(pj_pool_t *pool, pjpidf_tuple *t, 
-					   const pj_str_t *prio)
-{
-    pj_xml_node *node = pj_xml_find_node(t, &CONTACT);
-    pj_xml_attr *attr;
-
-    if (!node) {
-	node = pj_pool_alloc(pool, sizeof(*node));
-	xml_init_node(pool, node, &CONTACT, NULL);
-	pj_xml_add_node(t, node);
-    }
-    attr = pj_xml_find_attr(node, &PRIORITY, NULL);
-    if (!attr) {
-	attr = xml_create_attr(pool, &PRIORITY, prio);
-	pj_xml_add_attr(node, attr);
-    } else {
-	pj_strdup(pool, &attr->value, prio);
-    }
-}
-
-PJ_DEF(const pj_str_t*) pjpidf_tuple_get_contact_prio(const pjpidf_tuple *t)
-{
-    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)t, &CONTACT);
-    pj_xml_attr *attr;
-
-    if (!node)
-	return &EMPTY_STRING;
-    attr = pj_xml_find_attr(node, &PRIORITY, NULL);
-    if (!attr)
-	return &EMPTY_STRING;
-    return &attr->value;
-}
-
-
-PJ_DEF(pjpidf_note*) pjpidf_tuple_add_note(pj_pool_t *pool, pjpidf_tuple *t,
-					   const pj_str_t *text)
-{
-    pjpidf_note *note = pj_pool_alloc(pool, sizeof(*note));
-    xml_init_node(pool, note, &NOTE, text);
-    pj_xml_add_node(t, note);
-    return note;
-}
-
-PJ_DEF(pjpidf_note*) pjpidf_tuple_get_first_note(pjpidf_tuple *t)
-{
-    return pj_xml_find_node(t, &NOTE);
-}
-
-PJ_DEF(pjpidf_note*) pjpidf_tuple_get_next_note(pjpidf_tuple *t, pjpidf_note *n)
-{
-    return pj_xml_find_next_node(t, n, &NOTE);
-}
-
-
-PJ_DEF(const pj_str_t*) pjpidf_tuple_get_timestamp(const pjpidf_tuple *t)
-{
-    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)t, &TIMESTAMP);
-    return node ? &node->content : &EMPTY_STRING;
-}
-
-PJ_DEF(void) pjpidf_tuple_set_timestamp(pj_pool_t *pool, pjpidf_tuple *t,
-					const pj_str_t *ts)
-{
-    pj_xml_node *node = pj_xml_find_node(t, &TIMESTAMP);
-    if (!node) {
-	node = pj_pool_alloc(pool, sizeof(*node));
-	xml_init_node(pool, node, &TIMESTAMP, ts);
-    } else {
-	pj_strdup(pool, &node->content, ts);
-    }
-}
-
-
-PJ_DEF(void) pjpidf_tuple_set_timestamp_np(pj_pool_t *pool, pjpidf_tuple *t, 
-					   pj_str_t *ts)
-{
-    pj_xml_node *node = pj_xml_find_node(t, &TIMESTAMP);
-    if (!node) {
-	node = pj_pool_alloc(pool, sizeof(*node));
-	xml_init_node(pool, node, &TIMESTAMP, ts);
-    } else {
-	node->content = *ts;
-    }
-}
-
-
-/* Status */
-PJ_DEF(void) pjpidf_status_construct(pj_pool_t *pool, pjpidf_status *st)
-{
-    pj_xml_node *node;
-
-    xml_init_node(pool, st, &STATUS, NULL);
-    node = pj_pool_alloc(pool, sizeof(*node));
-    xml_init_node(pool, node, &BASIC, &CLOSED);
-    pj_xml_add_node(st, node);
-}
-
-PJ_DEF(pj_bool_t) pjpidf_status_is_basic_open(const pjpidf_status *st)
-{
-    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)st, &BASIC);
-    pj_assert(node != NULL);
-    return pj_stricmp(&node->content, &OPEN)==0;
-}
-
-PJ_DEF(void) pjpidf_status_set_basic_open(pjpidf_status *st, pj_bool_t open)
-{
-    pj_xml_node *node = pj_xml_find_node(st, &BASIC);
-    pj_assert(node != NULL);
-    node->content = open ? OPEN : CLOSED;
-}
-
-PJ_DEF(pjpidf_pres*) pjpidf_create(pj_pool_t *pool, const pj_str_t *entity)
-{
-    pjpidf_pres *pres = pj_pool_alloc(pool, sizeof(*pres));
-    pjpidf_pres_construct(pool, pres, entity);
-    return pres;
-}
-
-PJ_DEF(pjpidf_pres*) pjpidf_parse(pj_pool_t *pool, char *text, int len)
-{
-    pjpidf_pres *pres = pj_xml_parse(pool, text, len);
-    if (pres) {
-	if (pj_stricmp(&pres->name, &PRESENCE) != 0)
-	    return NULL;
-    }
-    return pres;
-}
-
-PJ_DEF(int) pjpidf_print(const pjpidf_pres* pres, char *buf, int len)
-{
-    return pj_xml_print(pres, buf, len, PJ_TRUE);
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip_simple/pidf.h>

+#include <pj/string.h>

+#include <pj/pool.h>

+

+struct pjpidf_op_desc pjpidf_op = 

+{

+    {

+	&pjpidf_pres_construct,

+	&pjpidf_pres_add_tuple,

+	&pjpidf_pres_get_first_tuple,

+	&pjpidf_pres_get_next_tuple,

+	&pjpidf_pres_find_tuple,

+	&pjpidf_pres_remove_tuple,

+	&pjpidf_pres_add_note,

+	&pjpidf_pres_get_first_note,

+	&pjpidf_pres_get_next_note

+    },

+    {

+	&pjpidf_tuple_construct,

+	&pjpidf_tuple_get_id,

+	&pjpidf_tuple_set_id,

+	&pjpidf_tuple_get_status,

+	&pjpidf_tuple_get_contact,

+	&pjpidf_tuple_set_contact,

+	&pjpidf_tuple_set_contact_prio,

+	&pjpidf_tuple_get_contact_prio,

+	&pjpidf_tuple_add_note,

+	&pjpidf_tuple_get_first_note,

+	&pjpidf_tuple_get_next_note,

+	&pjpidf_tuple_get_timestamp,

+	&pjpidf_tuple_set_timestamp,

+	&pjpidf_tuple_set_timestamp_np

+    },

+    {

+	&pjpidf_status_construct,

+	&pjpidf_status_is_basic_open,

+	&pjpidf_status_set_basic_open

+    }

+};

+

+static pj_str_t PRESENCE = { "presence", 8 };

+static pj_str_t ENTITY = { "entity", 6};

+static pj_str_t	TUPLE = { "tuple", 5 };

+static pj_str_t ID = { "id", 2 };

+static pj_str_t NOTE = { "note", 4 };

+static pj_str_t STATUS = { "status", 6 };

+static pj_str_t CONTACT = { "contact", 7 };

+static pj_str_t PRIORITY = { "priority", 8 };

+static pj_str_t TIMESTAMP = { "timestamp", 9 };

+static pj_str_t BASIC = { "basic", 5 };

+static pj_str_t OPEN = { "open", 4 };

+static pj_str_t CLOSED = { "closed", 6 };

+static pj_str_t EMPTY_STRING = { NULL, 0 };

+

+static void xml_init_node(pj_pool_t *pool, pj_xml_node *node,

+			  pj_str_t *name, const pj_str_t *value)

+{

+    pj_list_init(&node->attr_head);

+    pj_list_init(&node->node_head);

+    node->name = *name;

+    if (value) pj_strdup(pool, &node->content, value);

+    else node->content.ptr=NULL, node->content.slen=0;

+}

+

+static pj_xml_attr* xml_create_attr(pj_pool_t *pool, pj_str_t *name,

+				    const pj_str_t *value)

+{

+    pj_xml_attr *attr = pj_pool_alloc(pool, sizeof(*attr));

+    attr->name = *name;

+    pj_strdup(pool, &attr->value, value);

+    return attr;

+}

+

+/* Presence */

+PJ_DEF(void) pjpidf_pres_construct(pj_pool_t *pool, pjpidf_pres *pres,

+				   const pj_str_t *entity)

+{

+    pj_xml_attr *attr;

+

+    xml_init_node(pool, pres, &PRESENCE, NULL);

+    attr = xml_create_attr(pool, &ENTITY, entity);

+    pj_xml_add_attr(pres, attr);

+}

+

+PJ_DEF(pjpidf_tuple*) pjpidf_pres_add_tuple(pj_pool_t *pool, pjpidf_pres *pres,

+					    const pj_str_t *id)

+{

+    pjpidf_tuple *t = pj_pool_alloc(pool, sizeof(*t));

+    pjpidf_tuple_construct(pool, t, id);

+    pj_xml_add_node(pres, t);

+    return t;

+}

+

+PJ_DEF(pjpidf_tuple*) pjpidf_pres_get_first_tuple(pjpidf_pres *pres)

+{

+    return pj_xml_find_node(pres, &TUPLE);

+}

+

+PJ_DEF(pjpidf_tuple*) pjpidf_pres_get_next_tuple(pjpidf_pres *pres, 

+						 pjpidf_tuple *tuple)

+{

+    return pj_xml_find_next_node(pres, tuple, &TUPLE);

+}

+

+static pj_bool_t find_tuple_by_id(pj_xml_node *node, const void *id)

+{

+    return pj_xml_find_attr(node, &ID, id) != NULL;

+}

+

+PJ_DEF(pjpidf_tuple*) pjpidf_pres_find_tuple(pjpidf_pres *pres, const pj_str_t *id)

+{

+    return pj_xml_find(pres, &TUPLE, id, &find_tuple_by_id);

+}

+

+PJ_DEF(void) pjpidf_pres_remove_tuple(pjpidf_pres *pres, pjpidf_tuple *t)

+{

+    PJ_UNUSED_ARG(pres)

+    pj_list_erase(t);

+}

+

+PJ_DEF(pjpidf_note*) pjpidf_pres_add_note(pj_pool_t *pool, pjpidf_pres *pres, 

+					  const pj_str_t *text)

+{

+    pjpidf_note *note = pj_pool_alloc(pool, sizeof(*note));

+    xml_init_node(pool, note, &NOTE, text);

+    pj_xml_add_node(pres, note);

+    return note;

+}

+

+PJ_DEF(pjpidf_note*) pjpidf_pres_get_first_note(pjpidf_pres *pres)

+{

+    return pj_xml_find_node( pres, &NOTE);

+}

+

+PJ_DEF(pjpidf_note*) pjpidf_pres_get_next_note(pjpidf_pres *t, pjpidf_note *note)

+{

+    return pj_xml_find_next_node(t, note, &NOTE);

+}

+

+

+/* Tuple */

+PJ_DEF(void) pjpidf_tuple_construct(pj_pool_t *pool, pjpidf_tuple *t,

+				    const pj_str_t *id)

+{

+    pj_xml_attr *attr;

+    pjpidf_status *st;

+

+    xml_init_node(pool, t, &TUPLE, NULL);

+    attr = xml_create_attr(pool, &ID, id);

+    pj_xml_add_attr(t, attr);

+    st = pj_pool_alloc(pool, sizeof(*st));

+    pjpidf_status_construct(pool, st);

+    pj_xml_add_node(t, st);

+}

+

+PJ_DEF(const pj_str_t*) pjpidf_tuple_get_id(const pjpidf_tuple *t)

+{

+    const pj_xml_attr *attr = pj_xml_find_attr((pj_xml_node*)t, &ID, NULL);

+    pj_assert(attr);

+    return &attr->value;

+}

+

+PJ_DEF(void) pjpidf_tuple_set_id(pj_pool_t *pool, pjpidf_tuple *t, const pj_str_t *id)

+{

+    pj_xml_attr *attr = pj_xml_find_attr(t, &ID, NULL);

+    pj_assert(attr);

+    pj_strdup(pool, &attr->value, id);

+}

+

+

+PJ_DEF(pjpidf_status*) pjpidf_tuple_get_status(pjpidf_tuple *t)

+{

+    pjpidf_status *st = (pjpidf_status*)pj_xml_find_node(t, &STATUS);

+    pj_assert(st);

+    return st;

+}

+

+

+PJ_DEF(const pj_str_t*) pjpidf_tuple_get_contact(const pjpidf_tuple *t)

+{

+    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)t, &CONTACT);

+    if (!node)

+	return &EMPTY_STRING;

+    return &node->content;

+}

+

+PJ_DEF(void) pjpidf_tuple_set_contact(pj_pool_t *pool, pjpidf_tuple *t, 

+				      const pj_str_t *contact)

+{

+    pj_xml_node *node = pj_xml_find_node(t, &CONTACT);

+    if (!node) {

+	node = pj_pool_alloc(pool, sizeof(*node));

+	xml_init_node(pool, node, &CONTACT, contact);

+	pj_xml_add_node(t, node);

+    } else {

+	pj_strdup(pool, &node->content, contact);

+    }

+}

+

+PJ_DEF(void) pjpidf_tuple_set_contact_prio(pj_pool_t *pool, pjpidf_tuple *t, 

+					   const pj_str_t *prio)

+{

+    pj_xml_node *node = pj_xml_find_node(t, &CONTACT);

+    pj_xml_attr *attr;

+

+    if (!node) {

+	node = pj_pool_alloc(pool, sizeof(*node));

+	xml_init_node(pool, node, &CONTACT, NULL);

+	pj_xml_add_node(t, node);

+    }

+    attr = pj_xml_find_attr(node, &PRIORITY, NULL);

+    if (!attr) {

+	attr = xml_create_attr(pool, &PRIORITY, prio);

+	pj_xml_add_attr(node, attr);

+    } else {

+	pj_strdup(pool, &attr->value, prio);

+    }

+}

+

+PJ_DEF(const pj_str_t*) pjpidf_tuple_get_contact_prio(const pjpidf_tuple *t)

+{

+    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)t, &CONTACT);

+    pj_xml_attr *attr;

+

+    if (!node)

+	return &EMPTY_STRING;

+    attr = pj_xml_find_attr(node, &PRIORITY, NULL);

+    if (!attr)

+	return &EMPTY_STRING;

+    return &attr->value;

+}

+

+

+PJ_DEF(pjpidf_note*) pjpidf_tuple_add_note(pj_pool_t *pool, pjpidf_tuple *t,

+					   const pj_str_t *text)

+{

+    pjpidf_note *note = pj_pool_alloc(pool, sizeof(*note));

+    xml_init_node(pool, note, &NOTE, text);

+    pj_xml_add_node(t, note);

+    return note;

+}

+

+PJ_DEF(pjpidf_note*) pjpidf_tuple_get_first_note(pjpidf_tuple *t)

+{

+    return pj_xml_find_node(t, &NOTE);

+}

+

+PJ_DEF(pjpidf_note*) pjpidf_tuple_get_next_note(pjpidf_tuple *t, pjpidf_note *n)

+{

+    return pj_xml_find_next_node(t, n, &NOTE);

+}

+

+

+PJ_DEF(const pj_str_t*) pjpidf_tuple_get_timestamp(const pjpidf_tuple *t)

+{

+    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)t, &TIMESTAMP);

+    return node ? &node->content : &EMPTY_STRING;

+}

+

+PJ_DEF(void) pjpidf_tuple_set_timestamp(pj_pool_t *pool, pjpidf_tuple *t,

+					const pj_str_t *ts)

+{

+    pj_xml_node *node = pj_xml_find_node(t, &TIMESTAMP);

+    if (!node) {

+	node = pj_pool_alloc(pool, sizeof(*node));

+	xml_init_node(pool, node, &TIMESTAMP, ts);

+    } else {

+	pj_strdup(pool, &node->content, ts);

+    }

+}

+

+

+PJ_DEF(void) pjpidf_tuple_set_timestamp_np(pj_pool_t *pool, pjpidf_tuple *t, 

+					   pj_str_t *ts)

+{

+    pj_xml_node *node = pj_xml_find_node(t, &TIMESTAMP);

+    if (!node) {

+	node = pj_pool_alloc(pool, sizeof(*node));

+	xml_init_node(pool, node, &TIMESTAMP, ts);

+    } else {

+	node->content = *ts;

+    }

+}

+

+

+/* Status */

+PJ_DEF(void) pjpidf_status_construct(pj_pool_t *pool, pjpidf_status *st)

+{

+    pj_xml_node *node;

+

+    xml_init_node(pool, st, &STATUS, NULL);

+    node = pj_pool_alloc(pool, sizeof(*node));

+    xml_init_node(pool, node, &BASIC, &CLOSED);

+    pj_xml_add_node(st, node);

+}

+

+PJ_DEF(pj_bool_t) pjpidf_status_is_basic_open(const pjpidf_status *st)

+{

+    pj_xml_node *node = pj_xml_find_node((pj_xml_node*)st, &BASIC);

+    pj_assert(node != NULL);

+    return pj_stricmp(&node->content, &OPEN)==0;

+}

+

+PJ_DEF(void) pjpidf_status_set_basic_open(pjpidf_status *st, pj_bool_t open)

+{

+    pj_xml_node *node = pj_xml_find_node(st, &BASIC);

+    pj_assert(node != NULL);

+    node->content = open ? OPEN : CLOSED;

+}

+

+PJ_DEF(pjpidf_pres*) pjpidf_create(pj_pool_t *pool, const pj_str_t *entity)

+{

+    pjpidf_pres *pres = pj_pool_alloc(pool, sizeof(*pres));

+    pjpidf_pres_construct(pool, pres, entity);

+    return pres;

+}

+

+PJ_DEF(pjpidf_pres*) pjpidf_parse(pj_pool_t *pool, char *text, int len)

+{

+    pjpidf_pres *pres = pj_xml_parse(pool, text, len);

+    if (pres) {

+	if (pj_stricmp(&pres->name, &PRESENCE) != 0)

+	    return NULL;

+    }

+    return pres;

+}

+

+PJ_DEF(int) pjpidf_print(const pjpidf_pres* pres, char *buf, int len)

+{

+    return pj_xml_print(pres, buf, len, PJ_TRUE);

+}

+

diff --git a/pjsip/src/pjsip-simple/presence.c b/pjsip/src/pjsip-simple/presence.c
index 32ed8e3..5f5893a 100644
--- a/pjsip/src/pjsip-simple/presence.c
+++ b/pjsip/src/pjsip-simple/presence.c
@@ -1,384 +1,406 @@
-/* $Id$
- *
- */
-#include <pjsip_simple/presence.h>
-#include <pjsip/sip_transport.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/os.h>
-#include <stdio.h>
-
-/* Forward declarations. */
-static void on_query_subscribe(pjsip_rx_data *rdata, int *status);
-static void on_subscribe(pjsip_event_sub *sub, pjsip_rx_data *rdata,
-			 pjsip_event_sub_cb **cb, int *expires);
-static void on_sub_terminated(pjsip_event_sub *sub, const pj_str_t *reason);
-static void on_sub_received_refresh(pjsip_event_sub *sub, pjsip_rx_data *rdata);
-static void on_received_notify(pjsip_event_sub *sub, pjsip_rx_data *rdata);
-
-/* Some string constants. */
-static pj_str_t PRESENCE_EVENT = { "presence", 8 };
-
-/* Accept types. */
-static pj_str_t accept_names[] = {
-    { "application/pidf+xml", 20 },
-    { "application/xpidf+xml", 21 }
-};
-static pjsip_media_type accept_types[] = {
-    {
-	{ "application", 11 },
-	{ "pidf+xml", 8 }
-    },
-    {
-	{ "application", 11 },
-	{ "xpidf+xml", 9 }
-    }
-};
-
-/* Callback that is registered by application. */
-static pjsip_presence_cb cb;
-
-/* Package callback to be register to event_notify */
-static pjsip_event_sub_pkg_cb pkg_cb = { &on_query_subscribe,
-					 &on_subscribe };
-
-/* Global/static callback to be registered to event_notify */
-static pjsip_event_sub_cb sub_cb = { &on_sub_terminated,
-				     &on_sub_received_refresh,
-				     NULL,
-				     &on_received_notify,
-				     NULL };
-
-/*
- * Initialize presence module.
- * This will register event package "presence" to event framework.
- */
-PJ_DEF(void) pjsip_presence_init(const pjsip_presence_cb *pcb)
-{
-    pj_memcpy(&cb, pcb, sizeof(*pcb));
-    pjsip_event_sub_register_pkg( &PRESENCE_EVENT, 
-				  sizeof(accept_names)/sizeof(accept_names[0]),
-				  accept_names,
-				  &pkg_cb);
-}
-
-/*
- * Create presence subscription.
- */
-PJ_DEF(pjsip_presentity*) pjsip_presence_create( pjsip_endpoint *endpt,
-						 const pj_str_t *local_url,
-						 const pj_str_t *remote_url,
-						 int expires,
-						 void *user_data )
-{
-    pjsip_event_sub *sub;
-    pjsip_presentity *pres;
-
-    if (expires < 0)
-	expires = 300;
-
-    /* Create event subscription */
-    sub = pjsip_event_sub_create(endpt, local_url, remote_url, &PRESENCE_EVENT, 
-				 expires, 
-				 sizeof(accept_names)/sizeof(accept_names[0]),
-				 accept_names,
-				 NULL, &sub_cb);
-    if (!sub)
-	return NULL;
-
-    /* Allocate presence descriptor. */
-    pres = pj_pool_calloc(sub->pool, 1, sizeof(*pres));
-    pres->sub = sub;
-    pres->user_data = user_data;
-    sub->user_data = pres;
-
-    return pres;
-}
-
-/*
- * Send SUBSCRIBE.
- */
-PJ_DEF(pj_status_t) pjsip_presence_subscribe( pjsip_presentity *pres )
-{
-    return pjsip_event_sub_subscribe( pres->sub );
-}
-
-/*
- * Set credentials to be used for outgoing requests.
- */
-PJ_DEF(pj_status_t) pjsip_presence_set_credentials( pjsip_presentity *pres,
-						    int count,
-						    const pjsip_cred_info cred[])
-{
-    return pjsip_event_sub_set_credentials(pres->sub, count, cred);
-}
-
-/*
- * Set route-set.
- */
-PJ_DEF(pj_status_t) pjsip_presence_set_route_set( pjsip_presentity *pres,
-						  const pjsip_route_hdr *hdr )
-{
-    return pjsip_event_sub_set_route_set( pres->sub, hdr );
-}
-
-/*
- * Unsubscribe.
- */
-PJ_DEF(pj_status_t) pjsip_presence_unsubscribe( pjsip_presentity *pres )
-{
-    return pjsip_event_sub_unsubscribe(pres->sub);
-}
-
-/*
- * This is the pjsip_msg_body callback to print XML body.
- */
-static int print_xml(pjsip_msg_body *body, char *buf, pj_size_t size)
-{
-    return pj_xml_print( body->data, buf, size, PJ_TRUE );
-}
-
-/*
- * Create and initialize PIDF document and msg body (notifier only).
- */
-static pj_status_t init_presence_info( pjsip_presentity *pres )
-{
-    pj_str_t uri;
-    pj_pool_t *pool = pres->sub->pool;
-    char tmp[PJSIP_MAX_URL_SIZE];
-    pjpidf_tuple *tuple;
-    const pjsip_media_type *content_type = NULL;
-
-    pj_assert(pres->uas_body == NULL);
-
-    /* Make entity_id */
-    uri.ptr = tmp;
-    uri.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, pres->sub->from->uri, 
-			      tmp, sizeof(tmp));
-    if (uri.slen < 0)
-	return -1;
-
-    if (pres->pres_type == PJSIP_PRES_TYPE_PIDF) {
-	pj_str_t s;
-
-	/* Create <presence>. */
-	pres->uas_data.pidf = pjpidf_create(pool, &s);
-
-	/* Create <tuple> */
-	pj_create_unique_string(pool, &s);
-	tuple = pjpidf_pres_add_tuple(pool, pres->uas_data.pidf, &s);
-
-	/* Set <contact> */
-	s.ptr = tmp;
-	s.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, pres->sub->contact->uri, tmp, sizeof(tmp));
-	if (s.slen < 0)
-	    return -1;
-	pjpidf_tuple_set_contact(pool, tuple, &s);
-
-	/* Content-Type */
-	content_type = &accept_types[PJSIP_PRES_TYPE_PIDF];
-
-    } else if (pres->pres_type == PJSIP_PRES_TYPE_XPIDF) {
-
-	/* Create XPIDF */
-	pres->uas_data.xpidf = pjxpidf_create(pool, &uri);
-
-	/* Content-Type. */
-	content_type = &accept_types[PJSIP_PRES_TYPE_XPIDF];
-    }
-
-    /* Create message body */
-    pres->uas_body = pj_pool_alloc(pool, sizeof(pjsip_msg_body));
-    pres->uas_body->content_type = *content_type;
-    pres->uas_body->data = pres->uas_data.pidf;
-    pres->uas_body->len = 0;
-    pres->uas_body->print_body = &print_xml;
-
-    return 0;
-}
-
-/*
- * Send NOTIFY and set subscription state.
- */
-PJ_DEF(pj_status_t) pjsip_presence_notify( pjsip_presentity *pres,
-					   pjsip_event_sub_state state,
-					   pj_bool_t is_online )
-{
-    pj_str_t reason = { "", 0 };
-
-    if (pres->uas_data.pidf == NULL) {
-	if (init_presence_info(pres) != 0)
-	    return -1;
-    }
-
-    /* Update basic status in PIDF/XPIDF document. */
-    if (pres->pres_type == PJSIP_PRES_TYPE_PIDF) {
-	pjpidf_tuple *first;
-	pjpidf_status *status;
-	pj_time_val now;
-	pj_parsed_time pnow;
-
-	first = pjpidf_op.pres.get_first_tuple(pres->uas_data.pidf);
-	pj_assert(first);
-	status = pjpidf_op.tuple.get_status(first);
-	pj_assert(status);
-	pjpidf_op.status.set_basic_open(status, is_online);
-
-	/* Update timestamp. */
-	if (pres->timestamp.ptr == 0) {
-	    pres->timestamp.ptr = pj_pool_alloc(pres->sub->pool, 24);
-	}
-	pj_gettimeofday(&now);
-	pj_time_decode(&now, &pnow);
-	pres->timestamp.slen = sprintf(pres->timestamp.ptr,
-				       "%04d-%02d-%02dT%02d:%02d:%02dZ",
-				       pnow.year, pnow.mon, pnow.day,
-				       pnow.hour, pnow.min, pnow.sec);
-	pjpidf_op.tuple.set_timestamp_np(pres->sub->pool, first, &pres->timestamp);
-
-    } else if (pres->pres_type == PJSIP_PRES_TYPE_XPIDF) {
-	pjxpidf_set_status( pres->uas_data.xpidf, is_online );
-
-    } else {
-	pj_assert(0);
-    }
-
-    /* Send notify. */
-    return pjsip_event_sub_notify( pres->sub, state, &reason, pres->uas_body);
-}
-
-/*
- * Destroy subscription (can be called for both subscriber and notifier).
- */
-PJ_DEF(pj_status_t) pjsip_presence_destroy( pjsip_presentity *pres )
-{
-    return pjsip_event_sub_destroy(pres->sub);
-}
-
-/*
- * This callback is called by event framework to query whether we want to
- * accept an incoming subscription.
- */
-static void on_query_subscribe(pjsip_rx_data *rdata, int *status)
-{
-    if (cb.accept_presence) {
-	(*cb.accept_presence)(rdata, status);
-    }
-}
-
-/*
- * This callback is called by event framework after we accept the incoming
- * subscription, to notify about the new subscription instance.
- */
-static void on_subscribe(pjsip_event_sub *sub, pjsip_rx_data *rdata,
-			 pjsip_event_sub_cb **set_sub_cb, int *expires)
-{
-    pjsip_presentity *pres;
-    pjsip_accept_hdr *accept;
-
-    pres = pj_pool_calloc(sub->pool, 1, sizeof(*pres));
-    pres->sub = sub;
-    pres->pres_type = PJSIP_PRES_TYPE_PIDF;
-    sub->user_data = pres;
-    *set_sub_cb = &sub_cb;
-
-    accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL);
-    if (accept) {
-	unsigned i;
-	int found = 0;
-	for (i=0; i<accept->count && !found; ++i) {
-	    int j;
-	    for (j=0; j<sizeof(accept_names)/sizeof(accept_names[0]); ++j) {
-		if (!pj_stricmp(&accept->values[i], &accept_names[j])) {
-		    pres->pres_type = j;
-		    found = 1;
-		    break;
-		}
-	    }
-	}
-	pj_assert(found );
-    }
-
-    (*cb.on_received_request)(pres, rdata, expires);
-}
-
-/*
- * This callback is called by event framework when the subscription is
- * terminated.
- */
-static void on_sub_terminated(pjsip_event_sub *sub, const pj_str_t *reason)
-{
-    pjsip_presentity *pres = sub->user_data;
-    if (cb.on_terminated)
-	(*cb.on_terminated)(pres, reason);
-}
-
-/*
- * This callback is called by event framework when it receives incoming
- * SUBSCRIBE request to refresh the subscription.
- */
-static void on_sub_received_refresh(pjsip_event_sub *sub, pjsip_rx_data *rdata)
-{
-    pjsip_presentity *pres = sub->user_data;
-    if (cb.on_received_refresh)
-	(*cb.on_received_refresh)(pres, rdata);
-}
-
-/*
- * This callback is called by event framework when it receives incoming
- * NOTIFY request.
- */
-static void on_received_notify(pjsip_event_sub *sub, pjsip_rx_data *rdata)
-{
-    pjsip_presentity *pres = sub->user_data;
-
-    if (cb.on_received_update) {
-	pj_status_t is_open;
-	pjsip_msg_body *body;
-	int i;
-
-	body = rdata->msg->body;
-	if (!body)
-	    return;
-
-	for (i=0; i<sizeof(accept_types)/sizeof(accept_types[0]); ++i) {
-	    if (!pj_stricmp(&body->content_type.type, &accept_types[i].type) &&
-		!pj_stricmp(&body->content_type.subtype, &accept_types[i].subtype))
-	    {
-		break;
-	    }
-	}
-
-	if (i==PJSIP_PRES_TYPE_PIDF) {
-	    pjpidf_pres *pres;
-	    pjpidf_tuple *tuple;
-	    pjpidf_status *status;
-
-	    pres = pjpidf_parse(rdata->pool, body->data, body->len);
-	    if (!pres)
-		return;
-	    tuple = pjpidf_pres_get_first_tuple(pres);
-	    if (!tuple)
-		return;
-	    status = pjpidf_tuple_get_status(tuple);
-	    if (!status)
-		return;
-	    is_open = pjpidf_status_is_basic_open(status);
-
-	} else if (i==PJSIP_PRES_TYPE_XPIDF) {
-	    pjxpidf_pres *pres;
-
-	    pres = pjxpidf_parse(rdata->pool, body->data, body->len);
-	    if (!pres)
-		return;
-	    is_open = pjxpidf_get_status(pres);
-
-	} else {
-	    return;
-	}
-
-	(*cb.on_received_update)(pres, is_open);
-    }
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip_simple/presence.h>

+#include <pjsip/sip_transport.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/guid.h>

+#include <pj/os.h>

+#include <stdio.h>

+

+/* Forward declarations. */

+static void on_query_subscribe(pjsip_rx_data *rdata, int *status);

+static void on_subscribe(pjsip_event_sub *sub, pjsip_rx_data *rdata,

+			 pjsip_event_sub_cb **cb, int *expires);

+static void on_sub_terminated(pjsip_event_sub *sub, const pj_str_t *reason);

+static void on_sub_received_refresh(pjsip_event_sub *sub, pjsip_rx_data *rdata);

+static void on_received_notify(pjsip_event_sub *sub, pjsip_rx_data *rdata);

+

+/* Some string constants. */

+static pj_str_t PRESENCE_EVENT = { "presence", 8 };

+

+/* Accept types. */

+static pj_str_t accept_names[] = {

+    { "application/pidf+xml", 20 },

+    { "application/xpidf+xml", 21 }

+};

+static pjsip_media_type accept_types[] = {

+    {

+	{ "application", 11 },

+	{ "pidf+xml", 8 }

+    },

+    {

+	{ "application", 11 },

+	{ "xpidf+xml", 9 }

+    }

+};

+

+/* Callback that is registered by application. */

+static pjsip_presence_cb cb;

+

+/* Package callback to be register to event_notify */

+static pjsip_event_sub_pkg_cb pkg_cb = { &on_query_subscribe,

+					 &on_subscribe };

+

+/* Global/static callback to be registered to event_notify */

+static pjsip_event_sub_cb sub_cb = { &on_sub_terminated,

+				     &on_sub_received_refresh,

+				     NULL,

+				     &on_received_notify,

+				     NULL };

+

+/*

+ * Initialize presence module.

+ * This will register event package "presence" to event framework.

+ */

+PJ_DEF(void) pjsip_presence_init(const pjsip_presence_cb *pcb)

+{

+    pj_memcpy(&cb, pcb, sizeof(*pcb));

+    pjsip_event_sub_register_pkg( &PRESENCE_EVENT, 

+				  sizeof(accept_names)/sizeof(accept_names[0]),

+				  accept_names,

+				  &pkg_cb);

+}

+

+/*

+ * Create presence subscription.

+ */

+PJ_DEF(pjsip_presentity*) pjsip_presence_create( pjsip_endpoint *endpt,

+						 const pj_str_t *local_url,

+						 const pj_str_t *remote_url,

+						 int expires,

+						 void *user_data )

+{

+    pjsip_event_sub *sub;

+    pjsip_presentity *pres;

+

+    if (expires < 0)

+	expires = 300;

+

+    /* Create event subscription */

+    sub = pjsip_event_sub_create(endpt, local_url, remote_url, &PRESENCE_EVENT, 

+				 expires, 

+				 sizeof(accept_names)/sizeof(accept_names[0]),

+				 accept_names,

+				 NULL, &sub_cb);

+    if (!sub)

+	return NULL;

+

+    /* Allocate presence descriptor. */

+    pres = pj_pool_calloc(sub->pool, 1, sizeof(*pres));

+    pres->sub = sub;

+    pres->user_data = user_data;

+    sub->user_data = pres;

+

+    return pres;

+}

+

+/*

+ * Send SUBSCRIBE.

+ */

+PJ_DEF(pj_status_t) pjsip_presence_subscribe( pjsip_presentity *pres )

+{

+    return pjsip_event_sub_subscribe( pres->sub );

+}

+

+/*

+ * Set credentials to be used for outgoing requests.

+ */

+PJ_DEF(pj_status_t) pjsip_presence_set_credentials( pjsip_presentity *pres,

+						    int count,

+						    const pjsip_cred_info cred[])

+{

+    return pjsip_event_sub_set_credentials(pres->sub, count, cred);

+}

+

+/*

+ * Set route-set.

+ */

+PJ_DEF(pj_status_t) pjsip_presence_set_route_set( pjsip_presentity *pres,

+						  const pjsip_route_hdr *hdr )

+{

+    return pjsip_event_sub_set_route_set( pres->sub, hdr );

+}

+

+/*

+ * Unsubscribe.

+ */

+PJ_DEF(pj_status_t) pjsip_presence_unsubscribe( pjsip_presentity *pres )

+{

+    return pjsip_event_sub_unsubscribe(pres->sub);

+}

+

+/*

+ * This is the pjsip_msg_body callback to print XML body.

+ */

+static int print_xml(pjsip_msg_body *body, char *buf, pj_size_t size)

+{

+    return pj_xml_print( body->data, buf, size, PJ_TRUE );

+}

+

+/*

+ * Create and initialize PIDF document and msg body (notifier only).

+ */

+static pj_status_t init_presence_info( pjsip_presentity *pres )

+{

+    pj_str_t uri;

+    pj_pool_t *pool = pres->sub->pool;

+    char tmp[PJSIP_MAX_URL_SIZE];

+    pjpidf_tuple *tuple;

+    const pjsip_media_type *content_type = NULL;

+

+    pj_assert(pres->uas_body == NULL);

+

+    /* Make entity_id */

+    uri.ptr = tmp;

+    uri.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, pres->sub->from->uri, 

+			      tmp, sizeof(tmp));

+    if (uri.slen < 0)

+	return -1;

+

+    if (pres->pres_type == PJSIP_PRES_TYPE_PIDF) {

+	pj_str_t s;

+

+	/* Create <presence>. */

+	pres->uas_data.pidf = pjpidf_create(pool, &s);

+

+	/* Create <tuple> */

+	pj_create_unique_string(pool, &s);

+	tuple = pjpidf_pres_add_tuple(pool, pres->uas_data.pidf, &s);

+

+	/* Set <contact> */

+	s.ptr = tmp;

+	s.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, pres->sub->contact->uri, tmp, sizeof(tmp));

+	if (s.slen < 0)

+	    return -1;

+	pjpidf_tuple_set_contact(pool, tuple, &s);

+

+	/* Content-Type */

+	content_type = &accept_types[PJSIP_PRES_TYPE_PIDF];

+

+    } else if (pres->pres_type == PJSIP_PRES_TYPE_XPIDF) {

+

+	/* Create XPIDF */

+	pres->uas_data.xpidf = pjxpidf_create(pool, &uri);

+

+	/* Content-Type. */

+	content_type = &accept_types[PJSIP_PRES_TYPE_XPIDF];

+    }

+

+    /* Create message body */

+    pres->uas_body = pj_pool_alloc(pool, sizeof(pjsip_msg_body));

+    pres->uas_body->content_type = *content_type;

+    pres->uas_body->data = pres->uas_data.pidf;

+    pres->uas_body->len = 0;

+    pres->uas_body->print_body = &print_xml;

+

+    return 0;

+}

+

+/*

+ * Send NOTIFY and set subscription state.

+ */

+PJ_DEF(pj_status_t) pjsip_presence_notify( pjsip_presentity *pres,

+					   pjsip_event_sub_state state,

+					   pj_bool_t is_online )

+{

+    pj_str_t reason = { "", 0 };

+

+    if (pres->uas_data.pidf == NULL) {

+	if (init_presence_info(pres) != 0)

+	    return -1;

+    }

+

+    /* Update basic status in PIDF/XPIDF document. */

+    if (pres->pres_type == PJSIP_PRES_TYPE_PIDF) {

+	pjpidf_tuple *first;

+	pjpidf_status *status;

+	pj_time_val now;

+	pj_parsed_time pnow;

+

+	first = pjpidf_op.pres.get_first_tuple(pres->uas_data.pidf);

+	pj_assert(first);

+	status = pjpidf_op.tuple.get_status(first);

+	pj_assert(status);

+	pjpidf_op.status.set_basic_open(status, is_online);

+

+	/* Update timestamp. */

+	if (pres->timestamp.ptr == 0) {

+	    pres->timestamp.ptr = pj_pool_alloc(pres->sub->pool, 24);

+	}

+	pj_gettimeofday(&now);

+	pj_time_decode(&now, &pnow);

+	pres->timestamp.slen = sprintf(pres->timestamp.ptr,

+				       "%04d-%02d-%02dT%02d:%02d:%02dZ",

+				       pnow.year, pnow.mon, pnow.day,

+				       pnow.hour, pnow.min, pnow.sec);

+	pjpidf_op.tuple.set_timestamp_np(pres->sub->pool, first, &pres->timestamp);

+

+    } else if (pres->pres_type == PJSIP_PRES_TYPE_XPIDF) {

+	pjxpidf_set_status( pres->uas_data.xpidf, is_online );

+

+    } else {

+	pj_assert(0);

+    }

+

+    /* Send notify. */

+    return pjsip_event_sub_notify( pres->sub, state, &reason, pres->uas_body);

+}

+

+/*

+ * Destroy subscription (can be called for both subscriber and notifier).

+ */

+PJ_DEF(pj_status_t) pjsip_presence_destroy( pjsip_presentity *pres )

+{

+    return pjsip_event_sub_destroy(pres->sub);

+}

+

+/*

+ * This callback is called by event framework to query whether we want to

+ * accept an incoming subscription.

+ */

+static void on_query_subscribe(pjsip_rx_data *rdata, int *status)

+{

+    if (cb.accept_presence) {

+	(*cb.accept_presence)(rdata, status);

+    }

+}

+

+/*

+ * This callback is called by event framework after we accept the incoming

+ * subscription, to notify about the new subscription instance.

+ */

+static void on_subscribe(pjsip_event_sub *sub, pjsip_rx_data *rdata,

+			 pjsip_event_sub_cb **set_sub_cb, int *expires)

+{

+    pjsip_presentity *pres;

+    pjsip_accept_hdr *accept;

+

+    pres = pj_pool_calloc(sub->pool, 1, sizeof(*pres));

+    pres->sub = sub;

+    pres->pres_type = PJSIP_PRES_TYPE_PIDF;

+    sub->user_data = pres;

+    *set_sub_cb = &sub_cb;

+

+    accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL);

+    if (accept) {

+	unsigned i;

+	int found = 0;

+	for (i=0; i<accept->count && !found; ++i) {

+	    int j;

+	    for (j=0; j<sizeof(accept_names)/sizeof(accept_names[0]); ++j) {

+		if (!pj_stricmp(&accept->values[i], &accept_names[j])) {

+		    pres->pres_type = j;

+		    found = 1;

+		    break;

+		}

+	    }

+	}

+	pj_assert(found );

+    }

+

+    (*cb.on_received_request)(pres, rdata, expires);

+}

+

+/*

+ * This callback is called by event framework when the subscription is

+ * terminated.

+ */

+static void on_sub_terminated(pjsip_event_sub *sub, const pj_str_t *reason)

+{

+    pjsip_presentity *pres = sub->user_data;

+    if (cb.on_terminated)

+	(*cb.on_terminated)(pres, reason);

+}

+

+/*

+ * This callback is called by event framework when it receives incoming

+ * SUBSCRIBE request to refresh the subscription.

+ */

+static void on_sub_received_refresh(pjsip_event_sub *sub, pjsip_rx_data *rdata)

+{

+    pjsip_presentity *pres = sub->user_data;

+    if (cb.on_received_refresh)

+	(*cb.on_received_refresh)(pres, rdata);

+}

+

+/*

+ * This callback is called by event framework when it receives incoming

+ * NOTIFY request.

+ */

+static void on_received_notify(pjsip_event_sub *sub, pjsip_rx_data *rdata)

+{

+    pjsip_presentity *pres = sub->user_data;

+

+    if (cb.on_received_update) {

+	pj_status_t is_open;

+	pjsip_msg_body *body;

+	int i;

+

+	body = rdata->msg->body;

+	if (!body)

+	    return;

+

+	for (i=0; i<sizeof(accept_types)/sizeof(accept_types[0]); ++i) {

+	    if (!pj_stricmp(&body->content_type.type, &accept_types[i].type) &&

+		!pj_stricmp(&body->content_type.subtype, &accept_types[i].subtype))

+	    {

+		break;

+	    }

+	}

+

+	if (i==PJSIP_PRES_TYPE_PIDF) {

+	    pjpidf_pres *pres;

+	    pjpidf_tuple *tuple;

+	    pjpidf_status *status;

+

+	    pres = pjpidf_parse(rdata->pool, body->data, body->len);

+	    if (!pres)

+		return;

+	    tuple = pjpidf_pres_get_first_tuple(pres);

+	    if (!tuple)

+		return;

+	    status = pjpidf_tuple_get_status(tuple);

+	    if (!status)

+		return;

+	    is_open = pjpidf_status_is_basic_open(status);

+

+	} else if (i==PJSIP_PRES_TYPE_XPIDF) {

+	    pjxpidf_pres *pres;

+

+	    pres = pjxpidf_parse(rdata->pool, body->data, body->len);

+	    if (!pres)

+		return;

+	    is_open = pjxpidf_get_status(pres);

+

+	} else {

+	    return;

+	}

+

+	(*cb.on_received_update)(pres, is_open);

+    }

+}

+

diff --git a/pjsip/src/pjsip-simple/xpidf.c b/pjsip/src/pjsip-simple/xpidf.c
index 5787f67..cc9aaf4 100644
--- a/pjsip/src/pjsip-simple/xpidf.c
+++ b/pjsip/src/pjsip-simple/xpidf.c
@@ -1,279 +1,301 @@
-/* $Id$
- *
- */
-#include <pjsip_simple/xpidf.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-
-static pj_str_t PRESENCE = { "presence", 8 };
-static pj_str_t STATUS = { "status", 6 };
-static pj_str_t OPEN = { "open", 4 };
-static pj_str_t CLOSED = { "closed", 6 };
-static pj_str_t URI = { "uri", 3 };
-static pj_str_t ATOM = { "atom", 4 };
-static pj_str_t ATOMID = { "atomid", 6 };
-static pj_str_t ADDRESS = { "address", 7 };
-static pj_str_t SUBSCRIBE_PARAM = { ";method=SUBSCRIBE", 17 };
-static pj_str_t PRESENTITY = { "presentity", 10 };
-static pj_str_t EMPTY_STRING = { NULL, 0 };
-
-static pj_xml_node* xml_create_node(pj_pool_t *pool, 
-				    pj_str_t *name, const pj_str_t *value)
-{
-    pj_xml_node *node;
-
-    node = pj_pool_alloc(pool, sizeof(pj_xml_node));
-    pj_list_init(&node->attr_head);
-    pj_list_init(&node->node_head);
-    node->name = *name;
-    if (value) pj_strdup(pool, &node->content, value);
-    else node->content.ptr=NULL, node->content.slen=0;
-
-    return node;
-}
-
-static pj_xml_attr* xml_create_attr(pj_pool_t *pool, pj_str_t *name,
-				    const pj_str_t *value)
-{
-    pj_xml_attr *attr = pj_pool_alloc(pool, sizeof(*attr));
-    attr->name = *name;
-    pj_strdup(pool, &attr->value, value);
-    return attr;
-}
-
-
-PJ_DEF(pjxpidf_pres*) pjxpidf_create(pj_pool_t *pool, const pj_str_t *uri_cstr)
-{
-    pjxpidf_pres *pres;
-    pj_xml_node *presentity;
-    pj_xml_node *atom;
-    pj_xml_node *addr;
-    pj_xml_node *status;
-    pj_xml_attr *attr;
-    pj_str_t uri;
-    pj_str_t tmp;
-
-    /* <presence> */
-    pres = xml_create_node(pool, &PRESENCE, NULL);
-
-    /* <presentity> */
-    presentity = xml_create_node(pool, &PRESENTITY, NULL);
-    pj_xml_add_node(pres, presentity);
-
-    /* uri attribute */
-    uri.ptr = pj_pool_alloc(pool, uri_cstr->slen + SUBSCRIBE_PARAM.slen);
-    pj_strcpy( &uri, uri_cstr);
-    pj_strcat( &uri, &SUBSCRIBE_PARAM);
-    attr = xml_create_attr(pool, &URI, &uri);
-    pj_xml_add_attr(presentity, attr);
-
-    /* <atom> */
-    atom = xml_create_node(pool, &ATOM, NULL);
-    pj_xml_add_node(pres, atom);
-
-    /* atom id */
-    pj_create_unique_string(pool, &tmp);
-    attr = xml_create_attr(pool, &ATOMID, &tmp);
-    pj_xml_add_attr(atom, attr);
-
-    /* address */
-    addr = xml_create_node(pool, &ADDRESS, NULL);
-    pj_xml_add_node(atom, addr);
-
-    /* address'es uri */
-    attr = xml_create_attr(pool, &URI, uri_cstr);
-    pj_xml_add_attr(addr, attr);
-
-    /* status */
-    status = xml_create_node(pool, &STATUS, NULL);
-    pj_xml_add_node(addr, status);
-
-    /* status attr */
-    attr = xml_create_attr(pool, &STATUS, &OPEN);
-    pj_xml_add_attr(status, attr);
-
-    return pres;
-}   
-
-
-
-PJ_DEF(pjxpidf_pres*) pjxpidf_parse(pj_pool_t *pool, char *text, pj_size_t len)
-{
-    pjxpidf_pres *pres;
-    pj_xml_node *node;
-
-    pres = pj_xml_parse(pool, text, len);
-    if (!pres)
-	return NULL;
-
-    /* Validate <presence> */
-    if (pj_stricmp(&pres->name, &PRESENCE) != 0)
-	return NULL;
-    if (pj_xml_find_attr(pres, &URI, NULL) == NULL)
-	return NULL;
-
-    /* Validate <presentity> */
-    node = pj_xml_find_node(pres, &PRESENTITY);
-    if (node == NULL)
-	return NULL;
-
-    /* Validate <atom> */
-    node = pj_xml_find_node(pres, &ATOM);
-    if (node == NULL)
-	return NULL;
-    if (pj_xml_find_attr(node, &ATOMID, NULL) == NULL)
-	return NULL;
-
-    /* Address */
-    node = pj_xml_find_node(node, &ADDRESS);
-    if (node == NULL)
-	return NULL;
-    if (pj_xml_find_attr(node, &URI, NULL) == NULL)
-	return NULL;
-
-
-    /* Status */
-    node = pj_xml_find_node(node, &STATUS);
-    if (node == NULL)
-	return NULL;
-    if (pj_xml_find_attr(node, &STATUS, NULL) == NULL)
-	return NULL;
-
-    return pres;
-}
-
-
-PJ_DEF(int) pjxpidf_print( pjxpidf_pres *pres, char *text, pj_size_t len)
-{
-    return pj_xml_print(pres, text, len, PJ_TRUE);
-}
-
-
-PJ_DEF(pj_str_t*) pjxpidf_get_uri(pjxpidf_pres *pres)
-{
-    pj_xml_node *presentity;
-    pj_xml_attr *attr;
-
-    presentity = pj_xml_find_node(pres, &PRESENTITY);
-    if (!presentity)
-	return &EMPTY_STRING;
-
-    attr = pj_xml_find_attr(presentity, &URI, NULL);
-    if (!attr)
-	return &EMPTY_STRING;
-
-    return &attr->value;
-}
-
-
-PJ_DEF(pj_status_t) pjxpidf_set_uri(pj_pool_t *pool, pjxpidf_pres *pres, 
-				    const pj_str_t *uri)
-{
-    pj_xml_node *presentity;
-    pj_xml_node *atom;
-    pj_xml_node *addr;
-    pj_xml_attr *attr;
-    pj_str_t dup_uri;
-
-    presentity = pj_xml_find_node(pres, &PRESENTITY);
-    if (!presentity) {
-	pj_assert(0);
-	return -1;
-    }
-    atom = pj_xml_find_node(pres, &ATOM);
-    if (!atom) {
-	pj_assert(0);
-	return -1;
-    }
-    addr = pj_xml_find_node(atom, &ADDRESS);
-    if (!addr) {
-	pj_assert(0);
-	return -1;
-    }
-
-    /* Set uri in presentity */
-    attr = pj_xml_find_attr(presentity, &URI, NULL);
-    if (!attr) {
-	pj_assert(0);
-	return -1;
-    }
-    pj_strdup(pool, &dup_uri, uri);
-    attr->value = dup_uri;
-
-    /* Set uri in address. */
-    attr = pj_xml_find_attr(addr, &URI, NULL);
-    if (!attr) {
-	pj_assert(0);
-	return -1;
-    }
-    attr->value = dup_uri;
-
-    return 0;
-}
-
-
-PJ_DEF(pj_bool_t) pjxpidf_get_status(pjxpidf_pres *pres)
-{
-    pj_xml_node *atom;
-    pj_xml_node *addr;
-    pj_xml_node *status;
-    pj_xml_attr *attr;
-
-    atom = pj_xml_find_node(pres, &ATOM);
-    if (!atom) {
-	pj_assert(0);
-	return PJ_FALSE;
-    }
-    addr = pj_xml_find_node(atom, &ADDRESS);
-    if (!addr) {
-	pj_assert(0);
-	return PJ_FALSE;
-    }
-    status = pj_xml_find_node(atom, &STATUS);
-    if (!status) {
-	pj_assert(0);
-	return PJ_FALSE;
-    }
-    attr = pj_xml_find_attr(status, &STATUS, NULL);
-    if (!attr) {
-	pj_assert(0);
-	return PJ_FALSE;
-    }
-
-    return pj_stricmp(&attr->value, &OPEN) ? PJ_TRUE : PJ_FALSE;
-}
-
-
-PJ_DEF(pj_status_t) pjxpidf_set_status(pjxpidf_pres *pres, pj_bool_t online_status)
-{
-    pj_xml_node *atom;
-    pj_xml_node *addr;
-    pj_xml_node *status;
-    pj_xml_attr *attr;
-
-    atom = pj_xml_find_node(pres, &ATOM);
-    if (!atom) {
-	pj_assert(0);
-	return -1;
-    }
-    addr = pj_xml_find_node(atom, &ADDRESS);
-    if (!addr) {
-	pj_assert(0);
-	return -1;
-    }
-    status = pj_xml_find_node(addr, &STATUS);
-    if (!status) {
-	pj_assert(0);
-	return -1;
-    }
-    attr = pj_xml_find_attr(status, &STATUS, NULL);
-    if (!attr) {
-	pj_assert(0);
-	return -1;
-    }
-
-    attr->value = ( online_status ? OPEN : CLOSED );
-    return 0;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip_simple/xpidf.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/guid.h>

+

+static pj_str_t PRESENCE = { "presence", 8 };

+static pj_str_t STATUS = { "status", 6 };

+static pj_str_t OPEN = { "open", 4 };

+static pj_str_t CLOSED = { "closed", 6 };

+static pj_str_t URI = { "uri", 3 };

+static pj_str_t ATOM = { "atom", 4 };

+static pj_str_t ATOMID = { "atomid", 6 };

+static pj_str_t ADDRESS = { "address", 7 };

+static pj_str_t SUBSCRIBE_PARAM = { ";method=SUBSCRIBE", 17 };

+static pj_str_t PRESENTITY = { "presentity", 10 };

+static pj_str_t EMPTY_STRING = { NULL, 0 };

+

+static pj_xml_node* xml_create_node(pj_pool_t *pool, 

+				    pj_str_t *name, const pj_str_t *value)

+{

+    pj_xml_node *node;

+

+    node = pj_pool_alloc(pool, sizeof(pj_xml_node));

+    pj_list_init(&node->attr_head);

+    pj_list_init(&node->node_head);

+    node->name = *name;

+    if (value) pj_strdup(pool, &node->content, value);

+    else node->content.ptr=NULL, node->content.slen=0;

+

+    return node;

+}

+

+static pj_xml_attr* xml_create_attr(pj_pool_t *pool, pj_str_t *name,

+				    const pj_str_t *value)

+{

+    pj_xml_attr *attr = pj_pool_alloc(pool, sizeof(*attr));

+    attr->name = *name;

+    pj_strdup(pool, &attr->value, value);

+    return attr;

+}

+

+

+PJ_DEF(pjxpidf_pres*) pjxpidf_create(pj_pool_t *pool, const pj_str_t *uri_cstr)

+{

+    pjxpidf_pres *pres;

+    pj_xml_node *presentity;

+    pj_xml_node *atom;

+    pj_xml_node *addr;

+    pj_xml_node *status;

+    pj_xml_attr *attr;

+    pj_str_t uri;

+    pj_str_t tmp;

+

+    /* <presence> */

+    pres = xml_create_node(pool, &PRESENCE, NULL);

+

+    /* <presentity> */

+    presentity = xml_create_node(pool, &PRESENTITY, NULL);

+    pj_xml_add_node(pres, presentity);

+

+    /* uri attribute */

+    uri.ptr = pj_pool_alloc(pool, uri_cstr->slen + SUBSCRIBE_PARAM.slen);

+    pj_strcpy( &uri, uri_cstr);

+    pj_strcat( &uri, &SUBSCRIBE_PARAM);

+    attr = xml_create_attr(pool, &URI, &uri);

+    pj_xml_add_attr(presentity, attr);

+

+    /* <atom> */

+    atom = xml_create_node(pool, &ATOM, NULL);

+    pj_xml_add_node(pres, atom);

+

+    /* atom id */

+    pj_create_unique_string(pool, &tmp);

+    attr = xml_create_attr(pool, &ATOMID, &tmp);

+    pj_xml_add_attr(atom, attr);

+

+    /* address */

+    addr = xml_create_node(pool, &ADDRESS, NULL);

+    pj_xml_add_node(atom, addr);

+

+    /* address'es uri */

+    attr = xml_create_attr(pool, &URI, uri_cstr);

+    pj_xml_add_attr(addr, attr);

+

+    /* status */

+    status = xml_create_node(pool, &STATUS, NULL);

+    pj_xml_add_node(addr, status);

+

+    /* status attr */

+    attr = xml_create_attr(pool, &STATUS, &OPEN);

+    pj_xml_add_attr(status, attr);

+

+    return pres;

+}   

+

+

+

+PJ_DEF(pjxpidf_pres*) pjxpidf_parse(pj_pool_t *pool, char *text, pj_size_t len)

+{

+    pjxpidf_pres *pres;

+    pj_xml_node *node;

+

+    pres = pj_xml_parse(pool, text, len);

+    if (!pres)

+	return NULL;

+

+    /* Validate <presence> */

+    if (pj_stricmp(&pres->name, &PRESENCE) != 0)

+	return NULL;

+    if (pj_xml_find_attr(pres, &URI, NULL) == NULL)

+	return NULL;

+

+    /* Validate <presentity> */

+    node = pj_xml_find_node(pres, &PRESENTITY);

+    if (node == NULL)

+	return NULL;

+

+    /* Validate <atom> */

+    node = pj_xml_find_node(pres, &ATOM);

+    if (node == NULL)

+	return NULL;

+    if (pj_xml_find_attr(node, &ATOMID, NULL) == NULL)

+	return NULL;

+

+    /* Address */

+    node = pj_xml_find_node(node, &ADDRESS);

+    if (node == NULL)

+	return NULL;

+    if (pj_xml_find_attr(node, &URI, NULL) == NULL)

+	return NULL;

+

+

+    /* Status */

+    node = pj_xml_find_node(node, &STATUS);

+    if (node == NULL)

+	return NULL;

+    if (pj_xml_find_attr(node, &STATUS, NULL) == NULL)

+	return NULL;

+

+    return pres;

+}

+

+

+PJ_DEF(int) pjxpidf_print( pjxpidf_pres *pres, char *text, pj_size_t len)

+{

+    return pj_xml_print(pres, text, len, PJ_TRUE);

+}

+

+

+PJ_DEF(pj_str_t*) pjxpidf_get_uri(pjxpidf_pres *pres)

+{

+    pj_xml_node *presentity;

+    pj_xml_attr *attr;

+

+    presentity = pj_xml_find_node(pres, &PRESENTITY);

+    if (!presentity)

+	return &EMPTY_STRING;

+

+    attr = pj_xml_find_attr(presentity, &URI, NULL);

+    if (!attr)

+	return &EMPTY_STRING;

+

+    return &attr->value;

+}

+

+

+PJ_DEF(pj_status_t) pjxpidf_set_uri(pj_pool_t *pool, pjxpidf_pres *pres, 

+				    const pj_str_t *uri)

+{

+    pj_xml_node *presentity;

+    pj_xml_node *atom;

+    pj_xml_node *addr;

+    pj_xml_attr *attr;

+    pj_str_t dup_uri;

+

+    presentity = pj_xml_find_node(pres, &PRESENTITY);

+    if (!presentity) {

+	pj_assert(0);

+	return -1;

+    }

+    atom = pj_xml_find_node(pres, &ATOM);

+    if (!atom) {

+	pj_assert(0);

+	return -1;

+    }

+    addr = pj_xml_find_node(atom, &ADDRESS);

+    if (!addr) {

+	pj_assert(0);

+	return -1;

+    }

+

+    /* Set uri in presentity */

+    attr = pj_xml_find_attr(presentity, &URI, NULL);

+    if (!attr) {

+	pj_assert(0);

+	return -1;

+    }

+    pj_strdup(pool, &dup_uri, uri);

+    attr->value = dup_uri;

+

+    /* Set uri in address. */

+    attr = pj_xml_find_attr(addr, &URI, NULL);

+    if (!attr) {

+	pj_assert(0);

+	return -1;

+    }

+    attr->value = dup_uri;

+

+    return 0;

+}

+

+

+PJ_DEF(pj_bool_t) pjxpidf_get_status(pjxpidf_pres *pres)

+{

+    pj_xml_node *atom;

+    pj_xml_node *addr;

+    pj_xml_node *status;

+    pj_xml_attr *attr;

+

+    atom = pj_xml_find_node(pres, &ATOM);

+    if (!atom) {

+	pj_assert(0);

+	return PJ_FALSE;

+    }

+    addr = pj_xml_find_node(atom, &ADDRESS);

+    if (!addr) {

+	pj_assert(0);

+	return PJ_FALSE;

+    }

+    status = pj_xml_find_node(atom, &STATUS);

+    if (!status) {

+	pj_assert(0);

+	return PJ_FALSE;

+    }

+    attr = pj_xml_find_attr(status, &STATUS, NULL);

+    if (!attr) {

+	pj_assert(0);

+	return PJ_FALSE;

+    }

+

+    return pj_stricmp(&attr->value, &OPEN) ? PJ_TRUE : PJ_FALSE;

+}

+

+

+PJ_DEF(pj_status_t) pjxpidf_set_status(pjxpidf_pres *pres, pj_bool_t online_status)

+{

+    pj_xml_node *atom;

+    pj_xml_node *addr;

+    pj_xml_node *status;

+    pj_xml_attr *attr;

+

+    atom = pj_xml_find_node(pres, &ATOM);

+    if (!atom) {

+	pj_assert(0);

+	return -1;

+    }

+    addr = pj_xml_find_node(atom, &ADDRESS);

+    if (!addr) {

+	pj_assert(0);

+	return -1;

+    }

+    status = pj_xml_find_node(addr, &STATUS);

+    if (!status) {

+	pj_assert(0);

+	return -1;

+    }

+    attr = pj_xml_find_attr(status, &STATUS, NULL);

+    if (!attr) {

+	pj_assert(0);

+	return -1;

+    }

+

+    attr->value = ( online_status ? OPEN : CLOSED );

+    return 0;

+}

+

diff --git a/pjsip/src/pjsip-ua/sip_dialog.c b/pjsip/src/pjsip-ua/sip_dialog.c
index 0c9db5e..ade94b2 100644
--- a/pjsip/src/pjsip-ua/sip_dialog.c
+++ b/pjsip/src/pjsip-ua/sip_dialog.c
@@ -1,1786 +1,1808 @@
-/* $Id$
- *
- */
-#include <pjsip_mod_ua/sip_dialog.h>
-#include <pjsip_mod_ua/sip_ua.h>
-#include <pjsip_mod_ua/sip_ua_private.h>
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_types.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_misc.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_parser.h>
-#include <pj/string.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/guid.h>
-#include <pj/except.h>
-#include <pj/pool.h>
-
-/* TLS to keep dialog lock record (initialized by UA) */
-int pjsip_dlg_lock_tls_id;
-
-struct dialog_lock_data
-{
-    struct dialog_lock_data *prev;
-    pjsip_dlg	    *dlg;
-    int			     is_alive;
-};
-
-/*
- * Static function prototypes.
- */
-static void dlg_create_request_throw( pjsip_tx_data **p_tdata,
-				      pjsip_dlg *dlg,
-				      const pjsip_method *method,
-				      int cseq );
-static int  dlg_on_all_state_pre(  pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event);
-static int  dlg_on_all_state_post( pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event);
-static int  dlg_on_state_null( pjsip_dlg *dlg, 
-			       pjsip_transaction *tsx,
-			       pjsip_event *event);
-static int  dlg_on_state_incoming( pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event);
-static int  dlg_on_state_calling( pjsip_dlg *dlg, 
-				  pjsip_transaction *tsx,
-				  pjsip_event *event);
-static int  dlg_on_state_proceeding( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event);
-static int  dlg_on_state_proceeding_caller( pjsip_dlg *dlg, 
-					    pjsip_transaction *tsx,
-					    pjsip_event *event);
-static int  dlg_on_state_proceeding_callee( pjsip_dlg *dlg, 
-					    pjsip_transaction *tsx,
-					    pjsip_event *event);
-static int  dlg_on_state_connecting( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event);
-static int  dlg_on_state_established( pjsip_dlg *dlg, 
-				      pjsip_transaction *tsx,
-				      pjsip_event *event);
-static int  dlg_on_state_disconnected( pjsip_dlg *dlg, 
-				       pjsip_transaction *tsx,
-				       pjsip_event *event);
-static int  dlg_on_state_terminated( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event);
-
-/*
- * Dialog state handlers.
- */
-static int  (*dlg_state_handlers[])(struct pjsip_dlg *, pjsip_transaction *,
-				    pjsip_event *) = 
-{
-    &dlg_on_state_null,
-    &dlg_on_state_incoming,
-    &dlg_on_state_calling,
-    &dlg_on_state_proceeding,
-    &dlg_on_state_connecting,
-    &dlg_on_state_established,
-    &dlg_on_state_disconnected,
-    &dlg_on_state_terminated,
-};
-
-/*
- * Dialog state names.
- */
-static const char* dlg_state_names[] = 
-{
-    "STATE_NULL",
-    "STATE_INCOMING",
-    "STATE_CALLING",
-    "STATE_PROCEEDING",
-    "STATE_CONNECTING",
-    "STATE_ESTABLISHED",
-    "STATE_DISCONNECTED",
-    "STATE_TERMINATED",
-};
-
-
-/*
- * Get the dialog string state, normally for logging purpose.
- */
-const char *pjsip_dlg_state_str(pjsip_dlg_state_e state)
-{
-    return dlg_state_names[state];
-}
-
-/* Lock dialog mutex. */
-static void lock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)
-{
-    struct dialog_lock_data *prev;
-
-    pj_mutex_lock(dlg->mutex);
-    prev = pj_thread_local_get(pjsip_dlg_lock_tls_id);
-    lck->prev = prev;
-    lck->dlg = dlg;
-    lck->is_alive = 1;
-    pj_thread_local_set(pjsip_dlg_lock_tls_id, lck);
-}
-
-/* Carefully unlock dialog mutex, protect against situation when the dialog
- * has already been destroyed.
- */
-static pj_status_t unlock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)
-{
-    pj_assert(pj_thread_local_get(pjsip_dlg_lock_tls_id) == lck);
-    pj_assert(dlg == lck->dlg);
-
-    pj_thread_local_set(pjsip_dlg_lock_tls_id, lck->prev);
-    if (lck->is_alive)
-	pj_mutex_unlock(dlg->mutex);
-
-    return lck->is_alive ? 0 : -1;
-}
-
-/*
- * This is called by dialog's FSM to change dialog's state.
- */
-static void dlg_set_state( pjsip_dlg *dlg, pjsip_dlg_state_e state,
-			   pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event);
-
-    PJ_LOG(4, (dlg->obj_name, "State %s-->%s (ev=%s, src=%s, data=%p)", 
-	       pjsip_dlg_state_str(dlg->state), pjsip_dlg_state_str(state),
-	       event ? pjsip_event_str(event->type) : "", 
-	       event ? pjsip_event_str(event->src_type) : "",
-	       event ? event->src.data : NULL));
-
-    dlg->state = state;
-    dlg->handle_tsx_event = dlg_state_handlers[state];
-}
-
-/*
- * Invoke dialog's callback.
- * This function is called by dialog's FSM, and interpret the event and call
- * the corresponding callback registered by application.
- */
-static void dlg_call_dlg_callback( pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event,
-				   pjsip_event *event )
-{
-    pjsip_dlg_callback *cb = dlg->ua->dlg_cb;
-    if (!cb) {
-	PJ_LOG(4,(dlg->obj_name, "Can not call callback (none registered)."));
-	return;
-    }
-
-    /* Low level event: call the all-events callback. */
-    if (cb->on_all_events) {
-	(*cb->on_all_events)(dlg, dlg_event, event);
-    }
-
-    /* Low level event: call the tx/rx callback if this is a tx/rx event. */
-    if (event->type == PJSIP_EVENT_BEFORE_TX && cb->on_before_tx)
-    {
-	(*cb->on_before_tx)(dlg, event->obj.tsx, event->src.tdata, event->data.long_data);
-    }
-    else if (event->type == PJSIP_EVENT_TX_MSG && 
-	event->src_type == PJSIP_EVENT_TX_MSG && cb->on_tx_msg) 
-    {
-	(*cb->on_tx_msg)(dlg, event->obj.tsx, event->src.tdata);
-    } 
-    else if (event->type == PJSIP_EVENT_RX_MSG &&
-	     event->src_type == PJSIP_EVENT_RX_MSG && cb->on_rx_msg) {
-	(*cb->on_rx_msg)(dlg, event->obj.tsx, event->src.rdata);
-    }
-
-    /* Now trigger high level events. 
-     * High level event should only occurs when dialog's state has changed,
-     * except for on_provisional, which may be called multiple times whenever
-     * response message is sent
-     */
-    if (dlg->state == PJSIP_DIALOG_STATE_PROCEEDING &&
-	(event->type== PJSIP_EVENT_TSX_STATE_CHANGED) && 
-	event->obj.tsx == dlg->invite_tsx) 
-    {
-	/* Sent/received provisional responses. */
-	if (cb->on_provisional)
-	    (*cb->on_provisional)(dlg, event->obj.tsx, event);
-    }
-
-    if (dlg_event == PJSIP_DIALOG_EVENT_MID_CALL_REQUEST) {
-	if (cb->on_mid_call_events)
-	    (*cb->on_mid_call_events)(dlg, event);
-	return;
-    }
-
-    if (dlg_event != PJSIP_DIALOG_EVENT_STATE_CHANGED)
-	return;
-
-    if (dlg->state == PJSIP_DIALOG_STATE_INCOMING) {
-
-	/* New incoming dialog. */
-	pj_assert (event->src_type == PJSIP_EVENT_RX_MSG);
-	(*cb->on_incoming)(dlg, event->obj.tsx, event->src.rdata);
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_CALLING) {
-
-	/* Dialog has just sent the first INVITE. */
-	if (cb->on_calling) {
-	    (*cb->on_calling)(dlg, event->obj.tsx, event->src.tdata);
-	}
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_DISCONNECTED) {
-
-	if (cb->on_disconnected)
-	    (*cb->on_disconnected)(dlg, event);
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_TERMINATED) {
-
-	if (cb->on_terminated)
-	    (*cb->on_terminated)(dlg);
-
-	pjsip_ua_destroy_dialog(dlg);
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_CONNECTING) {
-
-	if (cb->on_connecting)
-	    (*cb->on_connecting)(dlg, event);
-
-    } else if (dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {
-
-	if (cb->on_established)
-	    (*cb->on_established)(dlg, event);
-    }
-}
-
-/*
- * This callback receives event from the transaction layer (via User Agent),
- * or from dialog timer (for 200/INVITE or ACK retransmission).
- */
-void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg, 
-			     pjsip_transaction *tsx, 
-			     pjsip_event *event)
-{
-    int status = 0;
-    struct dialog_lock_data lck;
-
-    PJ_LOG(4, (dlg->obj_name, "state=%s (evt=%s, src=%s)", 
-			 pjsip_dlg_state_str(dlg->state),
-			 pjsip_event_str(event->type),
-			 pjsip_event_str(event->src_type)));
-
-
-    lock_dialog(dlg, &lck);
-
-    status = dlg_on_all_state_pre( dlg, tsx, event);
-
-    if (status==0) {
-	status = (*dlg->handle_tsx_event)(dlg, tsx, event);
-    }
-    if (status==0) {
-	status = dlg_on_all_state_post( dlg, tsx, event);
-    }
-    
-    unlock_dialog(dlg, &lck);
-}
-
-/*
- * This function contains common processing in all states, and it is called
- * before the FSM is invoked.
- */
-static int  dlg_on_all_state_pre( pjsip_dlg *dlg, 
-				  pjsip_transaction *tsx,
-				  pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event)
-
-    if (event->type != PJSIP_EVENT_TSX_STATE_CHANGED)
-	return 0;
-
-    if (tsx && (tsx->state==PJSIP_TSX_STATE_CALLING || 
-	tsx->state==PJSIP_TSX_STATE_TRYING)) 
-    {
-	++dlg->pending_tsx_count;
-
-    } else if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED) 
-    {
-	--dlg->pending_tsx_count;
-	if (tsx == dlg->invite_tsx)
-	    dlg->invite_tsx = NULL;
-    }
-
-    if (tsx->method.id == PJSIP_INVITE_METHOD) {
-	tsx->handle_ack = 1;
-    }
-    return 0;
-}
-
-
-/*
- * This function contains common processing in all states, and it is called
- * after the FSM is invoked.
- */
-static int  dlg_on_all_state_post( pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event)
-
-    if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED) {
-	if (dlg->pending_tsx_count == 0 &&
-	    dlg->state != PJSIP_DIALOG_STATE_CONNECTING &&
-	    dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED &&
-	    dlg->state != PJSIP_DIALOG_STATE_TERMINATED) 
-	{
-	    dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-	    return -1;
-	}
-    }
-
-    return 0;
-}
-
-
-/*
- * Internal function to initialize dialog, contains common initialization
- * for both UAS and UAC dialog.
- */
-static pj_status_t dlg_init( pjsip_dlg *dlg )
-{
-    /* Init mutex. */
-    dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);
-    if (!dlg->mutex) {
-	PJ_PERROR((dlg->obj_name, "pj_mutex_create()"));
-	return -1;
-    }
-
-    /* Init route-set (Initially empty) */
-    pj_list_init(&dlg->route_set);
-
-    /* Init auth credential list. */
-    pj_list_init(&dlg->auth_sess);
-
-    return PJ_SUCCESS;
-}
-
-/*
- * This one is called just before dialog is destroyed.
- * It is called while mutex is held.
- */
-PJ_DEF(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg )
-{
-    struct dialog_lock_data *lck;
-
-    //PJ_TODO(CHECK_THIS);
-    pj_assert(dlg->pending_tsx_count == 0);
-
-    /* Mark dialog as dead. */
-    lck = pj_thread_local_get(pjsip_dlg_lock_tls_id);
-    while (lck) {
-	if (lck->dlg == dlg)
-	    lck->is_alive = 0;
-	lck = lck->prev;
-    }
-}
-
-/*
- * Initialize dialog from the received request.
- * This is an internal function which is called by the User Agent (sip_ua.c), 
- * and it will initialize most of dialog's properties with values from the
- * received message.
- */
-pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg, pjsip_rx_data *rdata )
-{
-    pjsip_msg *msg = rdata->msg;
-    pjsip_to_hdr *to;
-    pjsip_contact_hdr *contact;
-    pjsip_name_addr *name_addr;
-    pjsip_url *url;
-    unsigned flag;
-    pjsip_event event;
-
-    pj_assert(dlg && rdata);
-
-    PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p)", rdata));
-
-    /* Must be an INVITE request. */
-    pj_assert(msg->type == PJSIP_REQUEST_MSG && 
-	      msg->line.req.method.id == PJSIP_INVITE_METHOD);
-
-    /* Init general dialog data. */
-    if (dlg_init(dlg) != PJ_SUCCESS) {
-	return -1;
-    }
-
-    /* Get the To header. */
-    to = rdata->to;
-
-    /* Copy URI in the To header as our local URI. */
-    dlg->local.info = pjsip_hdr_clone( dlg->pool, to);
-
-    /* Set tag in the local info. */
-    dlg->local.info->tag = dlg->local.tag;
-
-    /* Create local Contact to be advertised in the response.
-     * At the moment, just copy URI from the local URI as our contact.
-     */
-    dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );
-    dlg->local.contact->star = 0;
-    name_addr = (pjsip_name_addr *)dlg->local.info->uri;
-    dlg->local.contact->uri = (pjsip_uri*) name_addr;
-    url = (pjsip_url*) name_addr->uri;
-    //url->port = rdata->via->sent_by.port;
-    //url->port = pj_sockaddr_get_port( pjsip_transport_get_local_addr(rdata->transport) );
-
-    /* Save remote URI. */
-    dlg->remote.info = pjsip_hdr_clone( dlg->pool, rdata->from );
-    pjsip_fromto_set_to( dlg->remote.info );
-    pj_strdup( dlg->pool, &dlg->remote.tag, &rdata->from->tag );
-
-    /* Save remote Contact. */
-    contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
-    if (contact) {
-    	dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );
-    } else {
-	PJ_LOG(3,(dlg->obj_name, "No Contact header in INVITE from %s", 
-		  pj_sockaddr_get_str_addr(&rdata->addr)));
-   	dlg->remote.contact = pjsip_contact_hdr_create( dlg->pool );
-	dlg->remote.contact->uri = dlg->remote.info->uri;
-    }
-
-    /* Save Call-ID. */
-    dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
-    pj_strdup( dlg->pool, &dlg->call_id->id, &rdata->call_id );
-
-    /* Initialize local CSeq and save remote CSeq.*/
-    dlg->local.cseq = rdata->timestamp.sec & 0xFFFF;
-    dlg->remote.cseq = rdata->cseq->cseq;
-
-    /* Secure? */
-    flag = pjsip_transport_get_flag(rdata->transport);
-    dlg->secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;
-
-    /* Initial state is NULL. */
-    event.type = event.src_type = PJSIP_EVENT_RX_MSG;
-    event.src.rdata = rdata;
-    dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);
-
-    PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p) complete",  rdata));
-    return PJ_SUCCESS;
-}
-
-/*
- * Set the contact details.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,
-					   const pj_str_t *contact )
-{
-    pjsip_uri *local_uri;
-    pj_str_t tmp;
-
-    pj_strdup_with_null(dlg->pool, &tmp, contact);
-    local_uri = pjsip_parse_uri( dlg->pool, tmp.ptr, tmp.slen, 
-				 PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (local_uri == NULL) {
-	PJ_LOG(2, (dlg->obj_name, "set_contact: invalid URI"));
-	return -1;
-    }
-
-    dlg->local.contact->star = 0;
-    dlg->local.contact->uri = local_uri;
-    return 0;
-}
-
-/*
- * Set route set.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,
-					     const pjsip_route_hdr *route_set )
-{
-    pjsip_route_hdr *hdr;
-
-    pj_list_init(&dlg->route_set);
-    hdr = route_set->next;
-    while (hdr != route_set) {
-	pjsip_route_hdr *cloned = pjsip_hdr_clone(dlg->pool, hdr);
-	pj_list_insert_before( &dlg->route_set, cloned);
-	hdr = hdr->next;
-    }
-    return 0;
-}
-
-/*
- * Set route set without cloning the header.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,
-						pjsip_route_hdr *route_set)
-{
-    pjsip_route_hdr *hdr;
-
-    pj_list_init(&dlg->route_set);
-    hdr = route_set->next;
-    while (hdr != route_set) {
-	pj_list_insert_before( &dlg->route_set, hdr);
-	hdr = hdr->next;
-    }
-    return 0;
-}
-
-/*
- * Application calls this function when it wants to initiate an outgoing
- * dialog (incoming dialogs are created automatically by UA when it receives
- * INVITE, by calling pjsip_dlg_init_from_rdata()).
- * This function should initialize most of the dialog's properties.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,
-				    const pj_str_t *c_local_info,
-				    const pj_str_t *c_remote_info,
-				    const pj_str_t *c_target)
-{
-    pj_time_val tv;
-    pjsip_event event;
-    pj_str_t buf;
-
-    if (!dlg || !c_local_info || !c_remote_info) {
-	pj_assert(dlg && c_local_info && c_remote_info);
-	return -1;
-    }
-
-    PJ_LOG(5, (dlg->obj_name, "initializing"));
-
-    /* Init general dialog */
-    if (dlg_init(dlg) != PJ_SUCCESS) {
-	return -1;
-    }
-
-    /* Duplicate local info. */
-    pj_strdup_with_null( dlg->pool, &buf, c_local_info);
-
-    /* Build local URI. */
-    dlg->local.target = pjsip_parse_uri(dlg->pool, buf.ptr, buf.slen, 
-				        PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (dlg->local.target == NULL) {
-	PJ_LOG(2, (dlg->obj_name, 
-		   "pjsip_dlg_init: invalid local URI %s", buf.ptr));
-	return -1;
-    }
-
-    /* Set local URI. */
-    dlg->local.info = pjsip_from_hdr_create(dlg->pool);
-    dlg->local.info->uri = dlg->local.target;
-    dlg->local.info->tag = dlg->local.tag;
-
-    /* Create local Contact to be advertised in the response. */
-    dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );
-    dlg->local.contact->star = 0;
-    dlg->local.contact->uri = dlg->local.target;
-
-    /* Set remote URI. */
-    dlg->remote.info = pjsip_to_hdr_create(dlg->pool);
-
-    /* Duplicate to buffer. */
-    pj_strdup_with_null( dlg->pool, &buf, c_remote_info);
-
-    /* Build remote info. */
-    dlg->remote.info->uri = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen,
-					     PJSIP_PARSE_URI_AS_NAMEADDR);
-    if (dlg->remote.info->uri == NULL) {
-	PJ_LOG(2, (dlg->obj_name, 
-		   "pjsip_dlg_init: invalid remote URI %s", buf.ptr));
-	return -1;
-    }
-
-    /* Set remote Contact initially equal to the remote URI. */
-    dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);
-    dlg->remote.contact->star = 0;
-    dlg->remote.contact->uri = dlg->remote.info->uri;
-
-    /* Set initial remote target. */
-    if (c_target != NULL) {
-	pj_strdup_with_null( dlg->pool, &buf, c_target);
-	dlg->remote.target = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen, 0);
-	if (dlg->remote.target == NULL) {
-	    PJ_LOG(2, (dlg->obj_name, 
-		       "pjsip_dlg_init: invalid remote target %s", buf.ptr));
-	    return -1;
-	}
-    } else {
-	dlg->remote.target = dlg->remote.info->uri;
-    }
-
-    /* Create globally unique Call-ID */
-    dlg->call_id = pjsip_cid_hdr_create(dlg->pool);
-    pj_create_unique_string( dlg->pool, &dlg->call_id->id );
-
-    /* Local and remote CSeq */
-    pj_gettimeofday(&tv);
-    dlg->local.cseq = tv.sec & 0xFFFF;
-    dlg->remote.cseq = 0;
-
-    /* Initial state is NULL. */
-    event.type = event.src_type = PJSIP_EVENT_TX_MSG;
-    event.src.data = NULL;
-    dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);
-
-    /* Done. */
-    PJ_LOG(4, (dlg->obj_name, "%s dialog initialized, From: %.*s, To: %.*s",
-	       pjsip_role_name(dlg->role), 
-	       c_local_info->slen, c_local_info->ptr,
-	       c_remote_info->slen, c_remote_info->ptr));
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Set credentials.
- */
-PJ_DEF(pj_status_t) pjsip_dlg_set_credentials(  pjsip_dlg *dlg,
-					        int count,
-						const pjsip_cred_info *cred)
-{
-    if (count > 0) {
-	dlg->cred_info = pj_pool_alloc(dlg->pool, count * sizeof(pjsip_cred_info));
-	pj_memcpy(dlg->cred_info, cred, count * sizeof(pjsip_cred_info));
-    }
-    dlg->cred_count = count;
-    return 0;
-}
-
-/*
- * Create a new request within dialog (i.e. after the dialog session has been
- * established). The construction of such requests follows the rule in 
- * RFC3261 section 12.2.1.
- */
-static void dlg_create_request_throw( pjsip_tx_data **p_tdata,
-				      pjsip_dlg *dlg,
-				      const pjsip_method *method,
-				      int cseq )
-{
-    pjsip_tx_data *tdata;
-    pjsip_contact_hdr *contact;
-    pjsip_route_hdr *route, *end_list;
-
-    /* Contact Header field.
-     * Contact can only be present in requests that establish dialog (in the 
-     * core SIP spec, only INVITE).
-     */
-    if (method->id == PJSIP_INVITE_METHOD)
-	contact = dlg->local.contact;
-    else
-	contact = NULL;
-
-    tdata = pjsip_endpt_create_request_from_hdr( dlg->ua->endpt,
-						 method,
-						 dlg->remote.target,
-						 dlg->local.info,
-						 dlg->remote.info,
-						 contact,
-						 dlg->call_id,
-						 cseq,
-						 NULL);
-    if (!tdata) {
-	PJ_THROW(1);
-	return;
-    }
-
-    /* Just copy dialog route-set to Route header. 
-     * The transaction will do the processing as specified in Section 12.2.1
-     * of RFC 3261 in function tsx_process_route() in sip_transaction.c.
-     */
-    route = dlg->route_set.next;
-    end_list = &dlg->route_set;
-    for (; route != end_list; route = route->next ) {
-	pjsip_route_hdr *r;
-	r = pjsip_hdr_shallow_clone( tdata->pool, route );
-	pjsip_routing_hdr_set_route(r);
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)r);
-    }
-
-    /* Copy authorization headers. */
-    pjsip_auth_init_req( dlg->pool, tdata, &dlg->auth_sess,
-			 dlg->cred_count, dlg->cred_info);
-
-    *p_tdata = tdata;
-}
-
-
-/*
- * This function is called by application to create new outgoing request
- * message for this dialog. After the request is created, application can
- * modify the message (such adding headers), and eventually send the request.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,
-						 const pjsip_method *method,
-						 int cseq)
-{
-    PJ_USE_EXCEPTION;
-    struct dialog_lock_data lck;
-    pjsip_tx_data *tdata = NULL;
-
-    pj_assert(dlg != NULL && method != NULL);
-    if (!dlg || !method) {
-	return NULL;
-    }
-
-    PJ_LOG(5, (dlg->obj_name, "Creating request"));
-
-    /* Lock dialog. */
-    lock_dialog(dlg, &lck);
-
-    /* Use outgoing CSeq and increment it by one. */
-    if (cseq < 0)
-	cseq = dlg->local.cseq + 1;
-
-    PJ_LOG(5, (dlg->obj_name, "creating request %.*s cseq=%d", 
-			      method->name.slen, method->name.ptr, cseq));
-
-    /* Create the request. */
-    PJ_TRY {
-	dlg_create_request_throw(&tdata, dlg, method, cseq);
-	PJ_LOG(5, (dlg->obj_name, "request data %s created", tdata->obj_name));
-    }
-    PJ_DEFAULT {
-	/* Failed! Delete transmit data. */
-	if (tdata) {
-	    pjsip_tx_data_dec_ref( tdata );
-	    tdata = NULL;
-	}
-    }
-    PJ_END;
-
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-
-    return tdata;
-}
-
-/*
- * Sends request.
- * Select the transport for the request message
- */
-static pj_status_t dlg_send_request( pjsip_dlg *dlg, pjsip_tx_data *tdata )
-{
-    pjsip_transaction *tsx;
-    pj_status_t status = PJ_SUCCESS;
-    struct dialog_lock_data lck;
-
-    pj_assert(dlg != NULL && tdata != NULL);
-    if (!dlg || !tdata) {
-	return -1;
-    }
-
-    PJ_LOG(5, (dlg->obj_name, "sending request %s", tdata->obj_name));
-
-    /* Lock dialog. */
-    lock_dialog(dlg, &lck);
-
-    /* Create a new transaction. */
-    tsx = pjsip_endpt_create_tsx( dlg->ua->endpt );
-    if (!tsx) {
-	unlock_dialog(dlg, &lck);
-	return -1;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "Created new UAC transaction: %s", tsx->obj_name));
-
-    /* Initialize transaction */
-    tsx->module_data[dlg->ua->mod_id] = dlg;
-    status = pjsip_tsx_init_uac( tsx, tdata );
-    if (status != PJ_SUCCESS) {
-	unlock_dialog(dlg, &lck);
-	pjsip_endpt_destroy_tsx( dlg->ua->endpt, tsx );
-	return -1;
-    }
-    pjsip_endpt_register_tsx( dlg->ua->endpt, tsx );
-
-    /* Start the transaction. */
-    pjsip_tsx_on_tx_msg(tsx, tdata);
-
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-
-    return status;
-}
-
-/*
- * This function can be called by application to send ANY outgoing message
- * to remote party. 
- */
-PJ_DEF(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg, pjsip_tx_data *tdata )
-{
-    pj_status_t status;
-    int tsx_status;
-    struct dialog_lock_data lck;
-
-    pj_assert(dlg != NULL && tdata != NULL);
-    if (!dlg || !tdata) {
-	return -1;
-    }
-
-    lock_dialog(dlg, &lck);
-
-    if (tdata->msg->type == PJSIP_REQUEST_MSG) {
-	int request_cseq;
-	pjsip_msg *msg = tdata->msg;
-	pjsip_cseq_hdr *cseq_hdr;
-
-	switch (msg->line.req.method.id) {
-	case PJSIP_CANCEL_METHOD:
-
-	    /* Check the INVITE transaction state. */
-	    tsx_status = dlg->invite_tsx->status_code;
-	    if (tsx_status >= 200) {
-		/* Already terminated. Can't cancel. */
-		status = -1;
-		goto on_return;
-	    }
-
-	    /* If we've got provisional response, then send CANCEL and wait for
-	     * the response to INVITE to arrive. Otherwise just send CANCEL and
-	     * terminate the INVITE.
-	     */
-	    if (tsx_status < 100) {
-		pjsip_tsx_terminate( dlg->invite_tsx, 
-				     PJSIP_SC_REQUEST_TERMINATED);
-		status = 0;
-		goto on_return;
-	    }
-
-	    status = 0;
-	    request_cseq = dlg->invite_tsx->cseq;
-	    break;
-
-	case PJSIP_ACK_METHOD:
-	    /* Sending ACK outside of transaction is not supported at present! */
-	    pj_assert(0);
-	    status = 0;
-	    request_cseq = dlg->local.cseq;
-	    break;
-
-	case PJSIP_INVITE_METHOD:
-	    /* For an initial INVITE, reset dialog state to NULL so we get
-	     * 'normal' UAC notifications such as on_provisional(), etc.
-	     * Initial INVITE is the request that is sent when the dialog has
-	     * not been established yet. It's not necessarily the first INVITE
-	     * sent, as when the Authorization fails, subsequent INVITE are also
-	     * considered as an initial INVITE.
-	     */
-	    if (dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
-		/* Set state to NULL. */
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, NULL);
-
-	    } else {
-		/* This is a re-INVITE */
-	    }
-	    status = 0;
-	    request_cseq = dlg->local.cseq + 1;
-	    break;
-
-	default:
-	    status = 0;
-	    request_cseq = dlg->local.cseq + 1;
-	    break;
-	}
-
-	if (status != 0)
-	    goto on_return;
-
-	/* Update dialog's local CSeq, if necessary. */
-	if (request_cseq != dlg->local.cseq)
-	    dlg->local.cseq = request_cseq;
-
-	/* Update CSeq header in the request. */
-	cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,
-							 PJSIP_H_CSEQ, NULL);
-	pj_assert(cseq_hdr != NULL);
-
-	/* Update the CSeq */
-	cseq_hdr->cseq = request_cseq;
-
-	/* Force the whole message to be re-printed. */
-	pjsip_tx_data_invalidate_msg( tdata );
-
-	/* Now send the request. */
-	status = dlg_send_request(dlg, tdata);
-
-    } else {
-	/*
-	 * This is only valid for sending response to INVITE!
-	 */
-	pjsip_cseq_hdr *cseq_hdr;
-
-	if (dlg->invite_tsx == NULL || dlg->invite_tsx->status_code >= 200) {
-	    status = -1;
-	    goto on_return;
-	}
-
-	cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,
-							 PJSIP_H_CSEQ, NULL);
-	pj_assert(cseq_hdr);
-
-	if (cseq_hdr->method.id != PJSIP_INVITE_METHOD) {
-	    status = -1;
-	    goto on_return;
-	}
-
-	pj_assert(cseq_hdr->cseq == dlg->invite_tsx->cseq);
-	
-	pjsip_tsx_on_tx_msg(dlg->invite_tsx, tdata);
-	status = 0;
-    }
-
-on_return:
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-   
-    /* Whatever happen delete the message. */
-    pjsip_tx_data_dec_ref( tdata );
-
-    return status;
-}
-
-/*
- * Sends outgoing invitation.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg )
-{
-    pjsip_method method;
-    struct dialog_lock_data lck;
-    const pjsip_allow_hdr *allow_hdr;
-    pjsip_tx_data *tdata;
-
-    pj_assert(dlg != NULL);
-    if (!dlg) {
-	return NULL;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "request to send invitation"));
-
-    /* Lock dialog. */
-    lock_dialog(dlg, &lck);
-
-    /* Create request. */
-    pjsip_method_set( &method, PJSIP_INVITE_METHOD);
-    tdata = pjsip_dlg_create_request( dlg, &method, -1 );
-    if (tdata == NULL) {
-	unlock_dialog(dlg, &lck);
-	return NULL;
-    }
-
-    /* Invite SHOULD contain "Allow" header. */
-    allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );
-    if (allow_hdr) {
-	pjsip_msg_add_hdr( tdata->msg, 
-			   pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));
-    }
-
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-
-    return tdata;
-}
-
-/*
- * Cancel pending outgoing dialog invitation. 
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg )
-{
-    pjsip_tx_data *tdata = NULL;
-    struct dialog_lock_data lck;
-
-    pj_assert(dlg != NULL);
-    if (!dlg) {
-	return NULL;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "request to cancel invitation"));
-
-    lock_dialog(dlg, &lck);
-
-    /* Check the INVITE transaction. */
-    if (dlg->invite_tsx == NULL || dlg->role != PJSIP_ROLE_UAC) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "
-				  "no INVITE transaction found"));
-	goto on_return;
-    }
-
-    /* Construct the CANCEL request. */
-    tdata = pjsip_endpt_create_cancel( dlg->ua->endpt,
-				       dlg->invite_tsx->last_tx );
-    if (tdata == NULL) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "
-				  "unable to construct request"));
-	goto on_return;
-    }
-
-    /* Add reference counter to tdata. */
-    pjsip_tx_data_add_ref(tdata);
-
-on_return:
-    unlock_dialog(dlg, &lck);
-    return tdata;
-}
-
-
-/*
- * Answer incoming dialog invitation, with either provisional responses
- * or a final response.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code )
-{
-    pjsip_tx_data *tdata = NULL;
-    pjsip_msg *msg;
-    struct dialog_lock_data lck;
-
-    pj_assert(dlg != NULL);
-    if (!dlg) {
-	return NULL;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "pjsip_dlg_answer: code=%d", code));
-
-    /* Lock dialog. */
-    lock_dialog(dlg, &lck);
-
-    /* Must have pending INVITE. */
-    if (dlg->invite_tsx == NULL) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: no INVITE transaction found"));
-	goto on_return;
-    }
-    /* Must be UAS. */
-    if (dlg->role != PJSIP_ROLE_UAS) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: not UAS"));
-	goto on_return;
-    }
-    /* Must have not answered with final response before. */
-    if (dlg->invite_tsx->status_code >= 200) {
-	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: transaction already terminated "
-				  "with status %d", dlg->invite_tsx->status_code));
-	goto on_return;
-    }
-
-    /* Get transmit data and the message. 
-     * We will rewrite the message with a new status code.
-     */
-    tdata = dlg->invite_tsx->last_tx;
-    msg = tdata->msg;
-
-    /* Set status code and reason phrase. */
-    if (code < 100 || code >= 700) code = 500;
-    msg->line.status.code = code;
-    msg->line.status.reason = *pjsip_get_status_text(code);
-
-    /* For 2xx response, Contact and Record-Route must be added. */
-    if (PJSIP_IS_STATUS_IN_CLASS(code,200)) {
-	const pjsip_allow_hdr *allow_hdr;
-
-	if (pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL) == NULL) {
-	    pjsip_contact_hdr *contact;
-	    contact = pjsip_hdr_shallow_clone( tdata->pool, dlg->local.contact);
-	    pjsip_msg_add_hdr( msg, (pjsip_hdr*)contact );
-	}
-
-	/* 2xx response MUST contain "Allow" header. */
-	allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );
-	if (allow_hdr) {
-	    pjsip_msg_add_hdr( msg, pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));
-	}
-    }
-
-    /* for all but 100 responses, To-tag must be set. */
-    if (code != 100) {
-	pjsip_to_hdr *to;
-	to = pjsip_msg_find_hdr( msg, PJSIP_H_TO, NULL);
-	to->tag = dlg->local.tag;
-    }
-
-    /* Reset packet buffer. */
-    pjsip_tx_data_invalidate_msg(tdata);
-
-    /* Add reference counter */
-    pjsip_tx_data_add_ref(tdata);
-
-on_return:
-
-    /* Unlock dialog. */
-    unlock_dialog(dlg, &lck);
-
-    return tdata;
-}
-
-
-/*
- * Send BYE request to terminate the dialog's session.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg )
-{
-    pjsip_method method;
-    struct dialog_lock_data lck;
-    pjsip_tx_data *tdata;
-
-    if (!dlg) {
-	pj_assert(dlg != NULL);
-	return NULL;
-    }
-
-    PJ_LOG(4, (dlg->obj_name, "request to terminate session"));
-
-    lock_dialog(dlg, &lck);
-
-    pjsip_method_set( &method, PJSIP_BYE_METHOD);
-    tdata = pjsip_dlg_create_request( dlg, &method, -1 );
-
-    unlock_dialog(dlg, &lck);
-
-    return tdata;
-}
-
-/*
- * High level function to disconnect dialog's session. Depending on dialog's 
- * state, this function will either send CANCEL, final response, or BYE to
- * trigger the disconnection. A status code must be supplied, which will be
- * sent if dialog will be transmitting a final response to INVITE.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg, 
-					     int status_code )
-{
-    pjsip_tx_data *tdata = NULL;
-
-    pj_assert(dlg != NULL);
-    if (!dlg) {
-	return NULL;
-    }
-
-    switch (dlg->state) {
-    case PJSIP_DIALOG_STATE_INCOMING:
-	tdata = pjsip_dlg_answer(dlg, status_code);
-	break;
-
-    case PJSIP_DIALOG_STATE_CALLING:
-	tdata = pjsip_dlg_cancel(dlg);
-	break;
-
-    case PJSIP_DIALOG_STATE_PROCEEDING:
-	if (dlg->role == PJSIP_ROLE_UAC) {
-	    tdata = pjsip_dlg_cancel(dlg);
-	} else {
-	    tdata = pjsip_dlg_answer(dlg, status_code);
-	}
-	break;
-
-    case PJSIP_DIALOG_STATE_ESTABLISHED:
-	tdata = pjsip_dlg_bye(dlg);
-	break;
-
-    default:
-	PJ_LOG(4,(dlg->obj_name, "Invalid state %s in pjsip_dlg_disconnect()", 
-		  dlg_state_names[dlg->state]));
-	break;
-    }
-
-    return tdata;
-}
-
-/*
- * Handling of the receipt of 2xx/INVITE response.
- */
-static void dlg_on_recv_2xx_invite( pjsip_dlg *dlg,
-				    pjsip_event *event )
-{
-    pjsip_msg *msg;
-    pjsip_contact_hdr *contact;
-    pjsip_hdr *hdr, *end_hdr;
-    pjsip_method method;
-    pjsip_tx_data *ack_tdata;
-    
-    /* Get the message */
-    msg = event->src.rdata->msg;
-    
-    /* Update remote's tag information. */
-    pj_strdup(dlg->pool, &dlg->remote.info->tag, &event->src.rdata->to_tag);
-
-    /* Copy Contact information in the 2xx/INVITE response to dialog's.
-     * remote contact
-     */
-    contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
-    if (contact) {
-	dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );
-    } else {
-	/* duplicate contact from "From" header (?) */
-	PJ_LOG(4,(dlg->obj_name, "Received 200/OK to INVITE with no Contact!"));
-	dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);
-	dlg->remote.contact->uri = dlg->remote.info->uri;
-    }
-    
-    /* Copy Record-Route header (in reverse order) as dialog's route-set,
-     * overwriting previous route-set, if any, even if the received route-set
-     * is empty.
-     */
-    pj_list_init(&dlg->route_set);
-    end_hdr = &msg->hdr;
-    for (hdr = msg->hdr.prev; hdr!=end_hdr; hdr = hdr->prev) {
-	if (hdr->type == PJSIP_H_RECORD_ROUTE) {
-	    pjsip_route_hdr *r;
-	    r = pjsip_hdr_clone(dlg->pool, hdr);
-	    pjsip_routing_hdr_set_route(r);
-	    pj_list_insert_before(&dlg->route_set, r);
-	}
-    }
-    
-    /* On receipt of 200/INVITE response, send ACK. 
-     * This ack must be saved and retransmitted whenever we receive
-     * 200/INVITE retransmission, until 64*T1 seconds elapsed.
-     */
-    pjsip_method_set( &method, PJSIP_ACK_METHOD);
-    ack_tdata = pjsip_dlg_create_request( dlg, &method, dlg->invite_tsx->cseq);
-    if (ack_tdata == NULL) {
-	//PJ_TODO(HANDLE_CREATE_ACK_FAILURE)
-	PJ_LOG(2, (dlg->obj_name, "Error sending ACK msg: can't create request"));
-	return;
-    }	
-    
-    /* Send with the transaction. */
-    pjsip_tsx_on_tx_ack( dlg->invite_tsx, ack_tdata);
-	
-    /* Decrement reference counter because pjsip_dlg_create_request 
-     * automatically increments the request.
-     */
-    pjsip_tx_data_dec_ref( ack_tdata );
-}
-
-/*
- * State NULL, before any events have been received.
- */
-static int  dlg_on_state_null( pjsip_dlg *dlg, 
-			       pjsip_transaction *tsx,
-			       pjsip_event *event)
-{
-    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	event->src_type == PJSIP_EVENT_RX_MSG) 
-    {
-	pjsip_hdr *hdr, *hdr_list;
-
-	pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);
-
-	/* Save the INVITE transaction. */
-	dlg->invite_tsx = tsx;
-
-	/* Change state to INCOMING */
-	dlg_set_state(dlg, PJSIP_DIALOG_STATE_INCOMING, event);
-
-	/* Create response buffer. */
-	tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata, 100);
-	pjsip_tx_data_add_ref(tsx->last_tx);
-
-	/* Copy the Record-Route headers into dialog's route_set, maintaining
-	 * the order.
-	 */
-	pj_list_init(&dlg->route_set);
-	hdr_list = &event->src.rdata->msg->hdr;
-	hdr = hdr_list->next;
-	while (hdr != hdr_list) {
-	    if (hdr->type == PJSIP_H_RECORD_ROUTE) {
-		pjsip_route_hdr *route;
-		route = pjsip_hdr_clone(dlg->pool, hdr);
-		pjsip_routing_hdr_set_route(route);
-		pj_list_insert_before(&dlg->route_set, route);
-	    }
-	    hdr = hdr->next;
-	}
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-    } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	       event->src_type == PJSIP_EVENT_TX_MSG) 
-    {
-	pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);
-
-	/* Save the INVITE transaction. */
-	dlg->invite_tsx = tsx;
-
-	/* Change state to CALLING. */
-	dlg_set_state(dlg, PJSIP_DIALOG_STATE_CALLING, event);
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-    } else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-
-    return 0;
-}
-
-/*
- * State INCOMING is after the (callee) dialog has been initialized with
- * the incoming request, but before any responses is sent by the dialog.
- */
-static int  dlg_on_state_incoming( pjsip_dlg *dlg, 
-				   pjsip_transaction *tsx,
-				   pjsip_event *event)
-{
-    return dlg_on_state_proceeding_callee( dlg, tsx, event );
-}
-
-/*
- * State CALLING is after the (caller) dialog has sent outgoing invitation
- * but before any responses are received.
- */
-static int  dlg_on_state_calling( pjsip_dlg *dlg, 
-				  pjsip_transaction *tsx,
-				  pjsip_event *event)
-{
-    if (tsx == dlg->invite_tsx) {
-	return dlg_on_state_proceeding_caller( dlg, tsx, event );
-    }
-    return 0;
-}
-
-/*
- * State PROCEEDING is after provisional response is received.
- * Since the processing is similar to state CALLING, this function is also
- * called for CALLING state.
- */
-static int  dlg_on_state_proceeding_caller( pjsip_dlg *dlg, 
-					    pjsip_transaction *tsx,
-					    pjsip_event *event)
-{
-    int dlg_is_terminated = 0;
-
-    /* We only care about our INVITE transaction. 
-     * Ignore other transaction progression (such as CANCEL).
-     */
-    if (tsx != dlg->invite_tsx) {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-	return 0;
-    }
-
-    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED) {
-	switch (tsx->state) {
-	case PJSIP_TSX_STATE_PROCEEDING:
-	    if (dlg->state != PJSIP_DIALOG_STATE_PROCEEDING) {
-		/* Change state to PROCEEDING */
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);
-
-		/* Notify application. */
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-	    } else {
-		/* Also notify application. */
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-	    }
-	    break;
-
-	case PJSIP_TSX_STATE_COMPLETED:
-	    /* Change dialog state. */
-	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
-		/* Update remote target, take it from the contact hdr. */
-		pjsip_contact_hdr *contact;
-		contact = pjsip_msg_find_hdr(event->src.rdata->msg, 
-					     PJSIP_H_CONTACT, NULL);
-		if (contact) {
-		    dlg->remote.target = pjsip_uri_clone(dlg->pool, contact->uri);
-		} else {
-		    PJ_LOG(4,(dlg->obj_name, 
-			      "Warning: found no Contact hdr in 200/OK"));
-		}
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);
-	    } else if (tsx->status_code==401 || tsx->status_code==407) {
-		/* Handle Authentication challenge. */
-		pjsip_tx_data *tdata;
-		tdata = pjsip_auth_reinit_req( dlg->ua->endpt,
-					       dlg->pool, &dlg->auth_sess,
-					       dlg->cred_count, dlg->cred_info,
-					       tsx->last_tx, event->src.rdata);
-		if (tdata) {
-		    /* Re-use original request, with a new transaction. 
-		     * Need not to worry about CSeq, dialog will take care.
-		     */
-		    pjsip_dlg_send_msg(dlg, tdata);
-		    return 0;
-		} else {
-		    dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-		}
-	    } else {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-	    }
-
-	    /* Notify application. */
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	    /* Send ACK when dialog is connected. */
-	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
-		pj_assert(event->src_type == PJSIP_EVENT_RX_MSG);
-		dlg_on_recv_2xx_invite(dlg, event);
-	    }
-	    break;
-
-	case PJSIP_TSX_STATE_TERMINATED:
-	    /*
-	     * Transaction is terminated because of timeout or transport error.
-	     * To let the application go to normal state progression, call the
-	     * callback twice. First is to emulate disconnection, and then call
-	     * again (with state TERMINATED) to destroy the dialog.
-	     */
-	    dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	    /* The INVITE transaction will be destroyed, so release reference 
-	     * to it. 
-	     */
-	    dlg->invite_tsx = NULL;
-
-	    /* We should terminate the dialog now.
-	     * But it's possible that we have other pending transactions (for 
-	     * example, outgoing CANCEL is in progress).
-	     * So destroy the dialog only if there's no other transaction.
-	     */
-	    if (dlg->pending_tsx_count == 0) {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-		dlg_is_terminated = 1;
-	    }
-	    break;
-
-	default:
-	    pj_assert(0);
-	    break;
-	}
-    } else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-    return dlg_is_terminated ? -1 : 0;
-}
-
-/*
- * State PROCEEDING for UAS is after the callee send provisional response.
- * This function is also called for INCOMING state.
- */
-static int  dlg_on_state_proceeding_callee( pjsip_dlg *dlg, 
-					    pjsip_transaction *tsx,
-					    pjsip_event *event)
-{
-    int dlg_is_terminated = 0;
-
-    pj_assert( dlg->invite_tsx != NULL );
-
-    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	event->src_type == PJSIP_EVENT_TX_MSG && 
-	tsx == dlg->invite_tsx) 
-    {
-	switch (tsx->state) {
-	case PJSIP_TSX_STATE_PROCEEDING:
-	    /* Change state to PROCEEDING */
-	    dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);
-
-	    /* Notify application. */
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-	    break;
-
-	case PJSIP_TSX_STATE_COMPLETED:
-	case PJSIP_TSX_STATE_TERMINATED:
-	    /* Change dialog state. */
-	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);
-	    } else {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-	    }
-
-	    /* Notify application. */
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	    /* If transaction is terminated in non-2xx situation, 
-	     * terminate dialog as well. This happens when something unexpected
-	     * occurs, such as transport error.
-	     */
-	    if (tsx->state == PJSIP_TSX_STATE_TERMINATED && 
-		!PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) 
-	    {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-		dlg_is_terminated = 1;
-	    }
-	    break;
-
-	default:
-	    pj_assert(0);
-	    break;
-	}
-
-    } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	       event->src_type == PJSIP_EVENT_RX_MSG && 
-	       tsx->method.id == PJSIP_CANCEL_METHOD) 
-    {
-	pjsip_tx_data *tdata;
-
-	/* Check if sequence number matches the pending INVITE. */
-	if (dlg->invite_tsx==NULL ||
-	    pj_strcmp(&tsx->branch, &dlg->invite_tsx->branch) != 0) 
-	{
-	    PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no matching INVITE"));
-
-	    /* No matching INVITE transaction found. */
-	    tdata = pjsip_endpt_create_response(dlg->ua->endpt,
-						event->src.rdata,
-						PJSIP_SC_CALL_TSX_DOES_NOT_EXIST );
-	    pjsip_tsx_on_tx_msg(tsx, tdata);
-	    return 0;
-	}
-
-	/* Always respond the CANCEL with 200/CANCEL no matter what. */
-	tdata = pjsip_endpt_create_response(dlg->ua->endpt,
-					    event->src.rdata,
-					    200 );
-	pjsip_tsx_on_tx_msg( tsx, tdata );
-
-	/* Respond the INVITE transaction with 487, only if transaction has
-	 * not completed. 
-	 */
-	if (dlg->invite_tsx->last_tx) {
-	    if (dlg->invite_tsx->status_code < 200) {
-		tdata = dlg->invite_tsx->last_tx;
-		tdata->msg->line.status.code = 487;
-		tdata->msg->line.status.reason = *pjsip_get_status_text(487);
-		/* Reset packet buffer. */
-		pjsip_tx_data_invalidate_msg(tdata);
-		pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );
-	    } else {
-		PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no effect, "
-					  "Transaction already terminated "
-					  "with status %d",
-					  dlg->invite_tsx->status_code));
-	    }
-	} else {
-	    tdata = pjsip_endpt_create_response(dlg->ua->endpt,
-						event->src.rdata,
-						487);
-	    pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );
-	}
-    } else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-
-    return dlg_is_terminated ? -1 : 0;
-}
-
-static int  dlg_on_state_proceeding( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event)
-{
-    if (dlg->role == PJSIP_ROLE_UAC) {
-	return dlg_on_state_proceeding_caller( dlg, tsx, event );
-    } else {
-	return dlg_on_state_proceeding_callee( dlg, tsx, event );
-    }
-}
-
-static int  dlg_on_state_connecting( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event)
-{
-    if (tsx == dlg->invite_tsx) {
-	if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	    (tsx->state == PJSIP_TSX_STATE_TERMINATED ||
-	    tsx->state == PJSIP_TSX_STATE_COMPLETED ||
-	    tsx->state == PJSIP_TSX_STATE_CONFIRMED)) 
-	{
-	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_ESTABLISHED, event);
-	    } else {
-		/* Probably because we never get the ACK, or transport error
-		* when sending ACK.
-		*/
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-	    }
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-	} else {
-	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-	}
-    } else {
-	/* Handle case when transaction is started when dialog is connecting
-	* (e.g. BYE requests cross wire.
-	*/
-	if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	    event->src_type == PJSIP_EVENT_RX_MSG &&
-	    tsx->role == PJSIP_ROLE_UAS)
-	{
-	    pjsip_tx_data *response;
-
-	    if (tsx->status_code >= 200)
-		return 0;
-
-	    if (tsx->method.id == PJSIP_BYE_METHOD) {
-		/* Set state to DISCONNECTED. */
-		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-
-		/* Notify application. */
-		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-		response = pjsip_endpt_create_response(	dlg->ua->endpt, 
-							event->src.rdata, 200);
-	    } else {
-		response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata,
-							PJSIP_SC_INTERNAL_SERVER_ERROR);
-	    }
-
-	    if (response)
-		pjsip_tsx_on_tx_msg(tsx, response);
-
-	    return 0;
-	}
-    }
-    return 0;
-}
-
-static int  dlg_on_state_established( pjsip_dlg *dlg, 
-				      pjsip_transaction *tsx,
-				      pjsip_event *event)
-{
-    PJ_UNUSED_ARG(tsx)
-
-    if (tsx && tsx->method.id == PJSIP_BYE_METHOD) {
-	/* Set state to DISCONNECTED. */
-	dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	/* Answer with 200/BYE. */
-	if (event->src_type == PJSIP_EVENT_RX_MSG) {
-	    pjsip_tx_data *tdata;
-	    tdata = pjsip_endpt_create_response(dlg->ua->endpt,
-						event->src.rdata,
-						200 );
-	    if (tdata)
-		pjsip_tsx_on_tx_msg( tsx, tdata );
-	}
-    } else if (tsx && event->src_type == PJSIP_EVENT_RX_MSG) {
-	pjsip_method_e method = event->src.rdata->cseq->method.id;
-
-	PJ_TODO(PROPERLY_HANDLE_REINVITATION)
-
-	/* Reinvitation. The message may be INVITE or an ACK. */
-	if (method == PJSIP_INVITE_METHOD) {
-	    if (dlg->invite_tsx && dlg->invite_tsx->status_code < 200) {
-		/* Section 14.2: A UAS that receives a second INVITE before it 
-		* sends the final response to a first INVITE with a lower
-		* CSeq sequence number on the same dialog MUST return a 500 
-		* (Server Internal Error) response to the second INVITE and 
-		* MUST include a Retry-After header field with a randomly 
-		* chosen value of between 0 and 10 seconds.
-		*/
-		pjsip_retry_after_hdr *hdr;
-		pjsip_tx_data *tdata = 
-		    pjsip_endpt_create_response(dlg->ua->endpt, 
-						event->src.rdata, 500);
-
-		if (!tdata)
-		    return 0;
-
-		/* Add Retry-After. */
-		hdr = pjsip_retry_after_hdr_create(tdata->pool);
-		hdr->ivalue = 9;
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
-
-		/* Send. */
-		pjsip_tsx_on_tx_msg(tsx, tdata);
-
-		return 0;
-	    }
-
-	    /* Keep this as our current INVITE transaction. */
-	    dlg->invite_tsx = tsx;
-
-	    /* Create response buffer. */
-	    tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt, 
-							event->src.rdata, 100);
-	    pjsip_tx_data_add_ref(tsx->last_tx);
-
-	}
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_MID_CALL_REQUEST, event);
-
-    }  else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-
-    return 0;
-}
-
-static int  dlg_on_state_disconnected( pjsip_dlg *dlg, 
-				       pjsip_transaction *tsx,
-				       pjsip_event *event)
-{
-    PJ_UNUSED_ARG(tsx)
-
-    /* Handle case when transaction is started when dialog is disconnected
-     * (e.g. BYE requests cross wire.
-     */
-    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	event->src_type == PJSIP_EVENT_RX_MSG &&
-	tsx->role == PJSIP_ROLE_UAS)
-    {
-	pjsip_tx_data *response = NULL;
-
-	if (tsx->status_code >= 200)
-	    return 0;
-
-	if (tsx->method.id == PJSIP_BYE_METHOD) {
-	    response = pjsip_endpt_create_response( dlg->ua->endpt, 
-						    event->src.rdata, 200);
-	} else {
-	    response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata, 
-						    PJSIP_SC_INTERNAL_SERVER_ERROR);
-	}
-	if (response)
-	    pjsip_tsx_on_tx_msg(tsx, response);
-
-	return 0;
-    } 
-    /* Handle case when outgoing BYE was rejected with 401/407 */
-    else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&
-	     event->src_type == PJSIP_EVENT_RX_MSG &&
-	     tsx->role == PJSIP_ROLE_UAC)
-    {
-	if (tsx->status_code==401 || tsx->status_code==407) {
-	    pjsip_tx_data *tdata;
-	    tdata = pjsip_auth_reinit_req( dlg->ua->endpt, dlg->pool,
-					   &dlg->auth_sess,
-					   dlg->cred_count, dlg->cred_info,
-					   tsx->last_tx, event->src.rdata);
-	    if (tdata) {
-		pjsip_dlg_send_msg(dlg, tdata);
-	    }
-	}
-    }
-	    
-
-    if (dlg->pending_tsx_count == 0) {
-	/* Set state to TERMINATED. */
-	dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);
-
-	/* Notify application. */
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);
-
-	return -1;
-    } else {
-	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);
-    }
-
-    return 0;
-}
-
-static int  dlg_on_state_terminated( pjsip_dlg *dlg, 
-				     pjsip_transaction *tsx,
-				     pjsip_event *event)
-{
-    PJ_UNUSED_ARG(dlg)
-    PJ_UNUSED_ARG(tsx)
-    PJ_UNUSED_ARG(event)
-
-    return -1;
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip_mod_ua/sip_dialog.h>

+#include <pjsip_mod_ua/sip_ua.h>

+#include <pjsip_mod_ua/sip_ua_private.h>

+#include <pjsip/sip_transport.h>

+#include <pjsip/sip_transaction.h>

+#include <pjsip/sip_types.h>

+#include <pjsip/sip_endpoint.h>

+#include <pjsip/sip_uri.h>

+#include <pjsip/sip_misc.h>

+#include <pjsip/sip_module.h>

+#include <pjsip/sip_event.h>

+#include <pjsip/sip_parser.h>

+#include <pj/string.h>

+#include <pj/log.h>

+#include <pj/os.h>

+#include <pj/guid.h>

+#include <pj/except.h>

+#include <pj/pool.h>

+

+/* TLS to keep dialog lock record (initialized by UA) */

+int pjsip_dlg_lock_tls_id;

+

+struct dialog_lock_data

+{

+    struct dialog_lock_data *prev;

+    pjsip_dlg	    *dlg;

+    int			     is_alive;

+};

+

+/*

+ * Static function prototypes.

+ */

+static void dlg_create_request_throw( pjsip_tx_data **p_tdata,

+				      pjsip_dlg *dlg,

+				      const pjsip_method *method,

+				      int cseq );

+static int  dlg_on_all_state_pre(  pjsip_dlg *dlg, 

+				   pjsip_transaction *tsx,

+				   pjsip_event *event);

+static int  dlg_on_all_state_post( pjsip_dlg *dlg, 

+				   pjsip_transaction *tsx,

+				   pjsip_event *event);

+static int  dlg_on_state_null( pjsip_dlg *dlg, 

+			       pjsip_transaction *tsx,

+			       pjsip_event *event);

+static int  dlg_on_state_incoming( pjsip_dlg *dlg, 

+				   pjsip_transaction *tsx,

+				   pjsip_event *event);

+static int  dlg_on_state_calling( pjsip_dlg *dlg, 

+				  pjsip_transaction *tsx,

+				  pjsip_event *event);

+static int  dlg_on_state_proceeding( pjsip_dlg *dlg, 

+				     pjsip_transaction *tsx,

+				     pjsip_event *event);

+static int  dlg_on_state_proceeding_caller( pjsip_dlg *dlg, 

+					    pjsip_transaction *tsx,

+					    pjsip_event *event);

+static int  dlg_on_state_proceeding_callee( pjsip_dlg *dlg, 

+					    pjsip_transaction *tsx,

+					    pjsip_event *event);

+static int  dlg_on_state_connecting( pjsip_dlg *dlg, 

+				     pjsip_transaction *tsx,

+				     pjsip_event *event);

+static int  dlg_on_state_established( pjsip_dlg *dlg, 

+				      pjsip_transaction *tsx,

+				      pjsip_event *event);

+static int  dlg_on_state_disconnected( pjsip_dlg *dlg, 

+				       pjsip_transaction *tsx,

+				       pjsip_event *event);

+static int  dlg_on_state_terminated( pjsip_dlg *dlg, 

+				     pjsip_transaction *tsx,

+				     pjsip_event *event);

+

+/*

+ * Dialog state handlers.

+ */

+static int  (*dlg_state_handlers[])(struct pjsip_dlg *, pjsip_transaction *,

+				    pjsip_event *) = 

+{

+    &dlg_on_state_null,

+    &dlg_on_state_incoming,

+    &dlg_on_state_calling,

+    &dlg_on_state_proceeding,

+    &dlg_on_state_connecting,

+    &dlg_on_state_established,

+    &dlg_on_state_disconnected,

+    &dlg_on_state_terminated,

+};

+

+/*

+ * Dialog state names.

+ */

+static const char* dlg_state_names[] = 

+{

+    "STATE_NULL",

+    "STATE_INCOMING",

+    "STATE_CALLING",

+    "STATE_PROCEEDING",

+    "STATE_CONNECTING",

+    "STATE_ESTABLISHED",

+    "STATE_DISCONNECTED",

+    "STATE_TERMINATED",

+};

+

+

+/*

+ * Get the dialog string state, normally for logging purpose.

+ */

+const char *pjsip_dlg_state_str(pjsip_dlg_state_e state)

+{

+    return dlg_state_names[state];

+}

+

+/* Lock dialog mutex. */

+static void lock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)

+{

+    struct dialog_lock_data *prev;

+

+    pj_mutex_lock(dlg->mutex);

+    prev = pj_thread_local_get(pjsip_dlg_lock_tls_id);

+    lck->prev = prev;

+    lck->dlg = dlg;

+    lck->is_alive = 1;

+    pj_thread_local_set(pjsip_dlg_lock_tls_id, lck);

+}

+

+/* Carefully unlock dialog mutex, protect against situation when the dialog

+ * has already been destroyed.

+ */

+static pj_status_t unlock_dialog(pjsip_dlg *dlg, struct dialog_lock_data *lck)

+{

+    pj_assert(pj_thread_local_get(pjsip_dlg_lock_tls_id) == lck);

+    pj_assert(dlg == lck->dlg);

+

+    pj_thread_local_set(pjsip_dlg_lock_tls_id, lck->prev);

+    if (lck->is_alive)

+	pj_mutex_unlock(dlg->mutex);

+

+    return lck->is_alive ? 0 : -1;

+}

+

+/*

+ * This is called by dialog's FSM to change dialog's state.

+ */

+static void dlg_set_state( pjsip_dlg *dlg, pjsip_dlg_state_e state,

+			   pjsip_event *event)

+{

+    PJ_UNUSED_ARG(event);

+

+    PJ_LOG(4, (dlg->obj_name, "State %s-->%s (ev=%s, src=%s, data=%p)", 

+	       pjsip_dlg_state_str(dlg->state), pjsip_dlg_state_str(state),

+	       event ? pjsip_event_str(event->type) : "", 

+	       event ? pjsip_event_str(event->src_type) : "",

+	       event ? event->src.data : NULL));

+

+    dlg->state = state;

+    dlg->handle_tsx_event = dlg_state_handlers[state];

+}

+

+/*

+ * Invoke dialog's callback.

+ * This function is called by dialog's FSM, and interpret the event and call

+ * the corresponding callback registered by application.

+ */

+static void dlg_call_dlg_callback( pjsip_dlg *dlg, pjsip_dlg_event_e dlg_event,

+				   pjsip_event *event )

+{

+    pjsip_dlg_callback *cb = dlg->ua->dlg_cb;

+    if (!cb) {

+	PJ_LOG(4,(dlg->obj_name, "Can not call callback (none registered)."));

+	return;

+    }

+

+    /* Low level event: call the all-events callback. */

+    if (cb->on_all_events) {

+	(*cb->on_all_events)(dlg, dlg_event, event);

+    }

+

+    /* Low level event: call the tx/rx callback if this is a tx/rx event. */

+    if (event->type == PJSIP_EVENT_BEFORE_TX && cb->on_before_tx)

+    {

+	(*cb->on_before_tx)(dlg, event->obj.tsx, event->src.tdata, event->data.long_data);

+    }

+    else if (event->type == PJSIP_EVENT_TX_MSG && 

+	event->src_type == PJSIP_EVENT_TX_MSG && cb->on_tx_msg) 

+    {

+	(*cb->on_tx_msg)(dlg, event->obj.tsx, event->src.tdata);

+    } 

+    else if (event->type == PJSIP_EVENT_RX_MSG &&

+	     event->src_type == PJSIP_EVENT_RX_MSG && cb->on_rx_msg) {

+	(*cb->on_rx_msg)(dlg, event->obj.tsx, event->src.rdata);

+    }

+

+    /* Now trigger high level events. 

+     * High level event should only occurs when dialog's state has changed,

+     * except for on_provisional, which may be called multiple times whenever

+     * response message is sent

+     */

+    if (dlg->state == PJSIP_DIALOG_STATE_PROCEEDING &&

+	(event->type== PJSIP_EVENT_TSX_STATE_CHANGED) && 

+	event->obj.tsx == dlg->invite_tsx) 

+    {

+	/* Sent/received provisional responses. */

+	if (cb->on_provisional)

+	    (*cb->on_provisional)(dlg, event->obj.tsx, event);

+    }

+

+    if (dlg_event == PJSIP_DIALOG_EVENT_MID_CALL_REQUEST) {

+	if (cb->on_mid_call_events)

+	    (*cb->on_mid_call_events)(dlg, event);

+	return;

+    }

+

+    if (dlg_event != PJSIP_DIALOG_EVENT_STATE_CHANGED)

+	return;

+

+    if (dlg->state == PJSIP_DIALOG_STATE_INCOMING) {

+

+	/* New incoming dialog. */

+	pj_assert (event->src_type == PJSIP_EVENT_RX_MSG);

+	(*cb->on_incoming)(dlg, event->obj.tsx, event->src.rdata);

+

+    } else if (dlg->state == PJSIP_DIALOG_STATE_CALLING) {

+

+	/* Dialog has just sent the first INVITE. */

+	if (cb->on_calling) {

+	    (*cb->on_calling)(dlg, event->obj.tsx, event->src.tdata);

+	}

+

+    } else if (dlg->state == PJSIP_DIALOG_STATE_DISCONNECTED) {

+

+	if (cb->on_disconnected)

+	    (*cb->on_disconnected)(dlg, event);

+

+    } else if (dlg->state == PJSIP_DIALOG_STATE_TERMINATED) {

+

+	if (cb->on_terminated)

+	    (*cb->on_terminated)(dlg);

+

+	pjsip_ua_destroy_dialog(dlg);

+

+    } else if (dlg->state == PJSIP_DIALOG_STATE_CONNECTING) {

+

+	if (cb->on_connecting)

+	    (*cb->on_connecting)(dlg, event);

+

+    } else if (dlg->state == PJSIP_DIALOG_STATE_ESTABLISHED) {

+

+	if (cb->on_established)

+	    (*cb->on_established)(dlg, event);

+    }

+}

+

+/*

+ * This callback receives event from the transaction layer (via User Agent),

+ * or from dialog timer (for 200/INVITE or ACK retransmission).

+ */

+void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg, 

+			     pjsip_transaction *tsx, 

+			     pjsip_event *event)

+{

+    int status = 0;

+    struct dialog_lock_data lck;

+

+    PJ_LOG(4, (dlg->obj_name, "state=%s (evt=%s, src=%s)", 

+			 pjsip_dlg_state_str(dlg->state),

+			 pjsip_event_str(event->type),

+			 pjsip_event_str(event->src_type)));

+

+

+    lock_dialog(dlg, &lck);

+

+    status = dlg_on_all_state_pre( dlg, tsx, event);

+

+    if (status==0) {

+	status = (*dlg->handle_tsx_event)(dlg, tsx, event);

+    }

+    if (status==0) {

+	status = dlg_on_all_state_post( dlg, tsx, event);

+    }

+    

+    unlock_dialog(dlg, &lck);

+}

+

+/*

+ * This function contains common processing in all states, and it is called

+ * before the FSM is invoked.

+ */

+static int  dlg_on_all_state_pre( pjsip_dlg *dlg, 

+				  pjsip_transaction *tsx,

+				  pjsip_event *event)

+{

+    PJ_UNUSED_ARG(event)

+

+    if (event->type != PJSIP_EVENT_TSX_STATE_CHANGED)

+	return 0;

+

+    if (tsx && (tsx->state==PJSIP_TSX_STATE_CALLING || 

+	tsx->state==PJSIP_TSX_STATE_TRYING)) 

+    {

+	++dlg->pending_tsx_count;

+

+    } else if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED) 

+    {

+	--dlg->pending_tsx_count;

+	if (tsx == dlg->invite_tsx)

+	    dlg->invite_tsx = NULL;

+    }

+

+    if (tsx->method.id == PJSIP_INVITE_METHOD) {

+	tsx->handle_ack = 1;

+    }

+    return 0;

+}

+

+

+/*

+ * This function contains common processing in all states, and it is called

+ * after the FSM is invoked.

+ */

+static int  dlg_on_all_state_post( pjsip_dlg *dlg, 

+				   pjsip_transaction *tsx,

+				   pjsip_event *event)

+{

+    PJ_UNUSED_ARG(event)

+

+    if (tsx && tsx->state==PJSIP_TSX_STATE_DESTROYED) {

+	if (dlg->pending_tsx_count == 0 &&

+	    dlg->state != PJSIP_DIALOG_STATE_CONNECTING &&

+	    dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED &&

+	    dlg->state != PJSIP_DIALOG_STATE_TERMINATED) 

+	{

+	    dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);

+	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+	    return -1;

+	}

+    }

+

+    return 0;

+}

+

+

+/*

+ * Internal function to initialize dialog, contains common initialization

+ * for both UAS and UAC dialog.

+ */

+static pj_status_t dlg_init( pjsip_dlg *dlg )

+{

+    /* Init mutex. */

+    dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);

+    if (!dlg->mutex) {

+	PJ_PERROR((dlg->obj_name, "pj_mutex_create()"));

+	return -1;

+    }

+

+    /* Init route-set (Initially empty) */

+    pj_list_init(&dlg->route_set);

+

+    /* Init auth credential list. */

+    pj_list_init(&dlg->auth_sess);

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * This one is called just before dialog is destroyed.

+ * It is called while mutex is held.

+ */

+PJ_DEF(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg )

+{

+    struct dialog_lock_data *lck;

+

+    //PJ_TODO(CHECK_THIS);

+    pj_assert(dlg->pending_tsx_count == 0);

+

+    /* Mark dialog as dead. */

+    lck = pj_thread_local_get(pjsip_dlg_lock_tls_id);

+    while (lck) {

+	if (lck->dlg == dlg)

+	    lck->is_alive = 0;

+	lck = lck->prev;

+    }

+}

+

+/*

+ * Initialize dialog from the received request.

+ * This is an internal function which is called by the User Agent (sip_ua.c), 

+ * and it will initialize most of dialog's properties with values from the

+ * received message.

+ */

+pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg, pjsip_rx_data *rdata )

+{

+    pjsip_msg *msg = rdata->msg;

+    pjsip_to_hdr *to;

+    pjsip_contact_hdr *contact;

+    pjsip_name_addr *name_addr;

+    pjsip_url *url;

+    unsigned flag;

+    pjsip_event event;

+

+    pj_assert(dlg && rdata);

+

+    PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p)", rdata));

+

+    /* Must be an INVITE request. */

+    pj_assert(msg->type == PJSIP_REQUEST_MSG && 

+	      msg->line.req.method.id == PJSIP_INVITE_METHOD);

+

+    /* Init general dialog data. */

+    if (dlg_init(dlg) != PJ_SUCCESS) {

+	return -1;

+    }

+

+    /* Get the To header. */

+    to = rdata->to;

+

+    /* Copy URI in the To header as our local URI. */

+    dlg->local.info = pjsip_hdr_clone( dlg->pool, to);

+

+    /* Set tag in the local info. */

+    dlg->local.info->tag = dlg->local.tag;

+

+    /* Create local Contact to be advertised in the response.

+     * At the moment, just copy URI from the local URI as our contact.

+     */

+    dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );

+    dlg->local.contact->star = 0;

+    name_addr = (pjsip_name_addr *)dlg->local.info->uri;

+    dlg->local.contact->uri = (pjsip_uri*) name_addr;

+    url = (pjsip_url*) name_addr->uri;

+    //url->port = rdata->via->sent_by.port;

+    //url->port = pj_sockaddr_get_port( pjsip_transport_get_local_addr(rdata->transport) );

+

+    /* Save remote URI. */

+    dlg->remote.info = pjsip_hdr_clone( dlg->pool, rdata->from );

+    pjsip_fromto_set_to( dlg->remote.info );

+    pj_strdup( dlg->pool, &dlg->remote.tag, &rdata->from->tag );

+

+    /* Save remote Contact. */

+    contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);

+    if (contact) {

+    	dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );

+    } else {

+	PJ_LOG(3,(dlg->obj_name, "No Contact header in INVITE from %s", 

+		  pj_sockaddr_get_str_addr(&rdata->addr)));

+   	dlg->remote.contact = pjsip_contact_hdr_create( dlg->pool );

+	dlg->remote.contact->uri = dlg->remote.info->uri;

+    }

+

+    /* Save Call-ID. */

+    dlg->call_id = pjsip_cid_hdr_create(dlg->pool);

+    pj_strdup( dlg->pool, &dlg->call_id->id, &rdata->call_id );

+

+    /* Initialize local CSeq and save remote CSeq.*/

+    dlg->local.cseq = rdata->timestamp.sec & 0xFFFF;

+    dlg->remote.cseq = rdata->cseq->cseq;

+

+    /* Secure? */

+    flag = pjsip_transport_get_flag(rdata->transport);

+    dlg->secure = (flag & PJSIP_TRANSPORT_SECURE) != 0;

+

+    /* Initial state is NULL. */

+    event.type = event.src_type = PJSIP_EVENT_RX_MSG;

+    event.src.rdata = rdata;

+    dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);

+

+    PJ_LOG(5, (dlg->obj_name, "init_from_rdata(%p) complete",  rdata));

+    return PJ_SUCCESS;

+}

+

+/*

+ * Set the contact details.

+ */

+PJ_DEF(pj_status_t) pjsip_dlg_set_contact( pjsip_dlg *dlg,

+					   const pj_str_t *contact )

+{

+    pjsip_uri *local_uri;

+    pj_str_t tmp;

+

+    pj_strdup_with_null(dlg->pool, &tmp, contact);

+    local_uri = pjsip_parse_uri( dlg->pool, tmp.ptr, tmp.slen, 

+				 PJSIP_PARSE_URI_AS_NAMEADDR);

+    if (local_uri == NULL) {

+	PJ_LOG(2, (dlg->obj_name, "set_contact: invalid URI"));

+	return -1;

+    }

+

+    dlg->local.contact->star = 0;

+    dlg->local.contact->uri = local_uri;

+    return 0;

+}

+

+/*

+ * Set route set.

+ */

+PJ_DEF(pj_status_t) pjsip_dlg_set_route_set( pjsip_dlg *dlg,

+					     const pjsip_route_hdr *route_set )

+{

+    pjsip_route_hdr *hdr;

+

+    pj_list_init(&dlg->route_set);

+    hdr = route_set->next;

+    while (hdr != route_set) {

+	pjsip_route_hdr *cloned = pjsip_hdr_clone(dlg->pool, hdr);

+	pj_list_insert_before( &dlg->route_set, cloned);

+	hdr = hdr->next;

+    }

+    return 0;

+}

+

+/*

+ * Set route set without cloning the header.

+ */

+PJ_DEF(pj_status_t) pjsip_dlg_set_route_set_np( pjsip_dlg *dlg,

+						pjsip_route_hdr *route_set)

+{

+    pjsip_route_hdr *hdr;

+

+    pj_list_init(&dlg->route_set);

+    hdr = route_set->next;

+    while (hdr != route_set) {

+	pj_list_insert_before( &dlg->route_set, hdr);

+	hdr = hdr->next;

+    }

+    return 0;

+}

+

+/*

+ * Application calls this function when it wants to initiate an outgoing

+ * dialog (incoming dialogs are created automatically by UA when it receives

+ * INVITE, by calling pjsip_dlg_init_from_rdata()).

+ * This function should initialize most of the dialog's properties.

+ */

+PJ_DEF(pj_status_t) pjsip_dlg_init( pjsip_dlg *dlg,

+				    const pj_str_t *c_local_info,

+				    const pj_str_t *c_remote_info,

+				    const pj_str_t *c_target)

+{

+    pj_time_val tv;

+    pjsip_event event;

+    pj_str_t buf;

+

+    if (!dlg || !c_local_info || !c_remote_info) {

+	pj_assert(dlg && c_local_info && c_remote_info);

+	return -1;

+    }

+

+    PJ_LOG(5, (dlg->obj_name, "initializing"));

+

+    /* Init general dialog */

+    if (dlg_init(dlg) != PJ_SUCCESS) {

+	return -1;

+    }

+

+    /* Duplicate local info. */

+    pj_strdup_with_null( dlg->pool, &buf, c_local_info);

+

+    /* Build local URI. */

+    dlg->local.target = pjsip_parse_uri(dlg->pool, buf.ptr, buf.slen, 

+				        PJSIP_PARSE_URI_AS_NAMEADDR);

+    if (dlg->local.target == NULL) {

+	PJ_LOG(2, (dlg->obj_name, 

+		   "pjsip_dlg_init: invalid local URI %s", buf.ptr));

+	return -1;

+    }

+

+    /* Set local URI. */

+    dlg->local.info = pjsip_from_hdr_create(dlg->pool);

+    dlg->local.info->uri = dlg->local.target;

+    dlg->local.info->tag = dlg->local.tag;

+

+    /* Create local Contact to be advertised in the response. */

+    dlg->local.contact = pjsip_contact_hdr_create( dlg->pool );

+    dlg->local.contact->star = 0;

+    dlg->local.contact->uri = dlg->local.target;

+

+    /* Set remote URI. */

+    dlg->remote.info = pjsip_to_hdr_create(dlg->pool);

+

+    /* Duplicate to buffer. */

+    pj_strdup_with_null( dlg->pool, &buf, c_remote_info);

+

+    /* Build remote info. */

+    dlg->remote.info->uri = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen,

+					     PJSIP_PARSE_URI_AS_NAMEADDR);

+    if (dlg->remote.info->uri == NULL) {

+	PJ_LOG(2, (dlg->obj_name, 

+		   "pjsip_dlg_init: invalid remote URI %s", buf.ptr));

+	return -1;

+    }

+

+    /* Set remote Contact initially equal to the remote URI. */

+    dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);

+    dlg->remote.contact->star = 0;

+    dlg->remote.contact->uri = dlg->remote.info->uri;

+

+    /* Set initial remote target. */

+    if (c_target != NULL) {

+	pj_strdup_with_null( dlg->pool, &buf, c_target);

+	dlg->remote.target = pjsip_parse_uri( dlg->pool, buf.ptr, buf.slen, 0);

+	if (dlg->remote.target == NULL) {

+	    PJ_LOG(2, (dlg->obj_name, 

+		       "pjsip_dlg_init: invalid remote target %s", buf.ptr));

+	    return -1;

+	}

+    } else {

+	dlg->remote.target = dlg->remote.info->uri;

+    }

+

+    /* Create globally unique Call-ID */

+    dlg->call_id = pjsip_cid_hdr_create(dlg->pool);

+    pj_create_unique_string( dlg->pool, &dlg->call_id->id );

+

+    /* Local and remote CSeq */

+    pj_gettimeofday(&tv);

+    dlg->local.cseq = tv.sec & 0xFFFF;

+    dlg->remote.cseq = 0;

+

+    /* Initial state is NULL. */

+    event.type = event.src_type = PJSIP_EVENT_TX_MSG;

+    event.src.data = NULL;

+    dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, &event);

+

+    /* Done. */

+    PJ_LOG(4, (dlg->obj_name, "%s dialog initialized, From: %.*s, To: %.*s",

+	       pjsip_role_name(dlg->role), 

+	       c_local_info->slen, c_local_info->ptr,

+	       c_remote_info->slen, c_remote_info->ptr));

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Set credentials.

+ */

+PJ_DEF(pj_status_t) pjsip_dlg_set_credentials(  pjsip_dlg *dlg,

+					        int count,

+						const pjsip_cred_info *cred)

+{

+    if (count > 0) {

+	dlg->cred_info = pj_pool_alloc(dlg->pool, count * sizeof(pjsip_cred_info));

+	pj_memcpy(dlg->cred_info, cred, count * sizeof(pjsip_cred_info));

+    }

+    dlg->cred_count = count;

+    return 0;

+}

+

+/*

+ * Create a new request within dialog (i.e. after the dialog session has been

+ * established). The construction of such requests follows the rule in 

+ * RFC3261 section 12.2.1.

+ */

+static void dlg_create_request_throw( pjsip_tx_data **p_tdata,

+				      pjsip_dlg *dlg,

+				      const pjsip_method *method,

+				      int cseq )

+{

+    pjsip_tx_data *tdata;

+    pjsip_contact_hdr *contact;

+    pjsip_route_hdr *route, *end_list;

+

+    /* Contact Header field.

+     * Contact can only be present in requests that establish dialog (in the 

+     * core SIP spec, only INVITE).

+     */

+    if (method->id == PJSIP_INVITE_METHOD)

+	contact = dlg->local.contact;

+    else

+	contact = NULL;

+

+    tdata = pjsip_endpt_create_request_from_hdr( dlg->ua->endpt,

+						 method,

+						 dlg->remote.target,

+						 dlg->local.info,

+						 dlg->remote.info,

+						 contact,

+						 dlg->call_id,

+						 cseq,

+						 NULL);

+    if (!tdata) {

+	PJ_THROW(1);

+	return;

+    }

+

+    /* Just copy dialog route-set to Route header. 

+     * The transaction will do the processing as specified in Section 12.2.1

+     * of RFC 3261 in function tsx_process_route() in sip_transaction.c.

+     */

+    route = dlg->route_set.next;

+    end_list = &dlg->route_set;

+    for (; route != end_list; route = route->next ) {

+	pjsip_route_hdr *r;

+	r = pjsip_hdr_shallow_clone( tdata->pool, route );

+	pjsip_routing_hdr_set_route(r);

+	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)r);

+    }

+

+    /* Copy authorization headers. */

+    pjsip_auth_init_req( dlg->pool, tdata, &dlg->auth_sess,

+			 dlg->cred_count, dlg->cred_info);

+

+    *p_tdata = tdata;

+}

+

+

+/*

+ * This function is called by application to create new outgoing request

+ * message for this dialog. After the request is created, application can

+ * modify the message (such adding headers), and eventually send the request.

+ */

+PJ_DEF(pjsip_tx_data*) pjsip_dlg_create_request( pjsip_dlg *dlg,

+						 const pjsip_method *method,

+						 int cseq)

+{

+    PJ_USE_EXCEPTION;

+    struct dialog_lock_data lck;

+    pjsip_tx_data *tdata = NULL;

+

+    pj_assert(dlg != NULL && method != NULL);

+    if (!dlg || !method) {

+	return NULL;

+    }

+

+    PJ_LOG(5, (dlg->obj_name, "Creating request"));

+

+    /* Lock dialog. */

+    lock_dialog(dlg, &lck);

+

+    /* Use outgoing CSeq and increment it by one. */

+    if (cseq < 0)

+	cseq = dlg->local.cseq + 1;

+

+    PJ_LOG(5, (dlg->obj_name, "creating request %.*s cseq=%d", 

+			      method->name.slen, method->name.ptr, cseq));

+

+    /* Create the request. */

+    PJ_TRY {

+	dlg_create_request_throw(&tdata, dlg, method, cseq);

+	PJ_LOG(5, (dlg->obj_name, "request data %s created", tdata->obj_name));

+    }

+    PJ_DEFAULT {

+	/* Failed! Delete transmit data. */

+	if (tdata) {

+	    pjsip_tx_data_dec_ref( tdata );

+	    tdata = NULL;

+	}

+    }

+    PJ_END;

+

+    /* Unlock dialog. */

+    unlock_dialog(dlg, &lck);

+

+    return tdata;

+}

+

+/*

+ * Sends request.

+ * Select the transport for the request message

+ */

+static pj_status_t dlg_send_request( pjsip_dlg *dlg, pjsip_tx_data *tdata )

+{

+    pjsip_transaction *tsx;

+    pj_status_t status = PJ_SUCCESS;

+    struct dialog_lock_data lck;

+

+    pj_assert(dlg != NULL && tdata != NULL);

+    if (!dlg || !tdata) {

+	return -1;

+    }

+

+    PJ_LOG(5, (dlg->obj_name, "sending request %s", tdata->obj_name));

+

+    /* Lock dialog. */

+    lock_dialog(dlg, &lck);

+

+    /* Create a new transaction. */

+    tsx = pjsip_endpt_create_tsx( dlg->ua->endpt );

+    if (!tsx) {

+	unlock_dialog(dlg, &lck);

+	return -1;

+    }

+

+    PJ_LOG(4, (dlg->obj_name, "Created new UAC transaction: %s", tsx->obj_name));

+

+    /* Initialize transaction */

+    tsx->module_data[dlg->ua->mod_id] = dlg;

+    status = pjsip_tsx_init_uac( tsx, tdata );

+    if (status != PJ_SUCCESS) {

+	unlock_dialog(dlg, &lck);

+	pjsip_endpt_destroy_tsx( dlg->ua->endpt, tsx );

+	return -1;

+    }

+    pjsip_endpt_register_tsx( dlg->ua->endpt, tsx );

+

+    /* Start the transaction. */

+    pjsip_tsx_on_tx_msg(tsx, tdata);

+

+    /* Unlock dialog. */

+    unlock_dialog(dlg, &lck);

+

+    return status;

+}

+

+/*

+ * This function can be called by application to send ANY outgoing message

+ * to remote party. 

+ */

+PJ_DEF(pj_status_t) pjsip_dlg_send_msg( pjsip_dlg *dlg, pjsip_tx_data *tdata )

+{

+    pj_status_t status;

+    int tsx_status;

+    struct dialog_lock_data lck;

+

+    pj_assert(dlg != NULL && tdata != NULL);

+    if (!dlg || !tdata) {

+	return -1;

+    }

+

+    lock_dialog(dlg, &lck);

+

+    if (tdata->msg->type == PJSIP_REQUEST_MSG) {

+	int request_cseq;

+	pjsip_msg *msg = tdata->msg;

+	pjsip_cseq_hdr *cseq_hdr;

+

+	switch (msg->line.req.method.id) {

+	case PJSIP_CANCEL_METHOD:

+

+	    /* Check the INVITE transaction state. */

+	    tsx_status = dlg->invite_tsx->status_code;

+	    if (tsx_status >= 200) {

+		/* Already terminated. Can't cancel. */

+		status = -1;

+		goto on_return;

+	    }

+

+	    /* If we've got provisional response, then send CANCEL and wait for

+	     * the response to INVITE to arrive. Otherwise just send CANCEL and

+	     * terminate the INVITE.

+	     */

+	    if (tsx_status < 100) {

+		pjsip_tsx_terminate( dlg->invite_tsx, 

+				     PJSIP_SC_REQUEST_TERMINATED);

+		status = 0;

+		goto on_return;

+	    }

+

+	    status = 0;

+	    request_cseq = dlg->invite_tsx->cseq;

+	    break;

+

+	case PJSIP_ACK_METHOD:

+	    /* Sending ACK outside of transaction is not supported at present! */

+	    pj_assert(0);

+	    status = 0;

+	    request_cseq = dlg->local.cseq;

+	    break;

+

+	case PJSIP_INVITE_METHOD:

+	    /* For an initial INVITE, reset dialog state to NULL so we get

+	     * 'normal' UAC notifications such as on_provisional(), etc.

+	     * Initial INVITE is the request that is sent when the dialog has

+	     * not been established yet. It's not necessarily the first INVITE

+	     * sent, as when the Authorization fails, subsequent INVITE are also

+	     * considered as an initial INVITE.

+	     */

+	    if (dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {

+		/* Set state to NULL. */

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_NULL, NULL);

+

+	    } else {

+		/* This is a re-INVITE */

+	    }

+	    status = 0;

+	    request_cseq = dlg->local.cseq + 1;

+	    break;

+

+	default:

+	    status = 0;

+	    request_cseq = dlg->local.cseq + 1;

+	    break;

+	}

+

+	if (status != 0)

+	    goto on_return;

+

+	/* Update dialog's local CSeq, if necessary. */

+	if (request_cseq != dlg->local.cseq)

+	    dlg->local.cseq = request_cseq;

+

+	/* Update CSeq header in the request. */

+	cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,

+							 PJSIP_H_CSEQ, NULL);

+	pj_assert(cseq_hdr != NULL);

+

+	/* Update the CSeq */

+	cseq_hdr->cseq = request_cseq;

+

+	/* Force the whole message to be re-printed. */

+	pjsip_tx_data_invalidate_msg( tdata );

+

+	/* Now send the request. */

+	status = dlg_send_request(dlg, tdata);

+

+    } else {

+	/*

+	 * This is only valid for sending response to INVITE!

+	 */

+	pjsip_cseq_hdr *cseq_hdr;

+

+	if (dlg->invite_tsx == NULL || dlg->invite_tsx->status_code >= 200) {

+	    status = -1;

+	    goto on_return;

+	}

+

+	cseq_hdr = (pjsip_cseq_hdr*) pjsip_msg_find_hdr( tdata->msg,

+							 PJSIP_H_CSEQ, NULL);

+	pj_assert(cseq_hdr);

+

+	if (cseq_hdr->method.id != PJSIP_INVITE_METHOD) {

+	    status = -1;

+	    goto on_return;

+	}

+

+	pj_assert(cseq_hdr->cseq == dlg->invite_tsx->cseq);

+	

+	pjsip_tsx_on_tx_msg(dlg->invite_tsx, tdata);

+	status = 0;

+    }

+

+on_return:

+    /* Unlock dialog. */

+    unlock_dialog(dlg, &lck);

+   

+    /* Whatever happen delete the message. */

+    pjsip_tx_data_dec_ref( tdata );

+

+    return status;

+}

+

+/*

+ * Sends outgoing invitation.

+ */

+PJ_DEF(pjsip_tx_data*) pjsip_dlg_invite( pjsip_dlg *dlg )

+{

+    pjsip_method method;

+    struct dialog_lock_data lck;

+    const pjsip_allow_hdr *allow_hdr;

+    pjsip_tx_data *tdata;

+

+    pj_assert(dlg != NULL);

+    if (!dlg) {

+	return NULL;

+    }

+

+    PJ_LOG(4, (dlg->obj_name, "request to send invitation"));

+

+    /* Lock dialog. */

+    lock_dialog(dlg, &lck);

+

+    /* Create request. */

+    pjsip_method_set( &method, PJSIP_INVITE_METHOD);

+    tdata = pjsip_dlg_create_request( dlg, &method, -1 );

+    if (tdata == NULL) {

+	unlock_dialog(dlg, &lck);

+	return NULL;

+    }

+

+    /* Invite SHOULD contain "Allow" header. */

+    allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );

+    if (allow_hdr) {

+	pjsip_msg_add_hdr( tdata->msg, 

+			   pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));

+    }

+

+    /* Unlock dialog. */

+    unlock_dialog(dlg, &lck);

+

+    return tdata;

+}

+

+/*

+ * Cancel pending outgoing dialog invitation. 

+ */

+PJ_DEF(pjsip_tx_data*) pjsip_dlg_cancel( pjsip_dlg *dlg )

+{

+    pjsip_tx_data *tdata = NULL;

+    struct dialog_lock_data lck;

+

+    pj_assert(dlg != NULL);

+    if (!dlg) {

+	return NULL;

+    }

+

+    PJ_LOG(4, (dlg->obj_name, "request to cancel invitation"));

+

+    lock_dialog(dlg, &lck);

+

+    /* Check the INVITE transaction. */

+    if (dlg->invite_tsx == NULL || dlg->role != PJSIP_ROLE_UAC) {

+	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "

+				  "no INVITE transaction found"));

+	goto on_return;

+    }

+

+    /* Construct the CANCEL request. */

+    tdata = pjsip_endpt_create_cancel( dlg->ua->endpt,

+				       dlg->invite_tsx->last_tx );

+    if (tdata == NULL) {

+	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_cancel failed: "

+				  "unable to construct request"));

+	goto on_return;

+    }

+

+    /* Add reference counter to tdata. */

+    pjsip_tx_data_add_ref(tdata);

+

+on_return:

+    unlock_dialog(dlg, &lck);

+    return tdata;

+}

+

+

+/*

+ * Answer incoming dialog invitation, with either provisional responses

+ * or a final response.

+ */

+PJ_DEF(pjsip_tx_data*) pjsip_dlg_answer( pjsip_dlg *dlg, int code )

+{

+    pjsip_tx_data *tdata = NULL;

+    pjsip_msg *msg;

+    struct dialog_lock_data lck;

+

+    pj_assert(dlg != NULL);

+    if (!dlg) {

+	return NULL;

+    }

+

+    PJ_LOG(4, (dlg->obj_name, "pjsip_dlg_answer: code=%d", code));

+

+    /* Lock dialog. */

+    lock_dialog(dlg, &lck);

+

+    /* Must have pending INVITE. */

+    if (dlg->invite_tsx == NULL) {

+	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: no INVITE transaction found"));

+	goto on_return;

+    }

+    /* Must be UAS. */

+    if (dlg->role != PJSIP_ROLE_UAS) {

+	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: not UAS"));

+	goto on_return;

+    }

+    /* Must have not answered with final response before. */

+    if (dlg->invite_tsx->status_code >= 200) {

+	PJ_LOG(2, (dlg->obj_name, "pjsip_dlg_answer: transaction already terminated "

+				  "with status %d", dlg->invite_tsx->status_code));

+	goto on_return;

+    }

+

+    /* Get transmit data and the message. 

+     * We will rewrite the message with a new status code.

+     */

+    tdata = dlg->invite_tsx->last_tx;

+    msg = tdata->msg;

+

+    /* Set status code and reason phrase. */

+    if (code < 100 || code >= 700) code = 500;

+    msg->line.status.code = code;

+    msg->line.status.reason = *pjsip_get_status_text(code);

+

+    /* For 2xx response, Contact and Record-Route must be added. */

+    if (PJSIP_IS_STATUS_IN_CLASS(code,200)) {

+	const pjsip_allow_hdr *allow_hdr;

+

+	if (pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL) == NULL) {

+	    pjsip_contact_hdr *contact;

+	    contact = pjsip_hdr_shallow_clone( tdata->pool, dlg->local.contact);

+	    pjsip_msg_add_hdr( msg, (pjsip_hdr*)contact );

+	}

+

+	/* 2xx response MUST contain "Allow" header. */

+	allow_hdr = pjsip_endpt_get_allow_hdr( dlg->ua->endpt );

+	if (allow_hdr) {

+	    pjsip_msg_add_hdr( msg, pjsip_hdr_shallow_clone( tdata->pool, allow_hdr));

+	}

+    }

+

+    /* for all but 100 responses, To-tag must be set. */

+    if (code != 100) {

+	pjsip_to_hdr *to;

+	to = pjsip_msg_find_hdr( msg, PJSIP_H_TO, NULL);

+	to->tag = dlg->local.tag;

+    }

+

+    /* Reset packet buffer. */

+    pjsip_tx_data_invalidate_msg(tdata);

+

+    /* Add reference counter */

+    pjsip_tx_data_add_ref(tdata);

+

+on_return:

+

+    /* Unlock dialog. */

+    unlock_dialog(dlg, &lck);

+

+    return tdata;

+}

+

+

+/*

+ * Send BYE request to terminate the dialog's session.

+ */

+PJ_DEF(pjsip_tx_data*) pjsip_dlg_bye( pjsip_dlg *dlg )

+{

+    pjsip_method method;

+    struct dialog_lock_data lck;

+    pjsip_tx_data *tdata;

+

+    if (!dlg) {

+	pj_assert(dlg != NULL);

+	return NULL;

+    }

+

+    PJ_LOG(4, (dlg->obj_name, "request to terminate session"));

+

+    lock_dialog(dlg, &lck);

+

+    pjsip_method_set( &method, PJSIP_BYE_METHOD);

+    tdata = pjsip_dlg_create_request( dlg, &method, -1 );

+

+    unlock_dialog(dlg, &lck);

+

+    return tdata;

+}

+

+/*

+ * High level function to disconnect dialog's session. Depending on dialog's 

+ * state, this function will either send CANCEL, final response, or BYE to

+ * trigger the disconnection. A status code must be supplied, which will be

+ * sent if dialog will be transmitting a final response to INVITE.

+ */

+PJ_DEF(pjsip_tx_data*) pjsip_dlg_disconnect( pjsip_dlg *dlg, 

+					     int status_code )

+{

+    pjsip_tx_data *tdata = NULL;

+

+    pj_assert(dlg != NULL);

+    if (!dlg) {

+	return NULL;

+    }

+

+    switch (dlg->state) {

+    case PJSIP_DIALOG_STATE_INCOMING:

+	tdata = pjsip_dlg_answer(dlg, status_code);

+	break;

+

+    case PJSIP_DIALOG_STATE_CALLING:

+	tdata = pjsip_dlg_cancel(dlg);

+	break;

+

+    case PJSIP_DIALOG_STATE_PROCEEDING:

+	if (dlg->role == PJSIP_ROLE_UAC) {

+	    tdata = pjsip_dlg_cancel(dlg);

+	} else {

+	    tdata = pjsip_dlg_answer(dlg, status_code);

+	}

+	break;

+

+    case PJSIP_DIALOG_STATE_ESTABLISHED:

+	tdata = pjsip_dlg_bye(dlg);

+	break;

+

+    default:

+	PJ_LOG(4,(dlg->obj_name, "Invalid state %s in pjsip_dlg_disconnect()", 

+		  dlg_state_names[dlg->state]));

+	break;

+    }

+

+    return tdata;

+}

+

+/*

+ * Handling of the receipt of 2xx/INVITE response.

+ */

+static void dlg_on_recv_2xx_invite( pjsip_dlg *dlg,

+				    pjsip_event *event )

+{

+    pjsip_msg *msg;

+    pjsip_contact_hdr *contact;

+    pjsip_hdr *hdr, *end_hdr;

+    pjsip_method method;

+    pjsip_tx_data *ack_tdata;

+    

+    /* Get the message */

+    msg = event->src.rdata->msg;

+    

+    /* Update remote's tag information. */

+    pj_strdup(dlg->pool, &dlg->remote.info->tag, &event->src.rdata->to_tag);

+

+    /* Copy Contact information in the 2xx/INVITE response to dialog's.

+     * remote contact

+     */

+    contact = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);

+    if (contact) {

+	dlg->remote.contact = pjsip_hdr_clone( dlg->pool, contact );

+    } else {

+	/* duplicate contact from "From" header (?) */

+	PJ_LOG(4,(dlg->obj_name, "Received 200/OK to INVITE with no Contact!"));

+	dlg->remote.contact = pjsip_contact_hdr_create(dlg->pool);

+	dlg->remote.contact->uri = dlg->remote.info->uri;

+    }

+    

+    /* Copy Record-Route header (in reverse order) as dialog's route-set,

+     * overwriting previous route-set, if any, even if the received route-set

+     * is empty.

+     */

+    pj_list_init(&dlg->route_set);

+    end_hdr = &msg->hdr;

+    for (hdr = msg->hdr.prev; hdr!=end_hdr; hdr = hdr->prev) {

+	if (hdr->type == PJSIP_H_RECORD_ROUTE) {

+	    pjsip_route_hdr *r;

+	    r = pjsip_hdr_clone(dlg->pool, hdr);

+	    pjsip_routing_hdr_set_route(r);

+	    pj_list_insert_before(&dlg->route_set, r);

+	}

+    }

+    

+    /* On receipt of 200/INVITE response, send ACK. 

+     * This ack must be saved and retransmitted whenever we receive

+     * 200/INVITE retransmission, until 64*T1 seconds elapsed.

+     */

+    pjsip_method_set( &method, PJSIP_ACK_METHOD);

+    ack_tdata = pjsip_dlg_create_request( dlg, &method, dlg->invite_tsx->cseq);

+    if (ack_tdata == NULL) {

+	//PJ_TODO(HANDLE_CREATE_ACK_FAILURE)

+	PJ_LOG(2, (dlg->obj_name, "Error sending ACK msg: can't create request"));

+	return;

+    }	

+    

+    /* Send with the transaction. */

+    pjsip_tsx_on_tx_ack( dlg->invite_tsx, ack_tdata);

+	

+    /* Decrement reference counter because pjsip_dlg_create_request 

+     * automatically increments the request.

+     */

+    pjsip_tx_data_dec_ref( ack_tdata );

+}

+

+/*

+ * State NULL, before any events have been received.

+ */

+static int  dlg_on_state_null( pjsip_dlg *dlg, 

+			       pjsip_transaction *tsx,

+			       pjsip_event *event)

+{

+    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&

+	event->src_type == PJSIP_EVENT_RX_MSG) 

+    {

+	pjsip_hdr *hdr, *hdr_list;

+

+	pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);

+

+	/* Save the INVITE transaction. */

+	dlg->invite_tsx = tsx;

+

+	/* Change state to INCOMING */

+	dlg_set_state(dlg, PJSIP_DIALOG_STATE_INCOMING, event);

+

+	/* Create response buffer. */

+	tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata, 100);

+	pjsip_tx_data_add_ref(tsx->last_tx);

+

+	/* Copy the Record-Route headers into dialog's route_set, maintaining

+	 * the order.

+	 */

+	pj_list_init(&dlg->route_set);

+	hdr_list = &event->src.rdata->msg->hdr;

+	hdr = hdr_list->next;

+	while (hdr != hdr_list) {

+	    if (hdr->type == PJSIP_H_RECORD_ROUTE) {

+		pjsip_route_hdr *route;

+		route = pjsip_hdr_clone(dlg->pool, hdr);

+		pjsip_routing_hdr_set_route(route);

+		pj_list_insert_before(&dlg->route_set, route);

+	    }

+	    hdr = hdr->next;

+	}

+

+	/* Notify application. */

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+

+    } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&

+	       event->src_type == PJSIP_EVENT_TX_MSG) 

+    {

+	pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);

+

+	/* Save the INVITE transaction. */

+	dlg->invite_tsx = tsx;

+

+	/* Change state to CALLING. */

+	dlg_set_state(dlg, PJSIP_DIALOG_STATE_CALLING, event);

+

+	/* Notify application. */

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+

+    } else {

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);

+    }

+

+    return 0;

+}

+

+/*

+ * State INCOMING is after the (callee) dialog has been initialized with

+ * the incoming request, but before any responses is sent by the dialog.

+ */

+static int  dlg_on_state_incoming( pjsip_dlg *dlg, 

+				   pjsip_transaction *tsx,

+				   pjsip_event *event)

+{

+    return dlg_on_state_proceeding_callee( dlg, tsx, event );

+}

+

+/*

+ * State CALLING is after the (caller) dialog has sent outgoing invitation

+ * but before any responses are received.

+ */

+static int  dlg_on_state_calling( pjsip_dlg *dlg, 

+				  pjsip_transaction *tsx,

+				  pjsip_event *event)

+{

+    if (tsx == dlg->invite_tsx) {

+	return dlg_on_state_proceeding_caller( dlg, tsx, event );

+    }

+    return 0;

+}

+

+/*

+ * State PROCEEDING is after provisional response is received.

+ * Since the processing is similar to state CALLING, this function is also

+ * called for CALLING state.

+ */

+static int  dlg_on_state_proceeding_caller( pjsip_dlg *dlg, 

+					    pjsip_transaction *tsx,

+					    pjsip_event *event)

+{

+    int dlg_is_terminated = 0;

+

+    /* We only care about our INVITE transaction. 

+     * Ignore other transaction progression (such as CANCEL).

+     */

+    if (tsx != dlg->invite_tsx) {

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);

+	return 0;

+    }

+

+    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED) {

+	switch (tsx->state) {

+	case PJSIP_TSX_STATE_PROCEEDING:

+	    if (dlg->state != PJSIP_DIALOG_STATE_PROCEEDING) {

+		/* Change state to PROCEEDING */

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);

+

+		/* Notify application. */

+		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+	    } else {

+		/* Also notify application. */

+		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);

+	    }

+	    break;

+

+	case PJSIP_TSX_STATE_COMPLETED:

+	    /* Change dialog state. */

+	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {

+		/* Update remote target, take it from the contact hdr. */

+		pjsip_contact_hdr *contact;

+		contact = pjsip_msg_find_hdr(event->src.rdata->msg, 

+					     PJSIP_H_CONTACT, NULL);

+		if (contact) {

+		    dlg->remote.target = pjsip_uri_clone(dlg->pool, contact->uri);

+		} else {

+		    PJ_LOG(4,(dlg->obj_name, 

+			      "Warning: found no Contact hdr in 200/OK"));

+		}

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);

+	    } else if (tsx->status_code==401 || tsx->status_code==407) {

+		/* Handle Authentication challenge. */

+		pjsip_tx_data *tdata;

+		tdata = pjsip_auth_reinit_req( dlg->ua->endpt,

+					       dlg->pool, &dlg->auth_sess,

+					       dlg->cred_count, dlg->cred_info,

+					       tsx->last_tx, event->src.rdata);

+		if (tdata) {

+		    /* Re-use original request, with a new transaction. 

+		     * Need not to worry about CSeq, dialog will take care.

+		     */

+		    pjsip_dlg_send_msg(dlg, tdata);

+		    return 0;

+		} else {

+		    dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);

+		}

+	    } else {

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);

+	    }

+

+	    /* Notify application. */

+	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+

+	    /* Send ACK when dialog is connected. */

+	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {

+		pj_assert(event->src_type == PJSIP_EVENT_RX_MSG);

+		dlg_on_recv_2xx_invite(dlg, event);

+	    }

+	    break;

+

+	case PJSIP_TSX_STATE_TERMINATED:

+	    /*

+	     * Transaction is terminated because of timeout or transport error.

+	     * To let the application go to normal state progression, call the

+	     * callback twice. First is to emulate disconnection, and then call

+	     * again (with state TERMINATED) to destroy the dialog.

+	     */

+	    dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);

+	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+

+	    /* The INVITE transaction will be destroyed, so release reference 

+	     * to it. 

+	     */

+	    dlg->invite_tsx = NULL;

+

+	    /* We should terminate the dialog now.

+	     * But it's possible that we have other pending transactions (for 

+	     * example, outgoing CANCEL is in progress).

+	     * So destroy the dialog only if there's no other transaction.

+	     */

+	    if (dlg->pending_tsx_count == 0) {

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);

+		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+		dlg_is_terminated = 1;

+	    }

+	    break;

+

+	default:

+	    pj_assert(0);

+	    break;

+	}

+    } else {

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);

+    }

+    return dlg_is_terminated ? -1 : 0;

+}

+

+/*

+ * State PROCEEDING for UAS is after the callee send provisional response.

+ * This function is also called for INCOMING state.

+ */

+static int  dlg_on_state_proceeding_callee( pjsip_dlg *dlg, 

+					    pjsip_transaction *tsx,

+					    pjsip_event *event)

+{

+    int dlg_is_terminated = 0;

+

+    pj_assert( dlg->invite_tsx != NULL );

+

+    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&

+	event->src_type == PJSIP_EVENT_TX_MSG && 

+	tsx == dlg->invite_tsx) 

+    {

+	switch (tsx->state) {

+	case PJSIP_TSX_STATE_PROCEEDING:

+	    /* Change state to PROCEEDING */

+	    dlg_set_state(dlg, PJSIP_DIALOG_STATE_PROCEEDING, event);

+

+	    /* Notify application. */

+	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+	    break;

+

+	case PJSIP_TSX_STATE_COMPLETED:

+	case PJSIP_TSX_STATE_TERMINATED:

+	    /* Change dialog state. */

+	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_CONNECTING, event);

+	    } else {

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);

+	    }

+

+	    /* Notify application. */

+	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+

+	    /* If transaction is terminated in non-2xx situation, 

+	     * terminate dialog as well. This happens when something unexpected

+	     * occurs, such as transport error.

+	     */

+	    if (tsx->state == PJSIP_TSX_STATE_TERMINATED && 

+		!PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) 

+	    {

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);

+		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+		dlg_is_terminated = 1;

+	    }

+	    break;

+

+	default:

+	    pj_assert(0);

+	    break;

+	}

+

+    } else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&

+	       event->src_type == PJSIP_EVENT_RX_MSG && 

+	       tsx->method.id == PJSIP_CANCEL_METHOD) 

+    {

+	pjsip_tx_data *tdata;

+

+	/* Check if sequence number matches the pending INVITE. */

+	if (dlg->invite_tsx==NULL ||

+	    pj_strcmp(&tsx->branch, &dlg->invite_tsx->branch) != 0) 

+	{

+	    PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no matching INVITE"));

+

+	    /* No matching INVITE transaction found. */

+	    tdata = pjsip_endpt_create_response(dlg->ua->endpt,

+						event->src.rdata,

+						PJSIP_SC_CALL_TSX_DOES_NOT_EXIST );

+	    pjsip_tsx_on_tx_msg(tsx, tdata);

+	    return 0;

+	}

+

+	/* Always respond the CANCEL with 200/CANCEL no matter what. */

+	tdata = pjsip_endpt_create_response(dlg->ua->endpt,

+					    event->src.rdata,

+					    200 );

+	pjsip_tsx_on_tx_msg( tsx, tdata );

+

+	/* Respond the INVITE transaction with 487, only if transaction has

+	 * not completed. 

+	 */

+	if (dlg->invite_tsx->last_tx) {

+	    if (dlg->invite_tsx->status_code < 200) {

+		tdata = dlg->invite_tsx->last_tx;

+		tdata->msg->line.status.code = 487;

+		tdata->msg->line.status.reason = *pjsip_get_status_text(487);

+		/* Reset packet buffer. */

+		pjsip_tx_data_invalidate_msg(tdata);

+		pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );

+	    } else {

+		PJ_LOG(4, (dlg->obj_name, "Received CANCEL with no effect, "

+					  "Transaction already terminated "

+					  "with status %d",

+					  dlg->invite_tsx->status_code));

+	    }

+	} else {

+	    tdata = pjsip_endpt_create_response(dlg->ua->endpt,

+						event->src.rdata,

+						487);

+	    pjsip_tsx_on_tx_msg( dlg->invite_tsx, tdata );

+	}

+    } else {

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);

+    }

+

+    return dlg_is_terminated ? -1 : 0;

+}

+

+static int  dlg_on_state_proceeding( pjsip_dlg *dlg, 

+				     pjsip_transaction *tsx,

+				     pjsip_event *event)

+{

+    if (dlg->role == PJSIP_ROLE_UAC) {

+	return dlg_on_state_proceeding_caller( dlg, tsx, event );

+    } else {

+	return dlg_on_state_proceeding_callee( dlg, tsx, event );

+    }

+}

+

+static int  dlg_on_state_connecting( pjsip_dlg *dlg, 

+				     pjsip_transaction *tsx,

+				     pjsip_event *event)

+{

+    if (tsx == dlg->invite_tsx) {

+	if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&

+	    (tsx->state == PJSIP_TSX_STATE_TERMINATED ||

+	    tsx->state == PJSIP_TSX_STATE_COMPLETED ||

+	    tsx->state == PJSIP_TSX_STATE_CONFIRMED)) 

+	{

+	    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_ESTABLISHED, event);

+	    } else {

+		/* Probably because we never get the ACK, or transport error

+		* when sending ACK.

+		*/

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);

+	    }

+	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+	} else {

+	    dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);

+	}

+    } else {

+	/* Handle case when transaction is started when dialog is connecting

+	* (e.g. BYE requests cross wire.

+	*/

+	if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&

+	    event->src_type == PJSIP_EVENT_RX_MSG &&

+	    tsx->role == PJSIP_ROLE_UAS)

+	{

+	    pjsip_tx_data *response;

+

+	    if (tsx->status_code >= 200)

+		return 0;

+

+	    if (tsx->method.id == PJSIP_BYE_METHOD) {

+		/* Set state to DISCONNECTED. */

+		dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);

+

+		/* Notify application. */

+		dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+

+		response = pjsip_endpt_create_response(	dlg->ua->endpt, 

+							event->src.rdata, 200);

+	    } else {

+		response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata,

+							PJSIP_SC_INTERNAL_SERVER_ERROR);

+	    }

+

+	    if (response)

+		pjsip_tsx_on_tx_msg(tsx, response);

+

+	    return 0;

+	}

+    }

+    return 0;

+}

+

+static int  dlg_on_state_established( pjsip_dlg *dlg, 

+				      pjsip_transaction *tsx,

+				      pjsip_event *event)

+{

+    PJ_UNUSED_ARG(tsx)

+

+    if (tsx && tsx->method.id == PJSIP_BYE_METHOD) {

+	/* Set state to DISCONNECTED. */

+	dlg_set_state(dlg, PJSIP_DIALOG_STATE_DISCONNECTED, event);

+

+	/* Notify application. */

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+

+	/* Answer with 200/BYE. */

+	if (event->src_type == PJSIP_EVENT_RX_MSG) {

+	    pjsip_tx_data *tdata;

+	    tdata = pjsip_endpt_create_response(dlg->ua->endpt,

+						event->src.rdata,

+						200 );

+	    if (tdata)

+		pjsip_tsx_on_tx_msg( tsx, tdata );

+	}

+    } else if (tsx && event->src_type == PJSIP_EVENT_RX_MSG) {

+	pjsip_method_e method = event->src.rdata->cseq->method.id;

+

+	PJ_TODO(PROPERLY_HANDLE_REINVITATION)

+

+	/* Reinvitation. The message may be INVITE or an ACK. */

+	if (method == PJSIP_INVITE_METHOD) {

+	    if (dlg->invite_tsx && dlg->invite_tsx->status_code < 200) {

+		/* Section 14.2: A UAS that receives a second INVITE before it 

+		* sends the final response to a first INVITE with a lower

+		* CSeq sequence number on the same dialog MUST return a 500 

+		* (Server Internal Error) response to the second INVITE and 

+		* MUST include a Retry-After header field with a randomly 

+		* chosen value of between 0 and 10 seconds.

+		*/

+		pjsip_retry_after_hdr *hdr;

+		pjsip_tx_data *tdata = 

+		    pjsip_endpt_create_response(dlg->ua->endpt, 

+						event->src.rdata, 500);

+

+		if (!tdata)

+		    return 0;

+

+		/* Add Retry-After. */

+		hdr = pjsip_retry_after_hdr_create(tdata->pool);

+		hdr->ivalue = 9;

+		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);

+

+		/* Send. */

+		pjsip_tsx_on_tx_msg(tsx, tdata);

+

+		return 0;

+	    }

+

+	    /* Keep this as our current INVITE transaction. */

+	    dlg->invite_tsx = tsx;

+

+	    /* Create response buffer. */

+	    tsx->last_tx = pjsip_endpt_create_response( dlg->ua->endpt, 

+							event->src.rdata, 100);

+	    pjsip_tx_data_add_ref(tsx->last_tx);

+

+	}

+

+	/* Notify application. */

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_MID_CALL_REQUEST, event);

+

+    }  else {

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);

+    }

+

+    return 0;

+}

+

+static int  dlg_on_state_disconnected( pjsip_dlg *dlg, 

+				       pjsip_transaction *tsx,

+				       pjsip_event *event)

+{

+    PJ_UNUSED_ARG(tsx)

+

+    /* Handle case when transaction is started when dialog is disconnected

+     * (e.g. BYE requests cross wire.

+     */

+    if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&

+	event->src_type == PJSIP_EVENT_RX_MSG &&

+	tsx->role == PJSIP_ROLE_UAS)

+    {

+	pjsip_tx_data *response = NULL;

+

+	if (tsx->status_code >= 200)

+	    return 0;

+

+	if (tsx->method.id == PJSIP_BYE_METHOD) {

+	    response = pjsip_endpt_create_response( dlg->ua->endpt, 

+						    event->src.rdata, 200);

+	} else {

+	    response = pjsip_endpt_create_response( dlg->ua->endpt, event->src.rdata, 

+						    PJSIP_SC_INTERNAL_SERVER_ERROR);

+	}

+	if (response)

+	    pjsip_tsx_on_tx_msg(tsx, response);

+

+	return 0;

+    } 

+    /* Handle case when outgoing BYE was rejected with 401/407 */

+    else if (event->type == PJSIP_EVENT_TSX_STATE_CHANGED &&

+	     event->src_type == PJSIP_EVENT_RX_MSG &&

+	     tsx->role == PJSIP_ROLE_UAC)

+    {

+	if (tsx->status_code==401 || tsx->status_code==407) {

+	    pjsip_tx_data *tdata;

+	    tdata = pjsip_auth_reinit_req( dlg->ua->endpt, dlg->pool,

+					   &dlg->auth_sess,

+					   dlg->cred_count, dlg->cred_info,

+					   tsx->last_tx, event->src.rdata);

+	    if (tdata) {

+		pjsip_dlg_send_msg(dlg, tdata);

+	    }

+	}

+    }

+	    

+

+    if (dlg->pending_tsx_count == 0) {

+	/* Set state to TERMINATED. */

+	dlg_set_state(dlg, PJSIP_DIALOG_STATE_TERMINATED, event);

+

+	/* Notify application. */

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_STATE_CHANGED, event);

+

+	return -1;

+    } else {

+	dlg_call_dlg_callback(dlg, PJSIP_DIALOG_EVENT_OTHER, event);

+    }

+

+    return 0;

+}

+

+static int  dlg_on_state_terminated( pjsip_dlg *dlg, 

+				     pjsip_transaction *tsx,

+				     pjsip_event *event)

+{

+    PJ_UNUSED_ARG(dlg)

+    PJ_UNUSED_ARG(tsx)

+    PJ_UNUSED_ARG(event)

+

+    return -1;

+}

+

diff --git a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c
index 1167975..508b5d9 100644
--- a/pjsip/src/pjsip-ua/sip_reg.c
+++ b/pjsip/src/pjsip-ua/sip_reg.c
@@ -1,496 +1,518 @@
-/* $Id$
- *
- */
-#include <pjsip_mod_ua/sip_reg.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_misc.h>
-#include <pjsip/sip_auth_msg.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/log.h>
-
-#define REFRESH_TIMER		1
-#define DELAY_BEFORE_REFRESH	5
-#define THIS_FILE		"sip_regc.c"
-
-/**
- * SIP client registration structure.
- */
-struct pjsip_regc
-{
-    pj_pool_t	        *pool;
-    pjsip_endpoint	*endpt;
-    pj_bool_t		 _delete_flag;
-    int			pending_tsx;
-
-    void		*token;
-    pjsip_regc_cb	*cb;
-
-    pj_str_t		str_srv_url;
-    pjsip_uri		*srv_url;
-    pjsip_cid_hdr	*cid_hdr;
-    pjsip_cseq_hdr	*cseq_hdr;
-    pjsip_from_hdr	*from_hdr;
-    pjsip_to_hdr	*to_hdr;
-    char		*contact_buf;
-    pjsip_generic_string_hdr	*contact_hdr;
-    pjsip_expires_hdr	*expires_hdr;
-    pjsip_contact_hdr	*unreg_contact_hdr;
-    pjsip_expires_hdr	*unreg_expires_hdr;
-    pj_uint32_t		 expires;
-
-    /* Credentials. */
-    int			 cred_count;
-    pjsip_cred_info     *cred_info;
-    
-    /* Authorization sessions. */
-    pjsip_auth_session	 auth_sess_list;
-
-    /* Auto refresh registration. */
-    pj_bool_t		 auto_reg;
-    pj_timer_entry	 timer;
-};
-
-
-
-PJ_DEF(pjsip_regc*) pjsip_regc_create( pjsip_endpoint *endpt, void *token,
-				       pjsip_regc_cb *cb)
-{
-    pj_pool_t *pool;
-    pjsip_regc *regc;
-
-    if (cb == NULL)
-	return NULL;
-
-    pool = pjsip_endpt_create_pool(endpt, "regc%p", 1024, 1024);
-    regc = pj_pool_calloc(pool, 1, sizeof(struct pjsip_regc));
-
-    regc->pool = pool;
-    regc->endpt = endpt;
-    regc->token = token;
-    regc->cb = cb;
-    regc->contact_buf = pj_pool_alloc(pool, PJSIP_REGC_CONTACT_BUF_SIZE);
-    regc->expires = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;
-
-    pj_list_init(&regc->auth_sess_list);
-
-    return regc;
-}
-
-
-PJ_DEF(void) pjsip_regc_destroy(pjsip_regc *regc)
-{
-    if (regc->pending_tsx) {
-	regc->_delete_flag = 1;
-	regc->cb = NULL;
-    } else {
-	pjsip_endpt_destroy_pool(regc->endpt, regc->pool);
-    }
-}
-
-
-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);
-	regc->expires_hdr->ivalue = expires;
-    } else {
-	regc->expires_hdr = NULL;
-    }
-}
-
-
-static pj_status_t set_contact( pjsip_regc *regc,
-			        int contact_cnt,
-				const pj_str_t contact[] )
-{
-    int i;
-    char *s;
-    const pj_str_t contact_STR = { "Contact", 7};
-
-    /* Concatenate contacts. */
-    for (i=0, s=regc->contact_buf; i<contact_cnt; ++i) {
-	if ((s-regc->contact_buf) + contact[i].slen + 2 > PJSIP_REGC_CONTACT_BUF_SIZE) {
-	    return -1;
-	}
-	pj_memcpy(s, contact[i].ptr, contact[i].slen);
-	s += contact[i].slen;
-
-	if (i != contact_cnt - 1) {
-	    *s++ = ',';
-	    *s++ = ' ';
-	}
-    }
-
-    /* Set "Contact" header. */
-    regc->contact_hdr = pjsip_generic_string_hdr_create( regc->pool, &contact_STR);
-    regc->contact_hdr->hvalue.ptr = regc->contact_buf;
-    regc->contact_hdr->hvalue.slen = (s - regc->contact_buf);
-
-    return 0;
-}
-
-
-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;
-
-    /* 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 -1;
-    }
-
-    /* Set "From" header. */
-    pj_strdup_with_null(regc->pool, &tmp, from_url);
-    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 -1;
-    }
-
-    /* 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 -1;
-    }
-
-
-    /* Set "Contact" header. */
-    if (set_contact( regc, contact_cnt, contact) != 0)
-	return -1;
-
-    /* Set "Expires" header, if required. */
-    set_expires( regc, expires);
-
-    /* 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 = 0;
-    pjsip_method_set( &regc->cseq_hdr->method, PJSIP_REGISTER_METHOD);
-
-    /* Create "Contact" header used in unregistration. */
-    regc->unreg_contact_hdr = pjsip_contact_hdr_create(regc->pool);
-    regc->unreg_contact_hdr->star = 1;
-
-    /* Create "Expires" header used in unregistration. */
-    regc->unreg_expires_hdr = pjsip_expires_hdr_create( regc->pool);
-    regc->unreg_expires_hdr->ivalue = 0;
-
-    /* Done. */
-    return 0;
-}
-
-PJ_DEF(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc,
-						int count,
-						const pjsip_cred_info cred[] )
-{
-    if (count > 0) {
-	regc->cred_info = pj_pool_alloc(regc->pool, count * sizeof(pjsip_cred_info));
-	pj_memcpy(regc->cred_info, cred, count * sizeof(pjsip_cred_info));
-    }
-    regc->cred_count = count;
-    return 0;
-}
-
-static pjsip_tx_data *create_request(pjsip_regc *regc)
-{
-    pjsip_tx_data *tdata;
-    pjsip_msg *msg;
-
-    /* Create transmit data. */
-    tdata = pjsip_endpt_create_tdata(regc->endpt);
-    if (!tdata) {
-	return NULL;
-    }
-
-    /* Create request message. */
-    msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);
-    tdata->msg = msg;
-
-    /* Initialize request line. */
-    pjsip_method_set(&msg->line.req.method, PJSIP_REGISTER_METHOD);
-    msg->line.req.uri = regc->srv_url;
-
-    /* Add headers. */
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->from_hdr);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->to_hdr);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->cid_hdr);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->cseq_hdr);
-    
-    /* Add cached authorization headers. */
-    pjsip_auth_init_req( regc->pool, tdata, &regc->auth_sess_list,
-			 regc->cred_count, regc->cred_info );
-
-    /* Add reference counter to transmit data. */
-    pjsip_tx_data_add_ref(tdata);
-
-    return tdata;
-}
-
-
-PJ_DEF(pjsip_tx_data*) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg)
-{
-    pjsip_msg *msg;
-    pjsip_tx_data *tdata;
-
-    tdata = create_request(regc);
-    if (!tdata)
-	return NULL;
-
-    msg = tdata->msg;
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->contact_hdr);
-    if (regc->expires_hdr)
-	pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->expires_hdr);
-
-    if (regc->timer.id != 0) {
-	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
-	regc->timer.id = 0;
-    }
-
-    regc->auto_reg = autoreg;
-
-    return tdata;
-}
-
-
-PJ_DEF(pjsip_tx_data*) pjsip_regc_unregister(pjsip_regc *regc)
-{
-    pjsip_tx_data *tdata;
-    pjsip_msg *msg;
-
-    if (regc->timer.id != 0) {
-	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
-	regc->timer.id = 0;
-    }
-
-    tdata = create_request(regc);
-    if (!tdata)
-	return NULL;
-
-    msg = tdata->msg;
-    pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_contact_hdr);
-    pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr);
-
-    return tdata;
-}
-
-
-PJ_DEF(pj_status_t) pjsip_regc_update_contact(  pjsip_regc *regc,
-					        int contact_cnt,
-						const pj_str_t contact[] )
-{
-    return set_contact( regc, contact_cnt, contact );
-}
-
-
-PJ_DEF(pj_status_t) pjsip_regc_update_expires(  pjsip_regc *regc,
-					        pj_uint32_t expires )
-{
-    set_expires( regc, expires );
-    return 0;
-}
-
-
-static void call_callback(pjsip_regc *regc, int status, 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;
-
-
-    cbparam.regc = regc;
-    cbparam.token = regc->token;
-    cbparam.code = status;
-    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*));
-    }
-
-    (*regc->cb)(&cbparam);
-}
-
-static void regc_refresh_timer_cb( pj_timer_heap_t *timer_heap,
-				   struct pj_timer_entry *entry)
-{
-    pjsip_regc *regc = entry->user_data;
-    pjsip_tx_data *tdata;
-    
-    PJ_UNUSED_ARG(timer_heap)
-
-    entry->id = 0;
-    tdata = pjsip_regc_register(regc, 1);
-    if (tdata) {
-	pjsip_regc_send(regc, tdata);
-    } else {
-	pj_str_t reason = pj_str("Unable to create txdata");
-	call_callback(regc, -1, &reason, NULL, -1, 0, NULL);
-    }
-}
-
-static void tsx_callback(void *token, pjsip_event *event)
-{
-    pjsip_regc *regc = token;
-    pjsip_transaction *tsx = event->obj.tsx;
-    
-    /* If registration data has been deleted by user then remove registration 
-     * data from transaction's callback, and don't call callback.
-     */
-    if (regc->_delete_flag) {
-	--regc->pending_tsx;
-
-    } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||
-	       tsx->status_code == PJSIP_SC_UNAUTHORIZED)
-    {
-	pjsip_rx_data *rdata = event->src.rdata;
-	pjsip_tx_data *tdata;
-
-	tdata = pjsip_auth_reinit_req( regc->endpt,
-				       regc->pool, &regc->auth_sess_list,
-				       regc->cred_count, regc->cred_info,
-				       tsx->last_tx, event->src.rdata );
-
-	if (tdata) {
-	    --regc->pending_tsx;
-	    pjsip_regc_send(regc, tdata);
-	    return;
-	} else {
-	    call_callback(regc, tsx->status_code, &rdata->msg->line.status.reason,
-			  rdata, -1, 0, NULL);
-	    --regc->pending_tsx;
-	}
-    } else {
-	int contact_cnt = 0;
-	pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT];
-	pjsip_rx_data *rdata;
-	pj_int32_t expiration = 0xFFFF;
-
-	if (tsx->status_code/100 == 2) {
-	    int i;
-	    pjsip_contact_hdr *hdr;
-	    pjsip_msg *msg;
-	    pjsip_expires_hdr *expires;
-
-	    rdata = event->src.rdata;
-	    msg = rdata->msg;
-	    hdr = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);
-	    while (hdr) {
-		contact[contact_cnt++] = hdr;
-		hdr = hdr->next;
-		if (hdr == (void*)&msg->hdr)
-		    break;
-		hdr = pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, hdr);
-	    }
-
-	    expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
-
-	    if (expires)
-		expiration = expires->ivalue;
-	    
-	    for (i=0; i<contact_cnt; ++i) {
-		hdr = contact[i];
-		if (hdr->expires >= 0 && hdr->expires < expiration)
-		    expiration = contact[i]->expires;
-	    }
-
-	    if (regc->auto_reg && expiration != 0 && expiration != 0xFFFF) {
-		pj_time_val delay = { 0, 0};
-
-		delay.sec = expiration - 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);
-	    }
-
-	} else {
-	    rdata = (event->src_type==PJSIP_EVENT_RX_MSG) ? event->src.rdata : NULL;
-	}
-
-
-	/* Call callback. */
-	if (expiration == 0xFFFF) expiration = -1;
-	call_callback(regc, tsx->status_code, 
-		      (rdata ? &rdata->msg->line.status.reason 
-			: pjsip_get_status_text(tsx->status_code)),
-		      rdata, expiration, 
-		      contact_cnt, contact);
-
-	--regc->pending_tsx;
-    }
-
-    /* Delete the record if user destroy regc during the callback. */
-    if (regc->_delete_flag && regc->pending_tsx==0) {
-	pjsip_regc_destroy(regc);
-    }
-}
-
-PJ_DEF(void) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)
-{
-    int status;
-
-    /* Make sure we don't have pending transaction. */
-    if (regc->pending_tsx) {
-	pj_str_t reason = pj_str("Transaction in progress");
-	call_callback(regc, -1, &reason, NULL, -1, 0, NULL);
-	pjsip_tx_data_dec_ref( tdata );
-	return;
-    }
-
-    /* Invalidate message buffer. */
-    pjsip_tx_data_invalidate_msg(tdata);
-
-    /* Increment CSeq */
-    regc->cseq_hdr->cseq++;
-
-    /* Send. */
-    status = pjsip_endpt_send_request(regc->endpt, tdata, -1, regc, &tsx_callback);
-    if (status==0)
-	++regc->pending_tsx;
-    else {
-	pj_str_t reason = pj_str("Unable to send request.");
-	call_callback(regc, status, &reason, NULL, -1, 0, NULL);
-    }
-}
-
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip_mod_ua/sip_reg.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_misc.h>

+#include <pjsip/sip_auth_msg.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/guid.h>

+#include <pj/log.h>

+

+#define REFRESH_TIMER		1

+#define DELAY_BEFORE_REFRESH	5

+#define THIS_FILE		"sip_regc.c"

+

+/**

+ * SIP client registration structure.

+ */

+struct pjsip_regc

+{

+    pj_pool_t	        *pool;

+    pjsip_endpoint	*endpt;

+    pj_bool_t		 _delete_flag;

+    int			pending_tsx;

+

+    void		*token;

+    pjsip_regc_cb	*cb;

+

+    pj_str_t		str_srv_url;

+    pjsip_uri		*srv_url;

+    pjsip_cid_hdr	*cid_hdr;

+    pjsip_cseq_hdr	*cseq_hdr;

+    pjsip_from_hdr	*from_hdr;

+    pjsip_to_hdr	*to_hdr;

+    char		*contact_buf;

+    pjsip_generic_string_hdr	*contact_hdr;

+    pjsip_expires_hdr	*expires_hdr;

+    pjsip_contact_hdr	*unreg_contact_hdr;

+    pjsip_expires_hdr	*unreg_expires_hdr;

+    pj_uint32_t		 expires;

+

+    /* Credentials. */

+    int			 cred_count;

+    pjsip_cred_info     *cred_info;

+    

+    /* Authorization sessions. */

+    pjsip_auth_session	 auth_sess_list;

+

+    /* Auto refresh registration. */

+    pj_bool_t		 auto_reg;

+    pj_timer_entry	 timer;

+};

+

+

+

+PJ_DEF(pjsip_regc*) pjsip_regc_create( pjsip_endpoint *endpt, void *token,

+				       pjsip_regc_cb *cb)

+{

+    pj_pool_t *pool;

+    pjsip_regc *regc;

+

+    if (cb == NULL)

+	return NULL;

+

+    pool = pjsip_endpt_create_pool(endpt, "regc%p", 1024, 1024);

+    regc = pj_pool_calloc(pool, 1, sizeof(struct pjsip_regc));

+

+    regc->pool = pool;

+    regc->endpt = endpt;

+    regc->token = token;

+    regc->cb = cb;

+    regc->contact_buf = pj_pool_alloc(pool, PJSIP_REGC_CONTACT_BUF_SIZE);

+    regc->expires = PJSIP_REGC_EXPIRATION_NOT_SPECIFIED;

+

+    pj_list_init(&regc->auth_sess_list);

+

+    return regc;

+}

+

+

+PJ_DEF(void) pjsip_regc_destroy(pjsip_regc *regc)

+{

+    if (regc->pending_tsx) {

+	regc->_delete_flag = 1;

+	regc->cb = NULL;

+    } else {

+	pjsip_endpt_destroy_pool(regc->endpt, regc->pool);

+    }

+}

+

+

+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);

+	regc->expires_hdr->ivalue = expires;

+    } else {

+	regc->expires_hdr = NULL;

+    }

+}

+

+

+static pj_status_t set_contact( pjsip_regc *regc,

+			        int contact_cnt,

+				const pj_str_t contact[] )

+{

+    int i;

+    char *s;

+    const pj_str_t contact_STR = { "Contact", 7};

+

+    /* Concatenate contacts. */

+    for (i=0, s=regc->contact_buf; i<contact_cnt; ++i) {

+	if ((s-regc->contact_buf) + contact[i].slen + 2 > PJSIP_REGC_CONTACT_BUF_SIZE) {

+	    return -1;

+	}

+	pj_memcpy(s, contact[i].ptr, contact[i].slen);

+	s += contact[i].slen;

+

+	if (i != contact_cnt - 1) {

+	    *s++ = ',';

+	    *s++ = ' ';

+	}

+    }

+

+    /* Set "Contact" header. */

+    regc->contact_hdr = pjsip_generic_string_hdr_create( regc->pool, &contact_STR);

+    regc->contact_hdr->hvalue.ptr = regc->contact_buf;

+    regc->contact_hdr->hvalue.slen = (s - regc->contact_buf);

+

+    return 0;

+}

+

+

+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;

+

+    /* 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 -1;

+    }

+

+    /* Set "From" header. */

+    pj_strdup_with_null(regc->pool, &tmp, from_url);

+    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 -1;

+    }

+

+    /* 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 -1;

+    }

+

+

+    /* Set "Contact" header. */

+    if (set_contact( regc, contact_cnt, contact) != 0)

+	return -1;

+

+    /* Set "Expires" header, if required. */

+    set_expires( regc, expires);

+

+    /* 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 = 0;

+    pjsip_method_set( &regc->cseq_hdr->method, PJSIP_REGISTER_METHOD);

+

+    /* Create "Contact" header used in unregistration. */

+    regc->unreg_contact_hdr = pjsip_contact_hdr_create(regc->pool);

+    regc->unreg_contact_hdr->star = 1;

+

+    /* Create "Expires" header used in unregistration. */

+    regc->unreg_expires_hdr = pjsip_expires_hdr_create( regc->pool);

+    regc->unreg_expires_hdr->ivalue = 0;

+

+    /* Done. */

+    return 0;

+}

+

+PJ_DEF(pj_status_t) pjsip_regc_set_credentials( pjsip_regc *regc,

+						int count,

+						const pjsip_cred_info cred[] )

+{

+    if (count > 0) {

+	regc->cred_info = pj_pool_alloc(regc->pool, count * sizeof(pjsip_cred_info));

+	pj_memcpy(regc->cred_info, cred, count * sizeof(pjsip_cred_info));

+    }

+    regc->cred_count = count;

+    return 0;

+}

+

+static pjsip_tx_data *create_request(pjsip_regc *regc)

+{

+    pjsip_tx_data *tdata;

+    pjsip_msg *msg;

+

+    /* Create transmit data. */

+    tdata = pjsip_endpt_create_tdata(regc->endpt);

+    if (!tdata) {

+	return NULL;

+    }

+

+    /* Create request message. */

+    msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);

+    tdata->msg = msg;

+

+    /* Initialize request line. */

+    pjsip_method_set(&msg->line.req.method, PJSIP_REGISTER_METHOD);

+    msg->line.req.uri = regc->srv_url;

+

+    /* Add headers. */

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->from_hdr);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->to_hdr);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->cid_hdr);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->cseq_hdr);

+    

+    /* Add cached authorization headers. */

+    pjsip_auth_init_req( regc->pool, tdata, &regc->auth_sess_list,

+			 regc->cred_count, regc->cred_info );

+

+    /* Add reference counter to transmit data. */

+    pjsip_tx_data_add_ref(tdata);

+

+    return tdata;

+}

+

+

+PJ_DEF(pjsip_tx_data*) pjsip_regc_register(pjsip_regc *regc, pj_bool_t autoreg)

+{

+    pjsip_msg *msg;

+    pjsip_tx_data *tdata;

+

+    tdata = create_request(regc);

+    if (!tdata)

+	return NULL;

+

+    msg = tdata->msg;

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->contact_hdr);

+    if (regc->expires_hdr)

+	pjsip_msg_add_hdr(msg, (pjsip_hdr*) regc->expires_hdr);

+

+    if (regc->timer.id != 0) {

+	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);

+	regc->timer.id = 0;

+    }

+

+    regc->auto_reg = autoreg;

+

+    return tdata;

+}

+

+

+PJ_DEF(pjsip_tx_data*) pjsip_regc_unregister(pjsip_regc *regc)

+{

+    pjsip_tx_data *tdata;

+    pjsip_msg *msg;

+

+    if (regc->timer.id != 0) {

+	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);

+	regc->timer.id = 0;

+    }

+

+    tdata = create_request(regc);

+    if (!tdata)

+	return NULL;

+

+    msg = tdata->msg;

+    pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_contact_hdr);

+    pjsip_msg_add_hdr( msg, (pjsip_hdr*)regc->unreg_expires_hdr);

+

+    return tdata;

+}

+

+

+PJ_DEF(pj_status_t) pjsip_regc_update_contact(  pjsip_regc *regc,

+					        int contact_cnt,

+						const pj_str_t contact[] )

+{

+    return set_contact( regc, contact_cnt, contact );

+}

+

+

+PJ_DEF(pj_status_t) pjsip_regc_update_expires(  pjsip_regc *regc,

+					        pj_uint32_t expires )

+{

+    set_expires( regc, expires );

+    return 0;

+}

+

+

+static void call_callback(pjsip_regc *regc, int status, 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;

+

+

+    cbparam.regc = regc;

+    cbparam.token = regc->token;

+    cbparam.code = status;

+    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*));

+    }

+

+    (*regc->cb)(&cbparam);

+}

+

+static void regc_refresh_timer_cb( pj_timer_heap_t *timer_heap,

+				   struct pj_timer_entry *entry)

+{

+    pjsip_regc *regc = entry->user_data;

+    pjsip_tx_data *tdata;

+    

+    PJ_UNUSED_ARG(timer_heap)

+

+    entry->id = 0;

+    tdata = pjsip_regc_register(regc, 1);

+    if (tdata) {

+	pjsip_regc_send(regc, tdata);

+    } else {

+	pj_str_t reason = pj_str("Unable to create txdata");

+	call_callback(regc, -1, &reason, NULL, -1, 0, NULL);

+    }

+}

+

+static void tsx_callback(void *token, pjsip_event *event)

+{

+    pjsip_regc *regc = token;

+    pjsip_transaction *tsx = event->obj.tsx;

+    

+    /* If registration data has been deleted by user then remove registration 

+     * data from transaction's callback, and don't call callback.

+     */

+    if (regc->_delete_flag) {

+	--regc->pending_tsx;

+

+    } else if (tsx->status_code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED ||

+	       tsx->status_code == PJSIP_SC_UNAUTHORIZED)

+    {

+	pjsip_rx_data *rdata = event->src.rdata;

+	pjsip_tx_data *tdata;

+

+	tdata = pjsip_auth_reinit_req( regc->endpt,

+				       regc->pool, &regc->auth_sess_list,

+				       regc->cred_count, regc->cred_info,

+				       tsx->last_tx, event->src.rdata );

+

+	if (tdata) {

+	    --regc->pending_tsx;

+	    pjsip_regc_send(regc, tdata);

+	    return;

+	} else {

+	    call_callback(regc, tsx->status_code, &rdata->msg->line.status.reason,

+			  rdata, -1, 0, NULL);

+	    --regc->pending_tsx;

+	}

+    } else {

+	int contact_cnt = 0;

+	pjsip_contact_hdr *contact[PJSIP_REGC_MAX_CONTACT];

+	pjsip_rx_data *rdata;

+	pj_int32_t expiration = 0xFFFF;

+

+	if (tsx->status_code/100 == 2) {

+	    int i;

+	    pjsip_contact_hdr *hdr;

+	    pjsip_msg *msg;

+	    pjsip_expires_hdr *expires;

+

+	    rdata = event->src.rdata;

+	    msg = rdata->msg;

+	    hdr = pjsip_msg_find_hdr( msg, PJSIP_H_CONTACT, NULL);

+	    while (hdr) {

+		contact[contact_cnt++] = hdr;

+		hdr = hdr->next;

+		if (hdr == (void*)&msg->hdr)

+		    break;

+		hdr = pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, hdr);

+	    }

+

+	    expires = pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);

+

+	    if (expires)

+		expiration = expires->ivalue;

+	    

+	    for (i=0; i<contact_cnt; ++i) {

+		hdr = contact[i];

+		if (hdr->expires >= 0 && hdr->expires < expiration)

+		    expiration = contact[i]->expires;

+	    }

+

+	    if (regc->auto_reg && expiration != 0 && expiration != 0xFFFF) {

+		pj_time_val delay = { 0, 0};

+

+		delay.sec = expiration - 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);

+	    }

+

+	} else {

+	    rdata = (event->src_type==PJSIP_EVENT_RX_MSG) ? event->src.rdata : NULL;

+	}

+

+

+	/* Call callback. */

+	if (expiration == 0xFFFF) expiration = -1;

+	call_callback(regc, tsx->status_code, 

+		      (rdata ? &rdata->msg->line.status.reason 

+			: pjsip_get_status_text(tsx->status_code)),

+		      rdata, expiration, 

+		      contact_cnt, contact);

+

+	--regc->pending_tsx;

+    }

+

+    /* Delete the record if user destroy regc during the callback. */

+    if (regc->_delete_flag && regc->pending_tsx==0) {

+	pjsip_regc_destroy(regc);

+    }

+}

+

+PJ_DEF(void) pjsip_regc_send(pjsip_regc *regc, pjsip_tx_data *tdata)

+{

+    int status;

+

+    /* Make sure we don't have pending transaction. */

+    if (regc->pending_tsx) {

+	pj_str_t reason = pj_str("Transaction in progress");

+	call_callback(regc, -1, &reason, NULL, -1, 0, NULL);

+	pjsip_tx_data_dec_ref( tdata );

+	return;

+    }

+

+    /* Invalidate message buffer. */

+    pjsip_tx_data_invalidate_msg(tdata);

+

+    /* Increment CSeq */

+    regc->cseq_hdr->cseq++;

+

+    /* Send. */

+    status = pjsip_endpt_send_request(regc->endpt, tdata, -1, regc, &tsx_callback);

+    if (status==0)

+	++regc->pending_tsx;

+    else {

+	pj_str_t reason = pj_str("Unable to send request.");

+	call_callback(regc, status, &reason, NULL, -1, 0, NULL);

+    }

+}

+

+

diff --git a/pjsip/src/pjsip-ua/sip_ua.c b/pjsip/src/pjsip-ua/sip_ua.c
index 6502a5e..fa77934 100644
--- a/pjsip/src/pjsip-ua/sip_ua.c
+++ b/pjsip/src/pjsip-ua/sip_ua.c
@@ -1,491 +1,513 @@
-/* $Id$
- *
- */
-#include <pjsip_mod_ua/sip_ua.h>
-#include <pjsip_mod_ua/sip_dialog.h>
-#include <pjsip_mod_ua/sip_ua_private.h>
-#include <pjsip/sip_module.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_misc.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_transaction.h>
-#include <pj/list.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/os.h>
-#include <pj/hash.h>
-#include <pj/pool.h>
-
-#define PJSIP_POOL_LEN_USER_AGENT   1024
-#define PJSIP_POOL_INC_USER_AGENT   0
-
-
-#define LOG_THIS    "useragent.."
-
-/*
- * Static prototypes.
- */
-static pj_status_t ua_init( pjsip_endpoint *endpt,
-			    struct pjsip_module *mod, pj_uint32_t id );
-static pj_status_t ua_start( struct pjsip_module *mod );
-static pj_status_t ua_deinit( struct pjsip_module *mod );
-static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *evt );
-static pjsip_dlg *find_dialog( pjsip_user_agent *ua,
-			       pjsip_rx_data *rdata );
-static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,
-				       pj_str_t *key );
-PJ_DECL(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg );
-
-/*
- * Default UA instance.
- */
-static pjsip_user_agent ua_instance;
-
-/*
- * Module interface.
- */
-static struct pjsip_module mod_ua = 
-{
-    { "User-Agent", 10 },   /* Name.		*/
-    0,			    /* Flag		*/
-    128,		    /* Priority		*/
-    NULL,		    /* User agent instance, initialized by APP.	*/
-    0,			    /* Number of methods supported (will be initialized later). */
-    { 0 },		    /* Array of methods (will be initialized later) */
-    &ua_init,		    /* init_module()	*/
-    &ua_start,		    /* start_module()	*/
-    &ua_deinit,		    /* deinit_module()	*/
-    &ua_tsx_handler,	    /* tsx_handler()	*/
-};
-
-/*
- * Initialize user agent instance.
- */
-static pj_status_t ua_init( pjsip_endpoint *endpt,
-			    struct pjsip_module *mod, pj_uint32_t id )
-{
-    static pjsip_method m_invite, m_ack, m_cancel, m_bye;
-    pjsip_user_agent *ua = mod->mod_data;
-    extern int pjsip_dlg_lock_tls_id;	/* defined in sip_dialog.c */
-
-    pjsip_method_set( &m_invite, PJSIP_INVITE_METHOD );
-    pjsip_method_set( &m_ack, PJSIP_ACK_METHOD );
-    pjsip_method_set( &m_cancel, PJSIP_CANCEL_METHOD );
-    pjsip_method_set( &m_bye, PJSIP_BYE_METHOD );
-
-    mod->method_cnt = 4;
-    mod->methods[0] = &m_invite;
-    mod->methods[1] = &m_ack;
-    mod->methods[2] = &m_cancel;
-    mod->methods[3] = &m_bye;
-
-    /* Initialize the user agent. */
-    ua->endpt = endpt;
-    ua->pool = pjsip_endpt_create_pool(endpt, "pua%p", PJSIP_POOL_LEN_UA, 
-				       PJSIP_POOL_INC_UA);
-    if (!ua->pool) {
-	return -1;
-    }
-    ua->mod_id = id;
-    ua->mutex = pj_mutex_create(ua->pool, " ua%p", 0);
-    if (!ua->mutex) {
-	return -1;
-    }
-    ua->dlg_table = pj_hash_create(ua->pool, PJSIP_MAX_DIALOG_COUNT);
-    if (ua->dlg_table == NULL) {
-	return -1;
-    }
-    pj_list_init(&ua->dlg_list);
-
-    /* Initialize dialog lock. */
-    pjsip_dlg_lock_tls_id = pj_thread_local_alloc();
-    if (pjsip_dlg_lock_tls_id == -1) {
-	return -1;
-    }
-    pj_thread_local_set(pjsip_dlg_lock_tls_id, NULL);
-
-    return 0;
-}
-
-/*
- * Start user agent instance.
- */
-static pj_status_t ua_start( struct pjsip_module *mod )
-{
-    PJ_UNUSED_ARG(mod)
-    return 0;
-}
-
-/*
- * Destroy user agent.
- */
-static pj_status_t ua_deinit( struct pjsip_module *mod )
-{
-    pjsip_user_agent *ua = mod->mod_data;
-
-    pj_mutex_unlock(ua->mutex);
-
-    /* Release pool */
-    if (ua->pool) {
-	pjsip_endpt_destroy_pool( ua->endpt, ua->pool );
-    }
-    return 0;
-}
-
-/*
- * Get the module interface for the UA module.
- */
-PJ_DEF(pjsip_module*) pjsip_ua_get_module(void)
-{
-    mod_ua.mod_data = &ua_instance;
-    return &mod_ua;
-}
-
-/*
- * Register callback to receive dialog notifications.
- */
-PJ_DEF(void) pjsip_ua_set_dialog_callback( pjsip_user_agent *ua, 
-					   pjsip_dlg_callback *cb )
-{
-    ua->dlg_cb = cb;
-}
-
-/* 
- * Find dialog.
- * This function is called for a new transactions, which a dialog hasn't been
- * 'attached' to the transaction.
- */
-static pjsip_dlg *find_dialog( pjsip_user_agent *ua, pjsip_rx_data *rdata )
-{
-    pjsip_dlg *dlg;
-    pj_str_t *tag;
-
-    /* Non-CANCEL requests/response can be found by looking at the tag in the
-     * hash table. CANCEL requests don't have tags, so instead we'll try to
-     * find the UAS INVITE transaction in endpoint's hash table
-     */
-    if (rdata->cseq->method.id == PJSIP_CANCEL_METHOD) {
-
-	/* Create key for the rdata, but this time, use INVITE as the
-	 * method.
-	 */
-	pj_str_t key;
-	pjsip_role_e role;
-	pjsip_method invite_method;
-	pjsip_transaction *invite_tsx;
-
-	if (rdata->msg->type == PJSIP_REQUEST_MSG) {
-	    role = PJSIP_ROLE_UAS;
-	} else {
-	    role = PJSIP_ROLE_UAC;
-	}
-	pjsip_method_set(&invite_method, PJSIP_INVITE_METHOD);
-	pjsip_tsx_create_key(rdata->pool, &key, role, &invite_method, rdata);
-
-	/* Lookup the INVITE transaction */
-	invite_tsx = pjsip_endpt_find_tsx(ua->endpt, &key);
-
-	/* We should find the dialog attached to the INVITE transaction */
-	return invite_tsx ? 
-	    (pjsip_dlg*) invite_tsx->module_data[ua->mod_id] : NULL;
-
-    } else {
-	if (rdata->msg->type == PJSIP_REQUEST_MSG) {
-	    tag = &rdata->to_tag;
-	} else {
-	    tag = &rdata->from_tag;
-	}
-	/* Find the dialog in UA hash table */
-	pj_mutex_lock(ua->mutex);
-	dlg = pj_hash_get( ua->dlg_table, tag->ptr, tag->slen );
-	pj_mutex_unlock(ua->mutex);
-    }
-    
-    return dlg;
-}
-
-/*
- * This function receives event notification from transactions. It is called by
- * endpoint.
- */
-static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *event )
-{
-    pjsip_user_agent *ua = mod->mod_data;
-    pjsip_dlg *dlg = NULL;
-    pjsip_transaction *tsx = event->obj.tsx;
-
-    PJ_LOG(5, (LOG_THIS, "ua_tsx_handler(tsx=%s, evt=%s, src=%s, data=%p)", 
-	       (tsx ? tsx->obj_name : "NULL"),  pjsip_event_str(event->type), 
-	       pjsip_event_str(event->src_type), event->src.data));
-
-    /* Special case to handle ACK which doesn't match any INVITE transactions. */
-    if (event->type == PJSIP_EVENT_RX_ACK_MSG) {
-	/* Find the dialog based on the "tag". */
-	dlg = find_dialog( ua, event->src.rdata );
-
-	/* We should be able to find it. */
-	if (!dlg) {
-	    PJ_LOG(4,(LOG_THIS, "Unable to find dialog for incoming ACK"));
-	    return;
-	}
-
-	/* Match CSeq with pending INVITE in dialog. */
-	if (dlg->invite_tsx && dlg->invite_tsx->cseq==event->src.rdata->cseq->cseq) {
-	    /* A match found. */
-	    tsx = dlg->invite_tsx;
-
-	    /* Pass the event to transaction if transaction handles ACK. */
-	    if (tsx->handle_ack) {
-		PJ_LOG(4,(LOG_THIS, "Re-routing strandled ACK to transaction"));
-		pjsip_tsx_on_rx_msg(tsx, event->src.rdata);
-		return;
-	    }
-	} else {
-	    tsx = NULL;
-	    PJ_LOG(4,(LOG_THIS, "Unable to find INVITE tsx for incoming ACK"));
-	    return;
-	}
-    }
-
-    /* For discard event, transaction is NULL. */
-    if (tsx == NULL) {
-	return;
-    }
-
-    /* Try to pickup the dlg from the transaction. */
-    dlg = (pjsip_dlg*) tsx->module_data[ua->mod_id];
-
-    if (dlg != NULL) {
-
-	/* Nothing to do now. */
-
-    } else if (event->src_type == PJSIP_EVENT_RX_MSG)  {
-
-	/* This must be a new UAS transaction. */
-
-	/* Finds dlg that can handle this transaction. */
-	dlg = find_dialog( ua, event->src.rdata);
-
-	/* Create a new dlg if there's no existing dlg that can handle 
-	   the request, ONLY if the incoming message is an INVITE request.
-	 */
-	if (dlg==NULL && event->src.rdata->msg->type == PJSIP_REQUEST_MSG) {
-
-	    if (event->src.rdata->msg->line.req.method.id == PJSIP_INVITE_METHOD) {
-		/* Create new dialog. */
-		dlg = pjsip_ua_create_dialog( ua, PJSIP_ROLE_UAS );
-
-		if (dlg == NULL ||
-		    pjsip_dlg_init_from_rdata( dlg, event->src.rdata) != 0) 
-		{
-		    pjsip_tx_data *tdata;
-
-		    /* Dialog initialization has failed. Respond request with 500 */
-		    if (dlg) {
-			pjsip_ua_destroy_dialog(dlg);
-		    }
-		    tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata, 
-							PJSIP_SC_INTERNAL_SERVER_ERROR);
-		    if (tdata) {
-			pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );
-		    }
-		    return;
-		}
-
-	    } else {
-		pjsip_tx_data *tdata;
-
-		/* Check the method */
-		switch (tsx->method.id) {
-		case PJSIP_INVITE_METHOD:
-		case PJSIP_ACK_METHOD:
-		case PJSIP_BYE_METHOD:
-		case PJSIP_CANCEL_METHOD:
-		    /* Stale non-INVITE request.
-		     * For now, respond all stale requests with 481 (?).
-		     */
-		    tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata, 
-							PJSIP_SC_CALL_TSX_DOES_NOT_EXIST);
-		    if (tdata) {
-			pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );
-		    }
-		    break;
-		}
-
-		return;
-	    }
-	} else {
-	    /* Check the method */
-	    switch (tsx->method.id) {
-	    case PJSIP_INVITE_METHOD:
-	    case PJSIP_ACK_METHOD:
-	    case PJSIP_BYE_METHOD:
-	    case PJSIP_CANCEL_METHOD:
-		/* These methods belongs to dialog.
-		 * If we receive these methods while no dialog is found, 
-		 * then it must be a stale responses.
-		 */
-		break;
-	    default:
-		return;
-	    }
-
-	}
-	
-	if (dlg == NULL) {
-	    PJ_LOG(3, (LOG_THIS, "Receives spurious rdata %p from %s:%d",
-		       event->src.rdata, 
-		       pj_sockaddr_get_str_addr(&event->src.rdata->addr),
-		       pj_sockaddr_get_port(&event->src.rdata->addr)));
-	}
-
-	/* Set the dlg in the transaction (dlg can be NULL). */
-	tsx->module_data[ua->mod_id] = dlg;
-
-    } else {
-	/* This CAN happen with event->src_type == PJSIP_EVENT_TX_MSG
-	 * if UAS is responding to a transaction which does not exist. 
-	 * Just ignore.
-	 */
-	return;
-    }
-
-    /* Pass the event to the dlg. */
-    if (dlg) {
-	pjsip_dlg_on_tsx_event(dlg, tsx, event);
-    }
-}
-
-/*
- * Register dialog to UA.
- */
-static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,
-				       pj_str_t *key )
-{
-    /* Assure that no entry with similar key exists in the hash table. */
-    pj_assert( pj_hash_get( ua->dlg_table, key->ptr, key->slen) == 0);
-
-    /* Insert entry to hash table. */
-    pj_hash_set( dlg->pool, ua->dlg_table, 
-		 key->ptr, key->slen, dlg);
-
-    /* Insert to the list. */
-    pj_list_insert_before(&ua->dlg_list, dlg);
-    return PJ_SUCCESS;
-}
-
-/*
- * Create a new dialog.
- */
-PJ_DEF(pjsip_dlg*) pjsip_ua_create_dialog( pjsip_user_agent *ua,
-					      pjsip_role_e role )
-{
-    pj_pool_t *pool;
-    pjsip_dlg *dlg;
-
-    PJ_UNUSED_ARG(ua)
-
-    /* Create pool for the dialog. */
-    pool = pjsip_endpt_create_pool( ua->endpt, "pdlg%p",
-				    PJSIP_POOL_LEN_DIALOG,
-				    PJSIP_POOL_INC_DIALOG);
-
-    /* Create the dialog. */
-    dlg = pj_pool_calloc(pool, 1, sizeof(pjsip_dlg));
-    dlg->pool = pool;
-    dlg->ua = ua;
-    dlg->role = role;
-    sprintf(dlg->obj_name, "dlg%p", dlg);
-
-    /* Create mutex for the dialog. */
-    dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);
-    if (!dlg->mutex) {
-	pjsip_endpt_destroy_pool(ua->endpt, pool);
-	return NULL;
-    }
-
-    /* Create unique tag for the dialog. */
-    pj_create_unique_string( pool, &dlg->local.tag );
-
-    /* Register dialog. */
-    pj_mutex_lock(ua->mutex);
-    if (ua_register_dialog(ua, dlg, &dlg->local.tag) != PJ_SUCCESS) {
-	pj_mutex_unlock(ua->mutex);
-	pj_mutex_destroy(dlg->mutex);
-	pjsip_endpt_destroy_pool( ua->endpt, pool );
-	return NULL;
-    }
-    pj_mutex_unlock(ua->mutex);
-
-    PJ_LOG(4, (dlg->obj_name, "new %s dialog created", pjsip_role_name(role)));
-    return dlg;
-}
-
-/*
- * Destroy dialog.
- */
-PJ_DEF(void) pjsip_ua_destroy_dialog( pjsip_dlg *dlg )
-{
-    PJ_LOG(5, (dlg->obj_name, "destroying.."));
-
-    /* Lock dialog's mutex. 
-     * Check the mutex validity first since this function can be called
-     * on dialog initialization failure (which might be because mutex could not
-     * be allocated in the first place).
-     */
-    if (dlg->mutex) {
-	pj_mutex_lock(dlg->mutex);
-    }
-
-    /* This must be called while holding dialog's mutex, if any. */
-    pjsip_on_dialog_destroyed(dlg);
-
-    /* Lock UA. */
-    pj_mutex_lock(dlg->ua->mutex);
-
-    /* Erase from hash table. */
-    pj_hash_set( dlg->pool, dlg->ua->dlg_table,
-		 dlg->local.tag.ptr, dlg->local.tag.slen, NULL);
-
-    /* Erase from the list. */
-    pj_list_erase(dlg);
-
-    /* Unlock UA. */
-    pj_mutex_unlock(dlg->ua->mutex);
-
-    /* Unlock mutex. */
-    if (dlg->mutex) {
-	pj_mutex_unlock(dlg->mutex);
-    }
-
-    /* Destroy the pool. */
-    pjsip_endpt_destroy_pool( dlg->ua->endpt, dlg->pool);
-}
-
-/*
- * Dump user agent state to log file.
- */
-PJ_DEF(void) pjsip_ua_dump(pjsip_user_agent *ua)
-{
-#if PJ_LOG_MAX_LEVEL >= 3
-    PJ_LOG(3,(LOG_THIS, "Dumping user agent"));
-    PJ_LOG(3,(LOG_THIS, "  Pool capacity=%u, used=%u", 
-			pj_pool_get_capacity(ua->pool),
-			pj_pool_get_used_size(ua->pool)));
-    PJ_LOG(3,(LOG_THIS, "  Number of dialogs=%u", pj_hash_count(ua->dlg_table)));
-
-    if (pj_hash_count(ua->dlg_table)) {
-	pjsip_dlg *dlg;
-
-	PJ_LOG(3,(LOG_THIS, "  Dumping dialog list:"));
-	dlg = ua->dlg_list.next;
-	while (dlg != (pjsip_dlg*) &ua->dlg_list) {
-	    PJ_LOG(3, (LOG_THIS, "    %s %s", dlg->obj_name, 
-		       pjsip_dlg_state_str(dlg->state)));
-	    dlg = dlg->next;
-	}
-    }
-#endif
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip_mod_ua/sip_ua.h>

+#include <pjsip_mod_ua/sip_dialog.h>

+#include <pjsip_mod_ua/sip_ua_private.h>

+#include <pjsip/sip_module.h>

+#include <pjsip/sip_event.h>

+#include <pjsip/sip_misc.h>

+#include <pjsip/sip_endpoint.h>

+#include <pjsip/sip_transaction.h>

+#include <pj/list.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/guid.h>

+#include <pj/os.h>

+#include <pj/hash.h>

+#include <pj/pool.h>

+

+#define PJSIP_POOL_LEN_USER_AGENT   1024

+#define PJSIP_POOL_INC_USER_AGENT   0

+

+

+#define LOG_THIS    "useragent.."

+

+/*

+ * Static prototypes.

+ */

+static pj_status_t ua_init( pjsip_endpoint *endpt,

+			    struct pjsip_module *mod, pj_uint32_t id );

+static pj_status_t ua_start( struct pjsip_module *mod );

+static pj_status_t ua_deinit( struct pjsip_module *mod );

+static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *evt );

+static pjsip_dlg *find_dialog( pjsip_user_agent *ua,

+			       pjsip_rx_data *rdata );

+static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,

+				       pj_str_t *key );

+PJ_DECL(void) pjsip_on_dialog_destroyed( pjsip_dlg *dlg );

+

+/*

+ * Default UA instance.

+ */

+static pjsip_user_agent ua_instance;

+

+/*

+ * Module interface.

+ */

+static struct pjsip_module mod_ua = 

+{

+    { "User-Agent", 10 },   /* Name.		*/

+    0,			    /* Flag		*/

+    128,		    /* Priority		*/

+    NULL,		    /* User agent instance, initialized by APP.	*/

+    0,			    /* Number of methods supported (will be initialized later). */

+    { 0 },		    /* Array of methods (will be initialized later) */

+    &ua_init,		    /* init_module()	*/

+    &ua_start,		    /* start_module()	*/

+    &ua_deinit,		    /* deinit_module()	*/

+    &ua_tsx_handler,	    /* tsx_handler()	*/

+};

+

+/*

+ * Initialize user agent instance.

+ */

+static pj_status_t ua_init( pjsip_endpoint *endpt,

+			    struct pjsip_module *mod, pj_uint32_t id )

+{

+    static pjsip_method m_invite, m_ack, m_cancel, m_bye;

+    pjsip_user_agent *ua = mod->mod_data;

+    extern int pjsip_dlg_lock_tls_id;	/* defined in sip_dialog.c */

+

+    pjsip_method_set( &m_invite, PJSIP_INVITE_METHOD );

+    pjsip_method_set( &m_ack, PJSIP_ACK_METHOD );

+    pjsip_method_set( &m_cancel, PJSIP_CANCEL_METHOD );

+    pjsip_method_set( &m_bye, PJSIP_BYE_METHOD );

+

+    mod->method_cnt = 4;

+    mod->methods[0] = &m_invite;

+    mod->methods[1] = &m_ack;

+    mod->methods[2] = &m_cancel;

+    mod->methods[3] = &m_bye;

+

+    /* Initialize the user agent. */

+    ua->endpt = endpt;

+    ua->pool = pjsip_endpt_create_pool(endpt, "pua%p", PJSIP_POOL_LEN_UA, 

+				       PJSIP_POOL_INC_UA);

+    if (!ua->pool) {

+	return -1;

+    }

+    ua->mod_id = id;

+    ua->mutex = pj_mutex_create(ua->pool, " ua%p", 0);

+    if (!ua->mutex) {

+	return -1;

+    }

+    ua->dlg_table = pj_hash_create(ua->pool, PJSIP_MAX_DIALOG_COUNT);

+    if (ua->dlg_table == NULL) {

+	return -1;

+    }

+    pj_list_init(&ua->dlg_list);

+

+    /* Initialize dialog lock. */

+    pjsip_dlg_lock_tls_id = pj_thread_local_alloc();

+    if (pjsip_dlg_lock_tls_id == -1) {

+	return -1;

+    }

+    pj_thread_local_set(pjsip_dlg_lock_tls_id, NULL);

+

+    return 0;

+}

+

+/*

+ * Start user agent instance.

+ */

+static pj_status_t ua_start( struct pjsip_module *mod )

+{

+    PJ_UNUSED_ARG(mod)

+    return 0;

+}

+

+/*

+ * Destroy user agent.

+ */

+static pj_status_t ua_deinit( struct pjsip_module *mod )

+{

+    pjsip_user_agent *ua = mod->mod_data;

+

+    pj_mutex_unlock(ua->mutex);

+

+    /* Release pool */

+    if (ua->pool) {

+	pjsip_endpt_destroy_pool( ua->endpt, ua->pool );

+    }

+    return 0;

+}

+

+/*

+ * Get the module interface for the UA module.

+ */

+PJ_DEF(pjsip_module*) pjsip_ua_get_module(void)

+{

+    mod_ua.mod_data = &ua_instance;

+    return &mod_ua;

+}

+

+/*

+ * Register callback to receive dialog notifications.

+ */

+PJ_DEF(void) pjsip_ua_set_dialog_callback( pjsip_user_agent *ua, 

+					   pjsip_dlg_callback *cb )

+{

+    ua->dlg_cb = cb;

+}

+

+/* 

+ * Find dialog.

+ * This function is called for a new transactions, which a dialog hasn't been

+ * 'attached' to the transaction.

+ */

+static pjsip_dlg *find_dialog( pjsip_user_agent *ua, pjsip_rx_data *rdata )

+{

+    pjsip_dlg *dlg;

+    pj_str_t *tag;

+

+    /* Non-CANCEL requests/response can be found by looking at the tag in the

+     * hash table. CANCEL requests don't have tags, so instead we'll try to

+     * find the UAS INVITE transaction in endpoint's hash table

+     */

+    if (rdata->cseq->method.id == PJSIP_CANCEL_METHOD) {

+

+	/* Create key for the rdata, but this time, use INVITE as the

+	 * method.

+	 */

+	pj_str_t key;

+	pjsip_role_e role;

+	pjsip_method invite_method;

+	pjsip_transaction *invite_tsx;

+

+	if (rdata->msg->type == PJSIP_REQUEST_MSG) {

+	    role = PJSIP_ROLE_UAS;

+	} else {

+	    role = PJSIP_ROLE_UAC;

+	}

+	pjsip_method_set(&invite_method, PJSIP_INVITE_METHOD);

+	pjsip_tsx_create_key(rdata->pool, &key, role, &invite_method, rdata);

+

+	/* Lookup the INVITE transaction */

+	invite_tsx = pjsip_endpt_find_tsx(ua->endpt, &key);

+

+	/* We should find the dialog attached to the INVITE transaction */

+	return invite_tsx ? 

+	    (pjsip_dlg*) invite_tsx->module_data[ua->mod_id] : NULL;

+

+    } else {

+	if (rdata->msg->type == PJSIP_REQUEST_MSG) {

+	    tag = &rdata->to_tag;

+	} else {

+	    tag = &rdata->from_tag;

+	}

+	/* Find the dialog in UA hash table */

+	pj_mutex_lock(ua->mutex);

+	dlg = pj_hash_get( ua->dlg_table, tag->ptr, tag->slen );

+	pj_mutex_unlock(ua->mutex);

+    }

+    

+    return dlg;

+}

+

+/*

+ * This function receives event notification from transactions. It is called by

+ * endpoint.

+ */

+static void ua_tsx_handler( struct pjsip_module *mod, pjsip_event *event )

+{

+    pjsip_user_agent *ua = mod->mod_data;

+    pjsip_dlg *dlg = NULL;

+    pjsip_transaction *tsx = event->obj.tsx;

+

+    PJ_LOG(5, (LOG_THIS, "ua_tsx_handler(tsx=%s, evt=%s, src=%s, data=%p)", 

+	       (tsx ? tsx->obj_name : "NULL"),  pjsip_event_str(event->type), 

+	       pjsip_event_str(event->src_type), event->src.data));

+

+    /* Special case to handle ACK which doesn't match any INVITE transactions. */

+    if (event->type == PJSIP_EVENT_RX_ACK_MSG) {

+	/* Find the dialog based on the "tag". */

+	dlg = find_dialog( ua, event->src.rdata );

+

+	/* We should be able to find it. */

+	if (!dlg) {

+	    PJ_LOG(4,(LOG_THIS, "Unable to find dialog for incoming ACK"));

+	    return;

+	}

+

+	/* Match CSeq with pending INVITE in dialog. */

+	if (dlg->invite_tsx && dlg->invite_tsx->cseq==event->src.rdata->cseq->cseq) {

+	    /* A match found. */

+	    tsx = dlg->invite_tsx;

+

+	    /* Pass the event to transaction if transaction handles ACK. */

+	    if (tsx->handle_ack) {

+		PJ_LOG(4,(LOG_THIS, "Re-routing strandled ACK to transaction"));

+		pjsip_tsx_on_rx_msg(tsx, event->src.rdata);

+		return;

+	    }

+	} else {

+	    tsx = NULL;

+	    PJ_LOG(4,(LOG_THIS, "Unable to find INVITE tsx for incoming ACK"));

+	    return;

+	}

+    }

+

+    /* For discard event, transaction is NULL. */

+    if (tsx == NULL) {

+	return;

+    }

+

+    /* Try to pickup the dlg from the transaction. */

+    dlg = (pjsip_dlg*) tsx->module_data[ua->mod_id];

+

+    if (dlg != NULL) {

+

+	/* Nothing to do now. */

+

+    } else if (event->src_type == PJSIP_EVENT_RX_MSG)  {

+

+	/* This must be a new UAS transaction. */

+

+	/* Finds dlg that can handle this transaction. */

+	dlg = find_dialog( ua, event->src.rdata);

+

+	/* Create a new dlg if there's no existing dlg that can handle 

+	   the request, ONLY if the incoming message is an INVITE request.

+	 */

+	if (dlg==NULL && event->src.rdata->msg->type == PJSIP_REQUEST_MSG) {

+

+	    if (event->src.rdata->msg->line.req.method.id == PJSIP_INVITE_METHOD) {

+		/* Create new dialog. */

+		dlg = pjsip_ua_create_dialog( ua, PJSIP_ROLE_UAS );

+

+		if (dlg == NULL ||

+		    pjsip_dlg_init_from_rdata( dlg, event->src.rdata) != 0) 

+		{

+		    pjsip_tx_data *tdata;

+

+		    /* Dialog initialization has failed. Respond request with 500 */

+		    if (dlg) {

+			pjsip_ua_destroy_dialog(dlg);

+		    }

+		    tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata, 

+							PJSIP_SC_INTERNAL_SERVER_ERROR);

+		    if (tdata) {

+			pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );

+		    }

+		    return;

+		}

+

+	    } else {

+		pjsip_tx_data *tdata;

+

+		/* Check the method */

+		switch (tsx->method.id) {

+		case PJSIP_INVITE_METHOD:

+		case PJSIP_ACK_METHOD:

+		case PJSIP_BYE_METHOD:

+		case PJSIP_CANCEL_METHOD:

+		    /* Stale non-INVITE request.

+		     * For now, respond all stale requests with 481 (?).

+		     */

+		    tdata = pjsip_endpt_create_response(ua->endpt, event->src.rdata, 

+							PJSIP_SC_CALL_TSX_DOES_NOT_EXIST);

+		    if (tdata) {

+			pjsip_tsx_on_tx_msg( event->obj.tsx, tdata );

+		    }

+		    break;

+		}

+

+		return;

+	    }

+	} else {

+	    /* Check the method */

+	    switch (tsx->method.id) {

+	    case PJSIP_INVITE_METHOD:

+	    case PJSIP_ACK_METHOD:

+	    case PJSIP_BYE_METHOD:

+	    case PJSIP_CANCEL_METHOD:

+		/* These methods belongs to dialog.

+		 * If we receive these methods while no dialog is found, 

+		 * then it must be a stale responses.

+		 */

+		break;

+	    default:

+		return;

+	    }

+

+	}

+	

+	if (dlg == NULL) {

+	    PJ_LOG(3, (LOG_THIS, "Receives spurious rdata %p from %s:%d",

+		       event->src.rdata, 

+		       pj_sockaddr_get_str_addr(&event->src.rdata->addr),

+		       pj_sockaddr_get_port(&event->src.rdata->addr)));

+	}

+

+	/* Set the dlg in the transaction (dlg can be NULL). */

+	tsx->module_data[ua->mod_id] = dlg;

+

+    } else {

+	/* This CAN happen with event->src_type == PJSIP_EVENT_TX_MSG

+	 * if UAS is responding to a transaction which does not exist. 

+	 * Just ignore.

+	 */

+	return;

+    }

+

+    /* Pass the event to the dlg. */

+    if (dlg) {

+	pjsip_dlg_on_tsx_event(dlg, tsx, event);

+    }

+}

+

+/*

+ * Register dialog to UA.

+ */

+static pj_status_t ua_register_dialog( pjsip_user_agent *ua, pjsip_dlg *dlg,

+				       pj_str_t *key )

+{

+    /* Assure that no entry with similar key exists in the hash table. */

+    pj_assert( pj_hash_get( ua->dlg_table, key->ptr, key->slen) == 0);

+

+    /* Insert entry to hash table. */

+    pj_hash_set( dlg->pool, ua->dlg_table, 

+		 key->ptr, key->slen, dlg);

+

+    /* Insert to the list. */

+    pj_list_insert_before(&ua->dlg_list, dlg);

+    return PJ_SUCCESS;

+}

+

+/*

+ * Create a new dialog.

+ */

+PJ_DEF(pjsip_dlg*) pjsip_ua_create_dialog( pjsip_user_agent *ua,

+					      pjsip_role_e role )

+{

+    pj_pool_t *pool;

+    pjsip_dlg *dlg;

+

+    PJ_UNUSED_ARG(ua)

+

+    /* Create pool for the dialog. */

+    pool = pjsip_endpt_create_pool( ua->endpt, "pdlg%p",

+				    PJSIP_POOL_LEN_DIALOG,

+				    PJSIP_POOL_INC_DIALOG);

+

+    /* Create the dialog. */

+    dlg = pj_pool_calloc(pool, 1, sizeof(pjsip_dlg));

+    dlg->pool = pool;

+    dlg->ua = ua;

+    dlg->role = role;

+    sprintf(dlg->obj_name, "dlg%p", dlg);

+

+    /* Create mutex for the dialog. */

+    dlg->mutex = pj_mutex_create(dlg->pool, "mdlg%p", 0);

+    if (!dlg->mutex) {

+	pjsip_endpt_destroy_pool(ua->endpt, pool);

+	return NULL;

+    }

+

+    /* Create unique tag for the dialog. */

+    pj_create_unique_string( pool, &dlg->local.tag );

+

+    /* Register dialog. */

+    pj_mutex_lock(ua->mutex);

+    if (ua_register_dialog(ua, dlg, &dlg->local.tag) != PJ_SUCCESS) {

+	pj_mutex_unlock(ua->mutex);

+	pj_mutex_destroy(dlg->mutex);

+	pjsip_endpt_destroy_pool( ua->endpt, pool );

+	return NULL;

+    }

+    pj_mutex_unlock(ua->mutex);

+

+    PJ_LOG(4, (dlg->obj_name, "new %s dialog created", pjsip_role_name(role)));

+    return dlg;

+}

+

+/*

+ * Destroy dialog.

+ */

+PJ_DEF(void) pjsip_ua_destroy_dialog( pjsip_dlg *dlg )

+{

+    PJ_LOG(5, (dlg->obj_name, "destroying.."));

+

+    /* Lock dialog's mutex. 

+     * Check the mutex validity first since this function can be called

+     * on dialog initialization failure (which might be because mutex could not

+     * be allocated in the first place).

+     */

+    if (dlg->mutex) {

+	pj_mutex_lock(dlg->mutex);

+    }

+

+    /* This must be called while holding dialog's mutex, if any. */

+    pjsip_on_dialog_destroyed(dlg);

+

+    /* Lock UA. */

+    pj_mutex_lock(dlg->ua->mutex);

+

+    /* Erase from hash table. */

+    pj_hash_set( dlg->pool, dlg->ua->dlg_table,

+		 dlg->local.tag.ptr, dlg->local.tag.slen, NULL);

+

+    /* Erase from the list. */

+    pj_list_erase(dlg);

+

+    /* Unlock UA. */

+    pj_mutex_unlock(dlg->ua->mutex);

+

+    /* Unlock mutex. */

+    if (dlg->mutex) {

+	pj_mutex_unlock(dlg->mutex);

+    }

+

+    /* Destroy the pool. */

+    pjsip_endpt_destroy_pool( dlg->ua->endpt, dlg->pool);

+}

+

+/*

+ * Dump user agent state to log file.

+ */

+PJ_DEF(void) pjsip_ua_dump(pjsip_user_agent *ua)

+{

+#if PJ_LOG_MAX_LEVEL >= 3

+    PJ_LOG(3,(LOG_THIS, "Dumping user agent"));

+    PJ_LOG(3,(LOG_THIS, "  Pool capacity=%u, used=%u", 

+			pj_pool_get_capacity(ua->pool),

+			pj_pool_get_used_size(ua->pool)));

+    PJ_LOG(3,(LOG_THIS, "  Number of dialogs=%u", pj_hash_count(ua->dlg_table)));

+

+    if (pj_hash_count(ua->dlg_table)) {

+	pjsip_dlg *dlg;

+

+	PJ_LOG(3,(LOG_THIS, "  Dumping dialog list:"));

+	dlg = ua->dlg_list.next;

+	while (dlg != (pjsip_dlg*) &ua->dlg_list) {

+	    PJ_LOG(3, (LOG_THIS, "    %s %s", dlg->obj_name, 

+		       pjsip_dlg_state_str(dlg->state)));

+	    dlg = dlg->next;

+	}

+    }

+#endif

+}

+

diff --git a/pjsip/src/pjsip-ua/sip_ua_private.h b/pjsip/src/pjsip-ua/sip_ua_private.h
index 471c4db..cc6dfcf 100644
--- a/pjsip/src/pjsip-ua/sip_ua_private.h
+++ b/pjsip/src/pjsip-ua/sip_ua_private.h
@@ -1,22 +1,44 @@
-/* $Id$
- *
- */
-
-#ifndef __PJSIP_UA_PRIVATE_H__
-#define __PJSIP_UA_PRIVATE_H__
-
-
-/*
- * Internal dialog functions.
- */
-pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg,
-				       pjsip_rx_data *rdata );
-
-
-void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg, 
-			     pjsip_transaction *tsx, 
-			     pjsip_event *event);
-
-
-#endif	/* __PJSIP_UA_PRIVATE_H__ */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+

+#ifndef __PJSIP_UA_PRIVATE_H__

+#define __PJSIP_UA_PRIVATE_H__

+

+

+/*

+ * Internal dialog functions.

+ */

+pj_status_t pjsip_dlg_init_from_rdata( pjsip_dlg *dlg,

+				       pjsip_rx_data *rdata );

+

+

+void pjsip_dlg_on_tsx_event( pjsip_dlg *dlg, 

+			     pjsip_transaction *tsx, 

+			     pjsip_event *event);

+

+

+#endif	/* __PJSIP_UA_PRIVATE_H__ */

+

diff --git a/pjsip/src/pjsip/sip_auth.c b/pjsip/src/pjsip/sip_auth.c
index 030b4a4..bf161a1 100644
--- a/pjsip/src/pjsip/sip_auth.c
+++ b/pjsip/src/pjsip/sip_auth.c
@@ -1,788 +1,810 @@
-/* $Id$
- */
-#include <pjsip/sip_auth.h>
-#include <pjsip/sip_auth_parser.h>	/* just to get pjsip_DIGEST_STR */
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjlib-util/md5.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/pool.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_auth.h>

+#include <pjsip/sip_auth_parser.h>	/* just to get pjsip_DIGEST_STR */

+#include <pjsip/sip_transport.h>

+#include <pjsip/sip_endpoint.h>

+#include <pjlib-util/md5.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/pool.h>

 #include <pj/guid.h>

-#include <pj/assert.h>
+#include <pj/assert.h>

 #include <pj/ctype.h>

-
-/* Length of digest string. */
-#define MD5STRLEN 32
-
-/* Maximum stack size we use for storing username+realm+password etc. */
-#define MAX_TEMP  128
-
-/* A macro just to get rid of type mismatch between char and unsigned char */
-#define MD5_APPEND(pms,buf,len)	md5_append(pms, (const unsigned char*)buf, len)
-
-/* Logging. */
-#define THIS_FILE   "sip_auth.c"
-#if 0
-#  define AUTH_TRACE_(expr)  PJ_LOG(3, expr)
-#else
-#  define AUTH_TRACE_(expr)
-#endif
-
-static const char hex[] = "0123456789abcdef";
-
-/* Transform digest to string.
- * output must be at least MD5STRLEN+1 bytes.
- *
- * NOTE: THE OUTPUT STRING IS NOT NULL TERMINATED!
- */
-static void digest2str(const unsigned char digest[], char *output)
-{
-    char *p = output;
-    int i;
-
-    for (i = 0; i<16; ++i) {
-	int val = digest[i];
-	*p++ = hex[val >> 4];
-	*p++ = hex[val & 0x0F];
-    }
-}
-
-/*
- * Create response digest based on the parameters and store the
- * digest ASCII in 'result'. 
- */
-static void create_digest( pj_str_t *result,
-			   const pj_str_t *nonce,
-			   const pj_str_t *nc,
-			   const pj_str_t *cnonce,
-			   const pj_str_t *qop,
-			   const pj_str_t *uri,
-			   const pjsip_cred_info *cred_info,
-			   const pj_str_t *method)
-{
-    char ha1[MD5STRLEN];
-    char ha2[MD5STRLEN];
-    unsigned char digest[16];
-    md5_state_t pms;
-
-    pj_assert(result->slen >= MD5STRLEN);
-
-    AUTH_TRACE_((THIS_FILE, "Begin creating digest"));
-
-    if (cred_info->data_type == PJSIP_CRED_DATA_PLAIN_PASSWD) {
-	/*** 
-	 *** ha1 = MD5(username ":" realm ":" password) 
-	 ***/
-	md5_init(&pms);
-	MD5_APPEND( &pms, cred_info->username.ptr, cred_info->username.slen);
-	MD5_APPEND( &pms, ":", 1);
-	MD5_APPEND( &pms, cred_info->realm.ptr, cred_info->realm.slen);
-	MD5_APPEND( &pms, ":", 1);
-	MD5_APPEND( &pms, cred_info->data.ptr, cred_info->data.slen);
-	md5_finish(&pms, digest);
-
-	digest2str(digest, ha1);
-
-    } else if (cred_info->data_type == PJSIP_CRED_DATA_DIGEST) {
-	pj_assert(cred_info->data.slen == 32);
-	pj_memcpy( ha1, cred_info->data.ptr, cred_info->data.slen );
-    }
-
-    AUTH_TRACE_((THIS_FILE, "  ha1=%.32s", ha1));
-
-    /***
-     *** ha2 = MD5(method ":" req_uri) 
-     ***/
-    md5_init(&pms);
-    MD5_APPEND( &pms, method->ptr, method->slen);
-    MD5_APPEND( &pms, ":", 1);
-    MD5_APPEND( &pms, uri->ptr, uri->slen);
-    md5_finish(&pms, digest);
-    digest2str(digest, ha2);
-
-    AUTH_TRACE_((THIS_FILE, "  ha2=%.32s", ha2));
-
-    /***
-     *** When qop is not used:
-     ***    response = MD5(ha1 ":" nonce ":" ha2) 
-     ***
-     *** When qop=auth is used:
-     ***    response = MD5(ha1 ":" nonce ":" nc ":" cnonce ":" qop ":" ha2)
-     ***/
-    md5_init(&pms);
-    MD5_APPEND( &pms, ha1, MD5STRLEN);
-    MD5_APPEND( &pms, ":", 1);
-    MD5_APPEND( &pms, nonce->ptr, nonce->slen);
-    if (qop && qop->slen != 0) {
-	MD5_APPEND( &pms, ":", 1);
-	MD5_APPEND( &pms, nc->ptr, nc->slen);
-	MD5_APPEND( &pms, ":", 1);
-	MD5_APPEND( &pms, cnonce->ptr, cnonce->slen);
-	MD5_APPEND( &pms, ":", 1);
-	MD5_APPEND( &pms, qop->ptr, qop->slen);
-    }
-    MD5_APPEND( &pms, ":", 1);
-    MD5_APPEND( &pms, ha2, MD5STRLEN);
-
-    /* This is the final response digest. */
-    md5_finish(&pms, digest);
-    
-    /* Convert digest to string and store in chal->response. */
-    result->slen = MD5STRLEN;
-    digest2str(digest, result->ptr);
-
-    AUTH_TRACE_((THIS_FILE, "  digest=%.32s", result->ptr));
-    AUTH_TRACE_((THIS_FILE, "Digest created"));
-}
-
-/*
- * Finds out if qop offer contains "auth" token.
- */
-static pj_bool_t has_auth_qop( pj_pool_t *pool, const pj_str_t *qop_offer)
-{
-    pj_str_t qop;
-    char *p;
-
-    pj_strdup_with_null( pool, &qop, qop_offer);
-    p = qop.ptr;
-    while (*p) {
-	*p = (char)pj_tolower(*p);
-	++p;
-    }
-
-    p = qop.ptr;
-    while (*p) {
-	if (*p=='a' && *(p+1)=='u' && *(p+2)=='t' && *(p+3)=='h') {
-	    int e = *(p+4);
-	    if (e=='"' || e==',' || e==0)
-		return PJ_TRUE;
-	    else
-		p += 4;
-	} else {
-	    ++p;
-	}
-    }
-
-    return PJ_FALSE;
-}
-
-/*
- * Generate response digest. 
- * Most of the parameters to generate the digest (i.e. username, realm, uri,
- * and nonce) are expected to be in the credential. Additional parameters (i.e.
- * password and method param) should be supplied in the argument.
- *
- * The resulting digest will be stored in cred->response.
- * The pool is used to allocate 32 bytes to store the digest in cred->response.
- */
-static pj_status_t respond_digest( pj_pool_t *pool,
-				   pjsip_digest_credential *cred,
-				   const pjsip_digest_challenge *chal,
-				   const pj_str_t *uri,
-				   const pjsip_cred_info *cred_info,
-				   const pj_str_t *cnonce,
-				   pj_uint32_t nc,
-				   const pj_str_t *method)
-{
-    /* Check algorithm is supported. We only support MD5. */
-    if (chal->algorithm.slen && pj_stricmp(&chal->algorithm, &pjsip_MD5_STR))
-    {
-	PJ_LOG(4,(THIS_FILE, "Unsupported digest algorithm \"%.*s\"",
-		  chal->algorithm.slen, chal->algorithm.ptr));
-	return -1;
-    }
-
-    /* Build digest credential from arguments. */
-    pj_strdup(pool, &cred->username, &cred_info->username);
-    pj_strdup(pool, &cred->realm, &chal->realm);
-    pj_strdup(pool, &cred->nonce, &chal->nonce);
-    pj_strdup(pool, &cred->uri, uri);
-    cred->algorithm = pjsip_MD5_STR;
-    pj_strdup(pool, &cred->opaque, &chal->opaque);
-    
-    /* Allocate memory. */
-    cred->response.ptr = pj_pool_alloc(pool, MD5STRLEN);
-    cred->response.slen = MD5STRLEN;
-
-    if (chal->qop.slen == 0) {
-	/* Server doesn't require quality of protection. */
-
-	/* Convert digest to string and store in chal->response. */
-	create_digest( &cred->response, &cred->nonce, NULL, NULL, NULL,
-		       uri, cred_info, method);
-
-    } else if (has_auth_qop(pool, &chal->qop)) {
-	/* Server requires quality of protection. 
-	 * We respond with selecting "qop=auth" protection.
-	 */
-	cred->qop = pjsip_AUTH_STR;
-	cred->nc.ptr = pj_pool_alloc(pool, 16);
-	pj_snprintf(cred->nc.ptr, 16, "%06u", nc);
-
-	if (cnonce && cnonce->slen) {
-	    pj_strdup(pool, &cred->cnonce, cnonce);
-	} else {
-	    pj_str_t dummy_cnonce = { "b39971", 6};
-	    pj_strdup(pool, &cred->cnonce, &dummy_cnonce);
-	}
-
-	create_digest( &cred->response, &cred->nonce, &cred->nc, cnonce, 
-		       &pjsip_AUTH_STR, uri, cred_info, method );
-
-    } else {
-	/* Server requires quality protection that we don't support. */
-	PJ_LOG(4,(THIS_FILE, "Unsupported qop offer %.*s", 
-		  chal->qop.slen, chal->qop.ptr));
-	return -1;
-    }
-
-    return 0;
-}
-
-#if PJSIP_AUTH_QOP_SUPPORT
-/*
- * Update authentication session with a challenge.
- */
-static void update_digest_session( pj_pool_t *ses_pool, 
-				   pjsip_auth_session *auth_sess,
-				   const pjsip_www_authenticate_hdr *hdr )
-{
-    if (hdr->challenge.digest.qop.slen == 0)
-	return;
-
-    /* Initialize cnonce and qop if not present. */
-    if (auth_sess->cnonce.slen == 0) {
-	/* Save the whole challenge */
-	auth_sess->last_chal = pjsip_hdr_clone(ses_pool, hdr);
-
-	/* Create cnonce */
-	pj_create_unique_string( ses_pool, &auth_sess->cnonce );
-
-	/* Initialize nonce-count */
-	auth_sess->nc = 1;
-
-	/* Save realm. */
-	pj_assert(auth_sess->realm.slen != 0);
-	if (auth_sess->realm.slen == 0) {
-	    pj_strdup(ses_pool, &auth_sess->realm, 
-		      &hdr->challenge.digest.realm);
-	}
-
-    } else {
-	/* Update last_nonce and nonce-count */
-	if (!pj_strcmp(&hdr->challenge.digest.nonce, 
-		       &auth_sess->last_chal->challenge.digest.nonce)) 
-	{
-	    /* Same nonce, increment nonce-count */
-	    ++auth_sess->nc;
-	} else {
-	    /* Server gives new nonce. */
-	    pj_strdup(ses_pool, &auth_sess->last_chal->challenge.digest.nonce,
-		      &hdr->challenge.digest.nonce);
-	    /* Has the opaque changed? */
-	    if (pj_strcmp(&auth_sess->last_chal->challenge.digest.opaque,
-			  &hdr->challenge.digest.opaque)) 
-	    {
-		pj_strdup(ses_pool, 
-			  &auth_sess->last_chal->challenge.digest.opaque,
-			  &hdr->challenge.digest.opaque);
-	    }
-	    auth_sess->nc = 1;
-	}
-    }
-}
-#endif	/* PJSIP_AUTH_QOP_SUPPORT */
-
-
-/* Find authentication session in the list. */
-static pjsip_auth_session *find_session( pjsip_auth_session *sess_list,
-					 const pj_str_t *realm )
-{
-    pjsip_auth_session *sess = sess_list->next;
-    while (sess != sess_list) {
-	if (pj_stricmp(&sess->realm, realm) == 0)
-	    return sess;
-	sess = sess->next;
-    }
-
-    return NULL;
-}
-
-/* 
- * Create Authorization/Proxy-Authorization response header based on the challege
- * in WWW-Authenticate/Proxy-Authenticate header.
- */
-PJ_DEF(pjsip_authorization_hdr*)
-pjsip_auth_respond( pj_pool_t *req_pool,
-		    const pjsip_www_authenticate_hdr *hdr,
-		    const pjsip_uri *uri,
-		    const pjsip_cred_info *cred_info,
-		    const pjsip_method *method,
-		    pj_pool_t *sess_pool,
-		    pjsip_auth_session *auth_sess)
-{
-    pjsip_authorization_hdr *auth;
-    char tmp[PJSIP_MAX_URL_SIZE];
-    pj_str_t uri_str;
-    pj_pool_t *pool;
-
-    pj_assert(hdr != NULL);
-    pj_assert(uri != NULL);
-    pj_assert(cred_info != NULL);
-    pj_assert(method != NULL);
-
-    /* Print URL in the original request. */
-    uri_str.ptr = tmp;
-    uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp, sizeof(tmp));
-    if (uri_str.slen < 1) {
-	pj_assert(!"URL is too long!");
-	PJ_LOG(4,(THIS_FILE, "Unable to authorize: URI is too long!"));
-	return NULL;
-    }
-
-#   if (PJSIP_AUTH_HEADER_CACHING)
-    {
-	pool = sess_pool;
-	PJ_UNUSED_ARG(req_pool);
-    }
-#   else
-    {
-	pool = req_pool;
-	PJ_UNUSED_ARG(sess_pool);
-    }
-#   endif
-
-    if (hdr->type == PJSIP_H_WWW_AUTHENTICATE)
-	auth = pjsip_authorization_hdr_create(pool);
-    else if (hdr->type == PJSIP_H_PROXY_AUTHENTICATE)
-	auth = pjsip_proxy_authorization_hdr_create(pool);
-    else {
-	pj_assert(0);
-	return NULL;
-    }
-
-    /* Only support digest scheme at the moment. */
-    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
-	pj_status_t rc;
-	pj_str_t *cnonce = NULL;
-	pj_uint32_t nc = 1;
-
-	/* Update the session (nonce-count etc) if required. */
-#	if PJSIP_AUTH_QOP_SUPPORT
-	{
-	    if (auth_sess) {
-		update_digest_session( sess_pool, auth_sess, hdr );
-
-		cnonce = &auth_sess->cnonce;
-		nc = auth_sess->nc;
-	    }
-	}
-#	endif	/* PJSIP_AUTH_QOP_SUPPORT */
-
-	auth->scheme = pjsip_DIGEST_STR;
-	rc = respond_digest( pool, &auth->credential.digest,
-			     &hdr->challenge.digest, &uri_str, cred_info,
-			     cnonce, nc, &method->name);
-	if (rc != 0)
-	    return NULL;
-
-	/* Set qop type in auth session the first time only. */
-	if (hdr->challenge.digest.qop.slen != 0 && auth_sess) {
-	    if (auth_sess->qop_value == PJSIP_AUTH_QOP_NONE) {
-		pj_str_t *qop_val = &auth->credential.digest.qop;
-		if (!pj_strcmp(qop_val, &pjsip_AUTH_STR)) {
-		    auth_sess->qop_value = PJSIP_AUTH_QOP_AUTH;
-		} else {
-		    auth_sess->qop_value = PJSIP_AUTH_QOP_UNKNOWN;
-		}
-	    }
-	}
-    } else {
-	auth = NULL;
-    }
-
-    /* Keep the new authorization header in the cache, only
-     * if no qop is not present.
-     */
-#   if PJSIP_AUTH_HEADER_CACHING
-    {
-	if (auth && auth_sess && auth_sess->qop_value == PJSIP_AUTH_QOP_NONE) {
-	    pjsip_cached_auth_hdr *cached_hdr;
-
-	    /* Delete old header with the same method. */
-	    cached_hdr = auth_sess->cached_hdr.next;
-	    while (cached_hdr != &auth_sess->cached_hdr) {
-		if (pjsip_method_cmp(method, &cached_hdr->method)==0)
-		    break;
-		cached_hdr = cached_hdr->next;
-	    }
-
-	    /* Save the header to the list. */
-	    if (cached_hdr != &auth_sess->cached_hdr) {
-		cached_hdr->hdr = auth;
-	    } else {
-		cached_hdr = pj_pool_alloc(pool, sizeof(*cached_hdr));
-		pjsip_method_copy( pool, &cached_hdr->method, method);
-		cached_hdr->hdr = auth;
-		pj_list_insert_before( &auth_sess->cached_hdr, cached_hdr );
-	    }
-	}
-    }
-#   endif
-
-    return auth;
-
-}
-
-/* Verify incoming Authorization/Proxy-Authorization header against existing
- * credentials. Will return TRUE if the authorization request matches any of
- * the credential.
- */
-PJ_DEF(pj_bool_t) pjsip_auth_verify(const pjsip_authorization_hdr *hdr,
-				    const pj_str_t *method,
-				    const pjsip_cred_info *cred_info )
-{
-    if (pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR) == 0) {
-	char digest_buf[MD5STRLEN];
-	pj_str_t digest;
-	const pjsip_digest_credential *dig = &hdr->credential.digest;
-
-	/* Check that username match. */
-	if (pj_strcmp(&dig->username, &cred_info->username) != 0)
-	    return PJ_FALSE;
-
-	/* Check that realm match. */
-	if (pj_strcmp(&dig->realm, &cred_info->realm) != 0)
-	    return PJ_FALSE;
-
-	/* Prepare for our digest calculation. */
-	digest.ptr = digest_buf;
-	digest.slen = MD5STRLEN;
-
-	/* Create digest for comparison. */
-	create_digest(  &digest, 
-			&hdr->credential.digest.nonce,
-			&hdr->credential.digest.nc, 
-			&hdr->credential.digest.cnonce,
-			&hdr->credential.digest.qop,
-			&hdr->credential.digest.uri,
-			cred_info, 
-			method );
-
-	return pj_stricmp(&digest, &hdr->credential.digest.response) == 0;
-
-    } else {
-	pj_assert(0);
-	return PJ_FALSE;
-    }
-}
-
-/* Find credential to use for the specified realm and scheme. */
-PJ_DEF(const pjsip_cred_info*) pjsip_auth_find_cred( unsigned count,
-						     const pjsip_cred_info cred[],
-						     const pj_str_t *realm,
-						     const pj_str_t *scheme)
-{
-    unsigned i;
-    PJ_UNUSED_ARG(scheme);
-    for (i=0; i<count; ++i) {
-	if (pj_stricmp(&cred[i].realm, realm) == 0)
-	    return &cred[i];
-    }
-    return NULL;
-}
-
-#if PJSIP_AUTH_AUTO_SEND_NEXT
-static void new_auth_for_req( pjsip_tx_data *tdata,
-			      pj_pool_t *sess_pool,
-			      pjsip_auth_session *sess,
-			      int cred_count,
-			      const pjsip_cred_info cred_info[])
-{
-    const pjsip_cred_info *cred;
-    pjsip_authorization_hdr *hauth;
-
-    pj_assert(sess->last_chal != NULL);
-
-    cred = pjsip_auth_find_cred( cred_count, cred_info, &sess->realm,
-				 &sess->last_chal->scheme );
-    if (!cred)
-	return;
-
-    
-    hauth = pjsip_auth_respond( tdata->pool, sess->last_chal,
-				tdata->msg->line.req.uri,
-				cred, &tdata->msg->line.req.method,
-				sess_pool, sess);
-    if (hauth) {
-	pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hauth);
-    }
-}
-#endif
-
-/* 
- * Initialize new request message with authorization headers.
- * This function will put Authorization/Proxy-Authorization headers to the
- * outgoing request message. If caching is enabled (PJSIP_AUTH_HEADER_CACHING)
- * and the session has previously sent Authorization/Proxy-Authorization header
- * with the same method, then the same Authorization/Proxy-Authorization header
- * will be resent from the cache only if qop is not present. If the stack is 
- * configured to automatically generate next Authorization/Proxy-Authorization
- * headers (PJSIP_AUTH_AUTO_SEND_NEXT flag), then new Authorization/Proxy-
- * Authorization headers are calculated and generated when they are not present
- * in the case or if authorization session has qop.
- *
- * If both PJSIP_AUTH_HEADER_CACHING flag and PJSIP_AUTH_AUTO_SEND_NEXT flag
- * are not set, this function will do nothing. The stack then will only send
- * Authorization/Proxy-Authorization to respond 401/407 response.
- */
-PJ_DEF(pj_status_t) pjsip_auth_init_req( pj_pool_t *sess_pool,
-					 pjsip_tx_data *tdata,
-					 pjsip_auth_session *sess_list,
-					 int cred_count, 
-					 const pjsip_cred_info cred_info[])
-{
-    pjsip_auth_session *sess;
-    pjsip_method *method = &tdata->msg->line.req.method;
-
-    pj_assert(tdata->msg->type == PJSIP_REQUEST_MSG);
-
-    if (!sess_list)
-	return 0;
-
-    sess = sess_list->next;
-    while (sess != sess_list) {
-	if (sess->qop_value == PJSIP_AUTH_QOP_NONE) {
-#	    if (PJSIP_AUTH_HEADER_CACHING)
-	    {
-		pjsip_cached_auth_hdr *entry = sess->cached_hdr.next;
-		while (entry != &sess->cached_hdr) {
-		    if (pjsip_method_cmp(&entry->method, method)==0) {
-			pjsip_authorization_hdr *hauth;
-			hauth = pjsip_hdr_shallow_clone(tdata->pool, entry->hdr);
-			pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
-		    } else {
-#			if (PJSIP_AUTH_AUTO_SEND_NEXT)
-			{
-			    new_auth_for_req( tdata, sess_pool, sess, 
-					      cred_count, cred_info);
-			}
-#			else
-			{
-			    PJ_UNUSED_ARG(sess_pool);
-			    PJ_UNUSED_ARG(cred_count);
-			    PJ_UNUSED_ARG(cred_info);
-			}
-#			endif	/* PJSIP_AUTH_AUTO_SEND_NEXT */
-		    }
-		    entry = entry->next;
-		}
-	    }
-#	    elif (PJSIP_AUTH_AUTO_SEND_NEXT)
-	    {
-		new_auth_for_req( tdata, sess_pool, sess, 
-				  cred_count, cred_info);
-	    }
-#	    else
-	    {
-		PJ_UNUSED_ARG(sess_pool);
-		PJ_UNUSED_ARG(cred_count);
-		PJ_UNUSED_ARG(cred_info);
-	    }
-#	    endif   /* PJSIP_AUTH_HEADER_CACHING */
-
-	} 
-#	if (PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT)
-	else if (sess->qop_value == PJSIP_AUTH_QOP_AUTH) {
-	    /* For qop="auth", we have to re-create the authorization header. 
-	     */
-	    const pjsip_cred_info *cred;
-	    pjsip_authorization_hdr *hauth;
-
-	    cred = pjsip_auth_find_cred( cred_count, cred_info, 
-					 &sess->realm, 
-					 &sess->last_chal->scheme);
-	    if (!cred) {
-		sess = sess->next;
-		continue;
-	    }
-
-	    hauth = pjsip_auth_respond( tdata->pool, sess->last_chal, 
-					tdata->msg->line.req.uri, 
-					cred,
-					&tdata->msg->line.req.method,
-					sess_pool, sess );
-	    if (hauth) {
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
-	    }
-	}
-#	endif	/* PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT */
-
-	sess = sess->next;
-    }
-    return 0;
-}
-
-/* Process authorization challenge */
-static pjsip_authorization_hdr *process_auth( pj_pool_t *req_pool,
-					      const pjsip_www_authenticate_hdr *hchal,
-					      const pjsip_uri *uri,
-					      pjsip_tx_data *tdata,
-					      int cred_count,
-					      const pjsip_cred_info cred_info[],
-					      pj_pool_t *ses_pool,
-					      pjsip_auth_session *auth_sess)
-{
-    const pjsip_cred_info *cred;
-    pjsip_authorization_hdr *sent_auth = NULL, *hauth;
-    pjsip_hdr *hdr;
-
-    /* See if we have sent authorization header for this realm */
-    hdr = tdata->msg->hdr.next;
-    while (hdr != &tdata->msg->hdr) {
-	if ((hchal->type == PJSIP_H_WWW_AUTHENTICATE &&
-	     hdr->type == PJSIP_H_AUTHORIZATION) ||
-	    (hchal->type == PJSIP_H_PROXY_AUTHENTICATE &&
-	     hdr->type == PJSIP_H_PROXY_AUTHORIZATION))
-	{
-	    sent_auth = (pjsip_authorization_hdr*) hdr;
-	    if (pj_stricmp(&hchal->challenge.common.realm, 
-			   &sent_auth->credential.common.realm )==0)
-	    {
-		break;
-	    }
-	}
-	hdr = hdr->next;
-    }
-
-    /* If we have sent, see if server rejected because of stale nonce or
-     * other causes.
-     */
-    if (hdr != &tdata->msg->hdr) {
-	if (hchal->challenge.digest.stale == 0) {
-	    /* Our credential is rejected. No point in trying to re-supply
-	     * the same credential.
-	     */
-	    PJ_LOG(4, (THIS_FILE, "Authorization failed for %.*s@%.*s",
-		       sent_auth->credential.digest.username.slen,
-		       sent_auth->credential.digest.username.ptr,
-		       sent_auth->credential.digest.realm.slen,
-		       sent_auth->credential.digest.realm.ptr));
-	    return NULL;
-	}
-
-	/* Otherwise remove old, stale authorization header from the mesasge.
-	 * We will supply a new one.
-	 */
-	pj_list_erase(sent_auth);
-    }
-
-    /* Find credential to be used for the challenge. */
-    cred = pjsip_auth_find_cred( cred_count, cred_info, 
-				 &hchal->challenge.common.realm, &hchal->scheme);
-    if (!cred) {
-	const pj_str_t *realm = &hchal->challenge.common.realm;
-	PJ_LOG(4,(THIS_FILE, 
-		  "Unable to set auth for %s: can not find credential for %.*s/%.*s",
-		  tdata->obj_name, 
-		  realm->slen, realm->ptr,
-		  hchal->scheme.slen, hchal->scheme.ptr));
-	return NULL;
-    }
-
-    /* Respond to authorization challenge. */
-    hauth = pjsip_auth_respond( req_pool, hchal, uri, cred, 
-				&tdata->msg->line.req.method, 
-				ses_pool, auth_sess);
-    return hauth;
-}
-
-
-/* Reinitialize outgoing request after 401/407 response is received.
- * The purpose of this function is:
- *  - to add a Authorization/Proxy-Authorization header.
- *  - to put the newly created Authorization/Proxy-Authorization header
- *    in cached_list.
- */
-PJ_DEF(pjsip_tx_data*) pjsip_auth_reinit_req( pjsip_endpoint *endpt, 
-					      pj_pool_t *ses_pool, 
-					      pjsip_auth_session *sess_list,
-					      int cred_count, 
-					      const pjsip_cred_info cred_info[],
-					      pjsip_tx_data *tdata, 
-					      const pjsip_rx_data *rdata)
-{
-    const pjsip_hdr *hdr;
-    pjsip_via_hdr *via;
-
-    PJ_UNUSED_ARG(endpt);
-
-    pj_assert(rdata->msg->type == PJSIP_RESPONSE_MSG);
-    pj_assert(rdata->msg->line.status.code == 401 ||
-	      rdata->msg->line.status.code == 407 );
-
-    /*
-     * Respond to each authentication challenge.
-     */
-    hdr = rdata->msg->hdr.next;
-    while (hdr != &rdata->msg->hdr) {
-	pjsip_auth_session *sess;
-	const pjsip_www_authenticate_hdr *hchal;
-	pjsip_authorization_hdr *hauth;
-
-	/* Find WWW-Authenticate or Proxy-Authenticate header. */
-	while (hdr->type != PJSIP_H_WWW_AUTHENTICATE &&
-	       hdr->type != PJSIP_H_PROXY_AUTHENTICATE &&
-	       hdr != &rdata->msg->hdr)
-	{
-	    hdr = hdr->next;
-	}
-	if (hdr == &rdata->msg->hdr)
-	    break;
-
-	hchal = (const pjsip_www_authenticate_hdr*) hdr;
-
-	/* Find authentication session for this realm, create a new one
-	 * if not present.
-	 */
-	sess = find_session(sess_list, &hchal->challenge.common.realm );
-	if (!sess) {
-	    sess = pj_pool_calloc( ses_pool, 1, sizeof(*sess));
-	    pj_strdup( ses_pool, &sess->realm, &hchal->challenge.common.realm);
-	    sess->is_proxy = (hchal->type == PJSIP_H_PROXY_AUTHENTICATE);
-#	    if (PJSIP_AUTH_HEADER_CACHING)
-	    {
-		pj_list_init(&sess->cached_hdr);
-	    }
-#	    endif
-	    pj_list_insert_before( sess_list, sess );
-	}
-
-	/* Create authorization header for this challenge, and update
-	 * authorization session.
-	 */
-	hauth = process_auth( tdata->pool, hchal, tdata->msg->line.req.uri, 
-			      tdata, cred_count, cred_info, ses_pool, sess );
-	if (!hauth)
-	    return NULL;
-
-	/* Add to the message. */
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
-
-	/* Process next header. */
-	hdr = hdr->next;
-    }
-
-
-    /* Remove branch param in Via header. */
-    via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
-    via->branch_param.slen = 0;
-
-    /* Increment reference counter. */
-    pjsip_tx_data_add_ref(tdata);
-
-    /* Done. */
-    return tdata;
-}
-
+

+/* Length of digest string. */

+#define MD5STRLEN 32

+

+/* Maximum stack size we use for storing username+realm+password etc. */

+#define MAX_TEMP  128

+

+/* A macro just to get rid of type mismatch between char and unsigned char */

+#define MD5_APPEND(pms,buf,len)	md5_append(pms, (const unsigned char*)buf, len)

+

+/* Logging. */

+#define THIS_FILE   "sip_auth.c"

+#if 0

+#  define AUTH_TRACE_(expr)  PJ_LOG(3, expr)

+#else

+#  define AUTH_TRACE_(expr)

+#endif

+

+static const char hex[] = "0123456789abcdef";

+

+/* Transform digest to string.

+ * output must be at least MD5STRLEN+1 bytes.

+ *

+ * NOTE: THE OUTPUT STRING IS NOT NULL TERMINATED!

+ */

+static void digest2str(const unsigned char digest[], char *output)

+{

+    char *p = output;

+    int i;

+

+    for (i = 0; i<16; ++i) {

+	int val = digest[i];

+	*p++ = hex[val >> 4];

+	*p++ = hex[val & 0x0F];

+    }

+}

+

+/*

+ * Create response digest based on the parameters and store the

+ * digest ASCII in 'result'. 

+ */

+static void create_digest( pj_str_t *result,

+			   const pj_str_t *nonce,

+			   const pj_str_t *nc,

+			   const pj_str_t *cnonce,

+			   const pj_str_t *qop,

+			   const pj_str_t *uri,

+			   const pjsip_cred_info *cred_info,

+			   const pj_str_t *method)

+{

+    char ha1[MD5STRLEN];

+    char ha2[MD5STRLEN];

+    unsigned char digest[16];

+    md5_state_t pms;

+

+    pj_assert(result->slen >= MD5STRLEN);

+

+    AUTH_TRACE_((THIS_FILE, "Begin creating digest"));

+

+    if (cred_info->data_type == PJSIP_CRED_DATA_PLAIN_PASSWD) {

+	/*** 

+	 *** ha1 = MD5(username ":" realm ":" password) 

+	 ***/

+	md5_init(&pms);

+	MD5_APPEND( &pms, cred_info->username.ptr, cred_info->username.slen);

+	MD5_APPEND( &pms, ":", 1);

+	MD5_APPEND( &pms, cred_info->realm.ptr, cred_info->realm.slen);

+	MD5_APPEND( &pms, ":", 1);

+	MD5_APPEND( &pms, cred_info->data.ptr, cred_info->data.slen);

+	md5_finish(&pms, digest);

+

+	digest2str(digest, ha1);

+

+    } else if (cred_info->data_type == PJSIP_CRED_DATA_DIGEST) {

+	pj_assert(cred_info->data.slen == 32);

+	pj_memcpy( ha1, cred_info->data.ptr, cred_info->data.slen );

+    }

+

+    AUTH_TRACE_((THIS_FILE, "  ha1=%.32s", ha1));

+

+    /***

+     *** ha2 = MD5(method ":" req_uri) 

+     ***/

+    md5_init(&pms);

+    MD5_APPEND( &pms, method->ptr, method->slen);

+    MD5_APPEND( &pms, ":", 1);

+    MD5_APPEND( &pms, uri->ptr, uri->slen);

+    md5_finish(&pms, digest);

+    digest2str(digest, ha2);

+

+    AUTH_TRACE_((THIS_FILE, "  ha2=%.32s", ha2));

+

+    /***

+     *** When qop is not used:

+     ***    response = MD5(ha1 ":" nonce ":" ha2) 

+     ***

+     *** When qop=auth is used:

+     ***    response = MD5(ha1 ":" nonce ":" nc ":" cnonce ":" qop ":" ha2)

+     ***/

+    md5_init(&pms);

+    MD5_APPEND( &pms, ha1, MD5STRLEN);

+    MD5_APPEND( &pms, ":", 1);

+    MD5_APPEND( &pms, nonce->ptr, nonce->slen);

+    if (qop && qop->slen != 0) {

+	MD5_APPEND( &pms, ":", 1);

+	MD5_APPEND( &pms, nc->ptr, nc->slen);

+	MD5_APPEND( &pms, ":", 1);

+	MD5_APPEND( &pms, cnonce->ptr, cnonce->slen);

+	MD5_APPEND( &pms, ":", 1);

+	MD5_APPEND( &pms, qop->ptr, qop->slen);

+    }

+    MD5_APPEND( &pms, ":", 1);

+    MD5_APPEND( &pms, ha2, MD5STRLEN);

+

+    /* This is the final response digest. */

+    md5_finish(&pms, digest);

+    

+    /* Convert digest to string and store in chal->response. */

+    result->slen = MD5STRLEN;

+    digest2str(digest, result->ptr);

+

+    AUTH_TRACE_((THIS_FILE, "  digest=%.32s", result->ptr));

+    AUTH_TRACE_((THIS_FILE, "Digest created"));

+}

+

+/*

+ * Finds out if qop offer contains "auth" token.

+ */

+static pj_bool_t has_auth_qop( pj_pool_t *pool, const pj_str_t *qop_offer)

+{

+    pj_str_t qop;

+    char *p;

+

+    pj_strdup_with_null( pool, &qop, qop_offer);

+    p = qop.ptr;

+    while (*p) {

+	*p = (char)pj_tolower(*p);

+	++p;

+    }

+

+    p = qop.ptr;

+    while (*p) {

+	if (*p=='a' && *(p+1)=='u' && *(p+2)=='t' && *(p+3)=='h') {

+	    int e = *(p+4);

+	    if (e=='"' || e==',' || e==0)

+		return PJ_TRUE;

+	    else

+		p += 4;

+	} else {

+	    ++p;

+	}

+    }

+

+    return PJ_FALSE;

+}

+

+/*

+ * Generate response digest. 

+ * Most of the parameters to generate the digest (i.e. username, realm, uri,

+ * and nonce) are expected to be in the credential. Additional parameters (i.e.

+ * password and method param) should be supplied in the argument.

+ *

+ * The resulting digest will be stored in cred->response.

+ * The pool is used to allocate 32 bytes to store the digest in cred->response.

+ */

+static pj_status_t respond_digest( pj_pool_t *pool,

+				   pjsip_digest_credential *cred,

+				   const pjsip_digest_challenge *chal,

+				   const pj_str_t *uri,

+				   const pjsip_cred_info *cred_info,

+				   const pj_str_t *cnonce,

+				   pj_uint32_t nc,

+				   const pj_str_t *method)

+{

+    /* Check algorithm is supported. We only support MD5. */

+    if (chal->algorithm.slen && pj_stricmp(&chal->algorithm, &pjsip_MD5_STR))

+    {

+	PJ_LOG(4,(THIS_FILE, "Unsupported digest algorithm \"%.*s\"",

+		  chal->algorithm.slen, chal->algorithm.ptr));

+	return -1;

+    }

+

+    /* Build digest credential from arguments. */

+    pj_strdup(pool, &cred->username, &cred_info->username);

+    pj_strdup(pool, &cred->realm, &chal->realm);

+    pj_strdup(pool, &cred->nonce, &chal->nonce);

+    pj_strdup(pool, &cred->uri, uri);

+    cred->algorithm = pjsip_MD5_STR;

+    pj_strdup(pool, &cred->opaque, &chal->opaque);

+    

+    /* Allocate memory. */

+    cred->response.ptr = pj_pool_alloc(pool, MD5STRLEN);

+    cred->response.slen = MD5STRLEN;

+

+    if (chal->qop.slen == 0) {

+	/* Server doesn't require quality of protection. */

+

+	/* Convert digest to string and store in chal->response. */

+	create_digest( &cred->response, &cred->nonce, NULL, NULL, NULL,

+		       uri, cred_info, method);

+

+    } else if (has_auth_qop(pool, &chal->qop)) {

+	/* Server requires quality of protection. 

+	 * We respond with selecting "qop=auth" protection.

+	 */

+	cred->qop = pjsip_AUTH_STR;

+	cred->nc.ptr = pj_pool_alloc(pool, 16);

+	pj_snprintf(cred->nc.ptr, 16, "%06u", nc);

+

+	if (cnonce && cnonce->slen) {

+	    pj_strdup(pool, &cred->cnonce, cnonce);

+	} else {

+	    pj_str_t dummy_cnonce = { "b39971", 6};

+	    pj_strdup(pool, &cred->cnonce, &dummy_cnonce);

+	}

+

+	create_digest( &cred->response, &cred->nonce, &cred->nc, cnonce, 

+		       &pjsip_AUTH_STR, uri, cred_info, method );

+

+    } else {

+	/* Server requires quality protection that we don't support. */

+	PJ_LOG(4,(THIS_FILE, "Unsupported qop offer %.*s", 

+		  chal->qop.slen, chal->qop.ptr));

+	return -1;

+    }

+

+    return 0;

+}

+

+#if PJSIP_AUTH_QOP_SUPPORT

+/*

+ * Update authentication session with a challenge.

+ */

+static void update_digest_session( pj_pool_t *ses_pool, 

+				   pjsip_auth_session *auth_sess,

+				   const pjsip_www_authenticate_hdr *hdr )

+{

+    if (hdr->challenge.digest.qop.slen == 0)

+	return;

+

+    /* Initialize cnonce and qop if not present. */

+    if (auth_sess->cnonce.slen == 0) {

+	/* Save the whole challenge */

+	auth_sess->last_chal = pjsip_hdr_clone(ses_pool, hdr);

+

+	/* Create cnonce */

+	pj_create_unique_string( ses_pool, &auth_sess->cnonce );

+

+	/* Initialize nonce-count */

+	auth_sess->nc = 1;

+

+	/* Save realm. */

+	pj_assert(auth_sess->realm.slen != 0);

+	if (auth_sess->realm.slen == 0) {

+	    pj_strdup(ses_pool, &auth_sess->realm, 

+		      &hdr->challenge.digest.realm);

+	}

+

+    } else {

+	/* Update last_nonce and nonce-count */

+	if (!pj_strcmp(&hdr->challenge.digest.nonce, 

+		       &auth_sess->last_chal->challenge.digest.nonce)) 

+	{

+	    /* Same nonce, increment nonce-count */

+	    ++auth_sess->nc;

+	} else {

+	    /* Server gives new nonce. */

+	    pj_strdup(ses_pool, &auth_sess->last_chal->challenge.digest.nonce,

+		      &hdr->challenge.digest.nonce);

+	    /* Has the opaque changed? */

+	    if (pj_strcmp(&auth_sess->last_chal->challenge.digest.opaque,

+			  &hdr->challenge.digest.opaque)) 

+	    {

+		pj_strdup(ses_pool, 

+			  &auth_sess->last_chal->challenge.digest.opaque,

+			  &hdr->challenge.digest.opaque);

+	    }

+	    auth_sess->nc = 1;

+	}

+    }

+}

+#endif	/* PJSIP_AUTH_QOP_SUPPORT */

+

+

+/* Find authentication session in the list. */

+static pjsip_auth_session *find_session( pjsip_auth_session *sess_list,

+					 const pj_str_t *realm )

+{

+    pjsip_auth_session *sess = sess_list->next;

+    while (sess != sess_list) {

+	if (pj_stricmp(&sess->realm, realm) == 0)

+	    return sess;

+	sess = sess->next;

+    }

+

+    return NULL;

+}

+

+/* 

+ * Create Authorization/Proxy-Authorization response header based on the challege

+ * in WWW-Authenticate/Proxy-Authenticate header.

+ */

+PJ_DEF(pjsip_authorization_hdr*)

+pjsip_auth_respond( pj_pool_t *req_pool,

+		    const pjsip_www_authenticate_hdr *hdr,

+		    const pjsip_uri *uri,

+		    const pjsip_cred_info *cred_info,

+		    const pjsip_method *method,

+		    pj_pool_t *sess_pool,

+		    pjsip_auth_session *auth_sess)

+{

+    pjsip_authorization_hdr *auth;

+    char tmp[PJSIP_MAX_URL_SIZE];

+    pj_str_t uri_str;

+    pj_pool_t *pool;

+

+    pj_assert(hdr != NULL);

+    pj_assert(uri != NULL);

+    pj_assert(cred_info != NULL);

+    pj_assert(method != NULL);

+

+    /* Print URL in the original request. */

+    uri_str.ptr = tmp;

+    uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp, sizeof(tmp));

+    if (uri_str.slen < 1) {

+	pj_assert(!"URL is too long!");

+	PJ_LOG(4,(THIS_FILE, "Unable to authorize: URI is too long!"));

+	return NULL;

+    }

+

+#   if (PJSIP_AUTH_HEADER_CACHING)

+    {

+	pool = sess_pool;

+	PJ_UNUSED_ARG(req_pool);

+    }

+#   else

+    {

+	pool = req_pool;

+	PJ_UNUSED_ARG(sess_pool);

+    }

+#   endif

+

+    if (hdr->type == PJSIP_H_WWW_AUTHENTICATE)

+	auth = pjsip_authorization_hdr_create(pool);

+    else if (hdr->type == PJSIP_H_PROXY_AUTHENTICATE)

+	auth = pjsip_proxy_authorization_hdr_create(pool);

+    else {

+	pj_assert(0);

+	return NULL;

+    }

+

+    /* Only support digest scheme at the moment. */

+    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {

+	pj_status_t rc;

+	pj_str_t *cnonce = NULL;

+	pj_uint32_t nc = 1;

+

+	/* Update the session (nonce-count etc) if required. */

+#	if PJSIP_AUTH_QOP_SUPPORT

+	{

+	    if (auth_sess) {

+		update_digest_session( sess_pool, auth_sess, hdr );

+

+		cnonce = &auth_sess->cnonce;

+		nc = auth_sess->nc;

+	    }

+	}

+#	endif	/* PJSIP_AUTH_QOP_SUPPORT */

+

+	auth->scheme = pjsip_DIGEST_STR;

+	rc = respond_digest( pool, &auth->credential.digest,

+			     &hdr->challenge.digest, &uri_str, cred_info,

+			     cnonce, nc, &method->name);

+	if (rc != 0)

+	    return NULL;

+

+	/* Set qop type in auth session the first time only. */

+	if (hdr->challenge.digest.qop.slen != 0 && auth_sess) {

+	    if (auth_sess->qop_value == PJSIP_AUTH_QOP_NONE) {

+		pj_str_t *qop_val = &auth->credential.digest.qop;

+		if (!pj_strcmp(qop_val, &pjsip_AUTH_STR)) {

+		    auth_sess->qop_value = PJSIP_AUTH_QOP_AUTH;

+		} else {

+		    auth_sess->qop_value = PJSIP_AUTH_QOP_UNKNOWN;

+		}

+	    }

+	}

+    } else {

+	auth = NULL;

+    }

+

+    /* Keep the new authorization header in the cache, only

+     * if no qop is not present.

+     */

+#   if PJSIP_AUTH_HEADER_CACHING

+    {

+	if (auth && auth_sess && auth_sess->qop_value == PJSIP_AUTH_QOP_NONE) {

+	    pjsip_cached_auth_hdr *cached_hdr;

+

+	    /* Delete old header with the same method. */

+	    cached_hdr = auth_sess->cached_hdr.next;

+	    while (cached_hdr != &auth_sess->cached_hdr) {

+		if (pjsip_method_cmp(method, &cached_hdr->method)==0)

+		    break;

+		cached_hdr = cached_hdr->next;

+	    }

+

+	    /* Save the header to the list. */

+	    if (cached_hdr != &auth_sess->cached_hdr) {

+		cached_hdr->hdr = auth;

+	    } else {

+		cached_hdr = pj_pool_alloc(pool, sizeof(*cached_hdr));

+		pjsip_method_copy( pool, &cached_hdr->method, method);

+		cached_hdr->hdr = auth;

+		pj_list_insert_before( &auth_sess->cached_hdr, cached_hdr );

+	    }

+	}

+    }

+#   endif

+

+    return auth;

+

+}

+

+/* Verify incoming Authorization/Proxy-Authorization header against existing

+ * credentials. Will return TRUE if the authorization request matches any of

+ * the credential.

+ */

+PJ_DEF(pj_bool_t) pjsip_auth_verify(const pjsip_authorization_hdr *hdr,

+				    const pj_str_t *method,

+				    const pjsip_cred_info *cred_info )

+{

+    if (pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR) == 0) {

+	char digest_buf[MD5STRLEN];

+	pj_str_t digest;

+	const pjsip_digest_credential *dig = &hdr->credential.digest;

+

+	/* Check that username match. */

+	if (pj_strcmp(&dig->username, &cred_info->username) != 0)

+	    return PJ_FALSE;

+

+	/* Check that realm match. */

+	if (pj_strcmp(&dig->realm, &cred_info->realm) != 0)

+	    return PJ_FALSE;

+

+	/* Prepare for our digest calculation. */

+	digest.ptr = digest_buf;

+	digest.slen = MD5STRLEN;

+

+	/* Create digest for comparison. */

+	create_digest(  &digest, 

+			&hdr->credential.digest.nonce,

+			&hdr->credential.digest.nc, 

+			&hdr->credential.digest.cnonce,

+			&hdr->credential.digest.qop,

+			&hdr->credential.digest.uri,

+			cred_info, 

+			method );

+

+	return pj_stricmp(&digest, &hdr->credential.digest.response) == 0;

+

+    } else {

+	pj_assert(0);

+	return PJ_FALSE;

+    }

+}

+

+/* Find credential to use for the specified realm and scheme. */

+PJ_DEF(const pjsip_cred_info*) pjsip_auth_find_cred( unsigned count,

+						     const pjsip_cred_info cred[],

+						     const pj_str_t *realm,

+						     const pj_str_t *scheme)

+{

+    unsigned i;

+    PJ_UNUSED_ARG(scheme);

+    for (i=0; i<count; ++i) {

+	if (pj_stricmp(&cred[i].realm, realm) == 0)

+	    return &cred[i];

+    }

+    return NULL;

+}

+

+#if PJSIP_AUTH_AUTO_SEND_NEXT

+static void new_auth_for_req( pjsip_tx_data *tdata,

+			      pj_pool_t *sess_pool,

+			      pjsip_auth_session *sess,

+			      int cred_count,

+			      const pjsip_cred_info cred_info[])

+{

+    const pjsip_cred_info *cred;

+    pjsip_authorization_hdr *hauth;

+

+    pj_assert(sess->last_chal != NULL);

+

+    cred = pjsip_auth_find_cred( cred_count, cred_info, &sess->realm,

+				 &sess->last_chal->scheme );

+    if (!cred)

+	return;

+

+    

+    hauth = pjsip_auth_respond( tdata->pool, sess->last_chal,

+				tdata->msg->line.req.uri,

+				cred, &tdata->msg->line.req.method,

+				sess_pool, sess);

+    if (hauth) {

+	pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hauth);

+    }

+}

+#endif

+

+/* 

+ * Initialize new request message with authorization headers.

+ * This function will put Authorization/Proxy-Authorization headers to the

+ * outgoing request message. If caching is enabled (PJSIP_AUTH_HEADER_CACHING)

+ * and the session has previously sent Authorization/Proxy-Authorization header

+ * with the same method, then the same Authorization/Proxy-Authorization header

+ * will be resent from the cache only if qop is not present. If the stack is 

+ * configured to automatically generate next Authorization/Proxy-Authorization

+ * headers (PJSIP_AUTH_AUTO_SEND_NEXT flag), then new Authorization/Proxy-

+ * Authorization headers are calculated and generated when they are not present

+ * in the case or if authorization session has qop.

+ *

+ * If both PJSIP_AUTH_HEADER_CACHING flag and PJSIP_AUTH_AUTO_SEND_NEXT flag

+ * are not set, this function will do nothing. The stack then will only send

+ * Authorization/Proxy-Authorization to respond 401/407 response.

+ */

+PJ_DEF(pj_status_t) pjsip_auth_init_req( pj_pool_t *sess_pool,

+					 pjsip_tx_data *tdata,

+					 pjsip_auth_session *sess_list,

+					 int cred_count, 

+					 const pjsip_cred_info cred_info[])

+{

+    pjsip_auth_session *sess;

+    pjsip_method *method = &tdata->msg->line.req.method;

+

+    pj_assert(tdata->msg->type == PJSIP_REQUEST_MSG);

+

+    if (!sess_list)

+	return 0;

+

+    sess = sess_list->next;

+    while (sess != sess_list) {

+	if (sess->qop_value == PJSIP_AUTH_QOP_NONE) {

+#	    if (PJSIP_AUTH_HEADER_CACHING)

+	    {

+		pjsip_cached_auth_hdr *entry = sess->cached_hdr.next;

+		while (entry != &sess->cached_hdr) {

+		    if (pjsip_method_cmp(&entry->method, method)==0) {

+			pjsip_authorization_hdr *hauth;

+			hauth = pjsip_hdr_shallow_clone(tdata->pool, entry->hdr);

+			pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);

+		    } else {

+#			if (PJSIP_AUTH_AUTO_SEND_NEXT)

+			{

+			    new_auth_for_req( tdata, sess_pool, sess, 

+					      cred_count, cred_info);

+			}

+#			else

+			{

+			    PJ_UNUSED_ARG(sess_pool);

+			    PJ_UNUSED_ARG(cred_count);

+			    PJ_UNUSED_ARG(cred_info);

+			}

+#			endif	/* PJSIP_AUTH_AUTO_SEND_NEXT */

+		    }

+		    entry = entry->next;

+		}

+	    }

+#	    elif (PJSIP_AUTH_AUTO_SEND_NEXT)

+	    {

+		new_auth_for_req( tdata, sess_pool, sess, 

+				  cred_count, cred_info);

+	    }

+#	    else

+	    {

+		PJ_UNUSED_ARG(sess_pool);

+		PJ_UNUSED_ARG(cred_count);

+		PJ_UNUSED_ARG(cred_info);

+	    }

+#	    endif   /* PJSIP_AUTH_HEADER_CACHING */

+

+	} 

+#	if (PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT)

+	else if (sess->qop_value == PJSIP_AUTH_QOP_AUTH) {

+	    /* For qop="auth", we have to re-create the authorization header. 

+	     */

+	    const pjsip_cred_info *cred;

+	    pjsip_authorization_hdr *hauth;

+

+	    cred = pjsip_auth_find_cred( cred_count, cred_info, 

+					 &sess->realm, 

+					 &sess->last_chal->scheme);

+	    if (!cred) {

+		sess = sess->next;

+		continue;

+	    }

+

+	    hauth = pjsip_auth_respond( tdata->pool, sess->last_chal, 

+					tdata->msg->line.req.uri, 

+					cred,

+					&tdata->msg->line.req.method,

+					sess_pool, sess );

+	    if (hauth) {

+		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);

+	    }

+	}

+#	endif	/* PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT */

+

+	sess = sess->next;

+    }

+    return 0;

+}

+

+/* Process authorization challenge */

+static pjsip_authorization_hdr *process_auth( pj_pool_t *req_pool,

+					      const pjsip_www_authenticate_hdr *hchal,

+					      const pjsip_uri *uri,

+					      pjsip_tx_data *tdata,

+					      int cred_count,

+					      const pjsip_cred_info cred_info[],

+					      pj_pool_t *ses_pool,

+					      pjsip_auth_session *auth_sess)

+{

+    const pjsip_cred_info *cred;

+    pjsip_authorization_hdr *sent_auth = NULL, *hauth;

+    pjsip_hdr *hdr;

+

+    /* See if we have sent authorization header for this realm */

+    hdr = tdata->msg->hdr.next;

+    while (hdr != &tdata->msg->hdr) {

+	if ((hchal->type == PJSIP_H_WWW_AUTHENTICATE &&

+	     hdr->type == PJSIP_H_AUTHORIZATION) ||

+	    (hchal->type == PJSIP_H_PROXY_AUTHENTICATE &&

+	     hdr->type == PJSIP_H_PROXY_AUTHORIZATION))

+	{

+	    sent_auth = (pjsip_authorization_hdr*) hdr;

+	    if (pj_stricmp(&hchal->challenge.common.realm, 

+			   &sent_auth->credential.common.realm )==0)

+	    {

+		break;

+	    }

+	}

+	hdr = hdr->next;

+    }

+

+    /* If we have sent, see if server rejected because of stale nonce or

+     * other causes.

+     */

+    if (hdr != &tdata->msg->hdr) {

+	if (hchal->challenge.digest.stale == 0) {

+	    /* Our credential is rejected. No point in trying to re-supply

+	     * the same credential.

+	     */

+	    PJ_LOG(4, (THIS_FILE, "Authorization failed for %.*s@%.*s",

+		       sent_auth->credential.digest.username.slen,

+		       sent_auth->credential.digest.username.ptr,

+		       sent_auth->credential.digest.realm.slen,

+		       sent_auth->credential.digest.realm.ptr));

+	    return NULL;

+	}

+

+	/* Otherwise remove old, stale authorization header from the mesasge.

+	 * We will supply a new one.

+	 */

+	pj_list_erase(sent_auth);

+    }

+

+    /* Find credential to be used for the challenge. */

+    cred = pjsip_auth_find_cred( cred_count, cred_info, 

+				 &hchal->challenge.common.realm, &hchal->scheme);

+    if (!cred) {

+	const pj_str_t *realm = &hchal->challenge.common.realm;

+	PJ_LOG(4,(THIS_FILE, 

+		  "Unable to set auth for %s: can not find credential for %.*s/%.*s",

+		  tdata->obj_name, 

+		  realm->slen, realm->ptr,

+		  hchal->scheme.slen, hchal->scheme.ptr));

+	return NULL;

+    }

+

+    /* Respond to authorization challenge. */

+    hauth = pjsip_auth_respond( req_pool, hchal, uri, cred, 

+				&tdata->msg->line.req.method, 

+				ses_pool, auth_sess);

+    return hauth;

+}

+

+

+/* Reinitialize outgoing request after 401/407 response is received.

+ * The purpose of this function is:

+ *  - to add a Authorization/Proxy-Authorization header.

+ *  - to put the newly created Authorization/Proxy-Authorization header

+ *    in cached_list.

+ */

+PJ_DEF(pjsip_tx_data*) pjsip_auth_reinit_req( pjsip_endpoint *endpt, 

+					      pj_pool_t *ses_pool, 

+					      pjsip_auth_session *sess_list,

+					      int cred_count, 

+					      const pjsip_cred_info cred_info[],

+					      pjsip_tx_data *tdata, 

+					      const pjsip_rx_data *rdata)

+{

+    const pjsip_hdr *hdr;

+    pjsip_via_hdr *via;

+

+    PJ_UNUSED_ARG(endpt);

+

+    pj_assert(rdata->msg->type == PJSIP_RESPONSE_MSG);

+    pj_assert(rdata->msg->line.status.code == 401 ||

+	      rdata->msg->line.status.code == 407 );

+

+    /*

+     * Respond to each authentication challenge.

+     */

+    hdr = rdata->msg->hdr.next;

+    while (hdr != &rdata->msg->hdr) {

+	pjsip_auth_session *sess;

+	const pjsip_www_authenticate_hdr *hchal;

+	pjsip_authorization_hdr *hauth;

+

+	/* Find WWW-Authenticate or Proxy-Authenticate header. */

+	while (hdr->type != PJSIP_H_WWW_AUTHENTICATE &&

+	       hdr->type != PJSIP_H_PROXY_AUTHENTICATE &&

+	       hdr != &rdata->msg->hdr)

+	{

+	    hdr = hdr->next;

+	}

+	if (hdr == &rdata->msg->hdr)

+	    break;

+

+	hchal = (const pjsip_www_authenticate_hdr*) hdr;

+

+	/* Find authentication session for this realm, create a new one

+	 * if not present.

+	 */

+	sess = find_session(sess_list, &hchal->challenge.common.realm );

+	if (!sess) {

+	    sess = pj_pool_calloc( ses_pool, 1, sizeof(*sess));

+	    pj_strdup( ses_pool, &sess->realm, &hchal->challenge.common.realm);

+	    sess->is_proxy = (hchal->type == PJSIP_H_PROXY_AUTHENTICATE);

+#	    if (PJSIP_AUTH_HEADER_CACHING)

+	    {

+		pj_list_init(&sess->cached_hdr);

+	    }

+#	    endif

+	    pj_list_insert_before( sess_list, sess );

+	}

+

+	/* Create authorization header for this challenge, and update

+	 * authorization session.

+	 */

+	hauth = process_auth( tdata->pool, hchal, tdata->msg->line.req.uri, 

+			      tdata, cred_count, cred_info, ses_pool, sess );

+	if (!hauth)

+	    return NULL;

+

+	/* Add to the message. */

+	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);

+

+	/* Process next header. */

+	hdr = hdr->next;

+    }

+

+

+    /* Remove branch param in Via header. */

+    via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);

+    via->branch_param.slen = 0;

+

+    /* Increment reference counter. */

+    pjsip_tx_data_add_ref(tdata);

+

+    /* Done. */

+    return tdata;

+}

+

diff --git a/pjsip/src/pjsip/sip_auth_msg.c b/pjsip/src/pjsip/sip_auth_msg.c
index 9e88ef4..b9fe296 100644
--- a/pjsip/src/pjsip/sip_auth_msg.c
+++ b/pjsip/src/pjsip/sip_auth_msg.c
@@ -1,294 +1,316 @@
-/* $Id$
- */
-#include <pjsip/sip_auth_msg.h>
-#include <pjsip/sip_auth_parser.h>
-#include <pj/pool.h>
-#include <pj/list.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_auth_msg.h>

+#include <pjsip/sip_auth_parser.h>

+#include <pj/pool.h>

+#include <pj/list.h>

 #include <pj/string.h>

-#include <pj/assert.h>
-#include <pjsip/print_util.h>
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Authorization and Proxy-Authorization header.
- */
-static pjsip_authorization_hdr* pjsip_authorization_hdr_clone( pj_pool_t *pool,
-							       const pjsip_authorization_hdr *hdr);
-static pjsip_authorization_hdr* pjsip_authorization_hdr_shallow_clone( pj_pool_t *pool,
-								       const pjsip_authorization_hdr *hdr);
-static int pjsip_authorization_hdr_print( pjsip_authorization_hdr *hdr,
-					  char *buf, pj_size_t size);
-
-static pjsip_hdr_vptr authorization_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_authorization_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_authorization_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_authorization_hdr_print,
-};
-
-
-PJ_DEF(pjsip_authorization_hdr*) pjsip_authorization_hdr_create(pj_pool_t *pool)
-{
-    pjsip_authorization_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_AUTHORIZATION, &authorization_hdr_vptr);
-    return hdr;
-}
-
-PJ_DEF(pjsip_proxy_authorization_hdr*) pjsip_proxy_authorization_hdr_create(pj_pool_t *pool)
-{
-    pjsip_proxy_authorization_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_PROXY_AUTHORIZATION, &authorization_hdr_vptr);
-    return hdr;
-}
-
-static int print_digest_credential(pjsip_digest_credential *cred, char *buf, pj_size_t size)
-{
-    int printed;
-    char *startbuf = buf;
-    char *endbuf = buf + size;
-    
-    copy_advance_pair_quote_cond(buf, "username=", 9, cred->username, '"', '"');
-    copy_advance_pair_quote_cond(buf, ", realm=", 8, cred->realm, '"', '"');
-    copy_advance_pair_quote_cond(buf, ", nonce=", 8, cred->nonce, '"', '"');
-    copy_advance_pair_quote_cond(buf, ", uri=", 6, cred->uri, '"', '"');
-    copy_advance_pair_quote_cond(buf, ", response=", 11, cred->response, '"', '"');
-    copy_advance_pair(buf, ", algorithm=", 12, cred->algorithm);
-    copy_advance_pair_quote_cond(buf, ", cnonce=", 9, cred->cnonce, '"', '"');
-    copy_advance_pair_quote_cond(buf, ", opaque=", 9, cred->opaque, '"', '"');
-    //Note: there's no dbl-quote in qop in Authorization header 
-    // (unlike WWW-Authenticate)
-    //copy_advance_pair_quote_cond(buf, ", qop=", 6, cred->qop, '"', '"');
-    copy_advance_pair(buf, ", qop=", 6, cred->qop);
-    copy_advance_pair(buf, ", nc=", 5, cred->nc);
-    copy_advance(buf, cred->other_param);
-
-    return (int) (buf-startbuf);
-}
-
-static int print_pgp_credential(pjsip_pgp_credential *cred, char *buf, pj_size_t size)
-{
-    PJ_UNUSED_ARG(cred);
-    PJ_UNUSED_ARG(buf);
-    PJ_UNUSED_ARG(size);
-    return -1;
-}
-
-static int pjsip_authorization_hdr_print( pjsip_authorization_hdr *hdr,
-					  char *buf, pj_size_t size)
-{
-    int printed;
-    char *startbuf = buf;
-    char *endbuf = buf + size;
-
-    copy_advance(buf, hdr->name);
-    *buf++ = ':';
-    *buf++ = ' ';
-
-    copy_advance(buf, hdr->scheme);
-    *buf++ = ' ';
-
-    if (pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR) == 0)
-    {
-	printed = print_digest_credential(&hdr->credential.digest, buf, endbuf - buf);
-    } 
-    else if (pj_stricmp(&hdr->scheme, &pjsip_PGP_STR) == 0)
-    {
-	printed = print_pgp_credential(&hdr->credential.pgp, buf, endbuf - buf);
-    } 
-    else {
-	pj_assert(0);
-	return -1;
-    }
-
-    if (printed == -1)
-	return -1;
-
-    buf += printed;
-    *buf = '\0';
-    return (int)(buf-startbuf);
-}
-
-static pjsip_authorization_hdr* pjsip_authorization_hdr_clone(  pj_pool_t *pool,
-								const pjsip_authorization_hdr *rhs)
-{
-    /* This function also serves Proxy-Authorization header. */
-    pjsip_authorization_hdr *hdr;
-    if (rhs->type == PJSIP_H_AUTHORIZATION)
-	hdr = pjsip_authorization_hdr_create(pool);
-    else
-	hdr = pjsip_proxy_authorization_hdr_create(pool);
-
-    pj_strdup(pool, &hdr->scheme, &rhs->scheme);
-
-    if (pj_stricmp2(&hdr->scheme, "digest") == 0) {
-	pj_strdup(pool, &hdr->credential.digest.username, &rhs->credential.digest.username);
-	pj_strdup(pool, &hdr->credential.digest.realm, &rhs->credential.digest.realm);
-	pj_strdup(pool, &hdr->credential.digest.nonce, &rhs->credential.digest.nonce);
-	pj_strdup(pool, &hdr->credential.digest.uri, &rhs->credential.digest.uri);
-	pj_strdup(pool, &hdr->credential.digest.response, &rhs->credential.digest.response);
-	pj_strdup(pool, &hdr->credential.digest.algorithm, &rhs->credential.digest.algorithm);
-	pj_strdup(pool, &hdr->credential.digest.cnonce, &rhs->credential.digest.cnonce);
-	pj_strdup(pool, &hdr->credential.digest.opaque, &rhs->credential.digest.opaque);
-	pj_strdup(pool, &hdr->credential.digest.qop, &rhs->credential.digest.qop);
-	pj_strdup(pool, &hdr->credential.digest.nc, &rhs->credential.digest.nc);
-	pj_strdup(pool, &hdr->credential.digest.other_param, &rhs->credential.digest.other_param);
-    } else if (pj_stricmp2(&hdr->scheme, "pgp") == 0) {
-	pj_assert(0);
-	return NULL;
-    } else {
-	pj_assert(0);
-	return NULL;
-    }
-
-    return hdr;
-}
-
-static pjsip_authorization_hdr* pjsip_authorization_hdr_shallow_clone( pj_pool_t *pool,
-								       const pjsip_authorization_hdr *rhs)
-{
-    /* This function also serves Proxy-Authorization header. */
-    pjsip_authorization_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Proxy-Authenticate and WWW-Authenticate header.
- */
-static int pjsip_www_authenticate_hdr_print( pjsip_www_authenticate_hdr *hdr,
-					     char *buf, pj_size_t size);
-static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_clone( pj_pool_t *pool,
-								     const pjsip_www_authenticate_hdr *hdr);
-static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_shallow_clone( pj_pool_t *pool,
-									     const pjsip_www_authenticate_hdr *hdr);
-
-static pjsip_hdr_vptr www_authenticate_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_www_authenticate_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_www_authenticate_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_www_authenticate_hdr_print,
-};
-
-
-PJ_DEF(pjsip_www_authenticate_hdr*) pjsip_www_authenticate_hdr_create(pj_pool_t *pool)
-{
-    pjsip_www_authenticate_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_WWW_AUTHENTICATE, &www_authenticate_hdr_vptr);
-    return hdr;
-}
-
-
-PJ_DEF(pjsip_proxy_authenticate_hdr*) pjsip_proxy_authenticate_hdr_create(pj_pool_t *pool)
-{
-    pjsip_proxy_authenticate_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_PROXY_AUTHENTICATE, &www_authenticate_hdr_vptr);
-    return hdr;
-}
-
-static int print_digest_challenge( pjsip_digest_challenge *chal,
-				   char *buf, pj_size_t size)
-{
-    int printed;
-    char *startbuf = buf;
-    char *endbuf = buf + size;
-
-    copy_advance_pair_quote_cond(buf, " realm=", 7, chal->realm, '"', '"');
-    copy_advance_pair_quote_cond(buf, ",domain=", 8, chal->domain, '"', '"');
-    copy_advance_pair_quote_cond(buf, ",nonce=", 7, chal->nonce, '"', '"');
-    copy_advance_pair_quote_cond(buf, ",opaque=", 8, chal->opaque, '"', '"');
-    if (chal->stale) {
-	pj_str_t true_str = { "true", 4 };
-	copy_advance_pair(buf, ",stale=", 7, true_str);
-    }
-    copy_advance_pair(buf, ",algorithm=", 11, chal->algorithm);
-    copy_advance_pair_quote_cond(buf, ",qop=", 5, chal->qop, '"', '"');
-    copy_advance(buf, chal->other_param);
-
-    return (int)(buf-startbuf);
-}
-
-static int print_pgp_challenge( pjsip_pgp_challenge *chal,
-			        char *buf, pj_size_t size)
-{
-    PJ_UNUSED_ARG(chal);
-    PJ_UNUSED_ARG(buf);
-    PJ_UNUSED_ARG(size);
-    return -1;
-}
-
-static int pjsip_www_authenticate_hdr_print( pjsip_www_authenticate_hdr *hdr,
-					     char *buf, pj_size_t size)
-{
-    int printed;
-    char *startbuf = buf;
-    char *endbuf = buf + size;
-
-    copy_advance(buf, hdr->name);
-    *buf++ = ':';
-    *buf++ = ' ';
-
-    copy_advance(buf, hdr->scheme);
-    *buf++ = ' ';
-
-    if (pj_stricmp2(&hdr->scheme, "digest") == 0)
-	printed = print_digest_challenge(&hdr->challenge.digest, buf, endbuf - buf);
-    else if (pj_stricmp2(&hdr->scheme, "pgp") == 0)
-	printed = print_pgp_challenge(&hdr->challenge.pgp, buf, endbuf - buf);
-    else {
-	pj_assert(0);
-	return -1;
-    }
-
-    if (printed == -1)
-	return -1;
-
-    buf += printed;
-    *buf = '\0';
-    return (int)(buf-startbuf);
-}
-
-static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_clone( pj_pool_t *pool,
-								     const pjsip_www_authenticate_hdr *rhs)
-{
-    /* This function also serves Proxy-Authenticate header. */
-    pjsip_www_authenticate_hdr *hdr;
-    if (rhs->type == PJSIP_H_WWW_AUTHENTICATE)
-	hdr = pjsip_www_authenticate_hdr_create(pool);
-    else
-	hdr = pjsip_proxy_authenticate_hdr_create(pool);
-
-    pj_strdup(pool, &hdr->scheme, &rhs->scheme);
-
-    if (pj_stricmp2(&hdr->scheme, "digest") == 0) {
-	pj_strdup(pool, &hdr->challenge.digest.realm, &rhs->challenge.digest.realm);
-	pj_strdup(pool, &hdr->challenge.digest.domain, &rhs->challenge.digest.domain);
-	pj_strdup(pool, &hdr->challenge.digest.nonce, &rhs->challenge.digest.nonce);
-	pj_strdup(pool, &hdr->challenge.digest.opaque, &rhs->challenge.digest.opaque);
-	hdr->challenge.digest.stale = rhs->challenge.digest.stale;
-	pj_strdup(pool, &hdr->challenge.digest.algorithm, &rhs->challenge.digest.algorithm);
-	pj_strdup(pool, &hdr->challenge.digest.qop, &rhs->challenge.digest.qop);
-	pj_strdup(pool, &hdr->challenge.digest.other_param, &rhs->challenge.digest.other_param);
-    } else if (pj_stricmp2(&hdr->scheme, "pgp") == 0) {
-	pj_assert(0);
-	return NULL;
-    } else {
-	pj_assert(0);
-	return NULL;
-    }
-
-    return hdr;
-
-}
-
-static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_shallow_clone( pj_pool_t *pool,
-									     const pjsip_www_authenticate_hdr *rhs)
-{
-    /* This function also serves Proxy-Authenticate header. */
-    pjsip_www_authenticate_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-
+#include <pj/assert.h>

+#include <pjsip/print_util.h>

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Authorization and Proxy-Authorization header.

+ */

+static pjsip_authorization_hdr* pjsip_authorization_hdr_clone( pj_pool_t *pool,

+							       const pjsip_authorization_hdr *hdr);

+static pjsip_authorization_hdr* pjsip_authorization_hdr_shallow_clone( pj_pool_t *pool,

+								       const pjsip_authorization_hdr *hdr);

+static int pjsip_authorization_hdr_print( pjsip_authorization_hdr *hdr,

+					  char *buf, pj_size_t size);

+

+static pjsip_hdr_vptr authorization_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_authorization_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_authorization_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_authorization_hdr_print,

+};

+

+

+PJ_DEF(pjsip_authorization_hdr*) pjsip_authorization_hdr_create(pj_pool_t *pool)

+{

+    pjsip_authorization_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_AUTHORIZATION, &authorization_hdr_vptr);

+    return hdr;

+}

+

+PJ_DEF(pjsip_proxy_authorization_hdr*) pjsip_proxy_authorization_hdr_create(pj_pool_t *pool)

+{

+    pjsip_proxy_authorization_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_PROXY_AUTHORIZATION, &authorization_hdr_vptr);

+    return hdr;

+}

+

+static int print_digest_credential(pjsip_digest_credential *cred, char *buf, pj_size_t size)

+{

+    int printed;

+    char *startbuf = buf;

+    char *endbuf = buf + size;

+    

+    copy_advance_pair_quote_cond(buf, "username=", 9, cred->username, '"', '"');

+    copy_advance_pair_quote_cond(buf, ", realm=", 8, cred->realm, '"', '"');

+    copy_advance_pair_quote_cond(buf, ", nonce=", 8, cred->nonce, '"', '"');

+    copy_advance_pair_quote_cond(buf, ", uri=", 6, cred->uri, '"', '"');

+    copy_advance_pair_quote_cond(buf, ", response=", 11, cred->response, '"', '"');

+    copy_advance_pair(buf, ", algorithm=", 12, cred->algorithm);

+    copy_advance_pair_quote_cond(buf, ", cnonce=", 9, cred->cnonce, '"', '"');

+    copy_advance_pair_quote_cond(buf, ", opaque=", 9, cred->opaque, '"', '"');

+    //Note: there's no dbl-quote in qop in Authorization header 

+    // (unlike WWW-Authenticate)

+    //copy_advance_pair_quote_cond(buf, ", qop=", 6, cred->qop, '"', '"');

+    copy_advance_pair(buf, ", qop=", 6, cred->qop);

+    copy_advance_pair(buf, ", nc=", 5, cred->nc);

+    copy_advance(buf, cred->other_param);

+

+    return (int) (buf-startbuf);

+}

+

+static int print_pgp_credential(pjsip_pgp_credential *cred, char *buf, pj_size_t size)

+{

+    PJ_UNUSED_ARG(cred);

+    PJ_UNUSED_ARG(buf);

+    PJ_UNUSED_ARG(size);

+    return -1;

+}

+

+static int pjsip_authorization_hdr_print( pjsip_authorization_hdr *hdr,

+					  char *buf, pj_size_t size)

+{

+    int printed;

+    char *startbuf = buf;

+    char *endbuf = buf + size;

+

+    copy_advance(buf, hdr->name);

+    *buf++ = ':';

+    *buf++ = ' ';

+

+    copy_advance(buf, hdr->scheme);

+    *buf++ = ' ';

+

+    if (pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR) == 0)

+    {

+	printed = print_digest_credential(&hdr->credential.digest, buf, endbuf - buf);

+    } 

+    else if (pj_stricmp(&hdr->scheme, &pjsip_PGP_STR) == 0)

+    {

+	printed = print_pgp_credential(&hdr->credential.pgp, buf, endbuf - buf);

+    } 

+    else {

+	pj_assert(0);

+	return -1;

+    }

+

+    if (printed == -1)

+	return -1;

+

+    buf += printed;

+    *buf = '\0';

+    return (int)(buf-startbuf);

+}

+

+static pjsip_authorization_hdr* pjsip_authorization_hdr_clone(  pj_pool_t *pool,

+								const pjsip_authorization_hdr *rhs)

+{

+    /* This function also serves Proxy-Authorization header. */

+    pjsip_authorization_hdr *hdr;

+    if (rhs->type == PJSIP_H_AUTHORIZATION)

+	hdr = pjsip_authorization_hdr_create(pool);

+    else

+	hdr = pjsip_proxy_authorization_hdr_create(pool);

+

+    pj_strdup(pool, &hdr->scheme, &rhs->scheme);

+

+    if (pj_stricmp2(&hdr->scheme, "digest") == 0) {

+	pj_strdup(pool, &hdr->credential.digest.username, &rhs->credential.digest.username);

+	pj_strdup(pool, &hdr->credential.digest.realm, &rhs->credential.digest.realm);

+	pj_strdup(pool, &hdr->credential.digest.nonce, &rhs->credential.digest.nonce);

+	pj_strdup(pool, &hdr->credential.digest.uri, &rhs->credential.digest.uri);

+	pj_strdup(pool, &hdr->credential.digest.response, &rhs->credential.digest.response);

+	pj_strdup(pool, &hdr->credential.digest.algorithm, &rhs->credential.digest.algorithm);

+	pj_strdup(pool, &hdr->credential.digest.cnonce, &rhs->credential.digest.cnonce);

+	pj_strdup(pool, &hdr->credential.digest.opaque, &rhs->credential.digest.opaque);

+	pj_strdup(pool, &hdr->credential.digest.qop, &rhs->credential.digest.qop);

+	pj_strdup(pool, &hdr->credential.digest.nc, &rhs->credential.digest.nc);

+	pj_strdup(pool, &hdr->credential.digest.other_param, &rhs->credential.digest.other_param);

+    } else if (pj_stricmp2(&hdr->scheme, "pgp") == 0) {

+	pj_assert(0);

+	return NULL;

+    } else {

+	pj_assert(0);

+	return NULL;

+    }

+

+    return hdr;

+}

+

+static pjsip_authorization_hdr* pjsip_authorization_hdr_shallow_clone( pj_pool_t *pool,

+								       const pjsip_authorization_hdr *rhs)

+{

+    /* This function also serves Proxy-Authorization header. */

+    pjsip_authorization_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Proxy-Authenticate and WWW-Authenticate header.

+ */

+static int pjsip_www_authenticate_hdr_print( pjsip_www_authenticate_hdr *hdr,

+					     char *buf, pj_size_t size);

+static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_clone( pj_pool_t *pool,

+								     const pjsip_www_authenticate_hdr *hdr);

+static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_shallow_clone( pj_pool_t *pool,

+									     const pjsip_www_authenticate_hdr *hdr);

+

+static pjsip_hdr_vptr www_authenticate_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_www_authenticate_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_www_authenticate_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_www_authenticate_hdr_print,

+};

+

+

+PJ_DEF(pjsip_www_authenticate_hdr*) pjsip_www_authenticate_hdr_create(pj_pool_t *pool)

+{

+    pjsip_www_authenticate_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_WWW_AUTHENTICATE, &www_authenticate_hdr_vptr);

+    return hdr;

+}

+

+

+PJ_DEF(pjsip_proxy_authenticate_hdr*) pjsip_proxy_authenticate_hdr_create(pj_pool_t *pool)

+{

+    pjsip_proxy_authenticate_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_PROXY_AUTHENTICATE, &www_authenticate_hdr_vptr);

+    return hdr;

+}

+

+static int print_digest_challenge( pjsip_digest_challenge *chal,

+				   char *buf, pj_size_t size)

+{

+    int printed;

+    char *startbuf = buf;

+    char *endbuf = buf + size;

+

+    copy_advance_pair_quote_cond(buf, " realm=", 7, chal->realm, '"', '"');

+    copy_advance_pair_quote_cond(buf, ",domain=", 8, chal->domain, '"', '"');

+    copy_advance_pair_quote_cond(buf, ",nonce=", 7, chal->nonce, '"', '"');

+    copy_advance_pair_quote_cond(buf, ",opaque=", 8, chal->opaque, '"', '"');

+    if (chal->stale) {

+	pj_str_t true_str = { "true", 4 };

+	copy_advance_pair(buf, ",stale=", 7, true_str);

+    }

+    copy_advance_pair(buf, ",algorithm=", 11, chal->algorithm);

+    copy_advance_pair_quote_cond(buf, ",qop=", 5, chal->qop, '"', '"');

+    copy_advance(buf, chal->other_param);

+

+    return (int)(buf-startbuf);

+}

+

+static int print_pgp_challenge( pjsip_pgp_challenge *chal,

+			        char *buf, pj_size_t size)

+{

+    PJ_UNUSED_ARG(chal);

+    PJ_UNUSED_ARG(buf);

+    PJ_UNUSED_ARG(size);

+    return -1;

+}

+

+static int pjsip_www_authenticate_hdr_print( pjsip_www_authenticate_hdr *hdr,

+					     char *buf, pj_size_t size)

+{

+    int printed;

+    char *startbuf = buf;

+    char *endbuf = buf + size;

+

+    copy_advance(buf, hdr->name);

+    *buf++ = ':';

+    *buf++ = ' ';

+

+    copy_advance(buf, hdr->scheme);

+    *buf++ = ' ';

+

+    if (pj_stricmp2(&hdr->scheme, "digest") == 0)

+	printed = print_digest_challenge(&hdr->challenge.digest, buf, endbuf - buf);

+    else if (pj_stricmp2(&hdr->scheme, "pgp") == 0)

+	printed = print_pgp_challenge(&hdr->challenge.pgp, buf, endbuf - buf);

+    else {

+	pj_assert(0);

+	return -1;

+    }

+

+    if (printed == -1)

+	return -1;

+

+    buf += printed;

+    *buf = '\0';

+    return (int)(buf-startbuf);

+}

+

+static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_clone( pj_pool_t *pool,

+								     const pjsip_www_authenticate_hdr *rhs)

+{

+    /* This function also serves Proxy-Authenticate header. */

+    pjsip_www_authenticate_hdr *hdr;

+    if (rhs->type == PJSIP_H_WWW_AUTHENTICATE)

+	hdr = pjsip_www_authenticate_hdr_create(pool);

+    else

+	hdr = pjsip_proxy_authenticate_hdr_create(pool);

+

+    pj_strdup(pool, &hdr->scheme, &rhs->scheme);

+

+    if (pj_stricmp2(&hdr->scheme, "digest") == 0) {

+	pj_strdup(pool, &hdr->challenge.digest.realm, &rhs->challenge.digest.realm);

+	pj_strdup(pool, &hdr->challenge.digest.domain, &rhs->challenge.digest.domain);

+	pj_strdup(pool, &hdr->challenge.digest.nonce, &rhs->challenge.digest.nonce);

+	pj_strdup(pool, &hdr->challenge.digest.opaque, &rhs->challenge.digest.opaque);

+	hdr->challenge.digest.stale = rhs->challenge.digest.stale;

+	pj_strdup(pool, &hdr->challenge.digest.algorithm, &rhs->challenge.digest.algorithm);

+	pj_strdup(pool, &hdr->challenge.digest.qop, &rhs->challenge.digest.qop);

+	pj_strdup(pool, &hdr->challenge.digest.other_param, &rhs->challenge.digest.other_param);

+    } else if (pj_stricmp2(&hdr->scheme, "pgp") == 0) {

+	pj_assert(0);

+	return NULL;

+    } else {

+	pj_assert(0);

+	return NULL;

+    }

+

+    return hdr;

+

+}

+

+static pjsip_www_authenticate_hdr* pjsip_www_authenticate_hdr_shallow_clone( pj_pool_t *pool,

+									     const pjsip_www_authenticate_hdr *rhs)

+{

+    /* This function also serves Proxy-Authenticate header. */

+    pjsip_www_authenticate_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+

diff --git a/pjsip/src/pjsip/sip_auth_parser.c b/pjsip/src/pjsip/sip_auth_parser.c
index 5e121b5..b6c8172 100644
--- a/pjsip/src/pjsip/sip_auth_parser.c
+++ b/pjsip/src/pjsip/sip_auth_parser.c
@@ -1,275 +1,297 @@
-/* $Id$
- */
-#include <pjsip/sip_auth_parser.h>
-#include <pjsip/sip_auth_msg.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_auth_parser.h>

+#include <pjsip/sip_auth_msg.h>

 #include <pjsip/sip_parser.h>

-#include <pj/assert.h>
-#include <pj/string.h>
-#include <pj/except.h>
-
-static pjsip_hdr* parse_hdr_authorization       ( pjsip_parse_ctx *ctx );
-static pjsip_hdr* parse_hdr_proxy_authorization ( pjsip_parse_ctx *ctx );
-static pjsip_hdr* parse_hdr_www_authenticate    ( pjsip_parse_ctx *ctx );
-static pjsip_hdr* parse_hdr_proxy_authenticate  ( pjsip_parse_ctx *ctx );
-
+#include <pj/assert.h>

+#include <pj/string.h>

+#include <pj/except.h>

+

+static pjsip_hdr* parse_hdr_authorization       ( pjsip_parse_ctx *ctx );

+static pjsip_hdr* parse_hdr_proxy_authorization ( pjsip_parse_ctx *ctx );

+static pjsip_hdr* parse_hdr_www_authenticate    ( pjsip_parse_ctx *ctx );

+static pjsip_hdr* parse_hdr_proxy_authenticate  ( pjsip_parse_ctx *ctx );

+

 static void parse_digest_credential ( pj_scanner *scanner, pj_pool_t *pool, 

-                                      pjsip_digest_credential *cred);
+                                      pjsip_digest_credential *cred);

 static void parse_pgp_credential    ( pj_scanner *scanner, pj_pool_t *pool, 

-                                      pjsip_pgp_credential *cred);
+                                      pjsip_pgp_credential *cred);

 static void parse_digest_challenge  ( pj_scanner *scanner, pj_pool_t *pool, 

-                                      pjsip_digest_challenge *chal);
+                                      pjsip_digest_challenge *chal);

 static void parse_pgp_challenge     ( pj_scanner *scanner, pj_pool_t *pool,

-                                      pjsip_pgp_challenge *chal);
-
-const pj_str_t	pjsip_USERNAME_STR =	    { "username", 8 },
-		pjsip_REALM_STR =	    { "realm", 5},
-		pjsip_NONCE_STR =	    { "nonce", 5},
-		pjsip_URI_STR =		    { "uri", 3 },
-		pjsip_RESPONSE_STR =	    { "response", 8 },
-		pjsip_ALGORITHM_STR =	    { "algorithm", 9 },
-		pjsip_DOMAIN_STR =	    { "domain", 6 },
-		pjsip_STALE_STR =	    { "stale", 5},
-		pjsip_QOP_STR =		    { "qop", 3},
-		pjsip_CNONCE_STR =	    { "cnonce", 6},
-		pjsip_OPAQUE_STR =	    { "opaque", 6},
-		pjsip_NC_STR =		    { "nc", 2},
-		pjsip_TRUE_STR =	    { "true", 4},
-		pjsip_QUOTED_TRUE_STR =	    { "\"true\"", 6},
-		pjsip_FALSE_STR =	    { "false", 5},
-		pjsip_QUOTED_FALSE_STR =    { "\"false\"", 7},
-		pjsip_DIGEST_STR =	    { "Digest", 6},
-		pjsip_QUOTED_DIGEST_STR =   { "\"Digest\"", 8},
-		pjsip_PGP_STR =		    { "PGP", 3 },
-		pjsip_QUOTED_PGP_STR =	    { "\"PGP\"", 5 },
-		pjsip_MD5_STR =		    { "md5", 3 },
-		pjsip_QUOTED_MD5_STR =	    { "\"md5\"", 5},
-		pjsip_AUTH_STR =	    { "auth", 4},
-		pjsip_QUOTED_AUTH_STR =	    { "\"auth\"", 6 };
-
-
+                                      pjsip_pgp_challenge *chal);

+

+const pj_str_t	pjsip_USERNAME_STR =	    { "username", 8 },

+		pjsip_REALM_STR =	    { "realm", 5},

+		pjsip_NONCE_STR =	    { "nonce", 5},

+		pjsip_URI_STR =		    { "uri", 3 },

+		pjsip_RESPONSE_STR =	    { "response", 8 },

+		pjsip_ALGORITHM_STR =	    { "algorithm", 9 },

+		pjsip_DOMAIN_STR =	    { "domain", 6 },

+		pjsip_STALE_STR =	    { "stale", 5},

+		pjsip_QOP_STR =		    { "qop", 3},

+		pjsip_CNONCE_STR =	    { "cnonce", 6},

+		pjsip_OPAQUE_STR =	    { "opaque", 6},

+		pjsip_NC_STR =		    { "nc", 2},

+		pjsip_TRUE_STR =	    { "true", 4},

+		pjsip_QUOTED_TRUE_STR =	    { "\"true\"", 6},

+		pjsip_FALSE_STR =	    { "false", 5},

+		pjsip_QUOTED_FALSE_STR =    { "\"false\"", 7},

+		pjsip_DIGEST_STR =	    { "Digest", 6},

+		pjsip_QUOTED_DIGEST_STR =   { "\"Digest\"", 8},

+		pjsip_PGP_STR =		    { "PGP", 3 },

+		pjsip_QUOTED_PGP_STR =	    { "\"PGP\"", 5 },

+		pjsip_MD5_STR =		    { "md5", 3 },

+		pjsip_QUOTED_MD5_STR =	    { "\"md5\"", 5},

+		pjsip_AUTH_STR =	    { "auth", 4},

+		pjsip_QUOTED_AUTH_STR =	    { "\"auth\"", 6 };

+

+

 static void parse_digest_credential( pj_scanner *scanner, pj_pool_t *pool, 

-                                     pjsip_digest_credential *cred)
-{
-    for (;;) {
-	pj_str_t name, value;
-
-	pjsip_parse_param_imp(scanner, &name, &value,PJSIP_PARSE_REMOVE_QUOTE);
-
-	if (!pj_stricmp(&name, &pjsip_USERNAME_STR)) {
-	    cred->username = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_REALM_STR)) {
-	    cred->realm = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) {
-	    cred->nonce = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_URI_STR)) {
-	    cred->uri = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_RESPONSE_STR)) {
-	    cred->response = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) {
-	    cred->algorithm = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_CNONCE_STR)) {
-	    cred->cnonce = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) {
-	    cred->opaque = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_QOP_STR)) {
-	    cred->qop = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_NC_STR)) {
-	    cred->nc = value;
-
-	} else {
-	    pjsip_concat_param_imp(&cred->other_param,pool,&name,&value, ',');
-	}
-
-	/* Eat comma */
-	if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',')
-	    pj_scan_get_char(scanner);
-	else
-	    break;
-    }
-}
-
+                                     pjsip_digest_credential *cred)

+{

+    for (;;) {

+	pj_str_t name, value;

+

+	pjsip_parse_param_imp(scanner, &name, &value,PJSIP_PARSE_REMOVE_QUOTE);

+

+	if (!pj_stricmp(&name, &pjsip_USERNAME_STR)) {

+	    cred->username = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_REALM_STR)) {

+	    cred->realm = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) {

+	    cred->nonce = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_URI_STR)) {

+	    cred->uri = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_RESPONSE_STR)) {

+	    cred->response = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) {

+	    cred->algorithm = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_CNONCE_STR)) {

+	    cred->cnonce = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) {

+	    cred->opaque = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_QOP_STR)) {

+	    cred->qop = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_NC_STR)) {

+	    cred->nc = value;

+

+	} else {

+	    pjsip_concat_param_imp(&cred->other_param,pool,&name,&value, ',');

+	}

+

+	/* Eat comma */

+	if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',')

+	    pj_scan_get_char(scanner);

+	else

+	    break;

+    }

+}

+

 static void parse_pgp_credential( pj_scanner *scanner, pj_pool_t *pool, 

-                                  pjsip_pgp_credential *cred)
-{
-    PJ_UNUSED_ARG(scanner);
-    PJ_UNUSED_ARG(pool);
-    PJ_UNUSED_ARG(cred);
-
-    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-}
-
+                                  pjsip_pgp_credential *cred)

+{

+    PJ_UNUSED_ARG(scanner);

+    PJ_UNUSED_ARG(pool);

+    PJ_UNUSED_ARG(cred);

+

+    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+}

+

 static void parse_digest_challenge( pj_scanner *scanner, pj_pool_t *pool, 

-                                    pjsip_digest_challenge *chal)
-{
-    for (;;) {
-	pj_str_t name, value;
-
-	pjsip_parse_param_imp(scanner, &name, &value,PJSIP_PARSE_REMOVE_QUOTE);
-
-	if (!pj_stricmp(&name, &pjsip_REALM_STR)) {
-	    chal->realm = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_DOMAIN_STR)) {
-	    chal->domain = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) {
-	    chal->nonce = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) {
-	    chal->opaque = value;
-
-	} else if (!pj_stricmp(&name, &pjsip_STALE_STR)) {
+                                    pjsip_digest_challenge *chal)

+{

+    for (;;) {

+	pj_str_t name, value;

+

+	pjsip_parse_param_imp(scanner, &name, &value,PJSIP_PARSE_REMOVE_QUOTE);

+

+	if (!pj_stricmp(&name, &pjsip_REALM_STR)) {

+	    chal->realm = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_DOMAIN_STR)) {

+	    chal->domain = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_NONCE_STR)) {

+	    chal->nonce = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_OPAQUE_STR)) {

+	    chal->opaque = value;

+

+	} else if (!pj_stricmp(&name, &pjsip_STALE_STR)) {

 	    if (!pj_stricmp(&value, &pjsip_TRUE_STR) || 

                 !pj_stricmp(&value, &pjsip_QUOTED_TRUE_STR))

-            {
+            {

 		chal->stale = 1;

-            }
-
-	} else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) {
-	    chal->algorithm = value;
-
-
-	} else if (!pj_stricmp(&name, &pjsip_QOP_STR)) {
-	    chal->qop = value;
-
-	} else {
+            }

+

+	} else if (!pj_stricmp(&name, &pjsip_ALGORITHM_STR)) {

+	    chal->algorithm = value;

+

+

+	} else if (!pj_stricmp(&name, &pjsip_QOP_STR)) {

+	    chal->qop = value;

+

+	} else {

 	    pjsip_concat_param_imp(&chal->other_param, pool, 

-                                   &name, &value, ',');
-	}
-
-	/* Eat comma */
-	if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',')
-	    pj_scan_get_char(scanner);
-	else
-	    break;
-    }
-}
-
+                                   &name, &value, ',');

+	}

+

+	/* Eat comma */

+	if (!pj_scan_is_eof(scanner) && *scanner->curptr == ',')

+	    pj_scan_get_char(scanner);

+	else

+	    break;

+    }

+}

+

 static void parse_pgp_challenge( pj_scanner *scanner, pj_pool_t *pool, 

-                                 pjsip_pgp_challenge *chal)
-{
-    PJ_UNUSED_ARG(scanner);
-    PJ_UNUSED_ARG(pool);
-    PJ_UNUSED_ARG(chal);
-
-    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-}
-
-static void int_parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool,
-					 pjsip_authorization_hdr *hdr)
-{
-    if (*scanner->curptr == '"') {
-	pj_scan_get_quote(scanner, '"', '"', &hdr->scheme);
-	hdr->scheme.ptr++;
-	hdr->scheme.slen -= 2;
-    } else {
-	pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->scheme);
-    }
-
-    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
-
-	parse_digest_credential(scanner, pool, &hdr->credential.digest);
-
-    } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) {
-
-	parse_pgp_credential( scanner, pool, &hdr->credential.pgp);
-
-    } else {
-	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-    }
-
-    pjsip_parse_end_hdr_imp( scanner );
-}
-
-static void int_parse_hdr_authenticate( pj_scanner *scanner, pj_pool_t *pool, 
-					pjsip_www_authenticate_hdr *hdr)
-{
-    if (*scanner->curptr == '"') {
-	pj_scan_get_quote(scanner, '"', '"', &hdr->scheme);
-	hdr->scheme.ptr++;
-	hdr->scheme.slen -= 2;
-    } else {
-	pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->scheme);
-    }
-
-    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
-
-	parse_digest_challenge(scanner, pool, &hdr->challenge.digest);
-
-    } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) {
-
-	parse_pgp_challenge(scanner, pool, &hdr->challenge.pgp);
-
-    } else {
-	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-    }
-
-    pjsip_parse_end_hdr_imp( scanner );
-}
-
-
-static pjsip_hdr* parse_hdr_authorization( pjsip_parse_ctx *ctx )
-{
-    pjsip_authorization_hdr *hdr = pjsip_authorization_hdr_create(ctx->pool);
-    int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr);
-    return (pjsip_hdr*)hdr;
-}
-
-static pjsip_hdr* parse_hdr_proxy_authorization( pjsip_parse_ctx *ctx )
-{
+                                 pjsip_pgp_challenge *chal)

+{

+    PJ_UNUSED_ARG(scanner);

+    PJ_UNUSED_ARG(pool);

+    PJ_UNUSED_ARG(chal);

+

+    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+}

+

+static void int_parse_hdr_authorization( pj_scanner *scanner, pj_pool_t *pool,

+					 pjsip_authorization_hdr *hdr)

+{

+    if (*scanner->curptr == '"') {

+	pj_scan_get_quote(scanner, '"', '"', &hdr->scheme);

+	hdr->scheme.ptr++;

+	hdr->scheme.slen -= 2;

+    } else {

+	pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->scheme);

+    }

+

+    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {

+

+	parse_digest_credential(scanner, pool, &hdr->credential.digest);

+

+    } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) {

+

+	parse_pgp_credential( scanner, pool, &hdr->credential.pgp);

+

+    } else {

+	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+    }

+

+    pjsip_parse_end_hdr_imp( scanner );

+}

+

+static void int_parse_hdr_authenticate( pj_scanner *scanner, pj_pool_t *pool, 

+					pjsip_www_authenticate_hdr *hdr)

+{

+    if (*scanner->curptr == '"') {

+	pj_scan_get_quote(scanner, '"', '"', &hdr->scheme);

+	hdr->scheme.ptr++;

+	hdr->scheme.slen -= 2;

+    } else {

+	pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->scheme);

+    }

+

+    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {

+

+	parse_digest_challenge(scanner, pool, &hdr->challenge.digest);

+

+    } else if (!pj_stricmp(&hdr->scheme, &pjsip_PGP_STR)) {

+

+	parse_pgp_challenge(scanner, pool, &hdr->challenge.pgp);

+

+    } else {

+	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+    }

+

+    pjsip_parse_end_hdr_imp( scanner );

+}

+

+

+static pjsip_hdr* parse_hdr_authorization( pjsip_parse_ctx *ctx )

+{

+    pjsip_authorization_hdr *hdr = pjsip_authorization_hdr_create(ctx->pool);

+    int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr);

+    return (pjsip_hdr*)hdr;

+}

+

+static pjsip_hdr* parse_hdr_proxy_authorization( pjsip_parse_ctx *ctx )

+{

     pjsip_proxy_authorization_hdr *hdr = 

-        pjsip_proxy_authorization_hdr_create(ctx->pool);
-    int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr);
-    return (pjsip_hdr*)hdr;
-}
-
-static pjsip_hdr* parse_hdr_www_authenticate( pjsip_parse_ctx *ctx )
-{
+        pjsip_proxy_authorization_hdr_create(ctx->pool);

+    int_parse_hdr_authorization(ctx->scanner, ctx->pool, hdr);

+    return (pjsip_hdr*)hdr;

+}

+

+static pjsip_hdr* parse_hdr_www_authenticate( pjsip_parse_ctx *ctx )

+{

     pjsip_www_authenticate_hdr *hdr = 

-        pjsip_www_authenticate_hdr_create(ctx->pool);
-    int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr);
-    return (pjsip_hdr*)hdr;
-}
-
-static pjsip_hdr* parse_hdr_proxy_authenticate( pjsip_parse_ctx *ctx )
-{
+        pjsip_www_authenticate_hdr_create(ctx->pool);

+    int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr);

+    return (pjsip_hdr*)hdr;

+}

+

+static pjsip_hdr* parse_hdr_proxy_authenticate( pjsip_parse_ctx *ctx )

+{

     pjsip_proxy_authenticate_hdr *hdr = 

-        pjsip_proxy_authenticate_hdr_create(ctx->pool);
-    int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr);
-    return (pjsip_hdr*)hdr;
-}
-
-
-PJ_DEF(pj_status_t) pjsip_auth_init_parser()
+        pjsip_proxy_authenticate_hdr_create(ctx->pool);

+    int_parse_hdr_authenticate(ctx->scanner, ctx->pool, hdr);

+    return (pjsip_hdr*)hdr;

+}

+

+

+PJ_DEF(pj_status_t) pjsip_auth_init_parser()

 {

     pj_status_t status;

-
+

     status = pjsip_register_hdr_parser( "Authorization", NULL, 

                                         &parse_hdr_authorization);

-    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);

     status = pjsip_register_hdr_parser( "Proxy-Authorization", NULL, 

                                         &parse_hdr_proxy_authorization);

-    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);

     status = pjsip_register_hdr_parser( "WWW-Authenticate", NULL, 

                                         &parse_hdr_www_authenticate);

-    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);

     status = pjsip_register_hdr_parser( "Proxy-Authenticate", NULL, 

                                         &parse_hdr_proxy_authenticate);

     PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);

 

-    return PJ_SUCCESS;
-}
-
-PJ_DEF(void) pjsip_auth_deinit_parser()
-{
-}
-
+    return PJ_SUCCESS;

+}

+

+PJ_DEF(void) pjsip_auth_deinit_parser()

+{

+}

+

diff --git a/pjsip/src/pjsip/sip_endpoint.c b/pjsip/src/pjsip/sip_endpoint.c
index 49c70b1..08d6827 100644
--- a/pjsip/src/pjsip/sip_endpoint.c
+++ b/pjsip/src/pjsip/sip_endpoint.c
@@ -1,841 +1,863 @@
-/* $Id$
- */
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_private.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_resolve.h>
-#include <pjsip/sip_module.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_endpoint.h>

+#include <pjsip/sip_transaction.h>

+#include <pjsip/sip_private.h>

+#include <pjsip/sip_event.h>

+#include <pjsip/sip_resolve.h>

+#include <pjsip/sip_module.h>

 #include <pjsip/sip_misc.h>

-#include <pjsip/sip_errno.h>
-#include <pj/except.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/hash.h>
+#include <pjsip/sip_errno.h>

+#include <pj/except.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/os.h>

+#include <pj/pool.h>

+#include <pj/hash.h>

 #include <pj/assert.h>

 #include <pj/errno.h>

-
-
-#define PJSIP_EX_NO_MEMORY  PJ_NO_MEMORY_EXCEPTION
-#define THIS_FILE	    "endpoint"
-
-#define MAX_METHODS   32
-
-/**
- * The SIP endpoint.
- */
-struct pjsip_endpoint
-{
-    /** Pool to allocate memory for the endpoint. */
-    pj_pool_t		*pool;
-
-    /** Mutex for the pool, hash table, and event list/queue. */
-    pj_mutex_t		*mutex;
-
-    /** Pool factory. */
-    pj_pool_factory	*pf;
-
-    /** Transaction table. */
-    pj_hash_table_t	*tsx_table;
-
-    /** Mutex for transaction table. */
-    pj_mutex_t		*tsx_table_mutex;
-
-    /** Timer heap. */
-    pj_timer_heap_t	*timer_heap;
-
-    /** Transport manager. */
-    pjsip_transport_mgr *transport_mgr;
-
-    /** DNS Resolver. */
-    pjsip_resolver_t	*resolver;
-
-    /** Number of modules registered. */
-    pj_uint32_t		 mod_count;
-
-    /** Modules. */
-    pjsip_module        *modules[PJSIP_MAX_MODULE];
-
-    /** Number of supported methods. */
-    unsigned		 method_cnt;
-
-    /** Array of supported methods. */
-    const pjsip_method	*methods[MAX_METHODS];
-
-    /** Allow header. */
-    pjsip_allow_hdr	*allow_hdr;
-
-    /** Route header list. */
-    pjsip_route_hdr	 route_hdr_list;
-
-    /** Additional request headers. */
-    pjsip_hdr		 req_hdr;
-};
-
-
-
-/*
- * Prototypes.
- */
-static void endpt_transport_callback( pjsip_endpoint *, pjsip_rx_data *rdata );
-
-
-/*
- * Create transaction.
- * Defined in sip_transaction.c
- */
-pj_status_t pjsip_tsx_create( pj_pool_t *pool, pjsip_endpoint *endpt,

-                              pjsip_transaction **tsx );
-
-/*
- * This is the global handler for memory allocation failure, for pools that
- * are created by the endpoint (by default, all pools ARE allocated by 
- * endpoint). The error is handled by throwing exception, and hopefully,
- * the exception will be handled by the application (or this library).
- */
-static void pool_callback( pj_pool_t *pool, pj_size_t size )
-{
-    PJ_UNUSED_ARG(pool);
-    PJ_UNUSED_ARG(size);
-
-    PJ_THROW(PJSIP_EX_NO_MEMORY);
-}
-
-
-/*
- * Initialize modules.
- */
-static pj_status_t init_modules( pjsip_endpoint *endpt )
-{
-    pj_status_t status;
-    unsigned i;
-    //pj_str_t str_COMMA = { ", ", 2 };
-    extern pjsip_module aux_tsx_module;
-
-    PJ_LOG(5, (THIS_FILE, "init_modules()"));
-
-    /* Load static modules. */
-    endpt->mod_count = PJSIP_MAX_MODULE;
-    status = register_static_modules( &endpt->mod_count, endpt->modules );
-    if (status != 0) {
-	return status;
-    }
-
-    /* Add mini aux module. */
-    endpt->modules[endpt->mod_count++] = &aux_tsx_module;
-
-    /* Load dynamic modules. */
-    // Not supported yet!
-
-    /* Sort modules on the priority. */
-    for (i=endpt->mod_count-1; i>0; --i) {
-	pj_uint32_t max = 0;
-	unsigned j;
-	for (j=1; j<=i; ++j) {
-	    if (endpt->modules[j]->priority > endpt->modules[max]->priority)
-		max = j;
-	}
-	if (max != i) {
-	    pjsip_module *temp = endpt->modules[max];
-	    endpt->modules[max] = endpt->modules[i];
-	    endpt->modules[i] = temp;
-	}
-    }
-
-    /* Initialize each module. */
-    for (i=0; i < endpt->mod_count; ++i) {
-	int j;
-
-	pjsip_module *mod = endpt->modules[i];
-	if (mod->init_module) {
-	    status = mod->init_module(endpt, mod, i);
-	    if (status != 0) {
-		return status;
-	    }
-	}
-
-	/* Collect all supported methods from modules. */
-	for (j=0; j<mod->method_cnt; ++j) {
-	    unsigned k;
-	    for (k=0; k<endpt->method_cnt; ++k) {
-		if (pjsip_method_cmp(mod->methods[j], endpt->methods[k]) == 0)
-		    break;
-	    }
-	    if (k == endpt->method_cnt) {
-		if (endpt->method_cnt < MAX_METHODS) {
-		    endpt->methods[endpt->method_cnt++] = mod->methods[j];
-		} else {
-		    PJ_LOG(1,(THIS_FILE, "Too many methods"));
-		    return -1;
-		}
-	    }
-	}
-    }
-
-    /* Create Allow header. */
-    endpt->allow_hdr = pjsip_allow_hdr_create( endpt->pool );
-    endpt->allow_hdr->count = endpt->method_cnt;
-    for (i=0; i<endpt->method_cnt; ++i) {
-	endpt->allow_hdr->values[i] = endpt->methods[i]->name;
-    }
-
-    /* Start each module. */
-    for (i=0; i < endpt->mod_count; ++i) {
-	pjsip_module *mod = endpt->modules[i];
-	if (mod->start_module) {
-	    status = mod->start_module(mod);
-	    if (status != 0) {
-		return status;
-	    }
-	}
-    }
-
-    /* Done. */
-    return 0;
-}
-
-/*
- * Unregister the transaction from the hash table, and destroy the resources
- * from the transaction.
- */
-PJ_DEF(void) pjsip_endpt_destroy_tsx( pjsip_endpoint *endpt,
-				      pjsip_transaction *tsx)
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy_tsx(%s)", tsx->obj_name));
-
-    pj_assert(tsx->state == PJSIP_TSX_STATE_DESTROYED);
-
-    /* No need to lock transaction. 
-     * This function typically is called from the transaction callback, which
-     * means that transaction mutex is being held.
-     */
-    pj_assert( pj_mutex_is_locked(tsx->mutex) );
-
-    /* Lock endpoint. */
-    pj_mutex_lock( endpt->tsx_table_mutex );
-
-    /* Unregister from the hash table. */
-    pj_hash_set( NULL, endpt->tsx_table, tsx->transaction_key.ptr, 
-		 tsx->transaction_key.slen, NULL);
-
-    /* Unlock endpoint mutex. */
-    pj_mutex_unlock( endpt->tsx_table_mutex );
-
-    /* Destroy transaction mutex. */
-    pj_mutex_destroy( tsx->mutex );
-
-    /* Release the pool for the transaction. */
-    pj_pool_release(tsx->pool);
-
-    PJ_LOG(4, (THIS_FILE, "tsx%p destroyed", tsx));
-}
-
-
-/*
- * Receive transaction events from transactions and dispatch them to the 
- * modules.
- */
-static void endpt_do_event( pjsip_endpoint *endpt, pjsip_event *evt)
-{
-    unsigned i;
-
-    /* Dispatch event to modules. */
-    for (i=0; i<endpt->mod_count; ++i) {
-	pjsip_module *mod = endpt->modules[i];
-	if (mod && mod->tsx_handler) {
-	    mod->tsx_handler( mod, evt );
-	}
-    }
-
-    /* Destroy transaction if it is terminated. */
-    if (evt->type == PJSIP_EVENT_TSX_STATE && 
-	evt->body.tsx_state.tsx->state == PJSIP_TSX_STATE_DESTROYED) 
-    {
-	/* No need to lock mutex. Mutex is locked inside the destroy function */
-	pjsip_endpt_destroy_tsx( endpt, evt->body.tsx_state.tsx );
-    }
-}
-
-/*
- * Receive transaction events from transactions and put in the event queue
- * to be processed later.
- */
-void pjsip_endpt_send_tsx_event( pjsip_endpoint *endpt, pjsip_event *evt )
+

+

+#define PJSIP_EX_NO_MEMORY  PJ_NO_MEMORY_EXCEPTION

+#define THIS_FILE	    "endpoint"

+

+#define MAX_METHODS   32

+

+/**

+ * The SIP endpoint.

+ */

+struct pjsip_endpoint

 {

-    // Need to protect this with try/catch?
-    endpt_do_event(endpt, evt);
-}
-
-/*
- * Get "Allow" header.
- */
-PJ_DECL(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt )
-{
-    return endpt->allow_hdr;
-}
-
-/*
- * Get additional headers to be put in outgoing request message.
- */
-PJ_DEF(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *endpt)
-{
-    return &endpt->req_hdr;
-}
-
-PJ_DEF(pj_status_t) pjsip_endpt_set_proxies( pjsip_endpoint *endpt,
-					     int url_cnt, const pj_str_t url[])
-{
-    int i;
-    pjsip_route_hdr *hdr;
-    pj_str_t str_ROUTE = { "Route", 5 };
-
-    /* Lock endpoint mutex. */
-    pj_mutex_lock(endpt->mutex);
-
-    pj_list_init(&endpt->route_hdr_list);
-
-    for (i=0; i<url_cnt; ++i) {
-	int len = url[i].slen;
-	char *dup = pj_pool_alloc(endpt->pool, len + 1);
-	pj_memcpy(dup, url[i].ptr, len);
-	dup[len] = '\0';
-
-	hdr = pjsip_parse_hdr(endpt->pool, &str_ROUTE, dup, len, NULL);
-	if (!hdr) {
-	    pj_mutex_unlock(endpt->mutex);
-	    PJ_LOG(4,(THIS_FILE, "Invalid URL %s in proxy URL", dup));
-	    return -1;
-	}
-
-	pj_assert(hdr->type == PJSIP_H_ROUTE);
-	pj_list_insert_before(&endpt->route_hdr_list, hdr);
-    }
-
-    /* Unlock endpoint mutex. */
-    pj_mutex_unlock(endpt->mutex);
-
-    return 0;
-}
-
-/*
- * Get "Route" header list.
- */
-PJ_DEF(const pjsip_route_hdr*) pjsip_endpt_get_routing( pjsip_endpoint *endpt )
-{
-    return &endpt->route_hdr_list;
-}
-
-
-/*
- * Initialize endpoint.
- */
+    /** Pool to allocate memory for the endpoint. */

+    pj_pool_t		*pool;

+

+    /** Mutex for the pool, hash table, and event list/queue. */

+    pj_mutex_t		*mutex;

+

+    /** Pool factory. */

+    pj_pool_factory	*pf;

+

+    /** Transaction table. */

+    pj_hash_table_t	*tsx_table;

+

+    /** Mutex for transaction table. */

+    pj_mutex_t		*tsx_table_mutex;

+

+    /** Timer heap. */

+    pj_timer_heap_t	*timer_heap;

+

+    /** Transport manager. */

+    pjsip_transport_mgr *transport_mgr;

+

+    /** DNS Resolver. */

+    pjsip_resolver_t	*resolver;

+

+    /** Number of modules registered. */

+    pj_uint32_t		 mod_count;

+

+    /** Modules. */

+    pjsip_module        *modules[PJSIP_MAX_MODULE];

+

+    /** Number of supported methods. */

+    unsigned		 method_cnt;

+

+    /** Array of supported methods. */

+    const pjsip_method	*methods[MAX_METHODS];

+

+    /** Allow header. */

+    pjsip_allow_hdr	*allow_hdr;

+

+    /** Route header list. */

+    pjsip_route_hdr	 route_hdr_list;

+

+    /** Additional request headers. */

+    pjsip_hdr		 req_hdr;

+};

+

+

+

+/*

+ * Prototypes.

+ */

+static void endpt_transport_callback( pjsip_endpoint *, pjsip_rx_data *rdata );

+

+

+/*

+ * Create transaction.

+ * Defined in sip_transaction.c

+ */

+pj_status_t pjsip_tsx_create( pj_pool_t *pool, pjsip_endpoint *endpt,

+                              pjsip_transaction **tsx );

+

+/*

+ * This is the global handler for memory allocation failure, for pools that

+ * are created by the endpoint (by default, all pools ARE allocated by 

+ * endpoint). The error is handled by throwing exception, and hopefully,

+ * the exception will be handled by the application (or this library).

+ */

+static void pool_callback( pj_pool_t *pool, pj_size_t size )

+{

+    PJ_UNUSED_ARG(pool);

+    PJ_UNUSED_ARG(size);

+

+    PJ_THROW(PJSIP_EX_NO_MEMORY);

+}

+

+

+/*

+ * Initialize modules.

+ */

+static pj_status_t init_modules( pjsip_endpoint *endpt )

+{

+    pj_status_t status;

+    unsigned i;

+    //pj_str_t str_COMMA = { ", ", 2 };

+    extern pjsip_module aux_tsx_module;

+

+    PJ_LOG(5, (THIS_FILE, "init_modules()"));

+

+    /* Load static modules. */

+    endpt->mod_count = PJSIP_MAX_MODULE;

+    status = register_static_modules( &endpt->mod_count, endpt->modules );

+    if (status != 0) {

+	return status;

+    }

+

+    /* Add mini aux module. */

+    endpt->modules[endpt->mod_count++] = &aux_tsx_module;

+

+    /* Load dynamic modules. */

+    // Not supported yet!

+

+    /* Sort modules on the priority. */

+    for (i=endpt->mod_count-1; i>0; --i) {

+	pj_uint32_t max = 0;

+	unsigned j;

+	for (j=1; j<=i; ++j) {

+	    if (endpt->modules[j]->priority > endpt->modules[max]->priority)

+		max = j;

+	}

+	if (max != i) {

+	    pjsip_module *temp = endpt->modules[max];

+	    endpt->modules[max] = endpt->modules[i];

+	    endpt->modules[i] = temp;

+	}

+    }

+

+    /* Initialize each module. */

+    for (i=0; i < endpt->mod_count; ++i) {

+	int j;

+

+	pjsip_module *mod = endpt->modules[i];

+	if (mod->init_module) {

+	    status = mod->init_module(endpt, mod, i);

+	    if (status != 0) {

+		return status;

+	    }

+	}

+

+	/* Collect all supported methods from modules. */

+	for (j=0; j<mod->method_cnt; ++j) {

+	    unsigned k;

+	    for (k=0; k<endpt->method_cnt; ++k) {

+		if (pjsip_method_cmp(mod->methods[j], endpt->methods[k]) == 0)

+		    break;

+	    }

+	    if (k == endpt->method_cnt) {

+		if (endpt->method_cnt < MAX_METHODS) {

+		    endpt->methods[endpt->method_cnt++] = mod->methods[j];

+		} else {

+		    PJ_LOG(1,(THIS_FILE, "Too many methods"));

+		    return -1;

+		}

+	    }

+	}

+    }

+

+    /* Create Allow header. */

+    endpt->allow_hdr = pjsip_allow_hdr_create( endpt->pool );

+    endpt->allow_hdr->count = endpt->method_cnt;

+    for (i=0; i<endpt->method_cnt; ++i) {

+	endpt->allow_hdr->values[i] = endpt->methods[i]->name;

+    }

+

+    /* Start each module. */

+    for (i=0; i < endpt->mod_count; ++i) {

+	pjsip_module *mod = endpt->modules[i];

+	if (mod->start_module) {

+	    status = mod->start_module(mod);

+	    if (status != 0) {

+		return status;

+	    }

+	}

+    }

+

+    /* Done. */

+    return 0;

+}

+

+/*

+ * Unregister the transaction from the hash table, and destroy the resources

+ * from the transaction.

+ */

+PJ_DEF(void) pjsip_endpt_destroy_tsx( pjsip_endpoint *endpt,

+				      pjsip_transaction *tsx)

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy_tsx(%s)", tsx->obj_name));

+

+    pj_assert(tsx->state == PJSIP_TSX_STATE_DESTROYED);

+

+    /* No need to lock transaction. 

+     * This function typically is called from the transaction callback, which

+     * means that transaction mutex is being held.

+     */

+    pj_assert( pj_mutex_is_locked(tsx->mutex) );

+

+    /* Lock endpoint. */

+    pj_mutex_lock( endpt->tsx_table_mutex );

+

+    /* Unregister from the hash table. */

+    pj_hash_set( NULL, endpt->tsx_table, tsx->transaction_key.ptr, 

+		 tsx->transaction_key.slen, NULL);

+

+    /* Unlock endpoint mutex. */

+    pj_mutex_unlock( endpt->tsx_table_mutex );

+

+    /* Destroy transaction mutex. */

+    pj_mutex_destroy( tsx->mutex );

+

+    /* Release the pool for the transaction. */

+    pj_pool_release(tsx->pool);

+

+    PJ_LOG(4, (THIS_FILE, "tsx%p destroyed", tsx));

+}

+

+

+/*

+ * Receive transaction events from transactions and dispatch them to the 

+ * modules.

+ */

+static void endpt_do_event( pjsip_endpoint *endpt, pjsip_event *evt)

+{

+    unsigned i;

+

+    /* Dispatch event to modules. */

+    for (i=0; i<endpt->mod_count; ++i) {

+	pjsip_module *mod = endpt->modules[i];

+	if (mod && mod->tsx_handler) {

+	    mod->tsx_handler( mod, evt );

+	}

+    }

+

+    /* Destroy transaction if it is terminated. */

+    if (evt->type == PJSIP_EVENT_TSX_STATE && 

+	evt->body.tsx_state.tsx->state == PJSIP_TSX_STATE_DESTROYED) 

+    {

+	/* No need to lock mutex. Mutex is locked inside the destroy function */

+	pjsip_endpt_destroy_tsx( endpt, evt->body.tsx_state.tsx );

+    }

+}

+

+/*

+ * Receive transaction events from transactions and put in the event queue

+ * to be processed later.

+ */

+void pjsip_endpt_send_tsx_event( pjsip_endpoint *endpt, pjsip_event *evt )

+{

+    // Need to protect this with try/catch?

+    endpt_do_event(endpt, evt);

+}

+

+/*

+ * Get "Allow" header.

+ */

+PJ_DECL(const pjsip_allow_hdr*) pjsip_endpt_get_allow_hdr( pjsip_endpoint *endpt )

+{

+    return endpt->allow_hdr;

+}

+

+/*

+ * Get additional headers to be put in outgoing request message.

+ */

+PJ_DEF(const pjsip_hdr*) pjsip_endpt_get_request_headers(pjsip_endpoint *endpt)

+{

+    return &endpt->req_hdr;

+}

+

+PJ_DEF(pj_status_t) pjsip_endpt_set_proxies( pjsip_endpoint *endpt,

+					     int url_cnt, const pj_str_t url[])

+{

+    int i;

+    pjsip_route_hdr *hdr;

+    pj_str_t str_ROUTE = { "Route", 5 };

+

+    /* Lock endpoint mutex. */

+    pj_mutex_lock(endpt->mutex);

+

+    pj_list_init(&endpt->route_hdr_list);

+

+    for (i=0; i<url_cnt; ++i) {

+	int len = url[i].slen;

+	char *dup = pj_pool_alloc(endpt->pool, len + 1);

+	pj_memcpy(dup, url[i].ptr, len);

+	dup[len] = '\0';

+

+	hdr = pjsip_parse_hdr(endpt->pool, &str_ROUTE, dup, len, NULL);

+	if (!hdr) {

+	    pj_mutex_unlock(endpt->mutex);

+	    PJ_LOG(4,(THIS_FILE, "Invalid URL %s in proxy URL", dup));

+	    return -1;

+	}

+

+	pj_assert(hdr->type == PJSIP_H_ROUTE);

+	pj_list_insert_before(&endpt->route_hdr_list, hdr);

+    }

+

+    /* Unlock endpoint mutex. */

+    pj_mutex_unlock(endpt->mutex);

+

+    return 0;

+}

+

+/*

+ * Get "Route" header list.

+ */

+PJ_DEF(const pjsip_route_hdr*) pjsip_endpt_get_routing( pjsip_endpoint *endpt )

+{

+    return &endpt->route_hdr_list;

+}

+

+

+/*

+ * Initialize endpoint.

+ */

 PJ_DEF(pj_status_t) pjsip_endpt_create(pj_pool_factory *pf,

-                                       pjsip_endpoint **p_endpt)
-{
-    pj_status_t status;
-    pj_pool_t *pool;
-    pjsip_endpoint *endpt;
-    pjsip_max_forwards_hdr *mf_hdr;
-
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create()"));
+                                       pjsip_endpoint **p_endpt)

+{

+    pj_status_t status;

+    pj_pool_t *pool;

+    pjsip_endpoint *endpt;

+    pjsip_max_forwards_hdr *mf_hdr;

+

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create()"));

 

     *p_endpt = NULL;

-
-    /* Create pool */
-    pool = pj_pool_create(pf, "pept%p", 
-			  PJSIP_POOL_LEN_ENDPT, PJSIP_POOL_INC_ENDPT,
-			  &pool_callback);
-    if (!pool)
-	return PJ_ENOMEM;
-
-    /* Create endpoint. */
-    endpt = pj_pool_calloc(pool, 1, sizeof(*endpt));
-    endpt->pool = pool;
-    endpt->pf = pf;
-
-    /* Create mutex for the events, etc. */
-    status = pj_mutex_create_recursive( endpt->pool, "ept%p", &endpt->mutex );
-    if (status != PJ_SUCCESS) {
-	goto on_error;
-    }
-
-    /* Create mutex for the transaction table. */
+

+    /* Create pool */

+    pool = pj_pool_create(pf, "pept%p", 

+			  PJSIP_POOL_LEN_ENDPT, PJSIP_POOL_INC_ENDPT,

+			  &pool_callback);

+    if (!pool)

+	return PJ_ENOMEM;

+

+    /* Create endpoint. */

+    endpt = pj_pool_calloc(pool, 1, sizeof(*endpt));

+    endpt->pool = pool;

+    endpt->pf = pf;

+

+    /* Create mutex for the events, etc. */

+    status = pj_mutex_create_recursive( endpt->pool, "ept%p", &endpt->mutex );

+    if (status != PJ_SUCCESS) {

+	goto on_error;

+    }

+

+    /* Create mutex for the transaction table. */

     status = pj_mutex_create_recursive( endpt->pool, "mtbl%p", 

-                                        &endpt->tsx_table_mutex);
-    if (status != PJ_SUCCESS) {
-	goto on_error;
-    }
-
-    /* Create hash table for transaction. */
-    endpt->tsx_table = pj_hash_create( endpt->pool, PJSIP_MAX_TSX_COUNT );
-    if (!endpt->tsx_table) {
-	status = PJ_ENOMEM;
-	goto on_error;
-    }
-
-    /* Create timer heap to manage all timers within this endpoint. */
+                                        &endpt->tsx_table_mutex);

+    if (status != PJ_SUCCESS) {

+	goto on_error;

+    }

+

+    /* Create hash table for transaction. */

+    endpt->tsx_table = pj_hash_create( endpt->pool, PJSIP_MAX_TSX_COUNT );

+    if (!endpt->tsx_table) {

+	status = PJ_ENOMEM;

+	goto on_error;

+    }

+

+    /* Create timer heap to manage all timers within this endpoint. */

     status = pj_timer_heap_create( endpt->pool, PJSIP_MAX_TIMER_COUNT, 

-                                   &endpt->timer_heap);
-    if (status != PJ_SUCCESS) {
-	goto on_error;
-    }
-
-    /* Create transport manager. */
-    status = pjsip_transport_mgr_create( endpt->pool,
-					 endpt,
+                                   &endpt->timer_heap);

+    if (status != PJ_SUCCESS) {

+	goto on_error;

+    }

+

+    /* Create transport manager. */

+    status = pjsip_transport_mgr_create( endpt->pool,

+					 endpt,

 					 &endpt_transport_callback,

-					 &endpt->transport_mgr);
-    if (status != PJ_SUCCESS) {
-	goto on_error;
-    }
-
-    /* Create asynchronous DNS resolver. */
-    endpt->resolver = pjsip_resolver_create(endpt->pool);
-    if (!endpt->resolver) {
-	PJ_LOG(4, (THIS_FILE, "pjsip_endpt_init(): error creating resolver"));
-	goto on_error;
-    }
-
-    /* Initialize TLS ID for transaction lock. */
-    status = pj_thread_local_alloc(&pjsip_tsx_lock_tls_id);
-    if (status != PJ_SUCCESS) {
-	goto on_error;
-    }
-    pj_thread_local_set(pjsip_tsx_lock_tls_id, NULL);
-
-    /* Initialize request headers. */
-    pj_list_init(&endpt->req_hdr);
-
-    /* Initialist "Route" header list. */
-    pj_list_init(&endpt->route_hdr_list);
-
-    /* Add "Max-Forwards" for request header. */
-    mf_hdr = pjsip_max_forwards_hdr_create(endpt->pool);
-    mf_hdr->ivalue = PJSIP_MAX_FORWARDS_VALUE;
-    pj_list_insert_before( &endpt->req_hdr, mf_hdr);
-
-    /* Load and init modules. */
-    status = init_modules(endpt);
-    if (status != PJ_SUCCESS) {
-	PJ_LOG(4, (THIS_FILE, "pjsip_endpt_init(): error in init_modules()"));
-	return status;
-    }
-
+					 &endpt->transport_mgr);

+    if (status != PJ_SUCCESS) {

+	goto on_error;

+    }

+

+    /* Create asynchronous DNS resolver. */

+    endpt->resolver = pjsip_resolver_create(endpt->pool);

+    if (!endpt->resolver) {

+	PJ_LOG(4, (THIS_FILE, "pjsip_endpt_init(): error creating resolver"));

+	goto on_error;

+    }

+

+    /* Initialize TLS ID for transaction lock. */

+    status = pj_thread_local_alloc(&pjsip_tsx_lock_tls_id);

+    if (status != PJ_SUCCESS) {

+	goto on_error;

+    }

+    pj_thread_local_set(pjsip_tsx_lock_tls_id, NULL);

+

+    /* Initialize request headers. */

+    pj_list_init(&endpt->req_hdr);

+

+    /* Initialist "Route" header list. */

+    pj_list_init(&endpt->route_hdr_list);

+

+    /* Add "Max-Forwards" for request header. */

+    mf_hdr = pjsip_max_forwards_hdr_create(endpt->pool);

+    mf_hdr->ivalue = PJSIP_MAX_FORWARDS_VALUE;

+    pj_list_insert_before( &endpt->req_hdr, mf_hdr);

+

+    /* Load and init modules. */

+    status = init_modules(endpt);

+    if (status != PJ_SUCCESS) {

+	PJ_LOG(4, (THIS_FILE, "pjsip_endpt_init(): error in init_modules()"));

+	return status;

+    }

+

     /* Done. */

-    *p_endpt = endpt;
-    return status;
-
-on_error:
-    if (endpt->transport_mgr) {
-	pjsip_transport_mgr_destroy(endpt->transport_mgr);
-	endpt->transport_mgr = NULL;
-    }
-    if (endpt->mutex) {
-	pj_mutex_destroy(endpt->mutex);
-	endpt->mutex = NULL;
-    }
-    if (endpt->tsx_table_mutex) {
-	pj_mutex_destroy(endpt->tsx_table_mutex);
-	endpt->tsx_table_mutex = NULL;
-    }
-    pj_pool_release( endpt->pool );
-
-    PJ_LOG(4, (THIS_FILE, "pjsip_endpt_init() failed"));
-    return status;
-}
-
-/*
- * Destroy endpoint.
- */
-PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt)
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy()"));
-
-    /* Shutdown and destroy all transports. */
-    pjsip_transport_mgr_destroy(endpt->transport_mgr);
-
-    /* Delete endpoint mutex. */
-    pj_mutex_destroy(endpt->mutex);
-
-    /* Delete transaction table mutex. */
-    pj_mutex_destroy(endpt->tsx_table_mutex);
-
-    /* Finally destroy pool. */
-    pj_pool_release(endpt->pool);
-}
-
-/*
- * Create new pool.
- */
-PJ_DEF(pj_pool_t*) pjsip_endpt_create_pool( pjsip_endpoint *endpt,
-					       const char *pool_name,
-					       pj_size_t initial,
-					       pj_size_t increment )
-{
-    pj_pool_t *pool;
-
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_pool()"));
-
-    /* Lock endpoint mutex. */
-    pj_mutex_lock(endpt->mutex);
-
-    /* Create pool */
-    pool = pj_pool_create( endpt->pf, pool_name,
-			   initial, increment, &pool_callback);
-
-    /* Unlock mutex. */
-    pj_mutex_unlock(endpt->mutex);
-
-    if (pool) {
-	PJ_LOG(5, (THIS_FILE, "   pool %s created", pj_pool_getobjname(pool)));
-    } else {
-	PJ_LOG(4, (THIS_FILE, "Unable to create pool %s!", pool_name));
-    }
-
-    return pool;
-}
-
-/*
- * Return back pool to endpoint's pool manager to be either destroyed or
- * recycled.
- */
-PJ_DEF(void) pjsip_endpt_destroy_pool( pjsip_endpoint *endpt, pj_pool_t *pool )
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy_pool(%s)", pj_pool_getobjname(pool)));
-
-    pj_mutex_lock(endpt->mutex);
-    pj_pool_release( pool );
-    pj_mutex_unlock(endpt->mutex);
-}
-
-/*
- * Handle events.
- */
-PJ_DEF(void) pjsip_endpt_handle_events( pjsip_endpoint *endpt,
-					const pj_time_val *max_timeout)
-{
-    pj_time_val timeout;
-    int i;
-
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_handle_events()"));
-
-    /* Poll the timer. The timer heap has its own mutex for better 
-     * granularity, so we don't need to lock end endpoint. We also keep
-     * polling the timer while we have events.
-     */
-    timeout.sec = timeout.msec = 0; /* timeout is 'out' var. This just to make compiler happy. */
-    for (i=0; i<10; ++i) {
-	if (pj_timer_heap_poll( endpt->timer_heap, &timeout ) < 1)
-	    break;
-    }
-
-    /* If caller specifies maximum time to wait, then compare the value with
-     * the timeout to wait from timer, and use the minimum value.
-     */
-    if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) {
-	timeout = *max_timeout;
-    }
-
-    /* Poll events in the transport manager. */
-    pjsip_transport_mgr_handle_events( endpt->transport_mgr, &timeout);
-}
-
-/*
- * Schedule timer.
- */
-PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer( pjsip_endpoint *endpt,
-						pj_timer_entry *entry,
-						const pj_time_val *delay )
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_schedule_timer(entry=%p, delay=%u.%u)",
-			 entry, delay->sec, delay->msec));
-    return pj_timer_heap_schedule( endpt->timer_heap, entry, delay );
-}
-
-/*
- * Cancel the previously registered timer.
- */
-PJ_DEF(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt, 
-				       pj_timer_entry *entry )
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_cancel_timer(entry=%p)", entry));
-    pj_timer_heap_cancel( endpt->timer_heap, entry );
-}
-
-/*
- * Create a new transaction.
- * Endpoint must then initialize the new transaction as either UAS or UAC, and
- * register it to the hash table.
- */
+    *p_endpt = endpt;

+    return status;

+

+on_error:

+    if (endpt->transport_mgr) {

+	pjsip_transport_mgr_destroy(endpt->transport_mgr);

+	endpt->transport_mgr = NULL;

+    }

+    if (endpt->mutex) {

+	pj_mutex_destroy(endpt->mutex);

+	endpt->mutex = NULL;

+    }

+    if (endpt->tsx_table_mutex) {

+	pj_mutex_destroy(endpt->tsx_table_mutex);

+	endpt->tsx_table_mutex = NULL;

+    }

+    pj_pool_release( endpt->pool );

+

+    PJ_LOG(4, (THIS_FILE, "pjsip_endpt_init() failed"));

+    return status;

+}

+

+/*

+ * Destroy endpoint.

+ */

+PJ_DEF(void) pjsip_endpt_destroy(pjsip_endpoint *endpt)

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy()"));

+

+    /* Shutdown and destroy all transports. */

+    pjsip_transport_mgr_destroy(endpt->transport_mgr);

+

+    /* Delete endpoint mutex. */

+    pj_mutex_destroy(endpt->mutex);

+

+    /* Delete transaction table mutex. */

+    pj_mutex_destroy(endpt->tsx_table_mutex);

+

+    /* Finally destroy pool. */

+    pj_pool_release(endpt->pool);

+}

+

+/*

+ * Create new pool.

+ */

+PJ_DEF(pj_pool_t*) pjsip_endpt_create_pool( pjsip_endpoint *endpt,

+					       const char *pool_name,

+					       pj_size_t initial,

+					       pj_size_t increment )

+{

+    pj_pool_t *pool;

+

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_pool()"));

+

+    /* Lock endpoint mutex. */

+    pj_mutex_lock(endpt->mutex);

+

+    /* Create pool */

+    pool = pj_pool_create( endpt->pf, pool_name,

+			   initial, increment, &pool_callback);

+

+    /* Unlock mutex. */

+    pj_mutex_unlock(endpt->mutex);

+

+    if (pool) {

+	PJ_LOG(5, (THIS_FILE, "   pool %s created", pj_pool_getobjname(pool)));

+    } else {

+	PJ_LOG(4, (THIS_FILE, "Unable to create pool %s!", pool_name));

+    }

+

+    return pool;

+}

+

+/*

+ * Return back pool to endpoint's pool manager to be either destroyed or

+ * recycled.

+ */

+PJ_DEF(void) pjsip_endpt_destroy_pool( pjsip_endpoint *endpt, pj_pool_t *pool )

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_destroy_pool(%s)", pj_pool_getobjname(pool)));

+

+    pj_mutex_lock(endpt->mutex);

+    pj_pool_release( pool );

+    pj_mutex_unlock(endpt->mutex);

+}

+

+/*

+ * Handle events.

+ */

+PJ_DEF(void) pjsip_endpt_handle_events( pjsip_endpoint *endpt,

+					const pj_time_val *max_timeout)

+{

+    pj_time_val timeout;

+    int i;

+

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_handle_events()"));

+

+    /* Poll the timer. The timer heap has its own mutex for better 

+     * granularity, so we don't need to lock end endpoint. We also keep

+     * polling the timer while we have events.

+     */

+    timeout.sec = timeout.msec = 0; /* timeout is 'out' var. This just to make compiler happy. */

+    for (i=0; i<10; ++i) {

+	if (pj_timer_heap_poll( endpt->timer_heap, &timeout ) < 1)

+	    break;

+    }

+

+    /* If caller specifies maximum time to wait, then compare the value with

+     * the timeout to wait from timer, and use the minimum value.

+     */

+    if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) {

+	timeout = *max_timeout;

+    }

+

+    /* Poll events in the transport manager. */

+    pjsip_transport_mgr_handle_events( endpt->transport_mgr, &timeout);

+}

+

+/*

+ * Schedule timer.

+ */

+PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer( pjsip_endpoint *endpt,

+						pj_timer_entry *entry,

+						const pj_time_val *delay )

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_schedule_timer(entry=%p, delay=%u.%u)",

+			 entry, delay->sec, delay->msec));

+    return pj_timer_heap_schedule( endpt->timer_heap, entry, delay );

+}

+

+/*

+ * Cancel the previously registered timer.

+ */

+PJ_DEF(void) pjsip_endpt_cancel_timer( pjsip_endpoint *endpt, 

+				       pj_timer_entry *entry )

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_cancel_timer(entry=%p)", entry));

+    pj_timer_heap_cancel( endpt->timer_heap, entry );

+}

+

+/*

+ * Create a new transaction.

+ * Endpoint must then initialize the new transaction as either UAS or UAC, and

+ * register it to the hash table.

+ */

 PJ_DEF(pj_status_t) pjsip_endpt_create_tsx(pjsip_endpoint *endpt,

-					   pjsip_transaction **p_tsx)
-{
-    pj_pool_t *pool;
+					   pjsip_transaction **p_tsx)

+{

+    pj_pool_t *pool;

 

     PJ_ASSERT_RETURN(endpt && p_tsx, PJ_EINVAL);

-
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_tsx()"));
-
-    /* Request one pool for the transaction. Mutex is locked there. */
-    pool = pjsip_endpt_create_pool(endpt, "ptsx%p", 
-				      PJSIP_POOL_LEN_TSX, PJSIP_POOL_INC_TSX);
-    if (pool == NULL) {
-	return PJ_ENOMEM;
-    }
-
-    /* Create the transaction. */
-    return pjsip_tsx_create(pool, endpt, p_tsx);
-}
-
-/*
- * Register the transaction to the endpoint.
- * This will put the transaction to the transaction hash table. Before calling
- * this function, the transaction must be INITIALIZED as either UAS or UAC, so
- * that the transaction key is built.
- */
-PJ_DEF(void) pjsip_endpt_register_tsx( pjsip_endpoint *endpt,
-				       pjsip_transaction *tsx)
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_register_tsx(%s)", tsx->obj_name));
-
-    pj_assert(tsx->transaction_key.slen != 0);
-    //pj_assert(tsx->state != PJSIP_TSX_STATE_NULL);
-
-    /* Lock hash table mutex. */
-    pj_mutex_lock(endpt->tsx_table_mutex);
-
-    /* Register the transaction to the hash table. */
-    pj_hash_set( tsx->pool, endpt->tsx_table, tsx->transaction_key.ptr,
-		 tsx->transaction_key.slen, tsx);
-
-    /* Unlock mutex. */
-    pj_mutex_unlock(endpt->tsx_table_mutex);
-}
-
-/*
- * Find transaction by the key.
- */
-PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,
-					          const pj_str_t *key )
-{
-    pjsip_transaction *tsx;
-
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_find_tsx()"));
-
-    /* Start lock mutex in the endpoint. */
-    pj_mutex_lock(endpt->tsx_table_mutex);
-
-    /* Find the transaction in the hash table. */
-    tsx = pj_hash_get( endpt->tsx_table, key->ptr, key->slen );
-
-    /* Unlock mutex. */
-    pj_mutex_unlock(endpt->tsx_table_mutex);
-
-    return tsx;
-}
-
-/*
- * Create key.
- */
-static void rdata_create_key( pjsip_rx_data *rdata)
-{
-    pjsip_role_e role;
-    if (rdata->msg->type == PJSIP_REQUEST_MSG) {
-	role = PJSIP_ROLE_UAS;
-    } else {
-	role = PJSIP_ROLE_UAC;
-    }
-    pjsip_tsx_create_key(rdata->pool, &rdata->key, role,
-			 &rdata->cseq->method, rdata);
-}
-
-/*
- * This is the callback that is called by the transport manager when it 
- * receives a message from the network.
- */
-static void endpt_transport_callback( pjsip_endpoint *endpt,
-				      pjsip_rx_data *rdata )
-{
-    pjsip_msg *msg = rdata->msg;
-    pjsip_transaction *tsx;
-    pj_bool_t a_new_transaction_just_been_created = PJ_FALSE;
-
-    PJ_LOG(5, (THIS_FILE, "endpt_transport_callback(rdata=%p)", rdata));
-
-    /* For response, check that the value in Via sent-by match the transport.
-     * If not matched, silently drop the response.
-     * Ref: RFC3261 Section 18.1.2 Receiving Response
-     */
-    if (msg->type == PJSIP_RESPONSE_MSG) {
-	const pj_sockaddr_in *addr;
-	const char *addr_addr;
-	int port = rdata->via->sent_by.port;
-	pj_bool_t mismatch = PJ_FALSE;
-	if (port == 0) {
-	    int type;
-	    type = pjsip_transport_get_type(rdata->transport);
-	    port = pjsip_transport_get_default_port_for_type(type);
-	}
-	addr = pjsip_transport_get_addr_name(rdata->transport);
-	addr_addr = pj_inet_ntoa(addr->sin_addr);
-	if (pj_strcmp2(&rdata->via->sent_by.host, addr_addr) != 0)
-	    mismatch = PJ_TRUE;
-	else if (port != pj_ntohs(addr->sin_port)) {
-	    /* Port or address mismatch, we should discard response */
-	    /* But we saw one implementation (we don't want to name it to 
-	     * protect the innocence) which put wrong sent-by port although
-	     * the "rport" parameter is correct.
-	     * So we discard the response only if the port doesn't match
-	     * both the port in sent-by and rport. We try to be lenient here!
-	     */
-	    if (rdata->via->rport_param != pj_sockaddr_in_get_port(addr))
-		mismatch = PJ_TRUE;
-	    else {
-		PJ_LOG(4,(THIS_FILE, "Response %p has mismatch port in sent-by"
-				    " but the rport parameter is correct",
-				    rdata));
-	    }
-	}
-
-	if (mismatch) {
-	    pjsip_event e;
-
-	    PJSIP_EVENT_INIT_DISCARD_MSG(e, rdata, PJSIP_EINVALIDVIA);
-	    endpt_do_event( endpt, &e );
-	    return;
-	}
-    } 
-
-    /* Create key for transaction lookup. */
-    rdata_create_key( rdata);
-
-    /* Find the transaction for the received message. */
-    PJ_LOG(5, (THIS_FILE, "finding tsx with key=%.*s", 
-			 rdata->key.slen, rdata->key.ptr));
-
-    /* Start lock mutex in the endpoint. */
-    pj_mutex_lock(endpt->tsx_table_mutex);
-
-    /* Find the transaction in the hash table. */
-    tsx = pj_hash_get( endpt->tsx_table, rdata->key.ptr, rdata->key.slen );
-
-    /* Unlock mutex. */
-    pj_mutex_unlock(endpt->tsx_table_mutex);
-
-    /* If the transaction is not found... */
-    if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) {
-
-	/* 
-	 * For response message, discard the message, except if the response is
-	 * an 2xx class response to INVITE, which in this case it must be
-	 * passed to TU to be acked.
-	 */
-	if (msg->type == PJSIP_RESPONSE_MSG) {
-
-	    /* Inform TU about the 200 message, only if it's INVITE. */
-	    if (PJSIP_IS_STATUS_IN_CLASS(msg->line.status.code, 200) &&
-		rdata->cseq->method.id == PJSIP_INVITE_METHOD) 
-	    {
-		pjsip_event e;
-
-		/* Should not happen for UA. Tsx theoritically lives until
-		 * all responses are absorbed.
-		 */
-		pj_assert(0);
-
-		PJSIP_EVENT_INIT_RX_200_MSG(e, rdata);
-		endpt_do_event( endpt, &e );
-
-	    } else {
-		/* Just discard the response, inform TU. */
-		pjsip_event e;
-
+

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_tsx()"));

+

+    /* Request one pool for the transaction. Mutex is locked there. */

+    pool = pjsip_endpt_create_pool(endpt, "ptsx%p", 

+				      PJSIP_POOL_LEN_TSX, PJSIP_POOL_INC_TSX);

+    if (pool == NULL) {

+	return PJ_ENOMEM;

+    }

+

+    /* Create the transaction. */

+    return pjsip_tsx_create(pool, endpt, p_tsx);

+}

+

+/*

+ * Register the transaction to the endpoint.

+ * This will put the transaction to the transaction hash table. Before calling

+ * this function, the transaction must be INITIALIZED as either UAS or UAC, so

+ * that the transaction key is built.

+ */

+PJ_DEF(void) pjsip_endpt_register_tsx( pjsip_endpoint *endpt,

+				       pjsip_transaction *tsx)

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_register_tsx(%s)", tsx->obj_name));

+

+    pj_assert(tsx->transaction_key.slen != 0);

+    //pj_assert(tsx->state != PJSIP_TSX_STATE_NULL);

+

+    /* Lock hash table mutex. */

+    pj_mutex_lock(endpt->tsx_table_mutex);

+

+    /* Register the transaction to the hash table. */

+    pj_hash_set( tsx->pool, endpt->tsx_table, tsx->transaction_key.ptr,

+		 tsx->transaction_key.slen, tsx);

+

+    /* Unlock mutex. */

+    pj_mutex_unlock(endpt->tsx_table_mutex);

+}

+

+/*

+ * Find transaction by the key.

+ */

+PJ_DECL(pjsip_transaction*) pjsip_endpt_find_tsx( pjsip_endpoint *endpt,

+					          const pj_str_t *key )

+{

+    pjsip_transaction *tsx;

+

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_find_tsx()"));

+

+    /* Start lock mutex in the endpoint. */

+    pj_mutex_lock(endpt->tsx_table_mutex);

+

+    /* Find the transaction in the hash table. */

+    tsx = pj_hash_get( endpt->tsx_table, key->ptr, key->slen );

+

+    /* Unlock mutex. */

+    pj_mutex_unlock(endpt->tsx_table_mutex);

+

+    return tsx;

+}

+

+/*

+ * Create key.

+ */

+static void rdata_create_key( pjsip_rx_data *rdata)

+{

+    pjsip_role_e role;

+    if (rdata->msg->type == PJSIP_REQUEST_MSG) {

+	role = PJSIP_ROLE_UAS;

+    } else {

+	role = PJSIP_ROLE_UAC;

+    }

+    pjsip_tsx_create_key(rdata->pool, &rdata->key, role,

+			 &rdata->cseq->method, rdata);

+}

+

+/*

+ * This is the callback that is called by the transport manager when it 

+ * receives a message from the network.

+ */

+static void endpt_transport_callback( pjsip_endpoint *endpt,

+				      pjsip_rx_data *rdata )

+{

+    pjsip_msg *msg = rdata->msg;

+    pjsip_transaction *tsx;

+    pj_bool_t a_new_transaction_just_been_created = PJ_FALSE;

+

+    PJ_LOG(5, (THIS_FILE, "endpt_transport_callback(rdata=%p)", rdata));

+

+    /* For response, check that the value in Via sent-by match the transport.

+     * If not matched, silently drop the response.

+     * Ref: RFC3261 Section 18.1.2 Receiving Response

+     */

+    if (msg->type == PJSIP_RESPONSE_MSG) {

+	const pj_sockaddr_in *addr;

+	const char *addr_addr;

+	int port = rdata->via->sent_by.port;

+	pj_bool_t mismatch = PJ_FALSE;

+	if (port == 0) {

+	    int type;

+	    type = pjsip_transport_get_type(rdata->transport);

+	    port = pjsip_transport_get_default_port_for_type(type);

+	}

+	addr = pjsip_transport_get_addr_name(rdata->transport);

+	addr_addr = pj_inet_ntoa(addr->sin_addr);

+	if (pj_strcmp2(&rdata->via->sent_by.host, addr_addr) != 0)

+	    mismatch = PJ_TRUE;

+	else if (port != pj_ntohs(addr->sin_port)) {

+	    /* Port or address mismatch, we should discard response */

+	    /* But we saw one implementation (we don't want to name it to 

+	     * protect the innocence) which put wrong sent-by port although

+	     * the "rport" parameter is correct.

+	     * So we discard the response only if the port doesn't match

+	     * both the port in sent-by and rport. We try to be lenient here!

+	     */

+	    if (rdata->via->rport_param != pj_sockaddr_in_get_port(addr))

+		mismatch = PJ_TRUE;

+	    else {

+		PJ_LOG(4,(THIS_FILE, "Response %p has mismatch port in sent-by"

+				    " but the rport parameter is correct",

+				    rdata));

+	    }

+	}

+

+	if (mismatch) {

+	    pjsip_event e;

+

+	    PJSIP_EVENT_INIT_DISCARD_MSG(e, rdata, PJSIP_EINVALIDVIA);

+	    endpt_do_event( endpt, &e );

+	    return;

+	}

+    } 

+

+    /* Create key for transaction lookup. */

+    rdata_create_key( rdata);

+

+    /* Find the transaction for the received message. */

+    PJ_LOG(5, (THIS_FILE, "finding tsx with key=%.*s", 

+			 rdata->key.slen, rdata->key.ptr));

+

+    /* Start lock mutex in the endpoint. */

+    pj_mutex_lock(endpt->tsx_table_mutex);

+

+    /* Find the transaction in the hash table. */

+    tsx = pj_hash_get( endpt->tsx_table, rdata->key.ptr, rdata->key.slen );

+

+    /* Unlock mutex. */

+    pj_mutex_unlock(endpt->tsx_table_mutex);

+

+    /* If the transaction is not found... */

+    if (tsx == NULL || tsx->state == PJSIP_TSX_STATE_TERMINATED) {

+

+	/* 

+	 * For response message, discard the message, except if the response is

+	 * an 2xx class response to INVITE, which in this case it must be

+	 * passed to TU to be acked.

+	 */

+	if (msg->type == PJSIP_RESPONSE_MSG) {

+

+	    /* Inform TU about the 200 message, only if it's INVITE. */

+	    if (PJSIP_IS_STATUS_IN_CLASS(msg->line.status.code, 200) &&

+		rdata->cseq->method.id == PJSIP_INVITE_METHOD) 

+	    {

+		pjsip_event e;

+

+		/* Should not happen for UA. Tsx theoritically lives until

+		 * all responses are absorbed.

+		 */

+		pj_assert(0);

+

+		PJSIP_EVENT_INIT_RX_200_MSG(e, rdata);

+		endpt_do_event( endpt, &e );

+

+	    } else {

+		/* Just discard the response, inform TU. */

+		pjsip_event e;

+

 		PJSIP_EVENT_INIT_DISCARD_MSG(e, rdata, 

-		    PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_CALL_TSX_DOES_NOT_EXIST));
-		endpt_do_event( endpt, &e );
-	    }
-
-	/*
-	 * For non-ACK request message, create a new transaction.
-	 */
+		    PJSIP_ERRNO_FROM_SIP_STATUS(PJSIP_SC_CALL_TSX_DOES_NOT_EXIST));

+		endpt_do_event( endpt, &e );

+	    }

+

+	/*

+	 * For non-ACK request message, create a new transaction.

+	 */

 	} else if (rdata->msg->line.req.method.id != PJSIP_ACK_METHOD) {

 

 	    pj_status_t status;

-
-	    /* Create transaction, mutex is locked there. */
-	    status = pjsip_endpt_create_tsx(endpt, &tsx);
+

+	    /* Create transaction, mutex is locked there. */

+	    status = pjsip_endpt_create_tsx(endpt, &tsx);

 	    if (status != PJ_SUCCESS) {

 		PJSIP_ENDPT_LOG_ERROR((endpt, THIS_FILE, status,

-				       "Unable to create transaction"));
+				       "Unable to create transaction"));

 		return;

-	    }
-
-	    /* Initialize transaction as UAS. */
-	    pjsip_tsx_init_uas( tsx, rdata );
-
-	    /* Register transaction, mutex is locked there. */
-	    pjsip_endpt_register_tsx( endpt, tsx );
-
-	    a_new_transaction_just_been_created = PJ_TRUE;
-	}
-    }
-
-    /* If transaction is found (or newly created), pass the message.
-     * Otherwise if it's an ACK request, pass directly to TU.
-     */
-    if (tsx && tsx->state != PJSIP_TSX_STATE_TERMINATED) {
-	/* Dispatch message to transaction. */
-	pjsip_tsx_on_rx_msg( tsx, rdata );
-
-    } else if (rdata->msg->line.req.method.id == PJSIP_ACK_METHOD) {
-	/*
-	 * This is an ACK message, but the INVITE transaction could not
-	 * be found (possibly because the branch parameter in Via in ACK msg
-	 * is different than the branch in original INVITE). This happens with
-	 * SER!
-	 */
-	pjsip_event event;
-
-	PJSIP_EVENT_INIT_RX_ACK_MSG(event,rdata);
-	endpt_do_event( endpt, &event );
-    }
-
-    /*
-     * If a new request message has just been receieved, but no modules
-     * seem to be able to handle the request message, then terminate the
-     * transaction.
-     *
-     * Ideally for cases like "unsupported method", we should be able to
-     * answer the request statelessly. But we can not do that since the
-     * endpoint shoule be able to be used as both user agent and proxy stack,
-     * and a proxy stack should be able to handle arbitrary methods.
-     */
-    if (a_new_transaction_just_been_created && tsx->status_code < 100) {
-	/* Certainly no modules has sent any response message.
-	 * Check that any modules has attached a module data.
-	 */
-	int i;
-	for (i=0; i<PJSIP_MAX_MODULE; ++i) {
-	    if (tsx->module_data[i] != NULL) {
-		break;
-	    }
-	}
-	if (i == PJSIP_MAX_MODULE) {
-	    /* No modules have attached itself to the transaction. 
-	     * Terminate the transaction with 501/Not Implemented.
-	     */
+	    }

+

+	    /* Initialize transaction as UAS. */

+	    pjsip_tsx_init_uas( tsx, rdata );

+

+	    /* Register transaction, mutex is locked there. */

+	    pjsip_endpt_register_tsx( endpt, tsx );

+

+	    a_new_transaction_just_been_created = PJ_TRUE;

+	}

+    }

+

+    /* If transaction is found (or newly created), pass the message.

+     * Otherwise if it's an ACK request, pass directly to TU.

+     */

+    if (tsx && tsx->state != PJSIP_TSX_STATE_TERMINATED) {

+	/* Dispatch message to transaction. */

+	pjsip_tsx_on_rx_msg( tsx, rdata );

+

+    } else if (rdata->msg->line.req.method.id == PJSIP_ACK_METHOD) {

+	/*

+	 * This is an ACK message, but the INVITE transaction could not

+	 * be found (possibly because the branch parameter in Via in ACK msg

+	 * is different than the branch in original INVITE). This happens with

+	 * SER!

+	 */

+	pjsip_event event;

+

+	PJSIP_EVENT_INIT_RX_ACK_MSG(event,rdata);

+	endpt_do_event( endpt, &event );

+    }

+

+    /*

+     * If a new request message has just been receieved, but no modules

+     * seem to be able to handle the request message, then terminate the

+     * transaction.

+     *

+     * Ideally for cases like "unsupported method", we should be able to

+     * answer the request statelessly. But we can not do that since the

+     * endpoint shoule be able to be used as both user agent and proxy stack,

+     * and a proxy stack should be able to handle arbitrary methods.

+     */

+    if (a_new_transaction_just_been_created && tsx->status_code < 100) {

+	/* Certainly no modules has sent any response message.

+	 * Check that any modules has attached a module data.

+	 */

+	int i;

+	for (i=0; i<PJSIP_MAX_MODULE; ++i) {

+	    if (tsx->module_data[i] != NULL) {

+		break;

+	    }

+	}

+	if (i == PJSIP_MAX_MODULE) {

+	    /* No modules have attached itself to the transaction. 

+	     * Terminate the transaction with 501/Not Implemented.

+	     */

 	    pjsip_tx_data *tdata;

-	    pj_status_t status;
-	    
-	    if (tsx->method.id == PJSIP_OPTIONS_METHOD) {
+	    pj_status_t status;

+	    

+	    if (tsx->method.id == PJSIP_OPTIONS_METHOD) {

 		status = pjsip_endpt_create_response(endpt, rdata, 200, 

-						     &tdata);
-	    } else {
-		status = pjsip_endpt_create_response(endpt, rdata, 
+						     &tdata);

+	    } else {

+		status = pjsip_endpt_create_response(endpt, rdata, 

 						     PJSIP_SC_METHOD_NOT_ALLOWED,

-						     &tdata);
+						     &tdata);

 	    }

 

 	    if (status != PJ_SUCCESS) {

@@ -843,202 +865,202 @@
 				       "Unable to create response"));

 		return;

 	    }

-
-	    if (endpt->allow_hdr) {
-		pjsip_msg_add_hdr( tdata->msg, 
-				   pjsip_hdr_shallow_clone(tdata->pool, endpt->allow_hdr));
-	    }
-	    pjsip_tsx_on_tx_msg( tsx, tdata );
-
-	} else {
-	    /*
-	     * If a module has registered itself in the transaction but it
-	     * hasn't responded the request, chances are the module wouldn't
-	     * respond to the request at all. We terminate the request here
-	     * with 500/Internal Server Error, to be safe.
-	     */
+

+	    if (endpt->allow_hdr) {

+		pjsip_msg_add_hdr( tdata->msg, 

+				   pjsip_hdr_shallow_clone(tdata->pool, endpt->allow_hdr));

+	    }

+	    pjsip_tsx_on_tx_msg( tsx, tdata );

+

+	} else {

+	    /*

+	     * If a module has registered itself in the transaction but it

+	     * hasn't responded the request, chances are the module wouldn't

+	     * respond to the request at all. We terminate the request here

+	     * with 500/Internal Server Error, to be safe.

+	     */

 	    pjsip_tx_data *tdata;

 	    pj_status_t status;

-
+

 	    status = pjsip_endpt_create_response(endpt, rdata, 500, &tdata);

 	    if (status != PJ_SUCCESS) {

 		PJSIP_ENDPT_LOG_ERROR((endpt, THIS_FILE, status,

 				       "Unable to create response"));

 		return;

 	    }

-
-	    pjsip_tsx_on_tx_msg(tsx, tdata);
-	}
-    }
-}
-
-/*
- * Create transmit data buffer.
- */
+

+	    pjsip_tsx_on_tx_msg(tsx, tdata);

+	}

+    }

+}

+

+/*

+ * Create transmit data buffer.

+ */

 PJ_DEF(pj_status_t) pjsip_endpt_create_tdata(  pjsip_endpoint *endpt,

 					       pjsip_tx_data **p_tdata)

-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_tdata()"));
-    return pjsip_tx_data_create(endpt->transport_mgr, p_tdata);
-}
-
-/*
- * Resolve
- */
-PJ_DEF(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,
-				  pj_pool_t *pool,
-				  pjsip_host_port *target,
-				  void *token,
-				  pjsip_resolver_callback *cb)
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_resolve()"));
-    pjsip_resolve( endpt->resolver, pool, target, token, cb);
-}
-
-/*
- * Find/create transport.
- */
-PJ_DEF(void) pjsip_endpt_get_transport( pjsip_endpoint *endpt,
-					pj_pool_t *pool,
-					pjsip_transport_type_e type,
-					const pj_sockaddr_in *remote,
-					void *token,
-					pjsip_transport_completion_callback *cb)
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_get_transport()"));
-    pjsip_transport_get( endpt->transport_mgr, pool, type,
-			 remote, token, cb);
-}
-
-
-PJ_DEF(pj_status_t) pjsip_endpt_create_listener( pjsip_endpoint *endpt,
-						 pjsip_transport_type_e type,
-						 pj_sockaddr_in *addr,
-						 const pj_sockaddr_in *addr_name)
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_listener()"));
-    return pjsip_create_listener( endpt->transport_mgr, type, addr, addr_name );
-}
-
-PJ_DEF(pj_status_t) pjsip_endpt_create_udp_listener( pjsip_endpoint *endpt,
-						     pj_sock_t sock,
-						     const pj_sockaddr_in *addr_name)
-{
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_udp_listener()"));
-    return pjsip_create_udp_listener( endpt->transport_mgr, sock, addr_name );
-}
-
-PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail )
-{
-#if PJ_LOG_MAX_LEVEL >= 3
-    unsigned count;
-    pj_hash_iterator_t itr_val;
-    pj_hash_iterator_t *itr;
-
-    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_dump()"));
-
-    /* Lock mutex. */
-    pj_mutex_lock(endpt->mutex);
-
-    PJ_LOG(3, (THIS_FILE, "Dumping endpoint %p:", endpt));
-    
-    /* Dumping pool factory. */
-    (*endpt->pf->dump_status)(endpt->pf, detail);
-
-    /* Pool health. */
-    PJ_LOG(3, (THIS_FILE," Endpoint pool capacity=%u, used_size=%u",
-	       pj_pool_get_capacity(endpt->pool),
-	       pj_pool_get_used_size(endpt->pool)));
-
-    /* Transaction tables. */
-    count = pj_hash_count(endpt->tsx_table);
-    PJ_LOG(3, (THIS_FILE, " Number of transactions: %u", count));
-
-    if (count && detail) {
-	pj_hash_iterator_t it_val;
-	pj_hash_iterator_t *it;
-	pj_time_val now;
-
-	PJ_LOG(3, (THIS_FILE, " Dumping transaction tables:"));
-
-	pj_gettimeofday(&now);
-	it = pj_hash_first(endpt->tsx_table, &it_val);
-
-	while (it != NULL) {
-	    int timeout_diff;
-
-	    /* Get the transaction. No need to lock transaction's mutex
-	     * since we already hold endpoint mutex, so that no transactions
-	     * will be deleted.
-	     */
-	    pjsip_transaction *tsx = pj_hash_this(endpt->tsx_table, it);
-
-	    const char *role = (tsx->role == PJSIP_ROLE_UAS ? "UAS" : "UAC");
-	
-	    if (tsx->timeout_timer._timer_id != -1) {
-		if (tsx->timeout_timer._timer_value.sec > now.sec) {
-		    timeout_diff = tsx->timeout_timer._timer_value.sec - now.sec;
-		} else {
-		    timeout_diff = now.sec - tsx->timeout_timer._timer_value.sec;
-		    timeout_diff = 0 - timeout_diff;
-		}
-	    } else {
-		timeout_diff = -1;
-	    }
-
-	    PJ_LOG(3, (THIS_FILE, "  %s %s %10.*s %.9u %s t=%ds", 
-		       tsx->obj_name, role, 
-		       tsx->method.name.slen, tsx->method.name.ptr,
-		       tsx->cseq,
-		       pjsip_tsx_state_str(tsx->state),
-		       timeout_diff));
-
-	    it = pj_hash_next(endpt->tsx_table, it);
-	}
-    }
-
-    /* Transports. 
-     * Note: transport is not properly locked in this function.
-     *       See pjsip_transport_first, pjsip_transport_next.
-     */
-    itr = pjsip_transport_first( endpt->transport_mgr, &itr_val );
-    if (itr) {
-	PJ_LOG(3, (THIS_FILE, " Dumping transports:"));
-
-	do {
-	    char src_addr[128], dst_addr[128];
-	    int src_port, dst_port;
-	    const pj_sockaddr_in *addr;
-	    pjsip_transport_t *t;
-
-	    t = pjsip_transport_this(endpt->transport_mgr, itr);
-	    addr = pjsip_transport_get_local_addr(t);
-	    pj_native_strcpy(src_addr, pj_inet_ntoa(addr->sin_addr));
-	    src_port = pj_ntohs(addr->sin_port);
-
-	    addr = pjsip_transport_get_remote_addr(t);
-	    pj_native_strcpy(dst_addr, pj_inet_ntoa(addr->sin_addr));
-	    dst_port = pj_ntohs(addr->sin_port);
-
-	    PJ_LOG(3, (THIS_FILE, "  %s %s %s:%d --> %s:%d (refcnt=%d)", 
-		       pjsip_transport_get_type_name(t),
-		       pjsip_transport_get_obj_name(t),
-		       src_addr, src_port,
-		       dst_addr, dst_port,
-		       pjsip_transport_get_ref_cnt(t)));
-
-	    itr = pjsip_transport_next(endpt->transport_mgr, itr);
-	} while (itr);
-    }
-
-    /* Timer. */
-    PJ_LOG(3,(THIS_FILE, " Timer heap has %u entries", 
-			pj_timer_heap_count(endpt->timer_heap)));
-
-    /* Unlock mutex. */
-    pj_mutex_unlock(endpt->mutex);
-#else
-    PJ_LOG(3,(THIS_FILE, "pjsip_end_dump: can't dump because it's disabled."));
-#endif
-}
-
+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_tdata()"));

+    return pjsip_tx_data_create(endpt->transport_mgr, p_tdata);

+}

+

+/*

+ * Resolve

+ */

+PJ_DEF(void) pjsip_endpt_resolve( pjsip_endpoint *endpt,

+				  pj_pool_t *pool,

+				  pjsip_host_port *target,

+				  void *token,

+				  pjsip_resolver_callback *cb)

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_resolve()"));

+    pjsip_resolve( endpt->resolver, pool, target, token, cb);

+}

+

+/*

+ * Find/create transport.

+ */

+PJ_DEF(void) pjsip_endpt_get_transport( pjsip_endpoint *endpt,

+					pj_pool_t *pool,

+					pjsip_transport_type_e type,

+					const pj_sockaddr_in *remote,

+					void *token,

+					pjsip_transport_completion_callback *cb)

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_get_transport()"));

+    pjsip_transport_get( endpt->transport_mgr, pool, type,

+			 remote, token, cb);

+}

+

+

+PJ_DEF(pj_status_t) pjsip_endpt_create_listener( pjsip_endpoint *endpt,

+						 pjsip_transport_type_e type,

+						 pj_sockaddr_in *addr,

+						 const pj_sockaddr_in *addr_name)

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_listener()"));

+    return pjsip_create_listener( endpt->transport_mgr, type, addr, addr_name );

+}

+

+PJ_DEF(pj_status_t) pjsip_endpt_create_udp_listener( pjsip_endpoint *endpt,

+						     pj_sock_t sock,

+						     const pj_sockaddr_in *addr_name)

+{

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_create_udp_listener()"));

+    return pjsip_create_udp_listener( endpt->transport_mgr, sock, addr_name );

+}

+

+PJ_DEF(void) pjsip_endpt_dump( pjsip_endpoint *endpt, pj_bool_t detail )

+{

+#if PJ_LOG_MAX_LEVEL >= 3

+    unsigned count;

+    pj_hash_iterator_t itr_val;

+    pj_hash_iterator_t *itr;

+

+    PJ_LOG(5, (THIS_FILE, "pjsip_endpt_dump()"));

+

+    /* Lock mutex. */

+    pj_mutex_lock(endpt->mutex);

+

+    PJ_LOG(3, (THIS_FILE, "Dumping endpoint %p:", endpt));

+    

+    /* Dumping pool factory. */

+    (*endpt->pf->dump_status)(endpt->pf, detail);

+

+    /* Pool health. */

+    PJ_LOG(3, (THIS_FILE," Endpoint pool capacity=%u, used_size=%u",

+	       pj_pool_get_capacity(endpt->pool),

+	       pj_pool_get_used_size(endpt->pool)));

+

+    /* Transaction tables. */

+    count = pj_hash_count(endpt->tsx_table);

+    PJ_LOG(3, (THIS_FILE, " Number of transactions: %u", count));

+

+    if (count && detail) {

+	pj_hash_iterator_t it_val;

+	pj_hash_iterator_t *it;

+	pj_time_val now;

+

+	PJ_LOG(3, (THIS_FILE, " Dumping transaction tables:"));

+

+	pj_gettimeofday(&now);

+	it = pj_hash_first(endpt->tsx_table, &it_val);

+

+	while (it != NULL) {

+	    int timeout_diff;

+

+	    /* Get the transaction. No need to lock transaction's mutex

+	     * since we already hold endpoint mutex, so that no transactions

+	     * will be deleted.

+	     */

+	    pjsip_transaction *tsx = pj_hash_this(endpt->tsx_table, it);

+

+	    const char *role = (tsx->role == PJSIP_ROLE_UAS ? "UAS" : "UAC");

+	

+	    if (tsx->timeout_timer._timer_id != -1) {

+		if (tsx->timeout_timer._timer_value.sec > now.sec) {

+		    timeout_diff = tsx->timeout_timer._timer_value.sec - now.sec;

+		} else {

+		    timeout_diff = now.sec - tsx->timeout_timer._timer_value.sec;

+		    timeout_diff = 0 - timeout_diff;

+		}

+	    } else {

+		timeout_diff = -1;

+	    }

+

+	    PJ_LOG(3, (THIS_FILE, "  %s %s %10.*s %.9u %s t=%ds", 

+		       tsx->obj_name, role, 

+		       tsx->method.name.slen, tsx->method.name.ptr,

+		       tsx->cseq,

+		       pjsip_tsx_state_str(tsx->state),

+		       timeout_diff));

+

+	    it = pj_hash_next(endpt->tsx_table, it);

+	}

+    }

+

+    /* Transports. 

+     * Note: transport is not properly locked in this function.

+     *       See pjsip_transport_first, pjsip_transport_next.

+     */

+    itr = pjsip_transport_first( endpt->transport_mgr, &itr_val );

+    if (itr) {

+	PJ_LOG(3, (THIS_FILE, " Dumping transports:"));

+

+	do {

+	    char src_addr[128], dst_addr[128];

+	    int src_port, dst_port;

+	    const pj_sockaddr_in *addr;

+	    pjsip_transport_t *t;

+

+	    t = pjsip_transport_this(endpt->transport_mgr, itr);

+	    addr = pjsip_transport_get_local_addr(t);

+	    pj_native_strcpy(src_addr, pj_inet_ntoa(addr->sin_addr));

+	    src_port = pj_ntohs(addr->sin_port);

+

+	    addr = pjsip_transport_get_remote_addr(t);

+	    pj_native_strcpy(dst_addr, pj_inet_ntoa(addr->sin_addr));

+	    dst_port = pj_ntohs(addr->sin_port);

+

+	    PJ_LOG(3, (THIS_FILE, "  %s %s %s:%d --> %s:%d (refcnt=%d)", 

+		       pjsip_transport_get_type_name(t),

+		       pjsip_transport_get_obj_name(t),

+		       src_addr, src_port,

+		       dst_addr, dst_port,

+		       pjsip_transport_get_ref_cnt(t)));

+

+	    itr = pjsip_transport_next(endpt->transport_mgr, itr);

+	} while (itr);

+    }

+

+    /* Timer. */

+    PJ_LOG(3,(THIS_FILE, " Timer heap has %u entries", 

+			pj_timer_heap_count(endpt->timer_heap)));

+

+    /* Unlock mutex. */

+    pj_mutex_unlock(endpt->mutex);

+#else

+    PJ_LOG(3,(THIS_FILE, "pjsip_end_dump: can't dump because it's disabled."));

+#endif

+}

+

diff --git a/pjsip/src/pjsip/sip_misc.c b/pjsip/src/pjsip/sip_misc.c
index a956239..ce1ceb8 100644
--- a/pjsip/src/pjsip/sip_misc.c
+++ b/pjsip/src/pjsip/sip_misc.c
@@ -1,166 +1,188 @@
-/* $Id$
- */
-#include <pjsip/sip_misc.h>
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_module.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/guid.h>
-#include <pj/pool.h>
-#include <pj/except.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_misc.h>

+#include <pjsip/sip_transport.h>

+#include <pjsip/sip_msg.h>

+#include <pjsip/sip_endpoint.h>

+#include <pjsip/sip_event.h>

+#include <pjsip/sip_transaction.h>

+#include <pjsip/sip_module.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/guid.h>

+#include <pj/pool.h>

+#include <pj/except.h>

 #include <pj/rand.h>

 #include <pj/assert.h>

 #include <pj/errno.h>

-
-#define THIS_FILE    "endpoint"
-
-static const char *event_str[] = 
-{
-    "UNIDENTIFIED",
-    "TIMER",
-    "TX_MSG",
-    "RX_MSG",
-    "TRANSPORT_ERROR",
-    "TSX_STATE",
-    "RX_2XX_RESPONSE",
-    "RX_ACK",
-    "DISCARD_MSG",
-    "USER",
-    "BEFORE_TX",
-};
-
-static pj_str_t str_TEXT = { "text", 4},
-		str_PLAIN = { "plain", 5 };
-static int aux_mod_id;
-
-struct aux_tsx_data
-{
-    void *token;
-    void (*cb)(void*,pjsip_event*);
-};
-
-static pj_status_t aux_tsx_init( pjsip_endpoint *endpt,
-				 struct pjsip_module *mod, pj_uint32_t id )
-{
-    PJ_UNUSED_ARG(endpt);
-    PJ_UNUSED_ARG(mod);
-
-    aux_mod_id = id;
-    return 0;
-}
-
-static void aux_tsx_handler( struct pjsip_module *mod, pjsip_event *event )
-{
-    pjsip_transaction *tsx;
-    struct aux_tsx_data *tsx_data;
-
-    PJ_UNUSED_ARG(mod);
-
-    if (event->type != PJSIP_EVENT_TSX_STATE)
+

+#define THIS_FILE    "endpoint"

+

+static const char *event_str[] = 

+{

+    "UNIDENTIFIED",

+    "TIMER",

+    "TX_MSG",

+    "RX_MSG",

+    "TRANSPORT_ERROR",

+    "TSX_STATE",

+    "RX_2XX_RESPONSE",

+    "RX_ACK",

+    "DISCARD_MSG",

+    "USER",

+    "BEFORE_TX",

+};

+

+static pj_str_t str_TEXT = { "text", 4},

+		str_PLAIN = { "plain", 5 };

+static int aux_mod_id;

+

+struct aux_tsx_data

+{

+    void *token;

+    void (*cb)(void*,pjsip_event*);

+};

+

+static pj_status_t aux_tsx_init( pjsip_endpoint *endpt,

+				 struct pjsip_module *mod, pj_uint32_t id )

+{

+    PJ_UNUSED_ARG(endpt);

+    PJ_UNUSED_ARG(mod);

+

+    aux_mod_id = id;

+    return 0;

+}

+

+static void aux_tsx_handler( struct pjsip_module *mod, pjsip_event *event )

+{

+    pjsip_transaction *tsx;

+    struct aux_tsx_data *tsx_data;

+

+    PJ_UNUSED_ARG(mod);

+

+    if (event->type != PJSIP_EVENT_TSX_STATE)

 	return;

 

     pj_assert(event->body.tsx_state.tsx != NULL);

-    tsx = event->body.tsx_state.tsx;
-    if (tsx == NULL)
-	return;
-    if (tsx->module_data[aux_mod_id] == NULL)
-	return;
-    if (tsx->status_code < 200)
-	return;
-
-    /* Call the callback, if any, and prevent the callback to be called again
-     * by clearing the transaction's module_data.
-     */
-    tsx_data = tsx->module_data[aux_mod_id];
-    tsx->module_data[aux_mod_id] = NULL;
-
-    if (tsx_data->cb) {
-	(*tsx_data->cb)(tsx_data->token, event);
-    }
-}
-
-pjsip_module aux_tsx_module = 
-{
-    { "Aux-Tsx", 7},	    /* Name.		*/
-    0,			    /* Flag		*/
-    128,		    /* Priority		*/
-    NULL,		    /* Arbitrary data.	*/
-    0,			    /* Number of methods supported (none). */
-    { 0 },		    /* Array of methods (none) */
-    &aux_tsx_init,	    /* init_module()	*/
-    NULL,		    /* start_module()	*/
-    NULL,		    /* deinit_module()	*/
-    &aux_tsx_handler,	    /* tsx_handler()	*/
-};
-
-PJ_DEF(pj_status_t) pjsip_endpt_send_request(  pjsip_endpoint *endpt,
-					       pjsip_tx_data *tdata,
-					       int timeout,
-					       void *token,
-					       void (*cb)(void*,pjsip_event*))
-{
-    pjsip_transaction *tsx;
+    tsx = event->body.tsx_state.tsx;

+    if (tsx == NULL)

+	return;

+    if (tsx->module_data[aux_mod_id] == NULL)

+	return;

+    if (tsx->status_code < 200)

+	return;

+

+    /* Call the callback, if any, and prevent the callback to be called again

+     * by clearing the transaction's module_data.

+     */

+    tsx_data = tsx->module_data[aux_mod_id];

+    tsx->module_data[aux_mod_id] = NULL;

+

+    if (tsx_data->cb) {

+	(*tsx_data->cb)(tsx_data->token, event);

+    }

+}

+

+pjsip_module aux_tsx_module = 

+{

+    { "Aux-Tsx", 7},	    /* Name.		*/

+    0,			    /* Flag		*/

+    128,		    /* Priority		*/

+    NULL,		    /* Arbitrary data.	*/

+    0,			    /* Number of methods supported (none). */

+    { 0 },		    /* Array of methods (none) */

+    &aux_tsx_init,	    /* init_module()	*/

+    NULL,		    /* start_module()	*/

+    NULL,		    /* deinit_module()	*/

+    &aux_tsx_handler,	    /* tsx_handler()	*/

+};

+

+PJ_DEF(pj_status_t) pjsip_endpt_send_request(  pjsip_endpoint *endpt,

+					       pjsip_tx_data *tdata,

+					       int timeout,

+					       void *token,

+					       void (*cb)(void*,pjsip_event*))

+{

+    pjsip_transaction *tsx;

     struct aux_tsx_data *tsx_data;

-    pj_status_t status;
-
-    status = pjsip_endpt_create_tsx(endpt, &tsx);
-    if (!tsx) {
-	pjsip_tx_data_dec_ref(tdata);
-	return -1;
-    }
-
-    tsx_data = pj_pool_alloc(tsx->pool, sizeof(struct aux_tsx_data));
-    tsx_data->token = token;
-    tsx_data->cb = cb;
-    tsx->module_data[aux_mod_id] = tsx_data;
-
-    if (pjsip_tsx_init_uac(tsx, tdata) != 0) {
-	pjsip_endpt_destroy_tsx(endpt, tsx);
-	pjsip_tx_data_dec_ref(tdata);
-	return -1;
-    }
-
-    pjsip_endpt_register_tsx(endpt, tsx);
-    pjsip_tx_data_invalidate_msg(tdata);
-    pjsip_tsx_on_tx_msg(tsx, tdata);
-    pjsip_tx_data_dec_ref(tdata);
-    return 0;
-}
-
-/*
- * Initialize transmit data (msg) with the headers and optional body.
- * This will just put the headers in the message as it is. Be carefull
- * when calling this function because once a header is put in a message, 
- * it CAN NOT be put in other message until the first message is deleted, 
- * because the way the header is put in the list.
- * That's why the session will shallow_clone it's headers before calling
- * this function.
- */
+    pj_status_t status;

+

+    status = pjsip_endpt_create_tsx(endpt, &tsx);

+    if (!tsx) {

+	pjsip_tx_data_dec_ref(tdata);

+	return -1;

+    }

+

+    tsx_data = pj_pool_alloc(tsx->pool, sizeof(struct aux_tsx_data));

+    tsx_data->token = token;

+    tsx_data->cb = cb;

+    tsx->module_data[aux_mod_id] = tsx_data;

+

+    if (pjsip_tsx_init_uac(tsx, tdata) != 0) {

+	pjsip_endpt_destroy_tsx(endpt, tsx);

+	pjsip_tx_data_dec_ref(tdata);

+	return -1;

+    }

+

+    pjsip_endpt_register_tsx(endpt, tsx);

+    pjsip_tx_data_invalidate_msg(tdata);

+    pjsip_tsx_on_tx_msg(tsx, tdata);

+    pjsip_tx_data_dec_ref(tdata);

+    return 0;

+}

+

+/*

+ * Initialize transmit data (msg) with the headers and optional body.

+ * This will just put the headers in the message as it is. Be carefull

+ * when calling this function because once a header is put in a message, 

+ * it CAN NOT be put in other message until the first message is deleted, 

+ * because the way the header is put in the list.

+ * That's why the session will shallow_clone it's headers before calling

+ * this function.

+ */

 static void init_request_throw( pjsip_endpoint *endpt,

-                                pjsip_tx_data *tdata, 
-				pjsip_method *method,
-				pjsip_uri *param_target,
-				pjsip_from_hdr *param_from,
-				pjsip_to_hdr *param_to, 
-				pjsip_contact_hdr *param_contact,
-				pjsip_cid_hdr *param_call_id,
-				pjsip_cseq_hdr *param_cseq, 
-				const pj_str_t *param_text)
-{
-    pjsip_msg *msg;
-    pjsip_msg_body *body;
+                                pjsip_tx_data *tdata, 

+				pjsip_method *method,

+				pjsip_uri *param_target,

+				pjsip_from_hdr *param_from,

+				pjsip_to_hdr *param_to, 

+				pjsip_contact_hdr *param_contact,

+				pjsip_cid_hdr *param_call_id,

+				pjsip_cseq_hdr *param_cseq, 

+				const pj_str_t *param_text)

+{

+    pjsip_msg *msg;

+    pjsip_msg_body *body;

     const pjsip_hdr *endpt_hdr;

-
-    /* Create the message. */
-    msg = tdata->msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);
-
-    /* Init request URI. */
-    pj_memcpy(&msg->line.req.method, method, sizeof(*method));
-    msg->line.req.uri = param_target;
+

+    /* Create the message. */

+    msg = tdata->msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);

+

+    /* Init request URI. */

+    pj_memcpy(&msg->line.req.method, method, sizeof(*method));

+    msg->line.req.uri = param_target;

 

     /* Add additional request headers from endpoint. */

     endpt_hdr = pjsip_endpt_get_request_headers(endpt)->next;

@@ -170,539 +192,539 @@
 	endpt_hdr = endpt_hdr->next;

     }

 

-    /* Add From header. */
-    if (param_from->tag.slen == 0)
-	pj_create_unique_string(tdata->pool, &param_from->tag);
-    pjsip_msg_add_hdr(msg, (void*)param_from);
-
-    /* Add To header. */
-    pjsip_msg_add_hdr(msg, (void*)param_to);
-
-    /* Add Contact header. */
-    if (param_contact) {
-	pjsip_msg_add_hdr(msg, (void*)param_contact);
-    }
-
-    /* Add Call-ID header. */
-    pjsip_msg_add_hdr(msg, (void*)param_call_id);
-
-    /* Add CSeq header. */
-    pjsip_msg_add_hdr(msg, (void*)param_cseq);
-
-    /* Create message body. */
-    if (param_text) {
-	body = pj_pool_calloc(tdata->pool, 1, sizeof(pjsip_msg_body));
-	body->content_type.type = str_TEXT;
-	body->content_type.subtype = str_PLAIN;
-	body->data = pj_pool_alloc(tdata->pool, param_text->slen );
-	pj_memcpy(body->data, param_text->ptr, param_text->slen);
-	body->len = param_text->slen;
-	body->print_body = &pjsip_print_text_body;
-	msg->body = body;
-    }
-}
-
-/*
- * Create arbitrary request.
- */
-PJ_DEF(pj_status_t) pjsip_endpt_create_request(  pjsip_endpoint *endpt, 
-						 const pjsip_method *method,
-						 const pj_str_t *param_target,
-						 const pj_str_t *param_from,
-						 const pj_str_t *param_to, 
-						 const pj_str_t *param_contact,
-						 const pj_str_t *param_call_id,
-						 int param_cseq, 
-						 const pj_str_t *param_text,

-						 pjsip_tx_data **p_tdata)
-{
-    pjsip_uri *target;
-    pjsip_tx_data *tdata;
-    pjsip_from_hdr *from;
-    pjsip_to_hdr *to;
-    pjsip_contact_hdr *contact;
-    pjsip_cseq_hdr *cseq = NULL;    /* = NULL, warning in VC6 */
-    pjsip_cid_hdr *call_id;
-    pj_str_t tmp;

-    pj_status_t status;
-    PJ_USE_EXCEPTION;
-
-    PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request()"));
-
-    status = pjsip_endpt_create_tdata(endpt, &tdata);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Init reference counter to 1. */
-    pjsip_tx_data_add_ref(tdata);
-
-    PJ_TRY {
-	/* Request target. */
-	pj_strdup_with_null(tdata->pool, &tmp, param_target);
-	target = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 0);
-	if (target == NULL) {
-	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid target %s", 
-		      tmp.ptr));
-	    goto on_error;
-	}
-
-	/* From */
-	from = pjsip_from_hdr_create(tdata->pool);
-	pj_strdup_with_null(tdata->pool, &tmp, param_from);
-	from->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 
-				     PJSIP_PARSE_URI_AS_NAMEADDR);
-	if (from->uri == NULL) {
-	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'From' URI '%s'",
-				tmp.ptr));
-	    goto on_error;
-	}
-	pj_create_unique_string(tdata->pool, &from->tag);
-
-	/* To */
-	to = pjsip_to_hdr_create(tdata->pool);
-	pj_strdup_with_null(tdata->pool, &tmp, param_to);
-	to->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 
-				   PJSIP_PARSE_URI_AS_NAMEADDR);
-	if (to->uri == NULL) {
-	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'To' URI '%s'",
-				tmp.ptr));
-	    goto on_error;
-	}
-
-	/* Contact. */
-	if (param_contact) {
-	    contact = pjsip_contact_hdr_create(tdata->pool);
-	    pj_strdup_with_null(tdata->pool, &tmp, param_contact);
-	    contact->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen,
-					    PJSIP_PARSE_URI_AS_NAMEADDR);
-	    if (contact->uri == NULL) {
-		PJ_LOG(4,(THIS_FILE, 
-			  "Error creating request: invalid 'Contact' URI '%s'",
-			  tmp.ptr));
-		goto on_error;
-	    }
-	} else {
-	    contact = NULL;
-	}
-
-	/* Call-ID */
-	call_id = pjsip_cid_hdr_create(tdata->pool);
-	if (param_call_id != NULL && param_call_id->slen)
-	    pj_strdup(tdata->pool, &call_id->id, param_call_id);
-	else
-	    pj_create_unique_string(tdata->pool, &call_id->id);
-
-	/* CSeq */
-	cseq = pjsip_cseq_hdr_create(tdata->pool);
-	if (param_cseq >= 0)
-	    cseq->cseq = param_cseq;
-	else
-	    cseq->cseq = pj_rand() & 0xFFFF;
-
-	/* Method */
-	pjsip_method_copy(tdata->pool, &cseq->method, method);
-
-	/* Create the request. */
-	init_request_throw( endpt, tdata, &cseq->method, target, from, to, 

-                            contact, call_id, cseq, param_text);
-    }
-    PJ_DEFAULT {
-	status = PJ_ENOMEM;
-	goto on_error;
-    }
-    PJ_END
-
-    PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", 
-		        tdata->obj_name, 
-			cseq->cseq, 
-			cseq->method.name.slen,
-			cseq->method.name.ptr));
+    /* Add From header. */

+    if (param_from->tag.slen == 0)

+	pj_create_unique_string(tdata->pool, &param_from->tag);

+    pjsip_msg_add_hdr(msg, (void*)param_from);

 

-    *p_tdata = tdata;
-    return PJ_SUCCESS;
-
-on_error:
-    pjsip_tx_data_dec_ref(tdata);
-    return status;
-}
-
-PJ_DEF(pj_status_t)
-pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,
-				     const pjsip_method *method,
-				     const pjsip_uri *param_target,
-				     const pjsip_from_hdr *param_from,
-				     const pjsip_to_hdr *param_to,
-				     const pjsip_contact_hdr *param_contact,
-				     const pjsip_cid_hdr *param_call_id,
-				     int param_cseq,
-				     const pj_str_t *param_text,

-				     pjsip_tx_data **p_tdata)
-{
-    pjsip_uri *target;
-    pjsip_tx_data *tdata;
-    pjsip_from_hdr *from;
-    pjsip_to_hdr *to;
-    pjsip_contact_hdr *contact;
-    pjsip_cid_hdr *call_id;
-    pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */

-    pj_status_t status;
-    PJ_USE_EXCEPTION;
-
-    PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request_from_hdr()"));
-
-    status = pjsip_endpt_create_tdata(endpt, &tdata);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    pjsip_tx_data_add_ref(tdata);
-
-    PJ_TRY {
-	target = pjsip_uri_clone(tdata->pool, param_target);
-	from = pjsip_hdr_shallow_clone(tdata->pool, param_from);
-	pjsip_fromto_set_from(from);
-	to = pjsip_hdr_shallow_clone(tdata->pool, param_to);
-	pjsip_fromto_set_to(to);
-	if (param_contact)
-	    contact = pjsip_hdr_shallow_clone(tdata->pool, param_contact);
-	else
-	    contact = NULL;
-	call_id = pjsip_hdr_shallow_clone(tdata->pool, param_call_id);
-	cseq = pjsip_cseq_hdr_create(tdata->pool);
-	if (param_cseq >= 0)
-	    cseq->cseq = param_cseq;
-	else
-	    cseq->cseq = pj_rand() % 0xFFFF;
-	pjsip_method_copy(tdata->pool, &cseq->method, method);
-
-	init_request_throw(endpt, tdata, &cseq->method, target, from, to, 

-                           contact, call_id, cseq, param_text);
-    }
-    PJ_DEFAULT {
-	status = PJ_ENOMEM;
-	goto on_error;
-    }
-    PJ_END;
-
-    PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", 
-			tdata->obj_name, 
-			cseq->cseq, 
-			cseq->method.name.slen,
+    /* Add To header. */

+    pjsip_msg_add_hdr(msg, (void*)param_to);

+

+    /* Add Contact header. */

+    if (param_contact) {

+	pjsip_msg_add_hdr(msg, (void*)param_contact);

+    }

+

+    /* Add Call-ID header. */

+    pjsip_msg_add_hdr(msg, (void*)param_call_id);

+

+    /* Add CSeq header. */

+    pjsip_msg_add_hdr(msg, (void*)param_cseq);

+

+    /* Create message body. */

+    if (param_text) {

+	body = pj_pool_calloc(tdata->pool, 1, sizeof(pjsip_msg_body));

+	body->content_type.type = str_TEXT;

+	body->content_type.subtype = str_PLAIN;

+	body->data = pj_pool_alloc(tdata->pool, param_text->slen );

+	pj_memcpy(body->data, param_text->ptr, param_text->slen);

+	body->len = param_text->slen;

+	body->print_body = &pjsip_print_text_body;

+	msg->body = body;

+    }

+}

+

+/*

+ * Create arbitrary request.

+ */

+PJ_DEF(pj_status_t) pjsip_endpt_create_request(  pjsip_endpoint *endpt, 

+						 const pjsip_method *method,

+						 const pj_str_t *param_target,

+						 const pj_str_t *param_from,

+						 const pj_str_t *param_to, 

+						 const pj_str_t *param_contact,

+						 const pj_str_t *param_call_id,

+						 int param_cseq, 

+						 const pj_str_t *param_text,

+						 pjsip_tx_data **p_tdata)

+{

+    pjsip_uri *target;

+    pjsip_tx_data *tdata;

+    pjsip_from_hdr *from;

+    pjsip_to_hdr *to;

+    pjsip_contact_hdr *contact;

+    pjsip_cseq_hdr *cseq = NULL;    /* = NULL, warning in VC6 */

+    pjsip_cid_hdr *call_id;

+    pj_str_t tmp;

+    pj_status_t status;

+    PJ_USE_EXCEPTION;

+

+    PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request()"));

+

+    status = pjsip_endpt_create_tdata(endpt, &tdata);

+    if (status != PJ_SUCCESS)

+	return status;

+

+    /* Init reference counter to 1. */

+    pjsip_tx_data_add_ref(tdata);

+

+    PJ_TRY {

+	/* Request target. */

+	pj_strdup_with_null(tdata->pool, &tmp, param_target);

+	target = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 0);

+	if (target == NULL) {

+	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid target %s", 

+		      tmp.ptr));

+	    goto on_error;

+	}

+

+	/* From */

+	from = pjsip_from_hdr_create(tdata->pool);

+	pj_strdup_with_null(tdata->pool, &tmp, param_from);

+	from->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 

+				     PJSIP_PARSE_URI_AS_NAMEADDR);

+	if (from->uri == NULL) {

+	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'From' URI '%s'",

+				tmp.ptr));

+	    goto on_error;

+	}

+	pj_create_unique_string(tdata->pool, &from->tag);

+

+	/* To */

+	to = pjsip_to_hdr_create(tdata->pool);

+	pj_strdup_with_null(tdata->pool, &tmp, param_to);

+	to->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 

+				   PJSIP_PARSE_URI_AS_NAMEADDR);

+	if (to->uri == NULL) {

+	    PJ_LOG(4,(THIS_FILE, "Error creating request: invalid 'To' URI '%s'",

+				tmp.ptr));

+	    goto on_error;

+	}

+

+	/* Contact. */

+	if (param_contact) {

+	    contact = pjsip_contact_hdr_create(tdata->pool);

+	    pj_strdup_with_null(tdata->pool, &tmp, param_contact);

+	    contact->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen,

+					    PJSIP_PARSE_URI_AS_NAMEADDR);

+	    if (contact->uri == NULL) {

+		PJ_LOG(4,(THIS_FILE, 

+			  "Error creating request: invalid 'Contact' URI '%s'",

+			  tmp.ptr));

+		goto on_error;

+	    }

+	} else {

+	    contact = NULL;

+	}

+

+	/* Call-ID */

+	call_id = pjsip_cid_hdr_create(tdata->pool);

+	if (param_call_id != NULL && param_call_id->slen)

+	    pj_strdup(tdata->pool, &call_id->id, param_call_id);

+	else

+	    pj_create_unique_string(tdata->pool, &call_id->id);

+

+	/* CSeq */

+	cseq = pjsip_cseq_hdr_create(tdata->pool);

+	if (param_cseq >= 0)

+	    cseq->cseq = param_cseq;

+	else

+	    cseq->cseq = pj_rand() & 0xFFFF;

+

+	/* Method */

+	pjsip_method_copy(tdata->pool, &cseq->method, method);

+

+	/* Create the request. */

+	init_request_throw( endpt, tdata, &cseq->method, target, from, to, 

+                            contact, call_id, cseq, param_text);

+    }

+    PJ_DEFAULT {

+	status = PJ_ENOMEM;

+	goto on_error;

+    }

+    PJ_END

+

+    PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", 

+		        tdata->obj_name, 

+			cseq->cseq, 

+			cseq->method.name.slen,

 			cseq->method.name.ptr));

 

-    *p_tdata = tdata;
-    return PJ_SUCCESS;
-
-on_error:
-    pjsip_tx_data_dec_ref(tdata);
-    return status;
-}
-
-/*
- * Construct a minimal response message for the received request.
- */
-PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
-						 const pjsip_rx_data *rdata,
+    *p_tdata = tdata;

+    return PJ_SUCCESS;

+

+on_error:

+    pjsip_tx_data_dec_ref(tdata);

+    return status;

+}

+

+PJ_DEF(pj_status_t)

+pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,

+				     const pjsip_method *method,

+				     const pjsip_uri *param_target,

+				     const pjsip_from_hdr *param_from,

+				     const pjsip_to_hdr *param_to,

+				     const pjsip_contact_hdr *param_contact,

+				     const pjsip_cid_hdr *param_call_id,

+				     int param_cseq,

+				     const pj_str_t *param_text,

+				     pjsip_tx_data **p_tdata)

+{

+    pjsip_uri *target;

+    pjsip_tx_data *tdata;

+    pjsip_from_hdr *from;

+    pjsip_to_hdr *to;

+    pjsip_contact_hdr *contact;

+    pjsip_cid_hdr *call_id;

+    pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */

+    pj_status_t status;

+    PJ_USE_EXCEPTION;

+

+    PJ_LOG(5,(THIS_FILE, "Entering pjsip_endpt_create_request_from_hdr()"));

+

+    status = pjsip_endpt_create_tdata(endpt, &tdata);

+    if (status != PJ_SUCCESS)

+	return status;

+

+    pjsip_tx_data_add_ref(tdata);

+

+    PJ_TRY {

+	target = pjsip_uri_clone(tdata->pool, param_target);

+	from = pjsip_hdr_shallow_clone(tdata->pool, param_from);

+	pjsip_fromto_set_from(from);

+	to = pjsip_hdr_shallow_clone(tdata->pool, param_to);

+	pjsip_fromto_set_to(to);

+	if (param_contact)

+	    contact = pjsip_hdr_shallow_clone(tdata->pool, param_contact);

+	else

+	    contact = NULL;

+	call_id = pjsip_hdr_shallow_clone(tdata->pool, param_call_id);

+	cseq = pjsip_cseq_hdr_create(tdata->pool);

+	if (param_cseq >= 0)

+	    cseq->cseq = param_cseq;

+	else

+	    cseq->cseq = pj_rand() % 0xFFFF;

+	pjsip_method_copy(tdata->pool, &cseq->method, method);

+

+	init_request_throw(endpt, tdata, &cseq->method, target, from, to, 

+                           contact, call_id, cseq, param_text);

+    }

+    PJ_DEFAULT {

+	status = PJ_ENOMEM;

+	goto on_error;

+    }

+    PJ_END;

+

+    PJ_LOG(4,(THIS_FILE, "Request %s (%d %.*s) created.", 

+			tdata->obj_name, 

+			cseq->cseq, 

+			cseq->method.name.slen,

+			cseq->method.name.ptr));

+

+    *p_tdata = tdata;

+    return PJ_SUCCESS;

+

+on_error:

+    pjsip_tx_data_dec_ref(tdata);

+    return status;

+}

+

+/*

+ * Construct a minimal response message for the received request.

+ */

+PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,

+						 const pjsip_rx_data *rdata,

 						 int code,

-						 pjsip_tx_data **p_tdata)
-{
-    pjsip_tx_data *tdata;
-    pjsip_msg *msg, *req_msg;
-    pjsip_hdr *hdr;
-    pjsip_via_hdr *via;
+						 pjsip_tx_data **p_tdata)

+{

+    pjsip_tx_data *tdata;

+    pjsip_msg *msg, *req_msg;

+    pjsip_hdr *hdr;

+    pjsip_via_hdr *via;

     pjsip_rr_hdr *rr;

-    pj_status_t status;
-
-    /* rdata must be a request message. */
-    req_msg = rdata->msg;
-    pj_assert(req_msg->type == PJSIP_REQUEST_MSG);
-
-    /* Log this action. */
-    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_response(rdata=%p, code=%d)", 
-		         rdata, code));
-
-    /* Create a new transmit buffer. */
-    status = pjsip_endpt_create_tdata( endpt, &tdata);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Create new response message. */
-    tdata->msg = msg = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG);
-
-    /* Set status code and reason text. */
-    msg->line.status.code = code;
-    msg->line.status.reason = *pjsip_get_status_text(code);
-
-    /* Set TX data attributes. */
-    tdata->rx_timestamp = rdata->timestamp;
-
-    /* Copy all the via headers, in order. */
-    via = rdata->via;
-    while (via) {
-	pjsip_msg_add_hdr( msg, pjsip_hdr_clone(tdata->pool, via));
-	via = via->next;
-	if (via != (void*)&req_msg->hdr)
-	    via = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, via);
-	else
-	    break;
-    }
-
-    /* Copy all Record-Route headers, in order. */
-    rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, NULL);
-    while (rr) {
-	pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, rr));
-	rr = rr->next;
-	if (rr != (void*)&req_msg->hdr)
-	    rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, rr);
-	else
-	    break;
-    }
-
-    /* Copy Call-ID header. */
-    hdr = pjsip_msg_find_hdr( req_msg, PJSIP_H_CALL_ID, NULL);
-    pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, hdr));
-
-    /* Copy From header. */
-    hdr = pjsip_hdr_clone(tdata->pool, rdata->from);
-    pjsip_msg_add_hdr( msg, hdr);
-
-    /* Copy To header. */
-    hdr = pjsip_hdr_clone(tdata->pool, rdata->to);
-    pjsip_msg_add_hdr( msg, hdr);
-
-    /* Copy CSeq header. */
-    hdr = pjsip_hdr_clone(tdata->pool, rdata->cseq);
-    pjsip_msg_add_hdr( msg, hdr);
-
+    pj_status_t status;

+

+    /* rdata must be a request message. */

+    req_msg = rdata->msg;

+    pj_assert(req_msg->type == PJSIP_REQUEST_MSG);

+

+    /* Log this action. */

+    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_response(rdata=%p, code=%d)", 

+		         rdata, code));

+

+    /* Create a new transmit buffer. */

+    status = pjsip_endpt_create_tdata( endpt, &tdata);

+    if (status != PJ_SUCCESS)

+	return status;

+

+    /* Create new response message. */

+    tdata->msg = msg = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG);

+

+    /* Set status code and reason text. */

+    msg->line.status.code = code;

+    msg->line.status.reason = *pjsip_get_status_text(code);

+

+    /* Set TX data attributes. */

+    tdata->rx_timestamp = rdata->timestamp;

+

+    /* Copy all the via headers, in order. */

+    via = rdata->via;

+    while (via) {

+	pjsip_msg_add_hdr( msg, pjsip_hdr_clone(tdata->pool, via));

+	via = via->next;

+	if (via != (void*)&req_msg->hdr)

+	    via = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, via);

+	else

+	    break;

+    }

+

+    /* Copy all Record-Route headers, in order. */

+    rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, NULL);

+    while (rr) {

+	pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, rr));

+	rr = rr->next;

+	if (rr != (void*)&req_msg->hdr)

+	    rr = pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, rr);

+	else

+	    break;

+    }

+

+    /* Copy Call-ID header. */

+    hdr = pjsip_msg_find_hdr( req_msg, PJSIP_H_CALL_ID, NULL);

+    pjsip_msg_add_hdr(msg, pjsip_hdr_clone(tdata->pool, hdr));

+

+    /* Copy From header. */

+    hdr = pjsip_hdr_clone(tdata->pool, rdata->from);

+    pjsip_msg_add_hdr( msg, hdr);

+

+    /* Copy To header. */

+    hdr = pjsip_hdr_clone(tdata->pool, rdata->to);

+    pjsip_msg_add_hdr( msg, hdr);

+

+    /* Copy CSeq header. */

+    hdr = pjsip_hdr_clone(tdata->pool, rdata->cseq);

+    pjsip_msg_add_hdr( msg, hdr);

+

     /* All done. */

-    *p_tdata = tdata;
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Construct ACK for 3xx-6xx final response (according to chapter 17.1.1 of
- * RFC3261). Note that the generation of ACK for 2xx response is different,
- * and one must not use this function to generate such ACK.
- */
-PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt,
-				    pjsip_tx_data *tdata,
-				    const pjsip_rx_data *rdata )
-{
-    pjsip_msg *ack_msg, *invite_msg;
-    pjsip_to_hdr *to;
-    pjsip_from_hdr *from;
-    pjsip_cseq_hdr *cseq;
-    pjsip_hdr *hdr;
-
-    /* Make compiler happy. */
-    PJ_UNUSED_ARG(endpt);
-
-    /* rdata must be a final response. */
-    pj_assert(rdata->msg->type==PJSIP_RESPONSE_MSG &&
-	      rdata->msg->line.status.code >= 300);
-
-    /* Log this action. */
-    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_ack(rdata=%p)", rdata));
-
-    /* Create new request message. */
-    ack_msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);
-    pjsip_method_set( &ack_msg->line.req.method, PJSIP_ACK_METHOD );
-
-    /* The original INVITE message. */
-    invite_msg = tdata->msg;
-
-    /* Copy Request-Uri from the original INVITE. */
-    ack_msg->line.req.uri = invite_msg->line.req.uri;
-    
-    /* Copy Call-ID from the original INVITE */
-    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_CALL_ID, NULL);
-    pjsip_msg_add_hdr( ack_msg, hdr );
-
-    /* Copy From header from the original INVITE. */
-    from = (pjsip_from_hdr*)pjsip_msg_find_remove_hdr(invite_msg, 
-						      PJSIP_H_FROM, NULL);
-    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)from );
-
-    /* Copy To header from the original INVITE. */
-    to = (pjsip_to_hdr*)pjsip_msg_find_remove_hdr( invite_msg, 
-						   PJSIP_H_TO, NULL);
-    pj_strdup(tdata->pool, &to->tag, &rdata->to->tag);
-    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)to );
-
-    /* Must contain single Via, just as the original INVITE. */
-    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_VIA, NULL);
-    pjsip_msg_insert_first_hdr( ack_msg, hdr );
-
-    /* Must have the same CSeq value as the original INVITE, but method 
-     * changed to ACK 
-     */
-    cseq = (pjsip_cseq_hdr*) pjsip_msg_find_remove_hdr( invite_msg, 
-							PJSIP_H_CSEQ, NULL);
-    pjsip_method_set( &cseq->method, PJSIP_ACK_METHOD );
-    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*) cseq );
-
-    /* If the original INVITE has Route headers, those header fields MUST 
-     * appear in the ACK.
-     */
-    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL);
-    while (hdr != NULL) {
-	pjsip_msg_add_hdr( ack_msg, hdr );
-	hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL);
-    }
-
-    /* Set the message in the "tdata" to point to the ACK message. */
-    tdata->msg = ack_msg;
-
-    /* Reset transmit packet buffer, to force 're-printing' of message. */
-    tdata->buf.cur = tdata->buf.start;
-
-    /* We're done.
-     * "tdata" parameter now contains the ACK message.
-     */
-}
-
-
-/*
- * Construct CANCEL request for the previously sent request, according to
- * chapter 9.1 of RFC3261.
- */
-PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
-					       pjsip_tx_data *req_tdata,

-					       pjsip_tx_data **p_tdata)
-{
-    pjsip_msg *req_msg;	/* the original request. */
-    pjsip_tx_data *cancel_tdata;
-    pjsip_msg *cancel_msg;
-    pjsip_hdr *hdr;
-    pjsip_cseq_hdr *req_cseq, *cseq;
-    pjsip_uri *req_uri;

-    pj_status_t status;
-
-    /* Log this action. */
-    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_cancel(tdata=%p)", req_tdata));
-
-    /* Get the original request. */
-    req_msg = req_tdata->msg;
-
-    /* The transmit buffer must INVITE request. */
-    PJ_ASSERT_RETURN(req_msg->type == PJSIP_REQUEST_MSG &&
-		     req_msg->line.req.method.id == PJSIP_INVITE_METHOD,

-		     PJ_EINVAL);
-
-    /* Create new transmit buffer. */
-    status = pjsip_endpt_create_tdata( endpt, &cancel_tdata);
-    if (status != PJ_SUCCESS) {
-	return status;
-    }
-
-    /* Create CANCEL request message. */
-    cancel_msg = pjsip_msg_create(cancel_tdata->pool, PJSIP_REQUEST_MSG);
-    cancel_tdata->msg = cancel_msg;
-
-    /* Request-URI, Call-ID, From, To, and the numeric part of the CSeq are
-     * copied from the original request.
-     */
-    /* Set request line. */
-    pjsip_method_set(&cancel_msg->line.req.method, PJSIP_CANCEL_METHOD);
-    req_uri = req_msg->line.req.uri;
-    cancel_msg->line.req.uri = pjsip_uri_clone(cancel_tdata->pool, req_uri);
-
-    /* Copy Call-ID */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_CALL_ID, NULL);
-    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
-
-    /* Copy From header. */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_FROM, NULL);
-    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
-
-    /* Copy To header. */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_TO, NULL);
-    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
-
-    /* Create new CSeq with equal number, but method set to CANCEL. */
-    req_cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(req_msg, PJSIP_H_CSEQ, NULL);
-    cseq = pjsip_cseq_hdr_create(cancel_tdata->pool);
-    cseq->cseq = req_cseq->cseq;
-    pjsip_method_set(&cseq->method, PJSIP_CANCEL_METHOD);
-    pjsip_msg_add_hdr(cancel_msg, (pjsip_hdr*)cseq);
-
-    /* Must only have single Via which matches the top-most Via in the 
-     * request being cancelled. 
-     */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, NULL);
-    pjsip_msg_insert_first_hdr(cancel_msg, 
-			       pjsip_hdr_clone(cancel_tdata->pool, hdr));
-
-    /* If the original request has Route header, the CANCEL request must also
-     * has exactly the same.
-     * Copy "Route" header from the request.
-     */
-    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, NULL);
-    while (hdr != NULL) {
-	pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));
-	hdr = hdr->next;
-	if (hdr != &cancel_msg->hdr)
-	    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, hdr);
-	else
-	    break;
-    }
-
-    /* Done.
-     * Return the transmit buffer containing the CANCEL request.
+    *p_tdata = tdata;

+    return PJ_SUCCESS;

+}

+

+

+/*

+ * Construct ACK for 3xx-6xx final response (according to chapter 17.1.1 of

+ * RFC3261). Note that the generation of ACK for 2xx response is different,

+ * and one must not use this function to generate such ACK.

+ */

+PJ_DEF(void) pjsip_endpt_create_ack(pjsip_endpoint *endpt,

+				    pjsip_tx_data *tdata,

+				    const pjsip_rx_data *rdata )

+{

+    pjsip_msg *ack_msg, *invite_msg;

+    pjsip_to_hdr *to;

+    pjsip_from_hdr *from;

+    pjsip_cseq_hdr *cseq;

+    pjsip_hdr *hdr;

+

+    /* Make compiler happy. */

+    PJ_UNUSED_ARG(endpt);

+

+    /* rdata must be a final response. */

+    pj_assert(rdata->msg->type==PJSIP_RESPONSE_MSG &&

+	      rdata->msg->line.status.code >= 300);

+

+    /* Log this action. */

+    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_ack(rdata=%p)", rdata));

+

+    /* Create new request message. */

+    ack_msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);

+    pjsip_method_set( &ack_msg->line.req.method, PJSIP_ACK_METHOD );

+

+    /* The original INVITE message. */

+    invite_msg = tdata->msg;

+

+    /* Copy Request-Uri from the original INVITE. */

+    ack_msg->line.req.uri = invite_msg->line.req.uri;

+    

+    /* Copy Call-ID from the original INVITE */

+    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_CALL_ID, NULL);

+    pjsip_msg_add_hdr( ack_msg, hdr );

+

+    /* Copy From header from the original INVITE. */

+    from = (pjsip_from_hdr*)pjsip_msg_find_remove_hdr(invite_msg, 

+						      PJSIP_H_FROM, NULL);

+    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)from );

+

+    /* Copy To header from the original INVITE. */

+    to = (pjsip_to_hdr*)pjsip_msg_find_remove_hdr( invite_msg, 

+						   PJSIP_H_TO, NULL);

+    pj_strdup(tdata->pool, &to->tag, &rdata->to->tag);

+    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*)to );

+

+    /* Must contain single Via, just as the original INVITE. */

+    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_VIA, NULL);

+    pjsip_msg_insert_first_hdr( ack_msg, hdr );

+

+    /* Must have the same CSeq value as the original INVITE, but method 

+     * changed to ACK 

      */

-    *p_tdata = cancel_tdata;
-    return PJ_SUCCESS;
-}
-
-/* Get the address parameters (host, port, flag, TTL, etc) to send the
- * response.
- */
-PJ_DEF(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,
-					    const pjsip_transport_t *req_transport,
-					    const pjsip_via_hdr *via,
-					    pjsip_host_port *send_addr)
-{
-    /* Determine the destination address (section 18.2.2):
-     * - for TCP, SCTP, or TLS, send the response using the transport where
-     *   the request was received.
-     * - if maddr parameter is present, send to this address using the port
-     *   in sent-by or 5060. If multicast is used, the TTL in the Via must
-     *   be used, or 1 if ttl parameter is not present.
-     * - otherwise if received parameter is present, set to this address.
-     * - otherwise send to the address in sent-by.
-     */
-    send_addr->flag = pjsip_transport_get_flag(req_transport);
-    send_addr->type = pjsip_transport_get_type(req_transport);
-
-    if (PJSIP_TRANSPORT_IS_RELIABLE(req_transport)) {
-	const pj_sockaddr_in *remote_addr;
-	remote_addr = pjsip_transport_get_remote_addr(req_transport);
-	pj_strdup2(pool, &send_addr->host, 
-		   pj_inet_ntoa(remote_addr->sin_addr));
-	send_addr->port = pj_sockaddr_in_get_port(remote_addr);
-
-    } else {
-	/* Set the host part */
-	if (via->maddr_param.slen) {
-	    pj_strdup(pool, &send_addr->host, &via->maddr_param);
-	} else if (via->recvd_param.slen) {
-	    pj_strdup(pool, &send_addr->host, &via->recvd_param);
-	} else {
-	    pj_strdup(pool, &send_addr->host, &via->sent_by.host);
-	}
-
-	/* Set the port */
-	send_addr->port = via->sent_by.port;
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Get the event string from the event ID.
- */
-PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e)
-{
-    return event_str[e];
-}
-
+    cseq = (pjsip_cseq_hdr*) pjsip_msg_find_remove_hdr( invite_msg, 

+							PJSIP_H_CSEQ, NULL);

+    pjsip_method_set( &cseq->method, PJSIP_ACK_METHOD );

+    pjsip_msg_add_hdr( ack_msg, (pjsip_hdr*) cseq );

+

+    /* If the original INVITE has Route headers, those header fields MUST 

+     * appear in the ACK.

+     */

+    hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL);

+    while (hdr != NULL) {

+	pjsip_msg_add_hdr( ack_msg, hdr );

+	hdr = pjsip_msg_find_remove_hdr( invite_msg, PJSIP_H_ROUTE, NULL);

+    }

+

+    /* Set the message in the "tdata" to point to the ACK message. */

+    tdata->msg = ack_msg;

+

+    /* Reset transmit packet buffer, to force 're-printing' of message. */

+    tdata->buf.cur = tdata->buf.start;

+

+    /* We're done.

+     * "tdata" parameter now contains the ACK message.

+     */

+}

+

+

+/*

+ * Construct CANCEL request for the previously sent request, according to

+ * chapter 9.1 of RFC3261.

+ */

+PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,

+					       pjsip_tx_data *req_tdata,

+					       pjsip_tx_data **p_tdata)

+{

+    pjsip_msg *req_msg;	/* the original request. */

+    pjsip_tx_data *cancel_tdata;

+    pjsip_msg *cancel_msg;

+    pjsip_hdr *hdr;

+    pjsip_cseq_hdr *req_cseq, *cseq;

+    pjsip_uri *req_uri;

+    pj_status_t status;

+

+    /* Log this action. */

+    PJ_LOG(5,(THIS_FILE, "pjsip_endpt_create_cancel(tdata=%p)", req_tdata));

+

+    /* Get the original request. */

+    req_msg = req_tdata->msg;

+

+    /* The transmit buffer must INVITE request. */

+    PJ_ASSERT_RETURN(req_msg->type == PJSIP_REQUEST_MSG &&

+		     req_msg->line.req.method.id == PJSIP_INVITE_METHOD,

+		     PJ_EINVAL);

+

+    /* Create new transmit buffer. */

+    status = pjsip_endpt_create_tdata( endpt, &cancel_tdata);

+    if (status != PJ_SUCCESS) {

+	return status;

+    }

+

+    /* Create CANCEL request message. */

+    cancel_msg = pjsip_msg_create(cancel_tdata->pool, PJSIP_REQUEST_MSG);

+    cancel_tdata->msg = cancel_msg;

+

+    /* Request-URI, Call-ID, From, To, and the numeric part of the CSeq are

+     * copied from the original request.

+     */

+    /* Set request line. */

+    pjsip_method_set(&cancel_msg->line.req.method, PJSIP_CANCEL_METHOD);

+    req_uri = req_msg->line.req.uri;

+    cancel_msg->line.req.uri = pjsip_uri_clone(cancel_tdata->pool, req_uri);

+

+    /* Copy Call-ID */

+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_CALL_ID, NULL);

+    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));

+

+    /* Copy From header. */

+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_FROM, NULL);

+    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));

+

+    /* Copy To header. */

+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_TO, NULL);

+    pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));

+

+    /* Create new CSeq with equal number, but method set to CANCEL. */

+    req_cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(req_msg, PJSIP_H_CSEQ, NULL);

+    cseq = pjsip_cseq_hdr_create(cancel_tdata->pool);

+    cseq->cseq = req_cseq->cseq;

+    pjsip_method_set(&cseq->method, PJSIP_CANCEL_METHOD);

+    pjsip_msg_add_hdr(cancel_msg, (pjsip_hdr*)cseq);

+

+    /* Must only have single Via which matches the top-most Via in the 

+     * request being cancelled. 

+     */

+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, NULL);

+    pjsip_msg_insert_first_hdr(cancel_msg, 

+			       pjsip_hdr_clone(cancel_tdata->pool, hdr));

+

+    /* If the original request has Route header, the CANCEL request must also

+     * has exactly the same.

+     * Copy "Route" header from the request.

+     */

+    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, NULL);

+    while (hdr != NULL) {

+	pjsip_msg_add_hdr(cancel_msg, pjsip_hdr_clone(cancel_tdata->pool, hdr));

+	hdr = hdr->next;

+	if (hdr != &cancel_msg->hdr)

+	    hdr = pjsip_msg_find_hdr(req_msg, PJSIP_H_ROUTE, hdr);

+	else

+	    break;

+    }

+

+    /* Done.

+     * Return the transmit buffer containing the CANCEL request.

+     */

+    *p_tdata = cancel_tdata;

+    return PJ_SUCCESS;

+}

+

+/* Get the address parameters (host, port, flag, TTL, etc) to send the

+ * response.

+ */

+PJ_DEF(pj_status_t) pjsip_get_response_addr(pj_pool_t *pool,

+					    const pjsip_transport_t *req_transport,

+					    const pjsip_via_hdr *via,

+					    pjsip_host_port *send_addr)

+{

+    /* Determine the destination address (section 18.2.2):

+     * - for TCP, SCTP, or TLS, send the response using the transport where

+     *   the request was received.

+     * - if maddr parameter is present, send to this address using the port

+     *   in sent-by or 5060. If multicast is used, the TTL in the Via must

+     *   be used, or 1 if ttl parameter is not present.

+     * - otherwise if received parameter is present, set to this address.

+     * - otherwise send to the address in sent-by.

+     */

+    send_addr->flag = pjsip_transport_get_flag(req_transport);

+    send_addr->type = pjsip_transport_get_type(req_transport);

+

+    if (PJSIP_TRANSPORT_IS_RELIABLE(req_transport)) {

+	const pj_sockaddr_in *remote_addr;

+	remote_addr = pjsip_transport_get_remote_addr(req_transport);

+	pj_strdup2(pool, &send_addr->host, 

+		   pj_inet_ntoa(remote_addr->sin_addr));

+	send_addr->port = pj_sockaddr_in_get_port(remote_addr);

+

+    } else {

+	/* Set the host part */

+	if (via->maddr_param.slen) {

+	    pj_strdup(pool, &send_addr->host, &via->maddr_param);

+	} else if (via->recvd_param.slen) {

+	    pj_strdup(pool, &send_addr->host, &via->recvd_param);

+	} else {

+	    pj_strdup(pool, &send_addr->host, &via->sent_by.host);

+	}

+

+	/* Set the port */

+	send_addr->port = via->sent_by.port;

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Get the event string from the event ID.

+ */

+PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e)

+{

+    return event_str[e];

+}

+

diff --git a/pjsip/src/pjsip/sip_msg.c b/pjsip/src/pjsip/sip_msg.c
index 587df86..6fd32f4 100644
--- a/pjsip/src/pjsip/sip_msg.c
+++ b/pjsip/src/pjsip/sip_msg.c
@@ -1,1416 +1,1438 @@
-/* $Id$
- */
-#include <pjsip/sip_msg.h>
-#include <pjsip/print_util.h>
-#include <pj/string.h>
-#include <pj/pool.h>
-
-/*
- * Include inline definitions here if functions are NOT inlined.
- */
-#if PJ_FUNCTIONS_ARE_INLINED==0
-#  include <pjsip/sip_msg_i.h>
-#endif
-
-static const pj_str_t method_names[] = 
-{
-    { "INVITE",	    6 },
-    { "CANCEL",	    6 },
-    { "ACK",	    3 },
-    { "BYE",	    3 },
-    { "REGISTER",   8 },
-    { "OPTIONS",    7 },
-};
-
-const pj_str_t pjsip_hdr_names[] = 
-{
-    { "Accept",		     6 },   // PJSIP_H_ACCEPT,
-    { "Accept-Encoding",    15 },   // PJSIP_H_ACCEPT_ENCODING,
-    { "Accept-Language",    15 },   // PJSIP_H_ACCEPT_LANGUAGE,
-    { "Alert-Info",	    10 },   // PJSIP_H_ALERT_INFO,
-    { "Allow",		     5 },   // PJSIP_H_ALLOW,
-    { "Authentication-Info",19 },   // PJSIP_H_AUTHENTICATION_INFO,
-    { "Authorization",	    13 },   // PJSIP_H_AUTHORIZATION,
-    { "Call-ID",	     7 },   // PJSIP_H_CALL_ID,
-    { "Call-Info",	     9 },   // PJSIP_H_CALL_INFO,
-    { "Contact",	     7 },   // PJSIP_H_CONTACT,
-    { "Content-Disposition",19 },   // PJSIP_H_CONTENT_DISPOSITION,
-    { "Content-Encoding",   16 },   // PJSIP_H_CONTENT_ENCODING,
-    { "Content-Language",   16 },   // PJSIP_H_CONTENT_LANGUAGE,
-    { "Content-Length",	    14 },   // PJSIP_H_CONTENT_LENGTH,
-    { "Content-Type",	    12 },   // PJSIP_H_CONTENT_TYPE,
-    { "CSeq",		     4 },   // PJSIP_H_CSEQ,
-    { "Date",		     4 },   // PJSIP_H_DATE,
-    { "Error-Info",	    10 },   // PJSIP_H_ERROR_INFO,
-    { "Expires",	     7 },   // PJSIP_H_EXPIRES,
-    { "From",		     4 },   // PJSIP_H_FROM,
-    { "In-Reply-To",	    11 },   // PJSIP_H_IN_REPLY_TO,
-    { "Max-Forwards",	    12 },   // PJSIP_H_MAX_FORWARDS,
-    { "MIME-Version",	    12 },   // PJSIP_H_MIME_VERSION,
-    { "Min-Expires",	    11 },   // PJSIP_H_MIN_EXPIRES,
-    { "Organization",	    12 },   // PJSIP_H_ORGANIZATION,
-    { "Priority",	     8 },   // PJSIP_H_PRIORITY,
-    { "Proxy-Authenticate", 18 },   // PJSIP_H_PROXY_AUTHENTICATE,
-    { "Proxy-Authorization",19 },   // PJSIP_H_PROXY_AUTHORIZATION,
-    { "Proxy-Require",	    13 },   // PJSIP_H_PROXY_REQUIRE,
-    { "Record-Route",	    12 },   // PJSIP_H_RECORD_ROUTE,
-    { "Reply-To",	     8 },   // PJSIP_H_REPLY_TO,
-    { "Require",	     7 },   // PJSIP_H_REQUIRE,
-    { "Retry-After",	    11 },   // PJSIP_H_RETRY_AFTER,
-    { "Route",		     5 },   // PJSIP_H_ROUTE,
-    { "Server",		     6 },   // PJSIP_H_SERVER,
-    { "Subject",	     7 },   // PJSIP_H_SUBJECT,
-    { "Supported",	     9 },   // PJSIP_H_SUPPORTED,
-    { "Timestamp",	     9 },   // PJSIP_H_TIMESTAMP,
-    { "To",		     2 },   // PJSIP_H_TO,
-    { "Unsupported",	    11 },   // PJSIP_H_UNSUPPORTED,
-    { "User-Agent",	    10 },   // PJSIP_H_USER_AGENT,
-    { "Via",		     3 },   // PJSIP_H_VIA,
-    { "Warning",	     7 },   // PJSIP_H_WARNING,
-    { "WWW-Authenticate",   16 },   // PJSIP_H_WWW_AUTHENTICATE,
-
-    { "_Unknown-Header",    15 },   // PJSIP_H_OTHER,
-};
-
-static pj_str_t status_phrase[710];
-static int print_media_type(char *buf, const pjsip_media_type *media);
-
-static int init_status_phrase()
-{
-    int i;
-    pj_str_t default_reason_phrase = { "Default status message", 22};
-
-    for (i=0; i<PJ_ARRAY_SIZE(status_phrase); ++i)
-	status_phrase[i] = default_reason_phrase;
-
-    pj_strset2( &status_phrase[100], "Trying");
-    pj_strset2( &status_phrase[180], "Ringing");
-    pj_strset2( &status_phrase[181], "Call Is Being Forwarded");
-    pj_strset2( &status_phrase[182], "Queued");
-    pj_strset2( &status_phrase[183], "Session Progress");
-
-    pj_strset2( &status_phrase[200], "OK");
-
-    pj_strset2( &status_phrase[300], "Multiple Choices");
-    pj_strset2( &status_phrase[301], "Moved Permanently");
-    pj_strset2( &status_phrase[302], "Moved Temporarily");
-    pj_strset2( &status_phrase[305], "Use Proxy");
-    pj_strset2( &status_phrase[380], "Alternative Service");
-
-    pj_strset2( &status_phrase[400], "Bad Request");
-    pj_strset2( &status_phrase[401], "Unauthorized");
-    pj_strset2( &status_phrase[402], "Payment Required");
-    pj_strset2( &status_phrase[403], "Forbidden");
-    pj_strset2( &status_phrase[404], "Not Found");
-    pj_strset2( &status_phrase[405], "Method Not Allowed");
-    pj_strset2( &status_phrase[406], "Not Acceptable");
-    pj_strset2( &status_phrase[407], "Proxy Authentication Required");
-    pj_strset2( &status_phrase[408], "Request Timeout");
-    pj_strset2( &status_phrase[410], "Gone");
-    pj_strset2( &status_phrase[413], "Request Entity Too Large");
-    pj_strset2( &status_phrase[414], "Request URI Too Long");
-    pj_strset2( &status_phrase[415], "Unsupported Media Type");
-    pj_strset2( &status_phrase[416], "Unsupported URI Scheme");
-    pj_strset2( &status_phrase[420], "Bad Extension");
-    pj_strset2( &status_phrase[421], "Extension Required");
-    pj_strset2( &status_phrase[423], "Interval Too Brief");
-    pj_strset2( &status_phrase[480], "Temporarily Unavailable");
-    pj_strset2( &status_phrase[481], "Call/Transaction Does Not Exist");
-    pj_strset2( &status_phrase[482], "Loop Detected");
-    pj_strset2( &status_phrase[483], "Too Many Hops");
-    pj_strset2( &status_phrase[484], "Address Incompleted");
-    pj_strset2( &status_phrase[485], "Ambiguous");
-    pj_strset2( &status_phrase[486], "Busy Here");
-    pj_strset2( &status_phrase[487], "Request Terminated");
-    pj_strset2( &status_phrase[488], "Not Acceptable Here");
-    pj_strset2( &status_phrase[491], "Request Pending");
-    pj_strset2( &status_phrase[493], "Undecipherable");
-
-    pj_strset2( &status_phrase[500], "Internal Server Error");
-    pj_strset2( &status_phrase[501], "Not Implemented");
-    pj_strset2( &status_phrase[502], "Bad Gateway");
-    pj_strset2( &status_phrase[503], "Service Unavailable");
-    pj_strset2( &status_phrase[504], "Server Timeout");
-    pj_strset2( &status_phrase[505], "Version Not Supported");
-    pj_strset2( &status_phrase[513], "Message Too Large");
-
-    pj_strset2( &status_phrase[600], "Busy Everywhere");
-    pj_strset2( &status_phrase[603], "Decline");
-    pj_strset2( &status_phrase[604], "Does Not Exist Anywhere");
-    pj_strset2( &status_phrase[606], "Not Acceptable");
-
-    pj_strset2( &status_phrase[701], "No response from destination server");
-    pj_strset2( &status_phrase[702], "Unable to resolve destination server");
-    pj_strset2( &status_phrase[703], "Error sending message to destination server");
-
-    return 1;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Method.
- */
-
-PJ_DEF(void) pjsip_method_init( pjsip_method *m, 
-			        pj_pool_t *pool, 
-			        const pj_str_t *str)
-{
-    pj_str_t dup;
-    pjsip_method_init_np(m, pj_strdup(pool, &dup, str));
-}
-
-PJ_DEF(void) pjsip_method_set( pjsip_method *m, pjsip_method_e me )
-{
-    m->id = me;
-    m->name = method_names[me];
-}
-
-PJ_DEF(void) pjsip_method_init_np(pjsip_method *m,
-				  pj_str_t *str)
-{
-    int i;
-    for (i=0; i<PJ_ARRAY_SIZE(method_names); ++i) {
-	if (pj_stricmp(str, &method_names[i])==0) {
-	    m->id = (pjsip_method_e)i;
-	    m->name = method_names[i];
-	    return;
-	}
-    }
-    m->id = PJSIP_OTHER_METHOD;
-    m->name = *str;
-}
-
-PJ_DEF(void) pjsip_method_copy( pj_pool_t *pool,
-				pjsip_method *method,
-				const pjsip_method *rhs )
-{
-    method->id = rhs->id;
-    if (rhs->id != PJSIP_OTHER_METHOD) {
-	method->name = rhs->name;
-    } else {
-	pj_strdup(pool, &method->name, &rhs->name);
-    }
-}
-
-
-PJ_DEF(int) pjsip_method_cmp( const pjsip_method *m1, const pjsip_method *m2)
-{
-    if (m1->id == m2->id) {
-	if (m1->id != PJSIP_OTHER_METHOD)
-	    return 0;
-	return pj_stricmp(&m1->name, &m2->name);
-    }
-    
-    return ( m1->id < m2->id ) ? -1 : 1;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Message.
- */
-
-PJ_DEF(pjsip_msg*) pjsip_msg_create( pj_pool_t *pool, pjsip_msg_type_e type)
-{
-    pjsip_msg *msg = pj_pool_alloc(pool, sizeof(pjsip_msg));
-    pj_list_init(&msg->hdr);
-    msg->type = type;
-    msg->body = NULL;
-    return msg;
-}
-
-PJ_DEF(void*)  pjsip_msg_find_hdr( pjsip_msg *msg, 
-				   pjsip_hdr_e hdr_type, void *start)
-{
-    pjsip_hdr *hdr=start, *end=&msg->hdr;
-
-    if (hdr == NULL) {
-	hdr = msg->hdr.next;
-    }
-    for (; hdr!=end; hdr = hdr->next) {
-	if (hdr->type == hdr_type)
-	    return hdr;
-    }
-    return NULL;
-}
-
-PJ_DEF(void*)  pjsip_msg_find_hdr_by_name( pjsip_msg *msg, 
-					   const pj_str_t *name, void *start)
-{
-    pjsip_hdr *hdr=start, *end=&msg->hdr;
-
-    if (hdr == NULL) {
-	hdr = msg->hdr.next;
-    }
-    for (; hdr!=end; hdr = hdr->next) {
-	if (hdr->type < PJSIP_H_OTHER) {
-	    if (pj_stricmp(&pjsip_hdr_names[hdr->type], name) == 0)
-		return hdr;
-	} else {
-	    if (pj_stricmp(&hdr->name, name) == 0)
-		return hdr;
-	}
-    }
-    return NULL;
-}
-
-PJ_DEF(void*) pjsip_msg_find_remove_hdr( pjsip_msg *msg, 
-				         pjsip_hdr_e hdr_type, void *start)
-{
-    pjsip_hdr *hdr = pjsip_msg_find_hdr(msg, hdr_type, start);
-    if (hdr) {
-	pj_list_erase(hdr);
-    }
-    return hdr;
-}
-
-PJ_DEF(pj_ssize_t) pjsip_msg_print( pjsip_msg *msg, char *buf, pj_size_t size)
-{
-    char *p=buf, *end=buf+size;
-    int len;
-    pjsip_hdr *hdr;
-    pj_str_t clen_hdr =  { "Content-Length: ", 16};
-
-    /* Get a wild guess on how many bytes are typically needed.
-     * We'll check this later in detail, but this serves as a quick check.
-     */
-    if (size < 256)
-	return -1;
-
-    /* Print request line or status line depending on message type */
-    if (msg->type == PJSIP_REQUEST_MSG) {
-	pjsip_uri *uri;
-
-	/* Add method. */
-	len = msg->line.req.method.name.slen;
-	pj_memcpy(p, msg->line.req.method.name.ptr, len);
-	p += len;
-	*p++ = ' ';
-
-	/* Add URI */
-	uri = pjsip_uri_get_uri(msg->line.req.uri);
-	len = pjsip_uri_print( PJSIP_URI_IN_REQ_URI, uri, p, end-p);
-	if (len < 1)
-	    return -1;
-	p += len;
-
-	/* Add ' SIP/2.0' */
-	if (end-p < 16)
-	    return -1;
-	pj_memcpy(p, " SIP/2.0\r\n", 10);
-	p += 10;
-
-    } else {
-
-	/* Add 'SIP/2.0 ' */
-	pj_memcpy(p, "SIP/2.0 ", 8);
-	p += 8;
-
-	/* Add status code. */
-	len = pj_utoa(msg->line.status.code, p);
-	p += len;
-	*p++ = ' ';
-
-	/* Add reason text. */
-	len = msg->line.status.reason.slen;
-	pj_memcpy(p, msg->line.status.reason.ptr, len );
-	p += len;
-
-	/* Add newline. */
-	*p++ = '\r';
-	*p++ = '\n';
-    }
-
-    /* Print each of the headers. */
-    for (hdr=msg->hdr.next; hdr!=&msg->hdr; hdr=hdr->next) {
-	len = (*hdr->vptr->print_on)(hdr, p, end-p);
-	if (len < 1)
-	    return -1;
-	p += len;
-
-	if (p+3 >= end)
-	    return -1;
-
-	*p++ = '\r';
-	*p++ = '\n';
-    }
-
-    /* Process message body. */
-    if (msg->body) {
-	pj_str_t ctype_hdr = { "Content-Type: ", 14};
-	int len;
-	const pjsip_media_type *media = &msg->body->content_type;
-	char *clen_pos;
-
-	/* Add Content-Type header. */
-	if ( (end-p) < 24+media->type.slen+media->subtype.slen+media->param.slen) {
-	    return -1;
-	}
-	pj_memcpy(p, ctype_hdr.ptr, ctype_hdr.slen);
-	p += ctype_hdr.slen;
-	p += print_media_type(p, media);
-	*p++ = '\r';
-	*p++ = '\n';
-
-	/* Add Content-Length header. */
-	if ((end-p) < clen_hdr.slen+12+2) {
-	    return -1;
-	}
-	pj_memcpy(p, clen_hdr.ptr, clen_hdr.slen);
-	p += clen_hdr.slen;
-	
-	/* Print blanks after "Content-Type:", this is where we'll put
-	 * the content length value after we know the length of the
-	 * body.
-	 */
-	pj_memset(p, ' ', 12);
-	clen_pos = p;
-	p += 12;
-	*p++ = '\r';
-	*p++ = '\n';
-	
-	/* Add blank newline. */
-	*p++ = '\r';
-	*p++ = '\n';
-
-	/* Print the message body itself. */
-	len = (*msg->body->print_body)(msg->body, p, end-p);
-	if (len < 0) {
-	    return -1;
-	}
-	p += len;
-
-	/* Now that we have the length of the body, print this to the
-	 * Content-Length header.
-	 */
-	len = pj_utoa(len, clen_pos);
-	clen_pos[len] = ' ';
-
-    } else {
-	/* There's no message body.
-	 * Add Content-Length with zero value.
-	 */
-	if ((end-p) < clen_hdr.slen+8) {
-	    return -1;
-	}
-	pj_memcpy(p, clen_hdr.ptr, clen_hdr.slen);
-	p += clen_hdr.slen;
-	*p++ = '0';
-	*p++ = '\r';
-	*p++ = '\n';
-	*p++ = '\r';
-	*p++ = '\n';
-    }
-
-    *p = '\0';
-    return p-buf;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-PJ_DEF(void*) pjsip_hdr_clone( pj_pool_t *pool, const void *hdr_ptr )
-{
-    const pjsip_hdr *hdr = hdr_ptr;
-    return (*hdr->vptr->clone)(pool, hdr_ptr);
-}
-
-
-PJ_DEF(void*) pjsip_hdr_shallow_clone( pj_pool_t *pool, const void *hdr_ptr )
-{
-    const pjsip_hdr *hdr = hdr_ptr;
-    return (*hdr->vptr->shallow_clone)(pool, hdr_ptr);
-}
-
-PJ_DEF(int) pjsip_hdr_print_on( void *hdr_ptr, char *buf, pj_size_t len)
-{
-    pjsip_hdr *hdr = hdr_ptr;
-    return (*hdr->vptr->print_on)(hdr_ptr, buf, len);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Status/Reason Phrase
- */
-
-PJ_DEF(const pj_str_t*) pjsip_get_status_text(int code)
-{
-    static int is_initialized;
-    if (is_initialized == 0) {
-	is_initialized = 1;
-	init_status_phrase();
-    }
-
-    return (code>=100 && code<(sizeof(status_phrase)/sizeof(status_phrase[0]))) ? 
-	&status_phrase[code] : &status_phrase[0];
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Generic pjsip_hdr_names/hvalue header.
- */
-
-static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr, 
-				    char *buf, pj_size_t size);
-static pjsip_generic_string_hdr* pjsip_generic_string_hdr_clone( pj_pool_t *pool, 
-						   const pjsip_generic_string_hdr *hdr);
-static pjsip_generic_string_hdr* pjsip_generic_string_hdr_shallow_clone( pj_pool_t *pool,
-							   const pjsip_generic_string_hdr *hdr );
-
-static pjsip_hdr_vptr generic_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_generic_string_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_generic_string_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_generic_string_hdr_print,
-};
-
-PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool,
-						     const pj_str_t *hnames )
-{
-    pjsip_generic_string_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_string_hdr));
-    init_hdr(hdr, PJSIP_H_OTHER, &generic_hdr_vptr);
-    if (hnames) {
-	pj_strdup(pool, &hdr->name, hnames);
-	hdr->sname = hdr->name;
-    }
-    hdr->hvalue.ptr = NULL;
-    hdr->hvalue.slen = 0;
-    return hdr;
-}
-
-PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,
-							       const pj_str_t *hname,
-							       const pj_str_t *hvalue)
-{
-    pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, hname);
-    pj_strdup(pool, &hdr->hvalue, hvalue);
-    return hdr;
-}
-
-static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr, 
-				    char *buf, pj_size_t size)
-{
-    char *p = buf;
-    
-    if ((pj_ssize_t)size < hdr->name.slen + hdr->hvalue.slen + 5)
-	return -1;
-
-    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);
-    p += hdr->name.slen;
-    *p++ = ':';
-    *p++ = ' ';
-    pj_memcpy(p, hdr->hvalue.ptr, hdr->hvalue.slen);
-    p += hdr->hvalue.slen;
-    *p = '\0';
-
-    return p - buf;
-}
-
-static pjsip_generic_string_hdr* pjsip_generic_string_hdr_clone( pj_pool_t *pool, 
-					           const pjsip_generic_string_hdr *rhs)
-{
-    pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, &rhs->name);
-
-    hdr->type = rhs->type;
-    hdr->sname = hdr->name;
-    pj_strdup( pool, &hdr->hvalue, &rhs->hvalue);
-    return hdr;
-}
-
-static pjsip_generic_string_hdr* pjsip_generic_string_hdr_shallow_clone( pj_pool_t *pool,
-							   const pjsip_generic_string_hdr *rhs )
-{
-    pjsip_generic_string_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Generic pjsip_hdr_names/integer value header.
- */
-
-static int pjsip_generic_int_hdr_print( pjsip_generic_int_hdr *hdr, 
-					char *buf, pj_size_t size);
-static pjsip_generic_int_hdr* pjsip_generic_int_hdr_clone( pj_pool_t *pool, 
-						   const pjsip_generic_int_hdr *hdr);
-static pjsip_generic_int_hdr* pjsip_generic_int_hdr_shallow_clone( pj_pool_t *pool,
-							   const pjsip_generic_int_hdr *hdr );
-
-static pjsip_hdr_vptr generic_int_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_generic_int_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_generic_int_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_generic_int_hdr_print,
-};
-
-PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,
-						     const pj_str_t *hnames )
-{
-    pjsip_generic_int_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_int_hdr));
-    init_hdr(hdr, PJSIP_H_OTHER, &generic_int_hdr_vptr);
-    if (hnames) {
-	pj_strdup(pool, &hdr->name, hnames);
-	hdr->sname = hdr->name;
-    }
-    hdr->ivalue = 0;
-    return hdr;
-}
-
-PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,
-							       const pj_str_t *hname,
-							       int value)
-{
-    pjsip_generic_int_hdr *hdr = pjsip_generic_int_hdr_create(pool, hname);
-    hdr->ivalue = value;
-    return hdr;
-}
-
-static int pjsip_generic_int_hdr_print( pjsip_generic_int_hdr *hdr, 
-					char *buf, pj_size_t size)
-{
-    char *p = buf;
-
-    if ((pj_ssize_t)size < hdr->name.slen + 15)
-	return -1;
-
-    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);
-    p += hdr->name.slen;
-    *p++ = ':';
-    *p++ = ' ';
-
-    p += pj_utoa(hdr->ivalue, p);
-
-    return p - buf;
-}
-
-static pjsip_generic_int_hdr* pjsip_generic_int_hdr_clone( pj_pool_t *pool, 
-					           const pjsip_generic_int_hdr *rhs)
-{
-    pjsip_generic_int_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-static pjsip_generic_int_hdr* pjsip_generic_int_hdr_shallow_clone( pj_pool_t *pool,
-							   const pjsip_generic_int_hdr *rhs )
-{
-    pjsip_generic_int_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Generic array header.
- */
-static int pjsip_generic_array_hdr_print( pjsip_generic_array_hdr *hdr, char *buf, pj_size_t size);
-static pjsip_generic_array_hdr* pjsip_generic_array_hdr_clone( pj_pool_t *pool, 
-						 const pjsip_generic_array_hdr *hdr);
-static pjsip_generic_array_hdr* pjsip_generic_array_hdr_shallow_clone( pj_pool_t *pool, 
-						 const pjsip_generic_array_hdr *hdr);
-
-static pjsip_hdr_vptr generic_array_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_generic_array_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_generic_array_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_generic_array_hdr_print,
-};
-
-PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_create( pj_pool_t *pool,
-							     const pj_str_t *hnames)
-{
-    pjsip_generic_array_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_array_hdr));
-    init_hdr(hdr, PJSIP_H_OTHER, &generic_array_hdr_vptr);
-    if (hnames) {
-	pj_strdup(pool, &hdr->name, hnames);
-	hdr->sname = hdr->name;
-    }
-    hdr->count = 0;
-    return hdr;
-
-}
-
-static int pjsip_generic_array_hdr_print( pjsip_generic_array_hdr *hdr, 
-					  char *buf, pj_size_t size)
-{
-    char *p = buf, *endbuf = buf+size;
-
-    copy_advance(p, hdr->name);
-    *p++ = ':';
-    *p++ = ' ';
-
-    if (hdr->count > 0) {
-	unsigned i;
-	int printed;
-	copy_advance(p, hdr->values[0]);
-	for (i=1; i<hdr->count; ++i) {
-	    copy_advance_pair(p, ", ", 2, hdr->values[i]);
-	}
-    }
-
-    return p - buf;
-}
-
-static pjsip_generic_array_hdr* pjsip_generic_array_hdr_clone( pj_pool_t *pool, 
-						 const pjsip_generic_array_hdr *rhs)
-{
-    unsigned i;
-    pjsip_generic_array_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    for (i=0; i<rhs->count; ++i) {
-	pj_strdup(pool, &hdr->values[i], &rhs->values[i]);
-    }
-
-    return hdr;
-}
-
-
-static pjsip_generic_array_hdr* pjsip_generic_array_hdr_shallow_clone( pj_pool_t *pool, 
-						 const pjsip_generic_array_hdr *rhs)
-{
-    pjsip_generic_array_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Accept header.
- */
-PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool)
-{
-    pjsip_accept_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_ACCEPT, &generic_array_hdr_vptr);
-    hdr->count = 0;
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Allow header.
- */
-
-PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool)
-{
-    pjsip_allow_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_ALLOW, &generic_array_hdr_vptr);
-    hdr->count = 0;
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Call-ID header.
- */
-
-PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool )
-{
-    pjsip_cid_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_CALL_ID, &generic_hdr_vptr);
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Content-Length header.
- */
-static int pjsip_clen_hdr_print( pjsip_clen_hdr *hdr, char *buf, pj_size_t size);
-static pjsip_clen_hdr* pjsip_clen_hdr_clone( pj_pool_t *pool, const pjsip_clen_hdr *hdr);
-#define pjsip_clen_hdr_shallow_clone pjsip_clen_hdr_clone
-
-static pjsip_hdr_vptr clen_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_clen_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_clen_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_clen_hdr_print,
-};
-
-PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool )
-{
-    pjsip_clen_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_clen_hdr));
-    init_hdr(hdr, PJSIP_H_CONTENT_LENGTH, &clen_hdr_vptr);
-    hdr->len = 0;
-    return hdr;
-}
-
-static int pjsip_clen_hdr_print( pjsip_clen_hdr *hdr, 
-				 char *buf, pj_size_t size)
-{
-    char *p = buf;
-    int len;
-
-    if ((pj_ssize_t)size < hdr->name.slen + 14)
-	return -1;
-
-    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);
-    p += hdr->name.slen;
-    *p++ = ':';
-    *p++ = ' ';
-
-    len = pj_utoa(hdr->len, p);
-    p += len;
-    *p = '\0';
-
-    return p-buf;
-}
-
-static pjsip_clen_hdr* pjsip_clen_hdr_clone( pj_pool_t *pool, const pjsip_clen_hdr *rhs)
-{
-    pjsip_clen_hdr *hdr = pjsip_clen_hdr_create(pool);
-    hdr->len = rhs->len;
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * CSeq header.
- */
-static int pjsip_cseq_hdr_print( pjsip_cseq_hdr *hdr, char *buf, pj_size_t size);
-static pjsip_cseq_hdr* pjsip_cseq_hdr_clone( pj_pool_t *pool, const pjsip_cseq_hdr *hdr);
-static pjsip_cseq_hdr* pjsip_cseq_hdr_shallow_clone( pj_pool_t *pool, const pjsip_cseq_hdr *hdr );
-
-static pjsip_hdr_vptr cseq_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_cseq_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_cseq_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_cseq_hdr_print,
-};
-
-PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )
-{
-    pjsip_cseq_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_cseq_hdr));
-    init_hdr(hdr, PJSIP_H_CSEQ, &cseq_hdr_vptr);
-    hdr->cseq = 0;
-    hdr->method.id = PJSIP_OTHER_METHOD;
-    hdr->method.name.ptr = NULL;
-    hdr->method.name.slen = 0;
-    return hdr;
-}
-
-static int pjsip_cseq_hdr_print( pjsip_cseq_hdr *hdr, char *buf, pj_size_t size)
-{
-    char *p = buf;
-    int len;
-
-    if ((pj_ssize_t)size < hdr->name.slen + hdr->method.name.slen + 15)
-	return -1;
-
-    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);
-    p += hdr->name.slen;
-    *p++ = ':';
-    *p++ = ' ';
-
-    len = pj_utoa(hdr->cseq, p);
-    p += len;
-    *p++ = ' ';
-
-    pj_memcpy(p, hdr->method.name.ptr, hdr->method.name.slen);
-    p += hdr->method.name.slen;
-
-    *p = '\0';
-
-    return p-buf;
-}
-
-static pjsip_cseq_hdr* pjsip_cseq_hdr_clone( pj_pool_t *pool, 
-					     const pjsip_cseq_hdr *rhs)
-{
-    pjsip_cseq_hdr *hdr = pjsip_cseq_hdr_create(pool);
-    hdr->cseq = rhs->cseq;
-    pjsip_method_copy(pool, &hdr->method, &rhs->method);
-    return hdr;
-}
-
-static pjsip_cseq_hdr* pjsip_cseq_hdr_shallow_clone( pj_pool_t *pool,
-						     const pjsip_cseq_hdr *rhs )
-{
-    pjsip_cseq_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Contact header.
- */
-static int pjsip_contact_hdr_print( pjsip_contact_hdr *hdr, char *buf, pj_size_t size);
-static pjsip_contact_hdr* pjsip_contact_hdr_clone( pj_pool_t *pool, const pjsip_contact_hdr *hdr);
-static pjsip_contact_hdr* pjsip_contact_hdr_shallow_clone( pj_pool_t *pool, const pjsip_contact_hdr *);
-
-static pjsip_hdr_vptr contact_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_contact_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_contact_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_contact_hdr_print,
-};
-
-PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool )
-{
-    pjsip_contact_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_CONTACT, &contact_hdr_vptr);
-    hdr->expires = -1;
-    return hdr;
-}
-
-static int pjsip_contact_hdr_print( pjsip_contact_hdr *hdr, char *buf, 
-				    pj_size_t size)
-{
-    if (hdr->star) {
-	char *p = buf;
-	if ((pj_ssize_t)size < hdr->name.slen + 6)
-	    return -1;
-	pj_memcpy(p, hdr->name.ptr, hdr->name.slen);
-	p += hdr->name.slen;
-	*p++ = ':';
-	*p++ = ' ';
-	*p++ = '*';
-	*p = '\0';
-	return p - buf;
-
-    } else {
-	int printed;
-	char *startbuf = buf;
-	char *endbuf = buf + size;
-
-	copy_advance(buf, hdr->name);
-	*buf++ = ':';
-	*buf++ = ' ';
-
-	printed = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, hdr->uri, 
-				  buf, endbuf-buf);
-	if (printed < 1)
-	    return -1;
-
-	buf += printed;
-
-	if (hdr->q1000) {
-	    if (buf+19 >= endbuf)
-		return -1;
-
-	    /*
-	    printed = sprintf(buf, ";q=%u.%03u",
-				   hdr->q1000/1000, hdr->q1000 % 1000);
-	     */
-	    pj_memcpy(buf, ";q=", 3);
-	    printed = pj_utoa(hdr->q1000/1000, buf+3);
-	    buf += printed + 3;
-	    *buf++ = '.';
-	    printed = pj_utoa(hdr->q1000 % 1000, buf);
-	    buf += printed;
-	}
-
-	if (hdr->expires >= 0) {
-	    if (buf+23 >= endbuf)
-		return -1;
-
-	    pj_memcpy(buf, ";expires=", 9);
-	    printed = pj_utoa(hdr->expires, buf+9);
-	    buf += printed + 9;
-	}
-
-	if (hdr->other_param.slen) {
-	    copy_advance(buf, hdr->other_param);
-	}
-
-	*buf = '\0';
-	return buf-startbuf;
-    }
-}
-
-static pjsip_contact_hdr* pjsip_contact_hdr_clone( pj_pool_t *pool, 
-					           const pjsip_contact_hdr *rhs)
-{
-    pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(pool);
-
-    hdr->star = rhs->star;
-    if (hdr->star)
-	return hdr;
-
-    hdr->uri = pjsip_uri_clone(pool, rhs->uri);
-    hdr->q1000 = rhs->q1000;
-    hdr->expires = rhs->expires;
-    pj_strdup(pool, &hdr->other_param, &rhs->other_param);
-    return hdr;
-}
-
-static pjsip_contact_hdr* pjsip_contact_hdr_shallow_clone( pj_pool_t *pool,
-							   const pjsip_contact_hdr *rhs)
-{
-    pjsip_contact_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Content-Type header..
- */
-static int pjsip_ctype_hdr_print( pjsip_ctype_hdr *hdr, char *buf, pj_size_t size);
-static pjsip_ctype_hdr* pjsip_ctype_hdr_clone( pj_pool_t *pool, const pjsip_ctype_hdr *hdr);
-#define pjsip_ctype_hdr_shallow_clone pjsip_ctype_hdr_clone
-
-static pjsip_hdr_vptr ctype_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_ctype_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_ctype_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_ctype_hdr_print,
-};
-
-PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool )
-{
-    pjsip_ctype_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_CONTENT_TYPE, &ctype_hdr_vptr);
-    return hdr;
-}
-
-static int print_media_type(char *buf, const pjsip_media_type *media)
-{
-    char *p = buf;
-
-    pj_memcpy(p, media->type.ptr, media->type.slen);
-    p += media->type.slen;
-    *p++ = '/';
-    pj_memcpy(p, media->subtype.ptr, media->subtype.slen);
-    p += media->subtype.slen;
-
-    if (media->param.slen) {
-	pj_memcpy(p, media->param.ptr, media->param.slen);
-	p += media->param.slen;
-    }
-
-    return p-buf;
-}
-
-static int pjsip_ctype_hdr_print( pjsip_ctype_hdr *hdr, 
-				  char *buf, pj_size_t size)
-{
-    char *p = buf;
-    int len;
-
-    if ((pj_ssize_t)size < hdr->name.slen + 
-			   hdr->media.type.slen + hdr->media.subtype.slen + 
-			   hdr->media.param.slen + 8)
-    {
-	return -1;
-    }
-
-    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);
-    p += hdr->name.slen;
-    *p++ = ':';
-    *p++ = ' ';
-
-    len = print_media_type(p, &hdr->media);
-    p += len;
-
-    *p = '\0';
-    return p-buf;
-}
-
-static pjsip_ctype_hdr* pjsip_ctype_hdr_clone( pj_pool_t *pool, 
-					       const pjsip_ctype_hdr *rhs)
-{
-    pjsip_ctype_hdr *hdr = pjsip_ctype_hdr_create(pool);
-    pj_strdup(pool, &hdr->media.type, &rhs->media.type);
-    pj_strdup(pool, &hdr->media.param, &rhs->media.param);
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Expires header.
- */
-PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool )
-{
-    pjsip_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_EXPIRES, &generic_int_hdr_vptr);
-    hdr->ivalue = 0;
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * To or From header.
- */
-static int pjsip_fromto_hdr_print( pjsip_fromto_hdr *hdr, 
-				   char *buf, pj_size_t size);
-static pjsip_fromto_hdr* pjsip_fromto_hdr_clone( pj_pool_t *pool, 
-					         const pjsip_fromto_hdr *hdr);
-static pjsip_fromto_hdr* pjsip_fromto_hdr_shallow_clone( pj_pool_t *pool,
-							 const pjsip_fromto_hdr *hdr);
-
-
-static pjsip_hdr_vptr fromto_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_fromto_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_fromto_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_fromto_hdr_print,
-};
-
-PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool )
-{
-    pjsip_from_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_FROM, &fromto_hdr_vptr);
-    return hdr;
-}
-
-PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool )
-{
-    pjsip_to_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_TO, &fromto_hdr_vptr);
-    return hdr;
-}
-
-PJ_DEF(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr )
-{
-    hdr->type = PJSIP_H_FROM;
-    hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_FROM];
-    return hdr;
-}
-
-PJ_DEF(pjsip_to_hdr*) pjsip_fromto_set_to( pjsip_fromto_hdr *hdr )
-{
-    hdr->type = PJSIP_H_TO;
-    hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_TO];
-    return hdr;
-}
-
-static int pjsip_fromto_hdr_print( pjsip_fromto_hdr *hdr, 
-				   char *buf, pj_size_t size)
-{
-    int printed;
-    char *startbuf = buf;
-    char *endbuf = buf + size;
-
-    copy_advance(buf, hdr->name);
-    *buf++ = ':';
-    *buf++ = ' ';
-
-    printed = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, hdr->uri, buf, endbuf-buf);
-    if (printed < 1)
-	return -1;
-
-    buf += printed;
-
-    copy_advance_pair(buf, ";tag=", 5, hdr->tag);
-    if (hdr->other_param.slen)
-	copy_advance(buf, hdr->other_param);
-
-    return buf-startbuf;
-}
-
-static pjsip_fromto_hdr* pjsip_fromto_hdr_clone( pj_pool_t *pool, 
-					         const pjsip_fromto_hdr *rhs)
-{
-    pjsip_fromto_hdr *hdr = pjsip_from_hdr_create(pool);
-
-    hdr->type = rhs->type;
-    hdr->name = rhs->name;
-    hdr->sname = rhs->sname;
-    hdr->uri = pjsip_uri_clone(pool, rhs->uri);
-    pj_strdup( pool, &hdr->tag, &rhs->tag);
-    pj_strdup( pool, &hdr->other_param, &rhs->other_param);
-
-    return hdr;
-}
-
-static pjsip_fromto_hdr* pjsip_fromto_hdr_shallow_clone( pj_pool_t *pool,
-							 const pjsip_fromto_hdr *rhs)
-{
-    pjsip_fromto_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Max-Forwards header.
- */
-PJ_DEF(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool)
-{
-    pjsip_max_forwards_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_MAX_FORWARDS, &generic_int_hdr_vptr);
-    hdr->ivalue = 0;
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Min-Expires header.
- */
-PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool)
-{
-    pjsip_min_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_MIN_EXPIRES, &generic_int_hdr_vptr);
-    hdr->ivalue = 0;
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Record-Route and Route header.
- */
-static int pjsip_routing_hdr_print( pjsip_routing_hdr *r, char *buf, pj_size_t size );
-static pjsip_routing_hdr* pjsip_routing_hdr_clone( pj_pool_t *pool, const pjsip_routing_hdr *r );
-static pjsip_routing_hdr* pjsip_routing_hdr_shallow_clone( pj_pool_t *pool, const pjsip_routing_hdr *r );
-
-static pjsip_hdr_vptr routing_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_routing_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_routing_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_routing_hdr_print,
-};
-
-PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool )
-{
-    pjsip_rr_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_RECORD_ROUTE, &routing_hdr_vptr);
-    pjsip_name_addr_init(&hdr->name_addr);
-    pj_memset(&hdr->other_param, 0, sizeof(hdr->other_param));
-    return hdr;
-}
-
-PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool )
-{
-    pjsip_route_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_ROUTE, &routing_hdr_vptr);
-    pjsip_name_addr_init(&hdr->name_addr);
-    pj_memset(&hdr->other_param, 0, sizeof(hdr->other_param));
-    return hdr;
-}
-
-PJ_DEF(pjsip_rr_hdr*) pjsip_routing_hdr_set_rr( pjsip_routing_hdr *hdr )
-{
-    hdr->type = PJSIP_H_RECORD_ROUTE;
-    hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_RECORD_ROUTE];
-    return hdr;
-}
-
-PJ_DEF(pjsip_route_hdr*) pjsip_routing_hdr_set_route( pjsip_routing_hdr *hdr )
-{
-    hdr->type = PJSIP_H_ROUTE;
-    hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_ROUTE];
-    return hdr;
-}
-
-static int pjsip_routing_hdr_print( pjsip_routing_hdr *hdr,
-				    char *buf, pj_size_t size )
-{
-    int printed;
-    char *startbuf = buf;
-    char *endbuf = buf + size;
-
-    copy_advance(buf, hdr->name);
-    *buf++ = ':';
-    *buf++ = ' ';
-
-    printed = pjsip_uri_print(PJSIP_URI_IN_ROUTING_HDR, &hdr->name_addr, buf, endbuf-buf);
-    if (printed < 1)
-	return -1;
-    buf += printed;
-
-    if (hdr->other_param.slen) {
-	copy_advance(buf, hdr->other_param);
-    }
-
-    return buf-startbuf;
-}
-
-static pjsip_routing_hdr* pjsip_routing_hdr_clone( pj_pool_t *pool,
-						   const pjsip_routing_hdr *rhs )
-{
-    pjsip_routing_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-
-    init_hdr(hdr, rhs->type, rhs->vptr);
-    pjsip_name_addr_init(&hdr->name_addr);
-    pjsip_name_addr_assign(pool, &hdr->name_addr, &rhs->name_addr);
-    pj_strdup( pool, &hdr->other_param, &rhs->other_param);
-    return hdr;
-}
-
-static pjsip_routing_hdr* pjsip_routing_hdr_shallow_clone( pj_pool_t *pool,
-							   const pjsip_routing_hdr *rhs )
-{
-    pjsip_routing_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Require header.
- */
-PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool)
-{
-    pjsip_require_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_REQUIRE, &generic_array_hdr_vptr);
-    hdr->count = 0;
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Retry-After header.
- */
-PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool)
-{
-    pjsip_retry_after_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_RETRY_AFTER, &generic_int_hdr_vptr);
-    hdr->ivalue = 0;
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Supported header.
- */
-PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool)
-{
-    pjsip_supported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_SUPPORTED, &generic_array_hdr_vptr);
-    hdr->count = 0;
-    return hdr;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Unsupported header.
- */
-PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool)
-{
-    pjsip_unsupported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_UNSUPPORTED, &generic_array_hdr_vptr);
-    hdr->count = 0;
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * Via header.
- */
-static int pjsip_via_hdr_print( pjsip_via_hdr *hdr, char *buf, pj_size_t size);
-static pjsip_via_hdr* pjsip_via_hdr_clone( pj_pool_t *pool, const pjsip_via_hdr *hdr);
-static pjsip_via_hdr* pjsip_via_hdr_shallow_clone( pj_pool_t *pool, const pjsip_via_hdr *hdr );
-
-static pjsip_hdr_vptr via_hdr_vptr = 
-{
-    (pjsip_hdr_clone_fptr) &pjsip_via_hdr_clone,
-    (pjsip_hdr_clone_fptr) &pjsip_via_hdr_shallow_clone,
-    (pjsip_hdr_print_fptr) &pjsip_via_hdr_print,
-};
-
-PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool )
-{
-    pjsip_via_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));
-    init_hdr(hdr, PJSIP_H_VIA, &via_hdr_vptr);
-    hdr->sent_by.port = 5060;
-    hdr->ttl_param = -1;
-    hdr->rport_param = -1;
-    return hdr;
-}
-
-static int pjsip_via_hdr_print( pjsip_via_hdr *hdr, 
-				char *buf, pj_size_t size)
-{
-    int printed;
-    char *startbuf = buf;
-    char *endbuf = buf + size;
-    pj_str_t sip_ver = { "SIP/2.0/", 8 };
-
-    if ((pj_ssize_t)size < hdr->name.slen + sip_ver.slen + 
-			   hdr->transport.slen + hdr->sent_by.host.slen + 12)
-    {
-	return -1;
-    }
-
-    /* pjsip_hdr_names */
-    copy_advance(buf, hdr->name);
-    *buf++ = ':';
-    *buf++ = ' ';
-
-    /* SIP/2.0/transport host:port */
-    pj_memcpy(buf, sip_ver.ptr, sip_ver.slen);
-    buf += sip_ver.slen;
-    pj_memcpy(buf, hdr->transport.ptr, hdr->transport.slen);
-    buf += hdr->transport.slen;
-    *buf++ = ' ';
-    pj_memcpy(buf, hdr->sent_by.host.ptr, hdr->sent_by.host.slen);
-    buf += hdr->sent_by.host.slen;
-    *buf++ = ':';
-    printed = pj_utoa(hdr->sent_by.port, buf);
-    buf += printed;
-
-    if (hdr->ttl_param >= 0) {
-	size = endbuf-buf;
-	if (size < 14)
-	    return -1;
-	pj_memcpy(buf, ";ttl=", 5);
-	printed = pj_utoa(hdr->ttl_param, buf+5);
-	buf += printed + 5;
-    }
-
-    if (hdr->rport_param >= 0) {
-	size = endbuf-buf;
-	if (size < 14)
-	    return -1;
-	pj_memcpy(buf, ";rport", 6);
-	buf += 6;
-	if (hdr->rport_param > 0) {
-	    *buf++ = '=';
-	    buf += pj_utoa(hdr->rport_param, buf);
-	}
-    }
-
-
-    copy_advance_pair(buf, ";maddr=", 7, hdr->maddr_param);
-    copy_advance_pair(buf, ";received=", 10, hdr->recvd_param);
-    copy_advance_pair(buf, ";branch=", 8, hdr->branch_param);
-    copy_advance(buf, hdr->other_param);
-    
-    *buf = '\0';
-    return buf-startbuf;
-}
-
-static pjsip_via_hdr* pjsip_via_hdr_clone( pj_pool_t *pool, 
-					   const pjsip_via_hdr *rhs)
-{
-    pjsip_via_hdr *hdr = pjsip_via_hdr_create(pool);
-    pj_strdup(pool, &hdr->transport, &rhs->transport);
-    pj_strdup(pool, &hdr->sent_by.host, &rhs->sent_by.host);
-    hdr->sent_by.port = rhs->sent_by.port;
-    hdr->ttl_param = rhs->ttl_param;
-    hdr->rport_param = rhs->rport_param;
-    pj_strdup(pool, &hdr->maddr_param, &rhs->maddr_param);
-    pj_strdup(pool, &hdr->recvd_param, &rhs->recvd_param);
-    pj_strdup(pool, &hdr->branch_param, &rhs->branch_param);
-    pj_strdup(pool, &hdr->other_param, &rhs->other_param);
-    return hdr;
-}
-
-static pjsip_via_hdr* pjsip_via_hdr_shallow_clone( pj_pool_t *pool,
-						   const pjsip_via_hdr *rhs )
-{
-    pjsip_via_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));
-    pj_memcpy(hdr, rhs, sizeof(*hdr));
-    return hdr;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-/*
- * General purpose function to textual data in a SIP body. 
- */
-PJ_DEF(int) pjsip_print_text_body(pjsip_msg_body *msg_body, char *buf, pj_size_t size)
-{
-    if (size < msg_body->len)
-	return -1;
-    pj_memcpy(buf, msg_body->data, msg_body->len);
-    return msg_body->len;
-}
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_msg.h>

+#include <pjsip/print_util.h>

+#include <pj/string.h>

+#include <pj/pool.h>

+

+/*

+ * Include inline definitions here if functions are NOT inlined.

+ */

+#if PJ_FUNCTIONS_ARE_INLINED==0

+#  include <pjsip/sip_msg_i.h>

+#endif

+

+static const pj_str_t method_names[] = 

+{

+    { "INVITE",	    6 },

+    { "CANCEL",	    6 },

+    { "ACK",	    3 },

+    { "BYE",	    3 },

+    { "REGISTER",   8 },

+    { "OPTIONS",    7 },

+};

+

+const pj_str_t pjsip_hdr_names[] = 

+{

+    { "Accept",		     6 },   // PJSIP_H_ACCEPT,

+    { "Accept-Encoding",    15 },   // PJSIP_H_ACCEPT_ENCODING,

+    { "Accept-Language",    15 },   // PJSIP_H_ACCEPT_LANGUAGE,

+    { "Alert-Info",	    10 },   // PJSIP_H_ALERT_INFO,

+    { "Allow",		     5 },   // PJSIP_H_ALLOW,

+    { "Authentication-Info",19 },   // PJSIP_H_AUTHENTICATION_INFO,

+    { "Authorization",	    13 },   // PJSIP_H_AUTHORIZATION,

+    { "Call-ID",	     7 },   // PJSIP_H_CALL_ID,

+    { "Call-Info",	     9 },   // PJSIP_H_CALL_INFO,

+    { "Contact",	     7 },   // PJSIP_H_CONTACT,

+    { "Content-Disposition",19 },   // PJSIP_H_CONTENT_DISPOSITION,

+    { "Content-Encoding",   16 },   // PJSIP_H_CONTENT_ENCODING,

+    { "Content-Language",   16 },   // PJSIP_H_CONTENT_LANGUAGE,

+    { "Content-Length",	    14 },   // PJSIP_H_CONTENT_LENGTH,

+    { "Content-Type",	    12 },   // PJSIP_H_CONTENT_TYPE,

+    { "CSeq",		     4 },   // PJSIP_H_CSEQ,

+    { "Date",		     4 },   // PJSIP_H_DATE,

+    { "Error-Info",	    10 },   // PJSIP_H_ERROR_INFO,

+    { "Expires",	     7 },   // PJSIP_H_EXPIRES,

+    { "From",		     4 },   // PJSIP_H_FROM,

+    { "In-Reply-To",	    11 },   // PJSIP_H_IN_REPLY_TO,

+    { "Max-Forwards",	    12 },   // PJSIP_H_MAX_FORWARDS,

+    { "MIME-Version",	    12 },   // PJSIP_H_MIME_VERSION,

+    { "Min-Expires",	    11 },   // PJSIP_H_MIN_EXPIRES,

+    { "Organization",	    12 },   // PJSIP_H_ORGANIZATION,

+    { "Priority",	     8 },   // PJSIP_H_PRIORITY,

+    { "Proxy-Authenticate", 18 },   // PJSIP_H_PROXY_AUTHENTICATE,

+    { "Proxy-Authorization",19 },   // PJSIP_H_PROXY_AUTHORIZATION,

+    { "Proxy-Require",	    13 },   // PJSIP_H_PROXY_REQUIRE,

+    { "Record-Route",	    12 },   // PJSIP_H_RECORD_ROUTE,

+    { "Reply-To",	     8 },   // PJSIP_H_REPLY_TO,

+    { "Require",	     7 },   // PJSIP_H_REQUIRE,

+    { "Retry-After",	    11 },   // PJSIP_H_RETRY_AFTER,

+    { "Route",		     5 },   // PJSIP_H_ROUTE,

+    { "Server",		     6 },   // PJSIP_H_SERVER,

+    { "Subject",	     7 },   // PJSIP_H_SUBJECT,

+    { "Supported",	     9 },   // PJSIP_H_SUPPORTED,

+    { "Timestamp",	     9 },   // PJSIP_H_TIMESTAMP,

+    { "To",		     2 },   // PJSIP_H_TO,

+    { "Unsupported",	    11 },   // PJSIP_H_UNSUPPORTED,

+    { "User-Agent",	    10 },   // PJSIP_H_USER_AGENT,

+    { "Via",		     3 },   // PJSIP_H_VIA,

+    { "Warning",	     7 },   // PJSIP_H_WARNING,

+    { "WWW-Authenticate",   16 },   // PJSIP_H_WWW_AUTHENTICATE,

+

+    { "_Unknown-Header",    15 },   // PJSIP_H_OTHER,

+};

+

+static pj_str_t status_phrase[710];

+static int print_media_type(char *buf, const pjsip_media_type *media);

+

+static int init_status_phrase()

+{

+    int i;

+    pj_str_t default_reason_phrase = { "Default status message", 22};

+

+    for (i=0; i<PJ_ARRAY_SIZE(status_phrase); ++i)

+	status_phrase[i] = default_reason_phrase;

+

+    pj_strset2( &status_phrase[100], "Trying");

+    pj_strset2( &status_phrase[180], "Ringing");

+    pj_strset2( &status_phrase[181], "Call Is Being Forwarded");

+    pj_strset2( &status_phrase[182], "Queued");

+    pj_strset2( &status_phrase[183], "Session Progress");

+

+    pj_strset2( &status_phrase[200], "OK");

+

+    pj_strset2( &status_phrase[300], "Multiple Choices");

+    pj_strset2( &status_phrase[301], "Moved Permanently");

+    pj_strset2( &status_phrase[302], "Moved Temporarily");

+    pj_strset2( &status_phrase[305], "Use Proxy");

+    pj_strset2( &status_phrase[380], "Alternative Service");

+

+    pj_strset2( &status_phrase[400], "Bad Request");

+    pj_strset2( &status_phrase[401], "Unauthorized");

+    pj_strset2( &status_phrase[402], "Payment Required");

+    pj_strset2( &status_phrase[403], "Forbidden");

+    pj_strset2( &status_phrase[404], "Not Found");

+    pj_strset2( &status_phrase[405], "Method Not Allowed");

+    pj_strset2( &status_phrase[406], "Not Acceptable");

+    pj_strset2( &status_phrase[407], "Proxy Authentication Required");

+    pj_strset2( &status_phrase[408], "Request Timeout");

+    pj_strset2( &status_phrase[410], "Gone");

+    pj_strset2( &status_phrase[413], "Request Entity Too Large");

+    pj_strset2( &status_phrase[414], "Request URI Too Long");

+    pj_strset2( &status_phrase[415], "Unsupported Media Type");

+    pj_strset2( &status_phrase[416], "Unsupported URI Scheme");

+    pj_strset2( &status_phrase[420], "Bad Extension");

+    pj_strset2( &status_phrase[421], "Extension Required");

+    pj_strset2( &status_phrase[423], "Interval Too Brief");

+    pj_strset2( &status_phrase[480], "Temporarily Unavailable");

+    pj_strset2( &status_phrase[481], "Call/Transaction Does Not Exist");

+    pj_strset2( &status_phrase[482], "Loop Detected");

+    pj_strset2( &status_phrase[483], "Too Many Hops");

+    pj_strset2( &status_phrase[484], "Address Incompleted");

+    pj_strset2( &status_phrase[485], "Ambiguous");

+    pj_strset2( &status_phrase[486], "Busy Here");

+    pj_strset2( &status_phrase[487], "Request Terminated");

+    pj_strset2( &status_phrase[488], "Not Acceptable Here");

+    pj_strset2( &status_phrase[491], "Request Pending");

+    pj_strset2( &status_phrase[493], "Undecipherable");

+

+    pj_strset2( &status_phrase[500], "Internal Server Error");

+    pj_strset2( &status_phrase[501], "Not Implemented");

+    pj_strset2( &status_phrase[502], "Bad Gateway");

+    pj_strset2( &status_phrase[503], "Service Unavailable");

+    pj_strset2( &status_phrase[504], "Server Timeout");

+    pj_strset2( &status_phrase[505], "Version Not Supported");

+    pj_strset2( &status_phrase[513], "Message Too Large");

+

+    pj_strset2( &status_phrase[600], "Busy Everywhere");

+    pj_strset2( &status_phrase[603], "Decline");

+    pj_strset2( &status_phrase[604], "Does Not Exist Anywhere");

+    pj_strset2( &status_phrase[606], "Not Acceptable");

+

+    pj_strset2( &status_phrase[701], "No response from destination server");

+    pj_strset2( &status_phrase[702], "Unable to resolve destination server");

+    pj_strset2( &status_phrase[703], "Error sending message to destination server");

+

+    return 1;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Method.

+ */

+

+PJ_DEF(void) pjsip_method_init( pjsip_method *m, 

+			        pj_pool_t *pool, 

+			        const pj_str_t *str)

+{

+    pj_str_t dup;

+    pjsip_method_init_np(m, pj_strdup(pool, &dup, str));

+}

+

+PJ_DEF(void) pjsip_method_set( pjsip_method *m, pjsip_method_e me )

+{

+    m->id = me;

+    m->name = method_names[me];

+}

+

+PJ_DEF(void) pjsip_method_init_np(pjsip_method *m,

+				  pj_str_t *str)

+{

+    int i;

+    for (i=0; i<PJ_ARRAY_SIZE(method_names); ++i) {

+	if (pj_stricmp(str, &method_names[i])==0) {

+	    m->id = (pjsip_method_e)i;

+	    m->name = method_names[i];

+	    return;

+	}

+    }

+    m->id = PJSIP_OTHER_METHOD;

+    m->name = *str;

+}

+

+PJ_DEF(void) pjsip_method_copy( pj_pool_t *pool,

+				pjsip_method *method,

+				const pjsip_method *rhs )

+{

+    method->id = rhs->id;

+    if (rhs->id != PJSIP_OTHER_METHOD) {

+	method->name = rhs->name;

+    } else {

+	pj_strdup(pool, &method->name, &rhs->name);

+    }

+}

+

+

+PJ_DEF(int) pjsip_method_cmp( const pjsip_method *m1, const pjsip_method *m2)

+{

+    if (m1->id == m2->id) {

+	if (m1->id != PJSIP_OTHER_METHOD)

+	    return 0;

+	return pj_stricmp(&m1->name, &m2->name);

+    }

+    

+    return ( m1->id < m2->id ) ? -1 : 1;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Message.

+ */

+

+PJ_DEF(pjsip_msg*) pjsip_msg_create( pj_pool_t *pool, pjsip_msg_type_e type)

+{

+    pjsip_msg *msg = pj_pool_alloc(pool, sizeof(pjsip_msg));

+    pj_list_init(&msg->hdr);

+    msg->type = type;

+    msg->body = NULL;

+    return msg;

+}

+

+PJ_DEF(void*)  pjsip_msg_find_hdr( pjsip_msg *msg, 

+				   pjsip_hdr_e hdr_type, void *start)

+{

+    pjsip_hdr *hdr=start, *end=&msg->hdr;

+

+    if (hdr == NULL) {

+	hdr = msg->hdr.next;

+    }

+    for (; hdr!=end; hdr = hdr->next) {

+	if (hdr->type == hdr_type)

+	    return hdr;

+    }

+    return NULL;

+}

+

+PJ_DEF(void*)  pjsip_msg_find_hdr_by_name( pjsip_msg *msg, 

+					   const pj_str_t *name, void *start)

+{

+    pjsip_hdr *hdr=start, *end=&msg->hdr;

+

+    if (hdr == NULL) {

+	hdr = msg->hdr.next;

+    }

+    for (; hdr!=end; hdr = hdr->next) {

+	if (hdr->type < PJSIP_H_OTHER) {

+	    if (pj_stricmp(&pjsip_hdr_names[hdr->type], name) == 0)

+		return hdr;

+	} else {

+	    if (pj_stricmp(&hdr->name, name) == 0)

+		return hdr;

+	}

+    }

+    return NULL;

+}

+

+PJ_DEF(void*) pjsip_msg_find_remove_hdr( pjsip_msg *msg, 

+				         pjsip_hdr_e hdr_type, void *start)

+{

+    pjsip_hdr *hdr = pjsip_msg_find_hdr(msg, hdr_type, start);

+    if (hdr) {

+	pj_list_erase(hdr);

+    }

+    return hdr;

+}

+

+PJ_DEF(pj_ssize_t) pjsip_msg_print( pjsip_msg *msg, char *buf, pj_size_t size)

+{

+    char *p=buf, *end=buf+size;

+    int len;

+    pjsip_hdr *hdr;

+    pj_str_t clen_hdr =  { "Content-Length: ", 16};

+

+    /* Get a wild guess on how many bytes are typically needed.

+     * We'll check this later in detail, but this serves as a quick check.

+     */

+    if (size < 256)

+	return -1;

+

+    /* Print request line or status line depending on message type */

+    if (msg->type == PJSIP_REQUEST_MSG) {

+	pjsip_uri *uri;

+

+	/* Add method. */

+	len = msg->line.req.method.name.slen;

+	pj_memcpy(p, msg->line.req.method.name.ptr, len);

+	p += len;

+	*p++ = ' ';

+

+	/* Add URI */

+	uri = pjsip_uri_get_uri(msg->line.req.uri);

+	len = pjsip_uri_print( PJSIP_URI_IN_REQ_URI, uri, p, end-p);

+	if (len < 1)

+	    return -1;

+	p += len;

+

+	/* Add ' SIP/2.0' */

+	if (end-p < 16)

+	    return -1;

+	pj_memcpy(p, " SIP/2.0\r\n", 10);

+	p += 10;

+

+    } else {

+

+	/* Add 'SIP/2.0 ' */

+	pj_memcpy(p, "SIP/2.0 ", 8);

+	p += 8;

+

+	/* Add status code. */

+	len = pj_utoa(msg->line.status.code, p);

+	p += len;

+	*p++ = ' ';

+

+	/* Add reason text. */

+	len = msg->line.status.reason.slen;

+	pj_memcpy(p, msg->line.status.reason.ptr, len );

+	p += len;

+

+	/* Add newline. */

+	*p++ = '\r';

+	*p++ = '\n';

+    }

+

+    /* Print each of the headers. */

+    for (hdr=msg->hdr.next; hdr!=&msg->hdr; hdr=hdr->next) {

+	len = (*hdr->vptr->print_on)(hdr, p, end-p);

+	if (len < 1)

+	    return -1;

+	p += len;

+

+	if (p+3 >= end)

+	    return -1;

+

+	*p++ = '\r';

+	*p++ = '\n';

+    }

+

+    /* Process message body. */

+    if (msg->body) {

+	pj_str_t ctype_hdr = { "Content-Type: ", 14};

+	int len;

+	const pjsip_media_type *media = &msg->body->content_type;

+	char *clen_pos;

+

+	/* Add Content-Type header. */

+	if ( (end-p) < 24+media->type.slen+media->subtype.slen+media->param.slen) {

+	    return -1;

+	}

+	pj_memcpy(p, ctype_hdr.ptr, ctype_hdr.slen);

+	p += ctype_hdr.slen;

+	p += print_media_type(p, media);

+	*p++ = '\r';

+	*p++ = '\n';

+

+	/* Add Content-Length header. */

+	if ((end-p) < clen_hdr.slen+12+2) {

+	    return -1;

+	}

+	pj_memcpy(p, clen_hdr.ptr, clen_hdr.slen);

+	p += clen_hdr.slen;

+	

+	/* Print blanks after "Content-Type:", this is where we'll put

+	 * the content length value after we know the length of the

+	 * body.

+	 */

+	pj_memset(p, ' ', 12);

+	clen_pos = p;

+	p += 12;

+	*p++ = '\r';

+	*p++ = '\n';

+	

+	/* Add blank newline. */

+	*p++ = '\r';

+	*p++ = '\n';

+

+	/* Print the message body itself. */

+	len = (*msg->body->print_body)(msg->body, p, end-p);

+	if (len < 0) {

+	    return -1;

+	}

+	p += len;

+

+	/* Now that we have the length of the body, print this to the

+	 * Content-Length header.

+	 */

+	len = pj_utoa(len, clen_pos);

+	clen_pos[len] = ' ';

+

+    } else {

+	/* There's no message body.

+	 * Add Content-Length with zero value.

+	 */

+	if ((end-p) < clen_hdr.slen+8) {

+	    return -1;

+	}

+	pj_memcpy(p, clen_hdr.ptr, clen_hdr.slen);

+	p += clen_hdr.slen;

+	*p++ = '0';

+	*p++ = '\r';

+	*p++ = '\n';

+	*p++ = '\r';

+	*p++ = '\n';

+    }

+

+    *p = '\0';

+    return p-buf;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+PJ_DEF(void*) pjsip_hdr_clone( pj_pool_t *pool, const void *hdr_ptr )

+{

+    const pjsip_hdr *hdr = hdr_ptr;

+    return (*hdr->vptr->clone)(pool, hdr_ptr);

+}

+

+

+PJ_DEF(void*) pjsip_hdr_shallow_clone( pj_pool_t *pool, const void *hdr_ptr )

+{

+    const pjsip_hdr *hdr = hdr_ptr;

+    return (*hdr->vptr->shallow_clone)(pool, hdr_ptr);

+}

+

+PJ_DEF(int) pjsip_hdr_print_on( void *hdr_ptr, char *buf, pj_size_t len)

+{

+    pjsip_hdr *hdr = hdr_ptr;

+    return (*hdr->vptr->print_on)(hdr_ptr, buf, len);

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Status/Reason Phrase

+ */

+

+PJ_DEF(const pj_str_t*) pjsip_get_status_text(int code)

+{

+    static int is_initialized;

+    if (is_initialized == 0) {

+	is_initialized = 1;

+	init_status_phrase();

+    }

+

+    return (code>=100 && code<(sizeof(status_phrase)/sizeof(status_phrase[0]))) ? 

+	&status_phrase[code] : &status_phrase[0];

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Generic pjsip_hdr_names/hvalue header.

+ */

+

+static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr, 

+				    char *buf, pj_size_t size);

+static pjsip_generic_string_hdr* pjsip_generic_string_hdr_clone( pj_pool_t *pool, 

+						   const pjsip_generic_string_hdr *hdr);

+static pjsip_generic_string_hdr* pjsip_generic_string_hdr_shallow_clone( pj_pool_t *pool,

+							   const pjsip_generic_string_hdr *hdr );

+

+static pjsip_hdr_vptr generic_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_generic_string_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_generic_string_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_generic_string_hdr_print,

+};

+

+PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create( pj_pool_t *pool,

+						     const pj_str_t *hnames )

+{

+    pjsip_generic_string_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_string_hdr));

+    init_hdr(hdr, PJSIP_H_OTHER, &generic_hdr_vptr);

+    if (hnames) {

+	pj_strdup(pool, &hdr->name, hnames);

+	hdr->sname = hdr->name;

+    }

+    hdr->hvalue.ptr = NULL;

+    hdr->hvalue.slen = 0;

+    return hdr;

+}

+

+PJ_DEF(pjsip_generic_string_hdr*) pjsip_generic_string_hdr_create_with_text( pj_pool_t *pool,

+							       const pj_str_t *hname,

+							       const pj_str_t *hvalue)

+{

+    pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, hname);

+    pj_strdup(pool, &hdr->hvalue, hvalue);

+    return hdr;

+}

+

+static int pjsip_generic_string_hdr_print( pjsip_generic_string_hdr *hdr, 

+				    char *buf, pj_size_t size)

+{

+    char *p = buf;

+    

+    if ((pj_ssize_t)size < hdr->name.slen + hdr->hvalue.slen + 5)

+	return -1;

+

+    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);

+    p += hdr->name.slen;

+    *p++ = ':';

+    *p++ = ' ';

+    pj_memcpy(p, hdr->hvalue.ptr, hdr->hvalue.slen);

+    p += hdr->hvalue.slen;

+    *p = '\0';

+

+    return p - buf;

+}

+

+static pjsip_generic_string_hdr* pjsip_generic_string_hdr_clone( pj_pool_t *pool, 

+					           const pjsip_generic_string_hdr *rhs)

+{

+    pjsip_generic_string_hdr *hdr = pjsip_generic_string_hdr_create(pool, &rhs->name);

+

+    hdr->type = rhs->type;

+    hdr->sname = hdr->name;

+    pj_strdup( pool, &hdr->hvalue, &rhs->hvalue);

+    return hdr;

+}

+

+static pjsip_generic_string_hdr* pjsip_generic_string_hdr_shallow_clone( pj_pool_t *pool,

+							   const pjsip_generic_string_hdr *rhs )

+{

+    pjsip_generic_string_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Generic pjsip_hdr_names/integer value header.

+ */

+

+static int pjsip_generic_int_hdr_print( pjsip_generic_int_hdr *hdr, 

+					char *buf, pj_size_t size);

+static pjsip_generic_int_hdr* pjsip_generic_int_hdr_clone( pj_pool_t *pool, 

+						   const pjsip_generic_int_hdr *hdr);

+static pjsip_generic_int_hdr* pjsip_generic_int_hdr_shallow_clone( pj_pool_t *pool,

+							   const pjsip_generic_int_hdr *hdr );

+

+static pjsip_hdr_vptr generic_int_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_generic_int_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_generic_int_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_generic_int_hdr_print,

+};

+

+PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create( pj_pool_t *pool,

+						     const pj_str_t *hnames )

+{

+    pjsip_generic_int_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_int_hdr));

+    init_hdr(hdr, PJSIP_H_OTHER, &generic_int_hdr_vptr);

+    if (hnames) {

+	pj_strdup(pool, &hdr->name, hnames);

+	hdr->sname = hdr->name;

+    }

+    hdr->ivalue = 0;

+    return hdr;

+}

+

+PJ_DEF(pjsip_generic_int_hdr*) pjsip_generic_int_hdr_create_with_value( pj_pool_t *pool,

+							       const pj_str_t *hname,

+							       int value)

+{

+    pjsip_generic_int_hdr *hdr = pjsip_generic_int_hdr_create(pool, hname);

+    hdr->ivalue = value;

+    return hdr;

+}

+

+static int pjsip_generic_int_hdr_print( pjsip_generic_int_hdr *hdr, 

+					char *buf, pj_size_t size)

+{

+    char *p = buf;

+

+    if ((pj_ssize_t)size < hdr->name.slen + 15)

+	return -1;

+

+    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);

+    p += hdr->name.slen;

+    *p++ = ':';

+    *p++ = ' ';

+

+    p += pj_utoa(hdr->ivalue, p);

+

+    return p - buf;

+}

+

+static pjsip_generic_int_hdr* pjsip_generic_int_hdr_clone( pj_pool_t *pool, 

+					           const pjsip_generic_int_hdr *rhs)

+{

+    pjsip_generic_int_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+static pjsip_generic_int_hdr* pjsip_generic_int_hdr_shallow_clone( pj_pool_t *pool,

+							   const pjsip_generic_int_hdr *rhs )

+{

+    pjsip_generic_int_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Generic array header.

+ */

+static int pjsip_generic_array_hdr_print( pjsip_generic_array_hdr *hdr, char *buf, pj_size_t size);

+static pjsip_generic_array_hdr* pjsip_generic_array_hdr_clone( pj_pool_t *pool, 

+						 const pjsip_generic_array_hdr *hdr);

+static pjsip_generic_array_hdr* pjsip_generic_array_hdr_shallow_clone( pj_pool_t *pool, 

+						 const pjsip_generic_array_hdr *hdr);

+

+static pjsip_hdr_vptr generic_array_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_generic_array_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_generic_array_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_generic_array_hdr_print,

+};

+

+PJ_DEF(pjsip_generic_array_hdr*) pjsip_generic_array_create( pj_pool_t *pool,

+							     const pj_str_t *hnames)

+{

+    pjsip_generic_array_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_generic_array_hdr));

+    init_hdr(hdr, PJSIP_H_OTHER, &generic_array_hdr_vptr);

+    if (hnames) {

+	pj_strdup(pool, &hdr->name, hnames);

+	hdr->sname = hdr->name;

+    }

+    hdr->count = 0;

+    return hdr;

+

+}

+

+static int pjsip_generic_array_hdr_print( pjsip_generic_array_hdr *hdr, 

+					  char *buf, pj_size_t size)

+{

+    char *p = buf, *endbuf = buf+size;

+

+    copy_advance(p, hdr->name);

+    *p++ = ':';

+    *p++ = ' ';

+

+    if (hdr->count > 0) {

+	unsigned i;

+	int printed;

+	copy_advance(p, hdr->values[0]);

+	for (i=1; i<hdr->count; ++i) {

+	    copy_advance_pair(p, ", ", 2, hdr->values[i]);

+	}

+    }

+

+    return p - buf;

+}

+

+static pjsip_generic_array_hdr* pjsip_generic_array_hdr_clone( pj_pool_t *pool, 

+						 const pjsip_generic_array_hdr *rhs)

+{

+    unsigned i;

+    pjsip_generic_array_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    for (i=0; i<rhs->count; ++i) {

+	pj_strdup(pool, &hdr->values[i], &rhs->values[i]);

+    }

+

+    return hdr;

+}

+

+

+static pjsip_generic_array_hdr* pjsip_generic_array_hdr_shallow_clone( pj_pool_t *pool, 

+						 const pjsip_generic_array_hdr *rhs)

+{

+    pjsip_generic_array_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Accept header.

+ */

+PJ_DEF(pjsip_accept_hdr*) pjsip_accept_hdr_create(pj_pool_t *pool)

+{

+    pjsip_accept_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_ACCEPT, &generic_array_hdr_vptr);

+    hdr->count = 0;

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Allow header.

+ */

+

+PJ_DEF(pjsip_allow_hdr*) pjsip_allow_hdr_create(pj_pool_t *pool)

+{

+    pjsip_allow_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_ALLOW, &generic_array_hdr_vptr);

+    hdr->count = 0;

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Call-ID header.

+ */

+

+PJ_DEF(pjsip_cid_hdr*) pjsip_cid_hdr_create( pj_pool_t *pool )

+{

+    pjsip_cid_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_CALL_ID, &generic_hdr_vptr);

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Content-Length header.

+ */

+static int pjsip_clen_hdr_print( pjsip_clen_hdr *hdr, char *buf, pj_size_t size);

+static pjsip_clen_hdr* pjsip_clen_hdr_clone( pj_pool_t *pool, const pjsip_clen_hdr *hdr);

+#define pjsip_clen_hdr_shallow_clone pjsip_clen_hdr_clone

+

+static pjsip_hdr_vptr clen_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_clen_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_clen_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_clen_hdr_print,

+};

+

+PJ_DEF(pjsip_clen_hdr*) pjsip_clen_hdr_create( pj_pool_t *pool )

+{

+    pjsip_clen_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_clen_hdr));

+    init_hdr(hdr, PJSIP_H_CONTENT_LENGTH, &clen_hdr_vptr);

+    hdr->len = 0;

+    return hdr;

+}

+

+static int pjsip_clen_hdr_print( pjsip_clen_hdr *hdr, 

+				 char *buf, pj_size_t size)

+{

+    char *p = buf;

+    int len;

+

+    if ((pj_ssize_t)size < hdr->name.slen + 14)

+	return -1;

+

+    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);

+    p += hdr->name.slen;

+    *p++ = ':';

+    *p++ = ' ';

+

+    len = pj_utoa(hdr->len, p);

+    p += len;

+    *p = '\0';

+

+    return p-buf;

+}

+

+static pjsip_clen_hdr* pjsip_clen_hdr_clone( pj_pool_t *pool, const pjsip_clen_hdr *rhs)

+{

+    pjsip_clen_hdr *hdr = pjsip_clen_hdr_create(pool);

+    hdr->len = rhs->len;

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * CSeq header.

+ */

+static int pjsip_cseq_hdr_print( pjsip_cseq_hdr *hdr, char *buf, pj_size_t size);

+static pjsip_cseq_hdr* pjsip_cseq_hdr_clone( pj_pool_t *pool, const pjsip_cseq_hdr *hdr);

+static pjsip_cseq_hdr* pjsip_cseq_hdr_shallow_clone( pj_pool_t *pool, const pjsip_cseq_hdr *hdr );

+

+static pjsip_hdr_vptr cseq_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_cseq_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_cseq_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_cseq_hdr_print,

+};

+

+PJ_DEF(pjsip_cseq_hdr*) pjsip_cseq_hdr_create( pj_pool_t *pool )

+{

+    pjsip_cseq_hdr *hdr = pj_pool_alloc(pool, sizeof(pjsip_cseq_hdr));

+    init_hdr(hdr, PJSIP_H_CSEQ, &cseq_hdr_vptr);

+    hdr->cseq = 0;

+    hdr->method.id = PJSIP_OTHER_METHOD;

+    hdr->method.name.ptr = NULL;

+    hdr->method.name.slen = 0;

+    return hdr;

+}

+

+static int pjsip_cseq_hdr_print( pjsip_cseq_hdr *hdr, char *buf, pj_size_t size)

+{

+    char *p = buf;

+    int len;

+

+    if ((pj_ssize_t)size < hdr->name.slen + hdr->method.name.slen + 15)

+	return -1;

+

+    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);

+    p += hdr->name.slen;

+    *p++ = ':';

+    *p++ = ' ';

+

+    len = pj_utoa(hdr->cseq, p);

+    p += len;

+    *p++ = ' ';

+

+    pj_memcpy(p, hdr->method.name.ptr, hdr->method.name.slen);

+    p += hdr->method.name.slen;

+

+    *p = '\0';

+

+    return p-buf;

+}

+

+static pjsip_cseq_hdr* pjsip_cseq_hdr_clone( pj_pool_t *pool, 

+					     const pjsip_cseq_hdr *rhs)

+{

+    pjsip_cseq_hdr *hdr = pjsip_cseq_hdr_create(pool);

+    hdr->cseq = rhs->cseq;

+    pjsip_method_copy(pool, &hdr->method, &rhs->method);

+    return hdr;

+}

+

+static pjsip_cseq_hdr* pjsip_cseq_hdr_shallow_clone( pj_pool_t *pool,

+						     const pjsip_cseq_hdr *rhs )

+{

+    pjsip_cseq_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Contact header.

+ */

+static int pjsip_contact_hdr_print( pjsip_contact_hdr *hdr, char *buf, pj_size_t size);

+static pjsip_contact_hdr* pjsip_contact_hdr_clone( pj_pool_t *pool, const pjsip_contact_hdr *hdr);

+static pjsip_contact_hdr* pjsip_contact_hdr_shallow_clone( pj_pool_t *pool, const pjsip_contact_hdr *);

+

+static pjsip_hdr_vptr contact_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_contact_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_contact_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_contact_hdr_print,

+};

+

+PJ_DEF(pjsip_contact_hdr*) pjsip_contact_hdr_create( pj_pool_t *pool )

+{

+    pjsip_contact_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_CONTACT, &contact_hdr_vptr);

+    hdr->expires = -1;

+    return hdr;

+}

+

+static int pjsip_contact_hdr_print( pjsip_contact_hdr *hdr, char *buf, 

+				    pj_size_t size)

+{

+    if (hdr->star) {

+	char *p = buf;

+	if ((pj_ssize_t)size < hdr->name.slen + 6)

+	    return -1;

+	pj_memcpy(p, hdr->name.ptr, hdr->name.slen);

+	p += hdr->name.slen;

+	*p++ = ':';

+	*p++ = ' ';

+	*p++ = '*';

+	*p = '\0';

+	return p - buf;

+

+    } else {

+	int printed;

+	char *startbuf = buf;

+	char *endbuf = buf + size;

+

+	copy_advance(buf, hdr->name);

+	*buf++ = ':';

+	*buf++ = ' ';

+

+	printed = pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, hdr->uri, 

+				  buf, endbuf-buf);

+	if (printed < 1)

+	    return -1;

+

+	buf += printed;

+

+	if (hdr->q1000) {

+	    if (buf+19 >= endbuf)

+		return -1;

+

+	    /*

+	    printed = sprintf(buf, ";q=%u.%03u",

+				   hdr->q1000/1000, hdr->q1000 % 1000);

+	     */

+	    pj_memcpy(buf, ";q=", 3);

+	    printed = pj_utoa(hdr->q1000/1000, buf+3);

+	    buf += printed + 3;

+	    *buf++ = '.';

+	    printed = pj_utoa(hdr->q1000 % 1000, buf);

+	    buf += printed;

+	}

+

+	if (hdr->expires >= 0) {

+	    if (buf+23 >= endbuf)

+		return -1;

+

+	    pj_memcpy(buf, ";expires=", 9);

+	    printed = pj_utoa(hdr->expires, buf+9);

+	    buf += printed + 9;

+	}

+

+	if (hdr->other_param.slen) {

+	    copy_advance(buf, hdr->other_param);

+	}

+

+	*buf = '\0';

+	return buf-startbuf;

+    }

+}

+

+static pjsip_contact_hdr* pjsip_contact_hdr_clone( pj_pool_t *pool, 

+					           const pjsip_contact_hdr *rhs)

+{

+    pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(pool);

+

+    hdr->star = rhs->star;

+    if (hdr->star)

+	return hdr;

+

+    hdr->uri = pjsip_uri_clone(pool, rhs->uri);

+    hdr->q1000 = rhs->q1000;

+    hdr->expires = rhs->expires;

+    pj_strdup(pool, &hdr->other_param, &rhs->other_param);

+    return hdr;

+}

+

+static pjsip_contact_hdr* pjsip_contact_hdr_shallow_clone( pj_pool_t *pool,

+							   const pjsip_contact_hdr *rhs)

+{

+    pjsip_contact_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Content-Type header..

+ */

+static int pjsip_ctype_hdr_print( pjsip_ctype_hdr *hdr, char *buf, pj_size_t size);

+static pjsip_ctype_hdr* pjsip_ctype_hdr_clone( pj_pool_t *pool, const pjsip_ctype_hdr *hdr);

+#define pjsip_ctype_hdr_shallow_clone pjsip_ctype_hdr_clone

+

+static pjsip_hdr_vptr ctype_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_ctype_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_ctype_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_ctype_hdr_print,

+};

+

+PJ_DEF(pjsip_ctype_hdr*) pjsip_ctype_hdr_create( pj_pool_t *pool )

+{

+    pjsip_ctype_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_CONTENT_TYPE, &ctype_hdr_vptr);

+    return hdr;

+}

+

+static int print_media_type(char *buf, const pjsip_media_type *media)

+{

+    char *p = buf;

+

+    pj_memcpy(p, media->type.ptr, media->type.slen);

+    p += media->type.slen;

+    *p++ = '/';

+    pj_memcpy(p, media->subtype.ptr, media->subtype.slen);

+    p += media->subtype.slen;

+

+    if (media->param.slen) {

+	pj_memcpy(p, media->param.ptr, media->param.slen);

+	p += media->param.slen;

+    }

+

+    return p-buf;

+}

+

+static int pjsip_ctype_hdr_print( pjsip_ctype_hdr *hdr, 

+				  char *buf, pj_size_t size)

+{

+    char *p = buf;

+    int len;

+

+    if ((pj_ssize_t)size < hdr->name.slen + 

+			   hdr->media.type.slen + hdr->media.subtype.slen + 

+			   hdr->media.param.slen + 8)

+    {

+	return -1;

+    }

+

+    pj_memcpy(p, hdr->name.ptr, hdr->name.slen);

+    p += hdr->name.slen;

+    *p++ = ':';

+    *p++ = ' ';

+

+    len = print_media_type(p, &hdr->media);

+    p += len;

+

+    *p = '\0';

+    return p-buf;

+}

+

+static pjsip_ctype_hdr* pjsip_ctype_hdr_clone( pj_pool_t *pool, 

+					       const pjsip_ctype_hdr *rhs)

+{

+    pjsip_ctype_hdr *hdr = pjsip_ctype_hdr_create(pool);

+    pj_strdup(pool, &hdr->media.type, &rhs->media.type);

+    pj_strdup(pool, &hdr->media.param, &rhs->media.param);

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Expires header.

+ */

+PJ_DEF(pjsip_expires_hdr*) pjsip_expires_hdr_create( pj_pool_t *pool )

+{

+    pjsip_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_EXPIRES, &generic_int_hdr_vptr);

+    hdr->ivalue = 0;

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * To or From header.

+ */

+static int pjsip_fromto_hdr_print( pjsip_fromto_hdr *hdr, 

+				   char *buf, pj_size_t size);

+static pjsip_fromto_hdr* pjsip_fromto_hdr_clone( pj_pool_t *pool, 

+					         const pjsip_fromto_hdr *hdr);

+static pjsip_fromto_hdr* pjsip_fromto_hdr_shallow_clone( pj_pool_t *pool,

+							 const pjsip_fromto_hdr *hdr);

+

+

+static pjsip_hdr_vptr fromto_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_fromto_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_fromto_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_fromto_hdr_print,

+};

+

+PJ_DEF(pjsip_from_hdr*) pjsip_from_hdr_create( pj_pool_t *pool )

+{

+    pjsip_from_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_FROM, &fromto_hdr_vptr);

+    return hdr;

+}

+

+PJ_DEF(pjsip_to_hdr*) pjsip_to_hdr_create( pj_pool_t *pool )

+{

+    pjsip_to_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_TO, &fromto_hdr_vptr);

+    return hdr;

+}

+

+PJ_DEF(pjsip_from_hdr*) pjsip_fromto_set_from( pjsip_fromto_hdr *hdr )

+{

+    hdr->type = PJSIP_H_FROM;

+    hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_FROM];

+    return hdr;

+}

+

+PJ_DEF(pjsip_to_hdr*) pjsip_fromto_set_to( pjsip_fromto_hdr *hdr )

+{

+    hdr->type = PJSIP_H_TO;

+    hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_TO];

+    return hdr;

+}

+

+static int pjsip_fromto_hdr_print( pjsip_fromto_hdr *hdr, 

+				   char *buf, pj_size_t size)

+{

+    int printed;

+    char *startbuf = buf;

+    char *endbuf = buf + size;

+

+    copy_advance(buf, hdr->name);

+    *buf++ = ':';

+    *buf++ = ' ';

+

+    printed = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, hdr->uri, buf, endbuf-buf);

+    if (printed < 1)

+	return -1;

+

+    buf += printed;

+

+    copy_advance_pair(buf, ";tag=", 5, hdr->tag);

+    if (hdr->other_param.slen)

+	copy_advance(buf, hdr->other_param);

+

+    return buf-startbuf;

+}

+

+static pjsip_fromto_hdr* pjsip_fromto_hdr_clone( pj_pool_t *pool, 

+					         const pjsip_fromto_hdr *rhs)

+{

+    pjsip_fromto_hdr *hdr = pjsip_from_hdr_create(pool);

+

+    hdr->type = rhs->type;

+    hdr->name = rhs->name;

+    hdr->sname = rhs->sname;

+    hdr->uri = pjsip_uri_clone(pool, rhs->uri);

+    pj_strdup( pool, &hdr->tag, &rhs->tag);

+    pj_strdup( pool, &hdr->other_param, &rhs->other_param);

+

+    return hdr;

+}

+

+static pjsip_fromto_hdr* pjsip_fromto_hdr_shallow_clone( pj_pool_t *pool,

+							 const pjsip_fromto_hdr *rhs)

+{

+    pjsip_fromto_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Max-Forwards header.

+ */

+PJ_DEF(pjsip_max_forwards_hdr*) pjsip_max_forwards_hdr_create(pj_pool_t *pool)

+{

+    pjsip_max_forwards_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_MAX_FORWARDS, &generic_int_hdr_vptr);

+    hdr->ivalue = 0;

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Min-Expires header.

+ */

+PJ_DECL(pjsip_min_expires_hdr*) pjsip_min_expires_hdr_create(pj_pool_t *pool)

+{

+    pjsip_min_expires_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_MIN_EXPIRES, &generic_int_hdr_vptr);

+    hdr->ivalue = 0;

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Record-Route and Route header.

+ */

+static int pjsip_routing_hdr_print( pjsip_routing_hdr *r, char *buf, pj_size_t size );

+static pjsip_routing_hdr* pjsip_routing_hdr_clone( pj_pool_t *pool, const pjsip_routing_hdr *r );

+static pjsip_routing_hdr* pjsip_routing_hdr_shallow_clone( pj_pool_t *pool, const pjsip_routing_hdr *r );

+

+static pjsip_hdr_vptr routing_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_routing_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_routing_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_routing_hdr_print,

+};

+

+PJ_DEF(pjsip_rr_hdr*) pjsip_rr_hdr_create( pj_pool_t *pool )

+{

+    pjsip_rr_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_RECORD_ROUTE, &routing_hdr_vptr);

+    pjsip_name_addr_init(&hdr->name_addr);

+    pj_memset(&hdr->other_param, 0, sizeof(hdr->other_param));

+    return hdr;

+}

+

+PJ_DEF(pjsip_route_hdr*) pjsip_route_hdr_create( pj_pool_t *pool )

+{

+    pjsip_route_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_ROUTE, &routing_hdr_vptr);

+    pjsip_name_addr_init(&hdr->name_addr);

+    pj_memset(&hdr->other_param, 0, sizeof(hdr->other_param));

+    return hdr;

+}

+

+PJ_DEF(pjsip_rr_hdr*) pjsip_routing_hdr_set_rr( pjsip_routing_hdr *hdr )

+{

+    hdr->type = PJSIP_H_RECORD_ROUTE;

+    hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_RECORD_ROUTE];

+    return hdr;

+}

+

+PJ_DEF(pjsip_route_hdr*) pjsip_routing_hdr_set_route( pjsip_routing_hdr *hdr )

+{

+    hdr->type = PJSIP_H_ROUTE;

+    hdr->name = hdr->sname = pjsip_hdr_names[PJSIP_H_ROUTE];

+    return hdr;

+}

+

+static int pjsip_routing_hdr_print( pjsip_routing_hdr *hdr,

+				    char *buf, pj_size_t size )

+{

+    int printed;

+    char *startbuf = buf;

+    char *endbuf = buf + size;

+

+    copy_advance(buf, hdr->name);

+    *buf++ = ':';

+    *buf++ = ' ';

+

+    printed = pjsip_uri_print(PJSIP_URI_IN_ROUTING_HDR, &hdr->name_addr, buf, endbuf-buf);

+    if (printed < 1)

+	return -1;

+    buf += printed;

+

+    if (hdr->other_param.slen) {

+	copy_advance(buf, hdr->other_param);

+    }

+

+    return buf-startbuf;

+}

+

+static pjsip_routing_hdr* pjsip_routing_hdr_clone( pj_pool_t *pool,

+						   const pjsip_routing_hdr *rhs )

+{

+    pjsip_routing_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+

+    init_hdr(hdr, rhs->type, rhs->vptr);

+    pjsip_name_addr_init(&hdr->name_addr);

+    pjsip_name_addr_assign(pool, &hdr->name_addr, &rhs->name_addr);

+    pj_strdup( pool, &hdr->other_param, &rhs->other_param);

+    return hdr;

+}

+

+static pjsip_routing_hdr* pjsip_routing_hdr_shallow_clone( pj_pool_t *pool,

+							   const pjsip_routing_hdr *rhs )

+{

+    pjsip_routing_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Require header.

+ */

+PJ_DEF(pjsip_require_hdr*) pjsip_require_hdr_create(pj_pool_t *pool)

+{

+    pjsip_require_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_REQUIRE, &generic_array_hdr_vptr);

+    hdr->count = 0;

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Retry-After header.

+ */

+PJ_DEF(pjsip_retry_after_hdr*) pjsip_retry_after_hdr_create(pj_pool_t *pool)

+{

+    pjsip_retry_after_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_RETRY_AFTER, &generic_int_hdr_vptr);

+    hdr->ivalue = 0;

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Supported header.

+ */

+PJ_DEF(pjsip_supported_hdr*) pjsip_supported_hdr_create(pj_pool_t *pool)

+{

+    pjsip_supported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_SUPPORTED, &generic_array_hdr_vptr);

+    hdr->count = 0;

+    return hdr;

+}

+

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Unsupported header.

+ */

+PJ_DEF(pjsip_unsupported_hdr*) pjsip_unsupported_hdr_create(pj_pool_t *pool)

+{

+    pjsip_unsupported_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_UNSUPPORTED, &generic_array_hdr_vptr);

+    hdr->count = 0;

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * Via header.

+ */

+static int pjsip_via_hdr_print( pjsip_via_hdr *hdr, char *buf, pj_size_t size);

+static pjsip_via_hdr* pjsip_via_hdr_clone( pj_pool_t *pool, const pjsip_via_hdr *hdr);

+static pjsip_via_hdr* pjsip_via_hdr_shallow_clone( pj_pool_t *pool, const pjsip_via_hdr *hdr );

+

+static pjsip_hdr_vptr via_hdr_vptr = 

+{

+    (pjsip_hdr_clone_fptr) &pjsip_via_hdr_clone,

+    (pjsip_hdr_clone_fptr) &pjsip_via_hdr_shallow_clone,

+    (pjsip_hdr_print_fptr) &pjsip_via_hdr_print,

+};

+

+PJ_DEF(pjsip_via_hdr*) pjsip_via_hdr_create( pj_pool_t *pool )

+{

+    pjsip_via_hdr *hdr = pj_pool_calloc(pool, 1, sizeof(*hdr));

+    init_hdr(hdr, PJSIP_H_VIA, &via_hdr_vptr);

+    hdr->sent_by.port = 5060;

+    hdr->ttl_param = -1;

+    hdr->rport_param = -1;

+    return hdr;

+}

+

+static int pjsip_via_hdr_print( pjsip_via_hdr *hdr, 

+				char *buf, pj_size_t size)

+{

+    int printed;

+    char *startbuf = buf;

+    char *endbuf = buf + size;

+    pj_str_t sip_ver = { "SIP/2.0/", 8 };

+

+    if ((pj_ssize_t)size < hdr->name.slen + sip_ver.slen + 

+			   hdr->transport.slen + hdr->sent_by.host.slen + 12)

+    {

+	return -1;

+    }

+

+    /* pjsip_hdr_names */

+    copy_advance(buf, hdr->name);

+    *buf++ = ':';

+    *buf++ = ' ';

+

+    /* SIP/2.0/transport host:port */

+    pj_memcpy(buf, sip_ver.ptr, sip_ver.slen);

+    buf += sip_ver.slen;

+    pj_memcpy(buf, hdr->transport.ptr, hdr->transport.slen);

+    buf += hdr->transport.slen;

+    *buf++ = ' ';

+    pj_memcpy(buf, hdr->sent_by.host.ptr, hdr->sent_by.host.slen);

+    buf += hdr->sent_by.host.slen;

+    *buf++ = ':';

+    printed = pj_utoa(hdr->sent_by.port, buf);

+    buf += printed;

+

+    if (hdr->ttl_param >= 0) {

+	size = endbuf-buf;

+	if (size < 14)

+	    return -1;

+	pj_memcpy(buf, ";ttl=", 5);

+	printed = pj_utoa(hdr->ttl_param, buf+5);

+	buf += printed + 5;

+    }

+

+    if (hdr->rport_param >= 0) {

+	size = endbuf-buf;

+	if (size < 14)

+	    return -1;

+	pj_memcpy(buf, ";rport", 6);

+	buf += 6;

+	if (hdr->rport_param > 0) {

+	    *buf++ = '=';

+	    buf += pj_utoa(hdr->rport_param, buf);

+	}

+    }

+

+

+    copy_advance_pair(buf, ";maddr=", 7, hdr->maddr_param);

+    copy_advance_pair(buf, ";received=", 10, hdr->recvd_param);

+    copy_advance_pair(buf, ";branch=", 8, hdr->branch_param);

+    copy_advance(buf, hdr->other_param);

+    

+    *buf = '\0';

+    return buf-startbuf;

+}

+

+static pjsip_via_hdr* pjsip_via_hdr_clone( pj_pool_t *pool, 

+					   const pjsip_via_hdr *rhs)

+{

+    pjsip_via_hdr *hdr = pjsip_via_hdr_create(pool);

+    pj_strdup(pool, &hdr->transport, &rhs->transport);

+    pj_strdup(pool, &hdr->sent_by.host, &rhs->sent_by.host);

+    hdr->sent_by.port = rhs->sent_by.port;

+    hdr->ttl_param = rhs->ttl_param;

+    hdr->rport_param = rhs->rport_param;

+    pj_strdup(pool, &hdr->maddr_param, &rhs->maddr_param);

+    pj_strdup(pool, &hdr->recvd_param, &rhs->recvd_param);

+    pj_strdup(pool, &hdr->branch_param, &rhs->branch_param);

+    pj_strdup(pool, &hdr->other_param, &rhs->other_param);

+    return hdr;

+}

+

+static pjsip_via_hdr* pjsip_via_hdr_shallow_clone( pj_pool_t *pool,

+						   const pjsip_via_hdr *rhs )

+{

+    pjsip_via_hdr *hdr = pj_pool_alloc(pool, sizeof(*hdr));

+    pj_memcpy(hdr, rhs, sizeof(*hdr));

+    return hdr;

+}

+

+///////////////////////////////////////////////////////////////////////////////

+/*

+ * General purpose function to textual data in a SIP body. 

+ */

+PJ_DEF(int) pjsip_print_text_body(pjsip_msg_body *msg_body, char *buf, pj_size_t size)

+{

+    if (size < msg_body->len)

+	return -1;

+    pj_memcpy(buf, msg_body->data, msg_body->len);

+    return msg_body->len;

+}

diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
index 63cc3b5..fc502e8 100644
--- a/pjsip/src/pjsip/sip_parser.c
+++ b/pjsip/src/pjsip/sip_parser.c
@@ -1,532 +1,554 @@
-/* $Id$
- */
-#include <pjsip/sip_parser.h>
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_msg.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_parser.h>

+#include <pjsip/sip_uri.h>

+#include <pjsip/sip_msg.h>

 #include <pjsip/sip_auth_parser.h>

 #include <pjsip/sip_errno.h>

-#include <pjsip/sip_transport.h>        /* rdata structure */
-#include <pjlib-util/scanner.h>
-#include <pj/except.h>
-#include <pj/log.h>
-#include <pj/hash.h>
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <pj/ctype.h>
+#include <pjsip/sip_transport.h>        /* rdata structure */

+#include <pjlib-util/scanner.h>

+#include <pj/except.h>

+#include <pj/log.h>

+#include <pj/hash.h>

+#include <pj/os.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <pj/ctype.h>

 #include <pj/assert.h>

-
-#define RESERVED    ";/?:@&=+$,"
-#define MARK	    "-_.!~*'()"
-#define ESCAPED	    "%"
-#define USER	    "&=+$,;?/"
-#define PASS	    "&=+$,"
+

+#define RESERVED    ";/?:@&=+$,"

+#define MARK	    "-_.!~*'()"

+#define ESCAPED	    "%"

+#define USER	    "&=+$,;?/"

+#define PASS	    "&=+$,"

 #define TOKEN	    "-.!%*_=`'~+"   /* '+' is because of application/pidf+xml

-                                     * in Content-Type! */
-#define HOST	    "_-."
-#define HEX_DIGIT   "abcdefABCDEF"
-#define PARAM_CHAR  "[]/:&+$" MARK "%"
-
-#define PJSIP_VERSION		"SIP/2.0"
-#define PJSIP_SYN_ERR_EXCEPTION	1
-
-#define UNREACHED(expr)
-
-typedef struct handler_rec
-{
-    char		  hname[PJSIP_MAX_HNAME_LEN+1];
-    pj_size_t		  hname_len;
-    pj_uint32_t		  hname_hash;
-    pjsip_parse_hdr_func *handler;
-} handler_rec;
-
-static handler_rec handler[127];
-static unsigned handler_count;
-static int parser_is_initialized;
-
-
-/*
- * Global vars (also extern).
- */
-const pj_str_t  pjsip_USER_STR      = { "user", 4};
-const pj_str_t  pjsip_METHOD_STR    = { "method", 6};
-const pj_str_t  pjsip_TRANSPORT_STR = { "transport", 9};
-const pj_str_t  pjsip_MADDR_STR     = { "maddr", 5 };
-const pj_str_t  pjsip_LR_STR        = { "lr", 2 };
-const pj_str_t  pjsip_SIP_STR       = { "sip", 3 };
-const pj_str_t  pjsip_SIPS_STR      = { "sips", 4 };
-const pj_str_t  pjsip_TEL_STR       = { "tel", 3 };
-const pj_str_t  pjsip_BRANCH_STR    = { "branch", 6 };
-const pj_str_t  pjsip_TTL_STR       = { "ttl", 3 };
-const pj_str_t  pjsip_PNAME_STR     = { "received", 8 };
-const pj_str_t  pjsip_Q_STR         = { "q", 1 };
-const pj_str_t  pjsip_EXPIRES_STR   = { "expires", 7 };
-const pj_str_t  pjsip_TAG_STR       = { "tag", 3 };
-const pj_str_t  pjsip_RPORT_STR     = { "rport", 5};
+                                     * in Content-Type! */

+#define HOST	    "_-."

+#define HEX_DIGIT   "abcdefABCDEF"

+#define PARAM_CHAR  "[]/:&+$" MARK "%"

+

+#define PJSIP_VERSION		"SIP/2.0"

+#define PJSIP_SYN_ERR_EXCEPTION	1

+

+#define UNREACHED(expr)

+

+typedef struct handler_rec

+{

+    char		  hname[PJSIP_MAX_HNAME_LEN+1];

+    pj_size_t		  hname_len;

+    pj_uint32_t		  hname_hash;

+    pjsip_parse_hdr_func *handler;

+} handler_rec;

+

+static handler_rec handler[127];

+static unsigned handler_count;

+static int parser_is_initialized;

+

+

+/*

+ * Global vars (also extern).

+ */

+const pj_str_t  pjsip_USER_STR      = { "user", 4};

+const pj_str_t  pjsip_METHOD_STR    = { "method", 6};

+const pj_str_t  pjsip_TRANSPORT_STR = { "transport", 9};

+const pj_str_t  pjsip_MADDR_STR     = { "maddr", 5 };

+const pj_str_t  pjsip_LR_STR        = { "lr", 2 };

+const pj_str_t  pjsip_SIP_STR       = { "sip", 3 };

+const pj_str_t  pjsip_SIPS_STR      = { "sips", 4 };

+const pj_str_t  pjsip_TEL_STR       = { "tel", 3 };

+const pj_str_t  pjsip_BRANCH_STR    = { "branch", 6 };

+const pj_str_t  pjsip_TTL_STR       = { "ttl", 3 };

+const pj_str_t  pjsip_PNAME_STR     = { "received", 8 };

+const pj_str_t  pjsip_Q_STR         = { "q", 1 };

+const pj_str_t  pjsip_EXPIRES_STR   = { "expires", 7 };

+const pj_str_t  pjsip_TAG_STR       = { "tag", 3 };

+const pj_str_t  pjsip_RPORT_STR     = { "rport", 5};

 

 /* Character Input Specification buffer. */

 static pj_cis_buf_t cis_buf;

 

-/* Character Input Specifications. */
-pj_cis_t    pjsip_HOST_SPEC,	        /* For scanning host part. */
-	    pjsip_DIGIT_SPEC,	        /* Decimal digits */
-	    pjsip_ALPHA_SPEC,	        /* Alpha (A-Z, a-z) */
-	    pjsip_ALNUM_SPEC,	        /* Decimal + Alpha. */
-	    pjsip_TOKEN_SPEC,	        /* Token. */
-	    pjsip_HEX_SPEC,	        /* Hexadecimal digits. */
+/* Character Input Specifications. */

+pj_cis_t    pjsip_HOST_SPEC,	        /* For scanning host part. */

+	    pjsip_DIGIT_SPEC,	        /* Decimal digits */

+	    pjsip_ALPHA_SPEC,	        /* Alpha (A-Z, a-z) */

+	    pjsip_ALNUM_SPEC,	        /* Decimal + Alpha. */

+	    pjsip_TOKEN_SPEC,	        /* Token. */

+	    pjsip_HEX_SPEC,	        /* Hexadecimal digits. */

 	    pjsip_PARAM_CHAR_SPEC,      /* For scanning pname (or pvalue when

-                                         * it's not quoted.) */
-	    pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */
-	    pjsip_PASSWD_SPEC,	        /* Password. */
-	    pjsip_USER_SPEC,	        /* User */
-	    pjsip_ARRAY_ELEMENTS,       /* Array separator. */
-	    pjsip_NEWLINE_OR_EOF_SPEC,  /* For eating up header.*/
+                                         * it's not quoted.) */

+	    pjsip_PROBE_USER_HOST_SPEC, /* Hostname characters. */

+	    pjsip_PASSWD_SPEC,	        /* Password. */

+	    pjsip_USER_SPEC,	        /* User */

+	    pjsip_ARRAY_ELEMENTS,       /* Array separator. */

+	    pjsip_NEWLINE_OR_EOF_SPEC,  /* For eating up header.*/

 	    pjsip_DISPLAY_SCAN_SPEC;    /* Used when searching for display name

-                                         * in URL. */
-
-
-/*
- * Forward decl.
- */
-static pjsip_msg *  int_parse_msg( pjsip_parse_ctx *ctx, 
-				   pjsip_parser_err_report *err_list);
-static void	    int_parse_param( pj_scanner *scanner, 
-				     pj_str_t *pname, 
-				     pj_str_t *pvalue);
-static void         int_parse_req_line( pj_scanner *scanner, 
-					pj_pool_t *pool,
-					pjsip_request_line *req_line);
-static int          int_is_next_user( pj_scanner *scanner);
-static void	    int_parse_status_line( pj_scanner *scanner, 
-					   pjsip_status_line *line);
-static void	    int_parse_user_pass( pj_scanner *scanner, 
-					 pj_str_t *user, 
-					 pj_str_t *pass);
-static void	    int_parse_uri_host_port( pj_scanner *scanner, 
-					     pj_str_t *p_host, 
-					     int *p_port);
-static pjsip_uri *  int_parse_uri_or_name_addr( pj_scanner *scanner, 
-					        pj_pool_t *pool, 

-                                                unsigned option);
-static pjsip_url *  int_parse_sip_url( pj_scanner *scanner, 
-				       pj_pool_t *pool,
-				       pj_bool_t parse_params);
-static pjsip_name_addr *

-                    int_parse_name_addr( pj_scanner *scanner, 
-					 pj_pool_t *pool );
-static void	    parse_hdr_end( pj_scanner *scanner );

-
-static pjsip_hdr*   parse_hdr_accept( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_allow( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_call_id( pjsip_parse_ctx *ctx);
-static pjsip_hdr*   parse_hdr_contact( pjsip_parse_ctx *ctx);
-static pjsip_hdr*   parse_hdr_content_len( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_content_type( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_cseq( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_expires( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_from( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_max_forwards( pjsip_parse_ctx *ctx);
-static pjsip_hdr*   parse_hdr_min_expires( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_rr( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_route( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_require( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_retry_after( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_supported( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_to( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_unsupported( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_via( pjsip_parse_ctx *ctx );
-static pjsip_hdr*   parse_hdr_generic_string( pjsip_parse_ctx *ctx);
-
-/* Convert non NULL terminated string to integer. */
-static unsigned long pj_strtoul_mindigit(const pj_str_t *str, 

-                                         unsigned mindig)
-{
-    unsigned long value;
-    unsigned i;
-
-    value = 0;
-    for (i=0; i<(unsigned)str->slen; ++i) {
-	value = value * 10 + (str->ptr[i] - '0');
-    }
-    for (; i<mindig; ++i) {
-	value = value * 10;
-    }
-    return value;
-}
-
-/* Case insensitive comparison */
-#define parser_stricmp(str1, str2)  pj_stricmp(&str1, &str2)
-
-
-/* Syntax error handler for parser. */
-static void on_syntax_error(pj_scanner *scanner)
-{
-    PJ_UNUSED_ARG(scanner);
-    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-}
-
-/* Concatenate unrecognized params into single string. */
-void pjsip_concat_param_imp( pj_str_t *param, pj_pool_t *pool, 
-			     const pj_str_t *pname, const pj_str_t *pvalue, 

-                             int sepchar)
-{
-    char *new_param, *p;
-    int len;
-
-    len = param->slen + pname->slen + pvalue->slen + 3;
-    p = new_param = pj_pool_alloc(pool, len);
-    
-    if (param->slen) {
-	int old_len = param->slen;
-	pj_memcpy(p, param->ptr, old_len);
-	p += old_len;
-    }
-    *p++ = (char)sepchar;
-    pj_memcpy(p, pname->ptr, pname->slen);
-    p += pname->slen;
-
-    if (pvalue->slen) {
-	*p++ = '=';
-	pj_memcpy(p, pvalue->ptr, pvalue->slen);
-	p += pvalue->slen;
-    }
-
-    *p = '\0';
-    
-    param->ptr = new_param;
-    param->slen = p - new_param;
-}
-
-/* Concatenate unrecognized params into single string. */
-static void concat_param( pj_str_t *param, pj_pool_t *pool, 
-			  const pj_str_t *pname, const pj_str_t *pvalue )
-{
-    pjsip_concat_param_imp(param, pool, pname, pvalue, ';');
-}
-
-/* Initialize static properties of the parser. */
-static pj_status_t init_parser()
-{
-    static int initialized;

-    pj_status_t status;
+                                         * in URL. */

 

-    if (initialized)
-	return PJ_SUCCESS;
-
-    initialized = 1;
+

+/*

+ * Forward decl.

+ */

+static pjsip_msg *  int_parse_msg( pjsip_parse_ctx *ctx, 

+				   pjsip_parser_err_report *err_list);

+static void	    int_parse_param( pj_scanner *scanner, 

+				     pj_str_t *pname, 

+				     pj_str_t *pvalue);

+static void         int_parse_req_line( pj_scanner *scanner, 

+					pj_pool_t *pool,

+					pjsip_request_line *req_line);

+static int          int_is_next_user( pj_scanner *scanner);

+static void	    int_parse_status_line( pj_scanner *scanner, 

+					   pjsip_status_line *line);

+static void	    int_parse_user_pass( pj_scanner *scanner, 

+					 pj_str_t *user, 

+					 pj_str_t *pass);

+static void	    int_parse_uri_host_port( pj_scanner *scanner, 

+					     pj_str_t *p_host, 

+					     int *p_port);

+static pjsip_uri *  int_parse_uri_or_name_addr( pj_scanner *scanner, 

+					        pj_pool_t *pool, 

+                                                unsigned option);

+static pjsip_url *  int_parse_sip_url( pj_scanner *scanner, 

+				       pj_pool_t *pool,

+				       pj_bool_t parse_params);

+static pjsip_name_addr *

+                    int_parse_name_addr( pj_scanner *scanner, 

+					 pj_pool_t *pool );

+static void	    parse_hdr_end( pj_scanner *scanner );

+

+static pjsip_hdr*   parse_hdr_accept( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_allow( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_call_id( pjsip_parse_ctx *ctx);

+static pjsip_hdr*   parse_hdr_contact( pjsip_parse_ctx *ctx);

+static pjsip_hdr*   parse_hdr_content_len( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_content_type( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_cseq( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_expires( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_from( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_max_forwards( pjsip_parse_ctx *ctx);

+static pjsip_hdr*   parse_hdr_min_expires( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_rr( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_route( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_require( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_retry_after( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_supported( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_to( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_unsupported( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_via( pjsip_parse_ctx *ctx );

+static pjsip_hdr*   parse_hdr_generic_string( pjsip_parse_ctx *ctx);

+

+/* Convert non NULL terminated string to integer. */

+static unsigned long pj_strtoul_mindigit(const pj_str_t *str, 

+                                         unsigned mindig)

+{

+    unsigned long value;

+    unsigned i;

+

+    value = 0;

+    for (i=0; i<(unsigned)str->slen; ++i) {

+	value = value * 10 + (str->ptr[i] - '0');

+    }

+    for (; i<mindig; ++i) {

+	value = value * 10;

+    }

+    return value;

+}

+

+/* Case insensitive comparison */

+#define parser_stricmp(str1, str2)  pj_stricmp(&str1, &str2)

+

+

+/* Syntax error handler for parser. */

+static void on_syntax_error(pj_scanner *scanner)

+{

+    PJ_UNUSED_ARG(scanner);

+    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+}

+

+/* Concatenate unrecognized params into single string. */

+void pjsip_concat_param_imp( pj_str_t *param, pj_pool_t *pool, 

+			     const pj_str_t *pname, const pj_str_t *pvalue, 

+                             int sepchar)

+{

+    char *new_param, *p;

+    int len;

+

+    len = param->slen + pname->slen + pvalue->slen + 3;

+    p = new_param = pj_pool_alloc(pool, len);

+    

+    if (param->slen) {

+	int old_len = param->slen;

+	pj_memcpy(p, param->ptr, old_len);

+	p += old_len;

+    }

+    *p++ = (char)sepchar;

+    pj_memcpy(p, pname->ptr, pname->slen);

+    p += pname->slen;

+

+    if (pvalue->slen) {

+	*p++ = '=';

+	pj_memcpy(p, pvalue->ptr, pvalue->slen);

+	p += pvalue->slen;

+    }

+

+    *p = '\0';

+    

+    param->ptr = new_param;

+    param->slen = p - new_param;

+}

+

+/* Concatenate unrecognized params into single string. */

+static void concat_param( pj_str_t *param, pj_pool_t *pool, 

+			  const pj_str_t *pname, const pj_str_t *pvalue )

+{

+    pjsip_concat_param_imp(param, pool, pname, pvalue, ';');

+}

+

+/* Initialize static properties of the parser. */

+static pj_status_t init_parser()

+{

+    static int initialized;

+    pj_status_t status;

+

+    if (initialized)

+	return PJ_SUCCESS;

+

+    initialized = 1;

 

     pj_cis_buf_init(&cis_buf);

 

     status = pj_cis_init(&cis_buf, &pjsip_DIGIT_SPEC);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-    pj_cis_add_num(&pjsip_DIGIT_SPEC);
+    pj_cis_add_num(&pjsip_DIGIT_SPEC);

     

     status = pj_cis_init(&cis_buf, &pjsip_ALPHA_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_alpha( &pjsip_ALPHA_SPEC );
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_alpha( &pjsip_ALPHA_SPEC );

     

     status = pj_cis_init(&cis_buf, &pjsip_ALNUM_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_alpha( &pjsip_ALNUM_SPEC );
-    pj_cis_add_num( &pjsip_ALNUM_SPEC );
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_alpha( &pjsip_ALNUM_SPEC );

+    pj_cis_add_num( &pjsip_ALNUM_SPEC );

 

     status = pj_cis_init(&cis_buf, &pjsip_NEWLINE_OR_EOF_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str(&pjsip_NEWLINE_OR_EOF_SPEC, "\r\n");
-    //pj_cs_set(pjsip_NEWLINE_OR_EOF_SPEC, 0);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str(&pjsip_NEWLINE_OR_EOF_SPEC, "\r\n");

+    //pj_cs_set(pjsip_NEWLINE_OR_EOF_SPEC, 0);

 

     status = pj_cis_init(&cis_buf, &pjsip_ARRAY_ELEMENTS);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str( &pjsip_ARRAY_ELEMENTS, ",\r\n");
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str( &pjsip_ARRAY_ELEMENTS, ",\r\n");

 

     status = pj_cis_dup(&pjsip_TOKEN_SPEC, &pjsip_ALNUM_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str( &pjsip_TOKEN_SPEC, TOKEN);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str( &pjsip_TOKEN_SPEC, TOKEN);

 

     status = pj_cis_dup(&pjsip_HOST_SPEC, &pjsip_ALNUM_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str( &pjsip_HOST_SPEC, HOST);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str( &pjsip_HOST_SPEC, HOST);

 

     status = pj_cis_dup(&pjsip_HEX_SPEC, &pjsip_DIGIT_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str( &pjsip_HEX_SPEC, HEX_DIGIT);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str( &pjsip_HEX_SPEC, HEX_DIGIT);

 

     status = pj_cis_dup(&pjsip_PARAM_CHAR_SPEC, &pjsip_ALNUM_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str(&pjsip_PARAM_CHAR_SPEC, PARAM_CHAR);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str(&pjsip_PARAM_CHAR_SPEC, PARAM_CHAR);

 

     status = pj_cis_dup(&pjsip_USER_SPEC, &pjsip_ALNUM_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str( &pjsip_USER_SPEC, MARK ESCAPED USER );
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str( &pjsip_USER_SPEC, MARK ESCAPED USER );

 

     status = pj_cis_dup(&pjsip_PASSWD_SPEC, &pjsip_ALNUM_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str( &pjsip_PASSWD_SPEC, MARK ESCAPED PASS);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str( &pjsip_PASSWD_SPEC, MARK ESCAPED PASS);

 

     status = pj_cis_init(&cis_buf, &pjsip_PROBE_USER_HOST_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str( &pjsip_PROBE_USER_HOST_SPEC, "@ \n>");
-    pj_cis_invert( &pjsip_PROBE_USER_HOST_SPEC );
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str( &pjsip_PROBE_USER_HOST_SPEC, "@ \n>");

+    pj_cis_invert( &pjsip_PROBE_USER_HOST_SPEC );

 

     status = pj_cis_init(&cis_buf, &pjsip_DISPLAY_SCAN_SPEC);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-    pj_cis_add_str( &pjsip_DISPLAY_SCAN_SPEC, ":\r\n<");
-
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+    pj_cis_add_str( &pjsip_DISPLAY_SCAN_SPEC, ":\r\n<");

+

     status = pjsip_register_hdr_parser( "Accept", NULL, &parse_hdr_accept);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Allow", NULL, &parse_hdr_allow);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Call-ID", NULL, &parse_hdr_call_id);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Contact", "m", &parse_hdr_contact);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Content-Length", NULL, 

                                         &parse_hdr_content_len);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Content-Type", NULL, 

                                         &parse_hdr_content_type);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "CSeq", NULL, &parse_hdr_cseq);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Expires", NULL, &parse_hdr_expires);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "From", "f", &parse_hdr_from);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Max-Forwards", NULL, 

                                         &parse_hdr_max_forwards);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Min-Expires", NULL, 

                                         &parse_hdr_min_expires);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Record-Route", NULL, &parse_hdr_rr);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Route", NULL, &parse_hdr_route);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Require", NULL, &parse_hdr_require);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Retry-After", NULL, 

                                         &parse_hdr_retry_after);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Supported", "k", 

                                         &parse_hdr_supported);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "To", "t", &parse_hdr_to);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
+

     status = pjsip_register_hdr_parser( "Unsupported", NULL, 

                                         &parse_hdr_unsupported);

     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

-
-    status = pjsip_register_hdr_parser( "Via", NULL, &parse_hdr_via);

-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-
-    /* Register auth parser. */
-    status = pjsip_auth_init_parser();
 

-    return status;
-}
-
-static void init_sip_parser(void)
-{
-    if (!parser_is_initialized) {
-	/* Prevent race cond. */
-	pj_enter_critical_section();
-	if (!parser_is_initialized) {
-	    init_parser();
-	    parser_is_initialized = 1;
-	}
-	pj_leave_critical_section();
-    }
-}
-
-/* Compare the handler record with header name, and return:
- * - 0  if handler match.
- * - <0 if handler is 'less' than the header name.
- * - >0 if handler is 'greater' than header name.
- */
-static int compare_handler( const handler_rec *r1, 
-			    const char *name, 
-			    pj_size_t name_len,
-			    pj_uint32_t hash )
-{
-    /* Compare length. */
-    if (r1->hname_len < name_len)
-	return -1;
-    if (r1->hname_len > name_len)
-	return 1;
-
-    /* Length is equal, compare hashed value. */
-    if (r1->hname_hash < hash)
-	return -1;
-    if (r1->hname_hash > hash)
-	return 1;
-
-    /* Equal length and equal hash. compare the strings. */
-    return pj_native_strcmp(r1->hname, name);
-}
-
-/* Register one handler for one header name. */
+    status = pjsip_register_hdr_parser( "Via", NULL, &parse_hdr_via);

+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);

+

+    /* Register auth parser. */

+    status = pjsip_auth_init_parser();

+

+    return status;

+}

+

+static void init_sip_parser(void)

+{

+    if (!parser_is_initialized) {

+	/* Prevent race cond. */

+	pj_enter_critical_section();

+	if (!parser_is_initialized) {

+	    init_parser();

+	    parser_is_initialized = 1;

+	}

+	pj_leave_critical_section();

+    }

+}

+

+/* Compare the handler record with header name, and return:

+ * - 0  if handler match.

+ * - <0 if handler is 'less' than the header name.

+ * - >0 if handler is 'greater' than header name.

+ */

+static int compare_handler( const handler_rec *r1, 

+			    const char *name, 

+			    pj_size_t name_len,

+			    pj_uint32_t hash )

+{

+    /* Compare length. */

+    if (r1->hname_len < name_len)

+	return -1;

+    if (r1->hname_len > name_len)

+	return 1;

+

+    /* Length is equal, compare hashed value. */

+    if (r1->hname_hash < hash)

+	return -1;

+    if (r1->hname_hash > hash)

+	return 1;

+

+    /* Equal length and equal hash. compare the strings. */

+    return pj_native_strcmp(r1->hname, name);

+}

+

+/* Register one handler for one header name. */

 static pj_status_t int_register_parser( const char *name, 

-                                        pjsip_parse_hdr_func *fptr )
-{
-    unsigned	pos;
-    handler_rec rec;
-    unsigned	i;
-
-    if (handler_count >= PJ_ARRAY_SIZE(handler)) {
-	return PJ_ETOOMANY;
-    }
-
-    /* Initialize temporary handler. */
-    rec.handler = fptr;
-    rec.hname_len = strlen(name);
-    if (rec.hname_len >= sizeof(rec.hname)) {
-	return PJ_ENAMETOOLONG;
-    }
-    /* Name is copied in lowercase. */
-    for (i=0; i<rec.hname_len; ++i) {
-	rec.hname[i] = (char)pj_tolower(name[i]);
-    }
-    rec.hname[i] = '\0';
-    /* Hash value is calculated from the lowercase name. */
-    rec.hname_hash = pj_hash_calc(0, rec.hname, PJ_HASH_KEY_STRING);
-
-    /* Get the pos to insert the new handler. */
-    for (pos=0; pos < handler_count; ++pos) {
-	int d;
+                                        pjsip_parse_hdr_func *fptr )

+{

+    unsigned	pos;

+    handler_rec rec;

+    unsigned	i;

+

+    if (handler_count >= PJ_ARRAY_SIZE(handler)) {

+	return PJ_ETOOMANY;

+    }

+

+    /* Initialize temporary handler. */

+    rec.handler = fptr;

+    rec.hname_len = strlen(name);

+    if (rec.hname_len >= sizeof(rec.hname)) {

+	return PJ_ENAMETOOLONG;

+    }

+    /* Name is copied in lowercase. */

+    for (i=0; i<rec.hname_len; ++i) {

+	rec.hname[i] = (char)pj_tolower(name[i]);

+    }

+    rec.hname[i] = '\0';

+    /* Hash value is calculated from the lowercase name. */

+    rec.hname_hash = pj_hash_calc(0, rec.hname, PJ_HASH_KEY_STRING);

+

+    /* Get the pos to insert the new handler. */

+    for (pos=0; pos < handler_count; ++pos) {

+	int d;

 	d = compare_handler(&handler[pos], rec.hname, rec.hname_len, 

-                            rec.hname_hash);
-	if (d == 0) {
-	    pj_assert(0);
-	    return PJ_EEXISTS;
-	}
-	if (d > 0) {
-	    break;
-	}
-    }
-
-    /* Shift handlers. */
-    if (pos != handler_count) {
+                            rec.hname_hash);

+	if (d == 0) {

+	    pj_assert(0);

+	    return PJ_EEXISTS;

+	}

+	if (d > 0) {

+	    break;

+	}

+    }

+

+    /* Shift handlers. */

+    if (pos != handler_count) {

 	pj_memmove( &handler[pos+1], &handler[pos], 

-                    (handler_count-pos)*sizeof(handler_rec));
-    }
-    /* Add new handler. */
-    pj_memcpy( &handler[pos], &rec, sizeof(handler_rec));
-    ++handler_count;
-
-    return PJ_SUCCESS;
-}
-
-/* Register parser handler. If both header name and short name are valid,
- * then two instances of handler will be registered.
- */
-PJ_DEF(pj_status_t) pjsip_register_hdr_parser( const char *hname,
-					       const char *hshortname,
-					       pjsip_parse_hdr_func *fptr)
+                    (handler_count-pos)*sizeof(handler_rec));

+    }

+    /* Add new handler. */

+    pj_memcpy( &handler[pos], &rec, sizeof(handler_rec));

+    ++handler_count;

+

+    return PJ_SUCCESS;

+}

+

+/* Register parser handler. If both header name and short name are valid,

+ * then two instances of handler will be registered.

+ */

+PJ_DEF(pj_status_t) pjsip_register_hdr_parser( const char *hname,

+					       const char *hshortname,

+					       pjsip_parse_hdr_func *fptr)

 {

     pj_status_t status;

 

-    status = int_register_parser(hname, fptr);
-    if (status != PJ_SUCCESS) {
-	return status;
-    }
+    status = int_register_parser(hname, fptr);

+    if (status != PJ_SUCCESS) {

+	return status;

+    }

     if (hshortname) {

         status = int_register_parser(hshortname, fptr);

-        if (status != PJ_SUCCESS) 
-	    return status;
-    }
-    return PJ_SUCCESS;
-}
-
-/* Find handler to parse the header name. */
-static pjsip_parse_hdr_func * find_handler(const pj_str_t *hname)
-{
-    handler_rec *first;
-    char	 hname_copy[PJSIP_MAX_HNAME_LEN];
-    pj_uint32_t  hash;
-    int		 comp;
-    unsigned	 n;
+        if (status != PJ_SUCCESS) 

+	    return status;

+    }

+    return PJ_SUCCESS;

+}

+

+/* Find handler to parse the header name. */

+static pjsip_parse_hdr_func * find_handler(const pj_str_t *hname)

+{

+    handler_rec *first;

+    char	 hname_copy[PJSIP_MAX_HNAME_LEN];

+    pj_uint32_t  hash;

+    int		 comp;

+    unsigned	 n;

 

     if (hname->slen >= PJSIP_MAX_HNAME_LEN) {

         pj_assert(!"Header name is too long!");

         return NULL;

     }

-
-    /* Calculate hash value while converting the header to lowercase. 
-     * Don't assume that 'hname' is NULL terminated.
-     */
+

+    /* Calculate hash value while converting the header to lowercase. 

+     * Don't assume that 'hname' is NULL terminated.

+     */

     hash = pj_hash_calc_tolower(0, hname_copy, hname);

-    hname_copy[hname->slen] = '\0';
-
-    /* Binary search for the handler. */
-    comp = -1;
-    first = &handler[0];
-    n = handler_count;
-    for (; n > 0; ) {
-	unsigned half = n / 2;
-	handler_rec *mid = first + half;
-
-	comp = compare_handler(mid, hname_copy, hname->slen, hash);
-	if (comp < 0) {
-	    first = ++mid;
-	    n -= half + 1;
-	} else if (comp==0) {
-	    first = mid;
-	    break;
-	} else {
-	    n = half;
-	}
-    }
-
-    return comp==0 ? first->handler : NULL;
-}
-
-/* Public function to parse SIP message. */
+    hname_copy[hname->slen] = '\0';

+

+    /* Binary search for the handler. */

+    comp = -1;

+    first = &handler[0];

+    n = handler_count;

+    for (; n > 0; ) {

+	unsigned half = n / 2;

+	handler_rec *mid = first + half;

+

+	comp = compare_handler(mid, hname_copy, hname->slen, hash);

+	if (comp < 0) {

+	    first = ++mid;

+	    n -= half + 1;

+	} else if (comp==0) {

+	    first = mid;

+	    break;

+	} else {

+	    n = half;

+	}

+    }

+

+    return comp==0 ? first->handler : NULL;

+}

+

+/* Public function to parse SIP message. */

 PJ_DEF(pjsip_msg*) pjsip_parse_msg( pj_pool_t *pool, 

-                                    char *buf, pj_size_t size,
-				    pjsip_parser_err_report *err_list)
-{
-    pjsip_msg *msg = NULL;
+                                    char *buf, pj_size_t size,

+				    pjsip_parser_err_report *err_list)

+{

+    pjsip_msg *msg = NULL;

     pj_scanner scanner;

-    pjsip_parse_ctx context;
-    PJ_USE_EXCEPTION;
-
-    init_sip_parser();
-
+    pjsip_parse_ctx context;

+    PJ_USE_EXCEPTION;

+

+    init_sip_parser();

+

     pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER, 

-                 &on_syntax_error);
+                 &on_syntax_error);

 

     context.scanner = &scanner;

     context.pool = pool;

     context.rdata = NULL;

-
-    PJ_TRY {
-	msg = int_parse_msg(&context, err_list);
-    } 
-    PJ_DEFAULT {
-	msg = NULL;
-    }
-    PJ_END
-
-    pj_scan_fini(&scanner);
-    return msg;
-}
+

+    PJ_TRY {

+	msg = int_parse_msg(&context, err_list);

+    } 

+    PJ_DEFAULT {

+	msg = NULL;

+    }

+    PJ_END

+

+    pj_scan_fini(&scanner);

+    return msg;

+}

 

 /* Public function to parse as rdata.*/

 PJ_DEF(pjsip_msg *) pjsip_parse_rdata( char *buf, pj_size_t size,

@@ -556,1151 +578,1151 @@
     pj_scan_fini(&scanner);

     return rdata->msg;

 }

-
-/* Determine if a message has been received. */
-PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, 
-				  pj_bool_t is_datagram, pj_size_t *msg_size)
-{
-#if PJ_HAS_TCP
-    const char *hdr_end;
-    const char *body_start;
-    const char *pos;
-    const char *line;
-    int content_length = -1;
-
-    *msg_size = size;
-
-    /* For datagram, the whole datagram IS the message. */
-    if (is_datagram) {
-	return PJ_SUCCESS;
-    }
-
-
-    /* Find the end of header area by finding an empty line. */
-    if ((pos = pj_native_strstr(buf, "\n\r\n")) == NULL) {
-	return PJSIP_EPARTIALMSG;
-    }
-
-    hdr_end = pos+1;
-    body_start = pos+3;
-
-    /* Find "Content-Length" header the hard way. */
-    line = pj_native_strchr(buf, '\n');
-    while (line && line < hdr_end-14) {
-	++line;
+

+/* Determine if a message has been received. */

+PJ_DEF(pj_bool_t) pjsip_find_msg( const char *buf, pj_size_t size, 

+				  pj_bool_t is_datagram, pj_size_t *msg_size)

+{

+#if PJ_HAS_TCP

+    const char *hdr_end;

+    const char *body_start;

+    const char *pos;

+    const char *line;

+    int content_length = -1;

+

+    *msg_size = size;

+

+    /* For datagram, the whole datagram IS the message. */

+    if (is_datagram) {

+	return PJ_SUCCESS;

+    }

+

+

+    /* Find the end of header area by finding an empty line. */

+    if ((pos = pj_native_strstr(buf, "\n\r\n")) == NULL) {

+	return PJSIP_EPARTIALMSG;

+    }

+

+    hdr_end = pos+1;

+    body_start = pos+3;

+

+    /* Find "Content-Length" header the hard way. */

+    line = pj_native_strchr(buf, '\n');

+    while (line && line < hdr_end-14) {

+	++line;

 	if ( ((*line=='C' || *line=='c') && 

-              pj_native_strncasecmp(line, "Content-Length", 14) == 0) ||
+              pj_native_strncasecmp(line, "Content-Length", 14) == 0) ||

 	     ((*line=='l' || *line=='L') && 

-              (*(line+1)==' ' || *(line+1)=='\t' || *(line+1)==':')))
-	{
-	    /* Try to parse the header. */
-	    pj_scanner scanner;
-	    PJ_USE_EXCEPTION;
-
-	    init_sip_parser();
-
-	    pj_scan_init(&scanner, (char*)line, hdr_end-line, 
-			 PJ_SCAN_AUTOSKIP_WS_HEADER, &on_syntax_error);
-
-	    PJ_TRY {
-		pj_str_t str_clen;
-
-		/* Get "Content-Length" or "L" name */
-		if (*line=='C' || *line=='c')
-		    pj_scan_advance_n(&scanner, 14, PJ_TRUE);
-		else if (*line=='l' || *line=='L')
-		    pj_scan_advance_n(&scanner, 1, PJ_TRUE);
-
-		/* Get colon */
-		if (pj_scan_get_char(&scanner) != ':') {
-		    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-		}
-
-		/* Get number */
-		pj_scan_get(&scanner, &pjsip_DIGIT_SPEC, &str_clen);
-
-		/* Get newline. */
-		pj_scan_get_newline(&scanner);
-
-		/* Found a valid Content-Length header. */
-		content_length = pj_strtoul(&str_clen);
-	    } 
-	    PJ_END
-
-	    pj_scan_fini(&scanner);
-	}
-
-	/* Found valid Content-Length? */
-	if (content_length != -1)
-	    break;
-
-	/* Go to next line. */
-	line = pj_native_strchr(line, '\n');
-    }
-
-    /* Found Content-Length? */
-    if (content_length == -1) {
-	return PJSIP_EMISSINGHDR;
-    }
-
-    /* Enough packet received? */
-    *msg_size = (body_start - buf) + content_length;
-    return (*msg_size) <= size ? PJ_SUCCESS : PJSIP_EPARTIALMSG;
-#else
-    PJ_UNUSED_ARG(buf);
-    PJ_UNUSED_ARG(is_datagram);
-    *msg_size = size;
-    return PJ_SUCCESS;
-#endif
-}
-
-/* Public function to parse URI */
-PJ_DEF(pjsip_uri*) pjsip_parse_uri( pj_pool_t *pool, 
-					 char *buf, pj_size_t size,
-					 unsigned option)
-{
-    PJ_USE_EXCEPTION;
-    pj_scanner scanner;
-    pjsip_uri *uri = NULL;
-
-    init_sip_parser();
-
-    pj_scan_init(&scanner, buf, size, 0, &on_syntax_error);
-
-    
-    PJ_TRY {
-	uri = int_parse_uri_or_name_addr(&scanner, pool, option);
-    }
-    PJ_END;
-
-    /* Must have exhausted all inputs. */
+              (*(line+1)==' ' || *(line+1)=='\t' || *(line+1)==':')))

+	{

+	    /* Try to parse the header. */

+	    pj_scanner scanner;

+	    PJ_USE_EXCEPTION;

+

+	    init_sip_parser();

+

+	    pj_scan_init(&scanner, (char*)line, hdr_end-line, 

+			 PJ_SCAN_AUTOSKIP_WS_HEADER, &on_syntax_error);

+

+	    PJ_TRY {

+		pj_str_t str_clen;

+

+		/* Get "Content-Length" or "L" name */

+		if (*line=='C' || *line=='c')

+		    pj_scan_advance_n(&scanner, 14, PJ_TRUE);

+		else if (*line=='l' || *line=='L')

+		    pj_scan_advance_n(&scanner, 1, PJ_TRUE);

+

+		/* Get colon */

+		if (pj_scan_get_char(&scanner) != ':') {

+		    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+		}

+

+		/* Get number */

+		pj_scan_get(&scanner, &pjsip_DIGIT_SPEC, &str_clen);

+

+		/* Get newline. */

+		pj_scan_get_newline(&scanner);

+

+		/* Found a valid Content-Length header. */

+		content_length = pj_strtoul(&str_clen);

+	    } 

+	    PJ_END

+

+	    pj_scan_fini(&scanner);

+	}

+

+	/* Found valid Content-Length? */

+	if (content_length != -1)

+	    break;

+

+	/* Go to next line. */

+	line = pj_native_strchr(line, '\n');

+    }

+

+    /* Found Content-Length? */

+    if (content_length == -1) {

+	return PJSIP_EMISSINGHDR;

+    }

+

+    /* Enough packet received? */

+    *msg_size = (body_start - buf) + content_length;

+    return (*msg_size) <= size ? PJ_SUCCESS : PJSIP_EPARTIALMSG;

+#else

+    PJ_UNUSED_ARG(buf);

+    PJ_UNUSED_ARG(is_datagram);

+    *msg_size = size;

+    return PJ_SUCCESS;

+#endif

+}

+

+/* Public function to parse URI */

+PJ_DEF(pjsip_uri*) pjsip_parse_uri( pj_pool_t *pool, 

+					 char *buf, pj_size_t size,

+					 unsigned option)

+{

+    PJ_USE_EXCEPTION;

+    pj_scanner scanner;

+    pjsip_uri *uri = NULL;

+

+    init_sip_parser();

+

+    pj_scan_init(&scanner, buf, size, 0, &on_syntax_error);

+

+    

+    PJ_TRY {

+	uri = int_parse_uri_or_name_addr(&scanner, pool, option);

+    }

+    PJ_END;

+

+    /* Must have exhausted all inputs. */

     if (pj_scan_is_eof(&scanner) || *scanner.curptr=='\r' || 

                        *scanner.curptr=='\n') 

-    {
-	/* Success. */
-	pj_scan_fini(&scanner);
-	return uri;
-    }
-
-    /* Still have some characters unparsed. */
-    pj_scan_fini(&scanner);
-    return NULL;
-}
-
-/* Generic function to print message body.
- * This assumes that the 'data' member points to a contigous memory where the 
- * actual body is laid.
- */
+    {

+	/* Success. */

+	pj_scan_fini(&scanner);

+	return uri;

+    }

+

+    /* Still have some characters unparsed. */

+    pj_scan_fini(&scanner);

+    return NULL;

+}

+

+/* Generic function to print message body.

+ * This assumes that the 'data' member points to a contigous memory where the 

+ * actual body is laid.

+ */

 static int generic_print_body (pjsip_msg_body *msg_body, 

-                               char *buf, pj_size_t size)
-{
-    pjsip_msg_body *body = msg_body;
-    if (size < body->len)
-	return 0;
-
-    pj_memcpy (buf, body->data, body->len);
-    return body->len;
-}
-
-/* Internal function to parse SIP message */
-static pjsip_msg *int_parse_msg( pjsip_parse_ctx *ctx,
-				 pjsip_parser_err_report *err_list)
-{
-    PJ_USE_EXCEPTION;
-    int ch;
-    pjsip_msg *msg;
-    pjsip_ctype_hdr *ctype_hdr = NULL;
+                               char *buf, pj_size_t size)

+{

+    pjsip_msg_body *body = msg_body;

+    if (size < body->len)

+	return 0;

+

+    pj_memcpy (buf, body->data, body->len);

+    return body->len;

+}

+

+/* Internal function to parse SIP message */

+static pjsip_msg *int_parse_msg( pjsip_parse_ctx *ctx,

+				 pjsip_parser_err_report *err_list)

+{

+    PJ_USE_EXCEPTION;

+    int ch;

+    pjsip_msg *msg;

+    pjsip_ctype_hdr *ctype_hdr = NULL;

     pj_scanner *scanner = ctx->scanner;

     pj_pool_t *pool = ctx->pool;

-
-    /* Skip leading newlines. */
-    ch = *scanner->curptr;
-    while (ch=='\r' || ch=='\n') {
-	pj_scan_get_char(scanner);
-	ch = *scanner->curptr;
-    }
-
-    msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG);
-
-    /* Parse request or status line */
-    if (pj_scan_stricmp( scanner, PJSIP_VERSION, 7) == 0) {
-	msg->type = PJSIP_RESPONSE_MSG;
-	int_parse_status_line( scanner, &msg->line.status );
-    } else {
-	msg->type = PJSIP_REQUEST_MSG;
-	int_parse_req_line(scanner, pool, &msg->line.req );
-    }
-
-    /* Parse headers. */
-    do {
-	pj_str_t hname;
-	pjsip_parse_hdr_func * handler;
-	pjsip_hdr *hdr = NULL;
-
-	/* Get hname. */
-	pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &hname);
-	ch = pj_scan_get_char( scanner );
-	if (ch != ':') {
-	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-	}
-
-	/* Find handler. */
-	handler = find_handler(&hname);
-
-	PJ_TRY {
-	    /* Call the handler if found.
-	     * If no handler is found, then treat the header as generic
-	     * hname/hvalue pair.
-	     */
-	    if (handler) {
-		hdr = (*handler)(ctx);
-	    } else {
-		hdr = parse_hdr_generic_string(ctx);
-		hdr->type = PJSIP_H_OTHER;
-		hdr->name = hdr->sname = hname;
-	    }
-
-	    /* Check if we've just parsed a Content-Type header. 
-	     * We will check for a message body if we've got Content-Type header.
-	     */
-	    if (hdr->type == PJSIP_H_CONTENT_TYPE) {
-		ctype_hdr = (pjsip_ctype_hdr*)hdr;
-	    }
-
-	}
-	PJ_DEFAULT {
-	    /* Exception was thrown during parsing. 
-	     * Skip until newline, and parse next header. 
-	     */
-	    pj_str_t token;
-	    hdr = NULL;
-
+

+    /* Skip leading newlines. */

+    ch = *scanner->curptr;

+    while (ch=='\r' || ch=='\n') {

+	pj_scan_get_char(scanner);

+	ch = *scanner->curptr;

+    }

+

+    msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG);

+

+    /* Parse request or status line */

+    if (pj_scan_stricmp( scanner, PJSIP_VERSION, 7) == 0) {

+	msg->type = PJSIP_RESPONSE_MSG;

+	int_parse_status_line( scanner, &msg->line.status );

+    } else {

+	msg->type = PJSIP_REQUEST_MSG;

+	int_parse_req_line(scanner, pool, &msg->line.req );

+    }

+

+    /* Parse headers. */

+    do {

+	pj_str_t hname;

+	pjsip_parse_hdr_func * handler;

+	pjsip_hdr *hdr = NULL;

+

+	/* Get hname. */

+	pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &hname);

+	ch = pj_scan_get_char( scanner );

+	if (ch != ':') {

+	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+	}

+

+	/* Find handler. */

+	handler = find_handler(&hname);

+

+	PJ_TRY {

+	    /* Call the handler if found.

+	     * If no handler is found, then treat the header as generic

+	     * hname/hvalue pair.

+	     */

+	    if (handler) {

+		hdr = (*handler)(ctx);

+	    } else {

+		hdr = parse_hdr_generic_string(ctx);

+		hdr->type = PJSIP_H_OTHER;

+		hdr->name = hdr->sname = hname;

+	    }

+

+	    /* Check if we've just parsed a Content-Type header. 

+	     * We will check for a message body if we've got Content-Type header.

+	     */

+	    if (hdr->type == PJSIP_H_CONTENT_TYPE) {

+		ctype_hdr = (pjsip_ctype_hdr*)hdr;

+	    }

+

+	}

+	PJ_DEFAULT {

+	    /* Exception was thrown during parsing. 

+	     * Skip until newline, and parse next header. 

+	     */

+	    pj_str_t token;

+	    hdr = NULL;

+

 	    //PJ_LOG(4,("sipparser", 

-            //          "Syntax error in line %d col %d (hname=%.*s)",
-	    //	      scanner->line, scanner->col, hname.slen, hname.ptr));
-
-	    if (err_list) {
-		pjsip_parser_err_report *err_info;
-		
-		err_info = pj_pool_alloc(pool, sizeof(*err_info));
-		err_info->exception_code = PJ_GET_EXCEPTION();
-		err_info->line = scanner->line;
-		err_info->col = scanner->col;
-		err_info->hname = hname;
-
-		pj_list_insert_before(err_list, err_info);
-	    }
-
-	    if (!pj_scan_is_eof(scanner)) {
-		pj_scan_get_until(scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &token);
-		parse_hdr_end(scanner);
-	    }
-	}
-	PJ_END;
-
-	if (hdr) {
-	    /* Single parse of header line can produce multiple headers.
-	     * For example, if one Contact: header contains Contact list
-	     * separated by comma, then these Contacts will be split into
-	     * different Contact headers.
-	     * So here we must insert list instead of just insert one header.
-	     */
-	    pj_list_insert_nodes_before(&msg->hdr, hdr);
-	}
-
-	/* Parse until EOF or an empty line is found. */
-    } while (!pj_scan_is_eof(scanner) && 
-	      *scanner->curptr != '\r' && *scanner->curptr != '\n');
-
-    /* If empty line is found, eat it. */
-    if (!pj_scan_is_eof(scanner)) {
-	if (*scanner->curptr=='\r' || *scanner->curptr=='\n') {
-	    pj_scan_get_newline(scanner);
-	}
-    }
-
-    /* If we have Content-Type header, treat the rest of the message as body.*/
-    if (ctype_hdr) {
-	pjsip_msg_body *body = pj_pool_alloc(pool, sizeof(pjsip_msg_body));
-	pj_strdup(pool, &body->content_type.type, &ctype_hdr->media.type);
-	pj_strdup(pool, &body->content_type.subtype, &ctype_hdr->media.subtype);
-	pj_strdup(pool, &body->content_type.param, &ctype_hdr->media.param);
-	body->data = scanner->curptr;
-	body->len = scanner->end - scanner->curptr;
-	body->print_body = &generic_print_body;
-
-	msg->body = body;
-    }
-
-    return msg;
-}
-
-/* Parse parameter (pname ["=" pvalue]). */
-void pjsip_parse_param_imp(  pj_scanner *scanner,
-			     pj_str_t *pname, pj_str_t *pvalue,
-			     unsigned option)
-{
-    /* pname */
-    pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pname);
-
-    /* pvalue, if any */
-    if (*scanner->curptr == '=') {
-	pj_scan_get_char(scanner);
-	/* pvalue can be a quoted string. */
-	if (*scanner->curptr == '"') {
-	    pj_scan_get_quote( scanner, '"', '"', pvalue);
-	    if (option & PJSIP_PARSE_REMOVE_QUOTE) {
-		pvalue->ptr++;
-		pvalue->slen -= 2;
-	    }
-	} else {
-	    pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pvalue);
-	}
-    } else {
-	pvalue->ptr = NULL;
-	pvalue->slen = 0;
-    }
-}
-
-/* Parse parameter (";" pname ["=" pvalue]). */
-static void int_parse_param( pj_scanner *scanner,
-			     pj_str_t *pname, pj_str_t *pvalue)
-{
-    /* Get ';' character */
-    pj_scan_get_char(scanner);
-
-    /* Get pname and optionally pvalue */
-    pjsip_parse_param_imp(scanner, pname, pvalue, 0);
-}
-
-/* Parse host:port in URI. */
-static void int_parse_uri_host_port( pj_scanner *scanner, 
-				     pj_str_t *host, int *p_port)
-{
-    pj_scan_get( scanner, &pjsip_HOST_SPEC, host);
-    if (*scanner->curptr == ':') {
-	pj_str_t port;
-	pj_scan_get_char(scanner);
-	pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &port);
-	*p_port = pj_strtoul(&port);
-    } else {
-	*p_port = 0;
-    }
-}
-
-/* Determine if the next token in an URI is a user specification. */
-static int int_is_next_user(pj_scanner *scanner)
-{
-    pj_str_t dummy;
-    int is_user;
-
-    /* Find character '@'. If this character exist, then the token
-     * must be a username.
-     */
-    if (pj_scan_peek( scanner, &pjsip_PROBE_USER_HOST_SPEC, &dummy) == '@')
-	is_user = 1;
-    else
-	is_user = 0;
-
-    return is_user;
-}
-
-/* Parse user:pass tokens in an URI. */
-static void int_parse_user_pass( pj_scanner *scanner, 
-				 pj_str_t *user, pj_str_t *pass)
-{
-    pj_scan_get( scanner, &pjsip_USER_SPEC, user);
-    if ( *scanner->curptr == ':') {
-	pj_scan_get_char( scanner );
-	pj_scan_get( scanner, &pjsip_PASSWD_SPEC, pass);
-    } else {
-	pass->ptr = NULL;
-	pass->slen = 0;
-    }
-
-    /* Get the '@' */
-    pj_scan_get_char( scanner );
-}
-
-/* Parse all types of URI. */
-static pjsip_uri *int_parse_uri_or_name_addr( pj_scanner *scanner, pj_pool_t *pool,
-					      unsigned opt)
-{
-    pjsip_uri *uri;
-    int is_name_addr = 0;
-
-    if (*scanner->curptr=='"' || *scanner->curptr=='<') {
-	uri = (pjsip_uri*)int_parse_name_addr( scanner, pool );
-	is_name_addr = 1;
-    } else {
-	pj_scan_state backtrack;
-	pj_str_t scheme;
-	int colon;
-
-	pj_scan_save_state( scanner, &backtrack);
-	pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &scheme);
-	colon = pj_scan_get_char( scanner );
-	pj_scan_restore_state( scanner, &backtrack);
-
+            //          "Syntax error in line %d col %d (hname=%.*s)",

+	    //	      scanner->line, scanner->col, hname.slen, hname.ptr));

+

+	    if (err_list) {

+		pjsip_parser_err_report *err_info;

+		

+		err_info = pj_pool_alloc(pool, sizeof(*err_info));

+		err_info->exception_code = PJ_GET_EXCEPTION();

+		err_info->line = scanner->line;

+		err_info->col = scanner->col;

+		err_info->hname = hname;

+

+		pj_list_insert_before(err_list, err_info);

+	    }

+

+	    if (!pj_scan_is_eof(scanner)) {

+		pj_scan_get_until(scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &token);

+		parse_hdr_end(scanner);

+	    }

+	}

+	PJ_END;

+

+	if (hdr) {

+	    /* Single parse of header line can produce multiple headers.

+	     * For example, if one Contact: header contains Contact list

+	     * separated by comma, then these Contacts will be split into

+	     * different Contact headers.

+	     * So here we must insert list instead of just insert one header.

+	     */

+	    pj_list_insert_nodes_before(&msg->hdr, hdr);

+	}

+

+	/* Parse until EOF or an empty line is found. */

+    } while (!pj_scan_is_eof(scanner) && 

+	      *scanner->curptr != '\r' && *scanner->curptr != '\n');

+

+    /* If empty line is found, eat it. */

+    if (!pj_scan_is_eof(scanner)) {

+	if (*scanner->curptr=='\r' || *scanner->curptr=='\n') {

+	    pj_scan_get_newline(scanner);

+	}

+    }

+

+    /* If we have Content-Type header, treat the rest of the message as body.*/

+    if (ctype_hdr) {

+	pjsip_msg_body *body = pj_pool_alloc(pool, sizeof(pjsip_msg_body));

+	pj_strdup(pool, &body->content_type.type, &ctype_hdr->media.type);

+	pj_strdup(pool, &body->content_type.subtype, &ctype_hdr->media.subtype);

+	pj_strdup(pool, &body->content_type.param, &ctype_hdr->media.param);

+	body->data = scanner->curptr;

+	body->len = scanner->end - scanner->curptr;

+	body->print_body = &generic_print_body;

+

+	msg->body = body;

+    }

+

+    return msg;

+}

+

+/* Parse parameter (pname ["=" pvalue]). */

+void pjsip_parse_param_imp(  pj_scanner *scanner,

+			     pj_str_t *pname, pj_str_t *pvalue,

+			     unsigned option)

+{

+    /* pname */

+    pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pname);

+

+    /* pvalue, if any */

+    if (*scanner->curptr == '=') {

+	pj_scan_get_char(scanner);

+	/* pvalue can be a quoted string. */

+	if (*scanner->curptr == '"') {

+	    pj_scan_get_quote( scanner, '"', '"', pvalue);

+	    if (option & PJSIP_PARSE_REMOVE_QUOTE) {

+		pvalue->ptr++;

+		pvalue->slen -= 2;

+	    }

+	} else {

+	    pj_scan_get(scanner, &pjsip_PARAM_CHAR_SPEC, pvalue);

+	}

+    } else {

+	pvalue->ptr = NULL;

+	pvalue->slen = 0;

+    }

+}

+

+/* Parse parameter (";" pname ["=" pvalue]). */

+static void int_parse_param( pj_scanner *scanner,

+			     pj_str_t *pname, pj_str_t *pvalue)

+{

+    /* Get ';' character */

+    pj_scan_get_char(scanner);

+

+    /* Get pname and optionally pvalue */

+    pjsip_parse_param_imp(scanner, pname, pvalue, 0);

+}

+

+/* Parse host:port in URI. */

+static void int_parse_uri_host_port( pj_scanner *scanner, 

+				     pj_str_t *host, int *p_port)

+{

+    pj_scan_get( scanner, &pjsip_HOST_SPEC, host);

+    if (*scanner->curptr == ':') {

+	pj_str_t port;

+	pj_scan_get_char(scanner);

+	pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &port);

+	*p_port = pj_strtoul(&port);

+    } else {

+	*p_port = 0;

+    }

+}

+

+/* Determine if the next token in an URI is a user specification. */

+static int int_is_next_user(pj_scanner *scanner)

+{

+    pj_str_t dummy;

+    int is_user;

+

+    /* Find character '@'. If this character exist, then the token

+     * must be a username.

+     */

+    if (pj_scan_peek( scanner, &pjsip_PROBE_USER_HOST_SPEC, &dummy) == '@')

+	is_user = 1;

+    else

+	is_user = 0;

+

+    return is_user;

+}

+

+/* Parse user:pass tokens in an URI. */

+static void int_parse_user_pass( pj_scanner *scanner, 

+				 pj_str_t *user, pj_str_t *pass)

+{

+    pj_scan_get( scanner, &pjsip_USER_SPEC, user);

+    if ( *scanner->curptr == ':') {

+	pj_scan_get_char( scanner );

+	pj_scan_get( scanner, &pjsip_PASSWD_SPEC, pass);

+    } else {

+	pass->ptr = NULL;

+	pass->slen = 0;

+    }

+

+    /* Get the '@' */

+    pj_scan_get_char( scanner );

+}

+

+/* Parse all types of URI. */

+static pjsip_uri *int_parse_uri_or_name_addr( pj_scanner *scanner, pj_pool_t *pool,

+					      unsigned opt)

+{

+    pjsip_uri *uri;

+    int is_name_addr = 0;

+

+    if (*scanner->curptr=='"' || *scanner->curptr=='<') {

+	uri = (pjsip_uri*)int_parse_name_addr( scanner, pool );

+	is_name_addr = 1;

+    } else {

+	pj_scan_state backtrack;

+	pj_str_t scheme;

+	int colon;

+

+	pj_scan_save_state( scanner, &backtrack);

+	pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &scheme);

+	colon = pj_scan_get_char( scanner );

+	pj_scan_restore_state( scanner, &backtrack);

+

 	if (colon==':' && 

             (parser_stricmp(scheme, pjsip_SIP_STR)==0 || 

-             parser_stricmp(scheme, pjsip_SIPS_STR)==0)) 
-	{
+             parser_stricmp(scheme, pjsip_SIPS_STR)==0)) 

+	{

 	    uri = (pjsip_uri*)

-                int_parse_sip_url( scanner, pool, 
-				   (opt & PJSIP_PARSE_URI_IN_FROM_TO_HDR)== 0);
-
-	} else if (colon==':' && parser_stricmp( scheme, pjsip_TEL_STR)==0) {
-
-	    /* Not supported. */
-	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-	    UNREACHED({return NULL; /* Not reached. */});
-
-	} else {
-	    uri = (pjsip_uri*)int_parse_name_addr( scanner, pool );
-	    is_name_addr = 1;
-	}
-    }
-
-    /* Should we return the URI object as name address? */
-    if (opt & PJSIP_PARSE_URI_AS_NAMEADDR) {
-	if (is_name_addr == 0) {
-	    pjsip_name_addr *name_addr;
-
-	    name_addr = pjsip_name_addr_create(pool);
-	    name_addr->uri = uri;
-
-	    uri = (pjsip_uri*)name_addr;
-	}
-    }
-
-    return uri;
-}
-
-/* Parse URI. */
-static pjsip_uri *int_parse_uri(pj_scanner *scanner, pj_pool_t *pool, 
-				pj_bool_t parse_params)
-{
-    if (*scanner->curptr=='"' || *scanner->curptr=='<') {
-	return (pjsip_uri*)int_parse_name_addr( scanner, pool );
-    } else {
-	pj_str_t scheme;
-	int colon;
-
-	/* Get scheme. */
-	colon = pj_scan_peek(scanner, &pjsip_TOKEN_SPEC, &scheme);
-	if (colon != ':') {
-	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-	}
-
+                int_parse_sip_url( scanner, pool, 

+				   (opt & PJSIP_PARSE_URI_IN_FROM_TO_HDR)== 0);

+

+	} else if (colon==':' && parser_stricmp( scheme, pjsip_TEL_STR)==0) {

+

+	    /* Not supported. */

+	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+	    UNREACHED({return NULL; /* Not reached. */});

+

+	} else {

+	    uri = (pjsip_uri*)int_parse_name_addr( scanner, pool );

+	    is_name_addr = 1;

+	}

+    }

+

+    /* Should we return the URI object as name address? */

+    if (opt & PJSIP_PARSE_URI_AS_NAMEADDR) {

+	if (is_name_addr == 0) {

+	    pjsip_name_addr *name_addr;

+

+	    name_addr = pjsip_name_addr_create(pool);

+	    name_addr->uri = uri;

+

+	    uri = (pjsip_uri*)name_addr;

+	}

+    }

+

+    return uri;

+}

+

+/* Parse URI. */

+static pjsip_uri *int_parse_uri(pj_scanner *scanner, pj_pool_t *pool, 

+				pj_bool_t parse_params)

+{

+    if (*scanner->curptr=='"' || *scanner->curptr=='<') {

+	return (pjsip_uri*)int_parse_name_addr( scanner, pool );

+    } else {

+	pj_str_t scheme;

+	int colon;

+

+	/* Get scheme. */

+	colon = pj_scan_peek(scanner, &pjsip_TOKEN_SPEC, &scheme);

+	if (colon != ':') {

+	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+	}

+

 	if ((parser_stricmp(scheme, pjsip_SIP_STR)==0 || 

-            parser_stricmp(scheme, pjsip_SIPS_STR)==0)) 
-	{
-	    return (pjsip_uri*)int_parse_sip_url( scanner, pool, parse_params);
-
-	} else if (parser_stricmp(scheme, pjsip_TEL_STR)==0) {
-	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-	    UNREACHED({ return NULL; /* Not reached. */ })
-
-	} else {
-	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-	    UNREACHED({ return NULL; /* Not reached. */ })
-	}
-    }
-}
-
-/* Parse "sip:" and "sips:" URI. */
-static pjsip_url *int_parse_sip_url( pj_scanner *scanner, 
-				     pj_pool_t *pool,
-				     pj_bool_t parse_params)
-{
-    pj_str_t scheme;
-    pjsip_url *url;
-    int colon;
-    int skip_ws = scanner->skip_ws;
-    scanner->skip_ws = 0;
-
-    pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &scheme);
-    colon = pj_scan_get_char(scanner);
-    if (colon != ':') {
-	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-    }
-
-    if (parser_stricmp(scheme, pjsip_SIP_STR)==0) {
-	url = pjsip_url_create(pool, 0);
-
-    } else if (parser_stricmp(scheme, pjsip_SIPS_STR)==0) {
-	url = pjsip_url_create(pool, 1);
-
-    } else {
-	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-	/* should not reach here */
-	UNREACHED({
-	    pj_assert(0);
-	    return 0;
-	})
-    }
-
-    if (int_is_next_user(scanner)) {
-	int_parse_user_pass(scanner, &url->user, &url->passwd);
-    }
-
-    /* Get host:port */
-    int_parse_uri_host_port(scanner, &url->host, &url->port);
-
-    /* Get URL parameters. */
-    while ( parse_params && *scanner->curptr == ';' ) {
-	pj_str_t pname, pvalue;
-
-	int_parse_param( scanner, &pname, &pvalue);
-
-	if (!parser_stricmp(pname, pjsip_USER_STR) && pvalue.slen) {
-	    url->user_param = pvalue;
-
-	} else if (!parser_stricmp(pname, pjsip_METHOD_STR) && pvalue.slen) {
-	    url->method_param = pvalue;
-
-	} else if (!parser_stricmp(pname,pjsip_TRANSPORT_STR) && pvalue.slen) {
-	    url->transport_param = pvalue;
-
-	} else if (!parser_stricmp(pname, pjsip_TTL_STR) && pvalue.slen) {
-	    url->ttl_param = pj_strtoul(&pvalue);
-
-	} else if (!parser_stricmp(pname, pjsip_MADDR_STR) && pvalue.slen) {
-	    url->maddr_param = pvalue;
-
-	} else if (!parser_stricmp(pname, pjsip_LR_STR)) {
-	    url->lr_param = 1;
-
-	} else {
-	    concat_param(&url->other_param, pool, &pname, &pvalue);
-	}
-    }
-
-    /* Get header params. */
-    if (parse_params && *scanner->curptr == '?') {
+            parser_stricmp(scheme, pjsip_SIPS_STR)==0)) 

+	{

+	    return (pjsip_uri*)int_parse_sip_url( scanner, pool, parse_params);

+

+	} else if (parser_stricmp(scheme, pjsip_TEL_STR)==0) {

+	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+	    UNREACHED({ return NULL; /* Not reached. */ })

+

+	} else {

+	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+	    UNREACHED({ return NULL; /* Not reached. */ })

+	}

+    }

+}

+

+/* Parse "sip:" and "sips:" URI. */

+static pjsip_url *int_parse_sip_url( pj_scanner *scanner, 

+				     pj_pool_t *pool,

+				     pj_bool_t parse_params)

+{

+    pj_str_t scheme;

+    pjsip_url *url;

+    int colon;

+    int skip_ws = scanner->skip_ws;

+    scanner->skip_ws = 0;

+

+    pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &scheme);

+    colon = pj_scan_get_char(scanner);

+    if (colon != ':') {

+	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+    }

+

+    if (parser_stricmp(scheme, pjsip_SIP_STR)==0) {

+	url = pjsip_url_create(pool, 0);

+

+    } else if (parser_stricmp(scheme, pjsip_SIPS_STR)==0) {

+	url = pjsip_url_create(pool, 1);

+

+    } else {

+	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+	/* should not reach here */

+	UNREACHED({

+	    pj_assert(0);

+	    return 0;

+	})

+    }

+

+    if (int_is_next_user(scanner)) {

+	int_parse_user_pass(scanner, &url->user, &url->passwd);

+    }

+

+    /* Get host:port */

+    int_parse_uri_host_port(scanner, &url->host, &url->port);

+

+    /* Get URL parameters. */

+    while ( parse_params && *scanner->curptr == ';' ) {

+	pj_str_t pname, pvalue;

+

+	int_parse_param( scanner, &pname, &pvalue);

+

+	if (!parser_stricmp(pname, pjsip_USER_STR) && pvalue.slen) {

+	    url->user_param = pvalue;

+

+	} else if (!parser_stricmp(pname, pjsip_METHOD_STR) && pvalue.slen) {

+	    url->method_param = pvalue;

+

+	} else if (!parser_stricmp(pname,pjsip_TRANSPORT_STR) && pvalue.slen) {

+	    url->transport_param = pvalue;

+

+	} else if (!parser_stricmp(pname, pjsip_TTL_STR) && pvalue.slen) {

+	    url->ttl_param = pj_strtoul(&pvalue);

+

+	} else if (!parser_stricmp(pname, pjsip_MADDR_STR) && pvalue.slen) {

+	    url->maddr_param = pvalue;

+

+	} else if (!parser_stricmp(pname, pjsip_LR_STR)) {

+	    url->lr_param = 1;

+

+	} else {

+	    concat_param(&url->other_param, pool, &pname, &pvalue);

+	}

+    }

+

+    /* Get header params. */

+    if (parse_params && *scanner->curptr == '?') {

 	pj_scan_get_until(scanner, &pjsip_NEWLINE_OR_EOF_SPEC, 

-                          &url->header_param);
-    }
-
-    scanner->skip_ws = skip_ws;
-    pj_scan_skip_whitespace(scanner);
-    return url;
-}
-
-/* Parse nameaddr. */
-static pjsip_name_addr *int_parse_name_addr( pj_scanner *scanner, 
-					     pj_pool_t *pool )
-{
-    int has_bracket;
-    pjsip_name_addr *name_addr;
-
-    name_addr = pjsip_name_addr_create(pool);
-
-    if (*scanner->curptr == '"') {
-	pj_scan_get_quote( scanner, '"', '"', &name_addr->display);
-
-    } else if (*scanner->curptr != '<') {
-	int next;
-	pj_str_t dummy;
-
-	/* This can be either the start of display name,
-	 * the start of URL ("sip:", "sips:", "tel:", etc.), or '<' char.
-	 * We're only interested in display name, because SIP URL
-	 * will be parser later.
-	 */
-	next = pj_scan_peek_until(scanner, &pjsip_DISPLAY_SCAN_SPEC, &dummy);
-	if (next == '<') {
-	    /* Ok, this is what we're looking for, a display name. */
-	    pj_scan_get_until_ch( scanner, '<', &name_addr->display);
-	    pj_strtrim(&name_addr->display);
-	}
-    }
-
-    /* Manually skip whitespace. */
-    pj_scan_skip_whitespace(scanner);
-
-    /* Get the SIP-URL */
-    has_bracket = (*scanner->curptr == '<');
-    if (has_bracket)
-	pj_scan_get_char(scanner);
-    name_addr->uri = int_parse_uri( scanner, pool, PJ_TRUE );
-    if (has_bracket)
-	pj_scan_get_char(scanner);
-
-    return name_addr;
-}
-
-
-/* Parse SIP request line. */
-static void int_parse_req_line( pj_scanner *scanner, pj_pool_t *pool,
-				pjsip_request_line *req_line)
-{
-    pj_str_t token;
-
-    pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &token);
-    pjsip_method_init_np( &req_line->method, &token);
-
-    req_line->uri = int_parse_uri(scanner, pool, PJ_TRUE);
-    if (pj_scan_stricmp( scanner, PJSIP_VERSION, 7) != 0)
-	PJ_THROW( PJSIP_SYN_ERR_EXCEPTION);
-    pj_scan_advance_n (scanner, 7, 1);
-    pj_scan_get_newline( scanner );
-}
-
-/* Parse status line. */
-static void int_parse_status_line( pj_scanner *scanner, 
-				   pjsip_status_line *status_line)
-{
-    pj_str_t token;
-
-    if (pj_scan_stricmp(scanner, PJSIP_VERSION, 7) != 0)
-	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-    pj_scan_advance_n( scanner, 7, 1);
-
-    pj_scan_get( scanner, &pjsip_DIGIT_SPEC, &token);
-    status_line->code = pj_strtoul(&token);
+                          &url->header_param);

+    }

+

+    scanner->skip_ws = skip_ws;

+    pj_scan_skip_whitespace(scanner);

+    return url;

+}

+

+/* Parse nameaddr. */

+static pjsip_name_addr *int_parse_name_addr( pj_scanner *scanner, 

+					     pj_pool_t *pool )

+{

+    int has_bracket;

+    pjsip_name_addr *name_addr;

+

+    name_addr = pjsip_name_addr_create(pool);

+

+    if (*scanner->curptr == '"') {

+	pj_scan_get_quote( scanner, '"', '"', &name_addr->display);

+

+    } else if (*scanner->curptr != '<') {

+	int next;

+	pj_str_t dummy;

+

+	/* This can be either the start of display name,

+	 * the start of URL ("sip:", "sips:", "tel:", etc.), or '<' char.

+	 * We're only interested in display name, because SIP URL

+	 * will be parser later.

+	 */

+	next = pj_scan_peek_until(scanner, &pjsip_DISPLAY_SCAN_SPEC, &dummy);

+	if (next == '<') {

+	    /* Ok, this is what we're looking for, a display name. */

+	    pj_scan_get_until_ch( scanner, '<', &name_addr->display);

+	    pj_strtrim(&name_addr->display);

+	}

+    }

+

+    /* Manually skip whitespace. */

+    pj_scan_skip_whitespace(scanner);

+

+    /* Get the SIP-URL */

+    has_bracket = (*scanner->curptr == '<');

+    if (has_bracket)

+	pj_scan_get_char(scanner);

+    name_addr->uri = int_parse_uri( scanner, pool, PJ_TRUE );

+    if (has_bracket)

+	pj_scan_get_char(scanner);

+

+    return name_addr;

+}

+

+

+/* Parse SIP request line. */

+static void int_parse_req_line( pj_scanner *scanner, pj_pool_t *pool,

+				pjsip_request_line *req_line)

+{

+    pj_str_t token;

+

+    pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &token);

+    pjsip_method_init_np( &req_line->method, &token);

+

+    req_line->uri = int_parse_uri(scanner, pool, PJ_TRUE);

+    if (pj_scan_stricmp( scanner, PJSIP_VERSION, 7) != 0)

+	PJ_THROW( PJSIP_SYN_ERR_EXCEPTION);

+    pj_scan_advance_n (scanner, 7, 1);

+    pj_scan_get_newline( scanner );

+}

+

+/* Parse status line. */

+static void int_parse_status_line( pj_scanner *scanner, 

+				   pjsip_status_line *status_line)

+{

+    pj_str_t token;

+

+    if (pj_scan_stricmp(scanner, PJSIP_VERSION, 7) != 0)

+	PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+    pj_scan_advance_n( scanner, 7, 1);

+

+    pj_scan_get( scanner, &pjsip_DIGIT_SPEC, &token);

+    status_line->code = pj_strtoul(&token);

     pj_scan_get_until( scanner, &pjsip_NEWLINE_OR_EOF_SPEC, 

-                       &status_line->reason);
-    pj_scan_get_newline( scanner );
-}
-
-/* Parse ending of header. */
-static void parse_hdr_end( pj_scanner *scanner )
-{
-    if (pj_scan_is_eof(scanner)) {
-	;   /* Do nothing. */
-    } else if (*scanner->curptr == '&') {
-	pj_scan_get_char(scanner);
-    } else {
-	pj_scan_get_newline(scanner);
-    }
-}
-
-/* Parse ending of header. */
-void pjsip_parse_end_hdr_imp( pj_scanner *scanner )
-{
-    parse_hdr_end(scanner);
-}
-
-/* Parse generic array header. */
-static void parse_generic_array_hdr( pjsip_generic_array_hdr *hdr,
-				     pj_scanner *scanner)
-{
-    pj_scan_get_until( scanner, &pjsip_ARRAY_ELEMENTS, &hdr->values[0]);
-    hdr->count++;
-
-    while (*scanner->curptr == ',') {
-	pj_scan_get_char(scanner);
+                       &status_line->reason);

+    pj_scan_get_newline( scanner );

+}

+

+/* Parse ending of header. */

+static void parse_hdr_end( pj_scanner *scanner )

+{

+    if (pj_scan_is_eof(scanner)) {

+	;   /* Do nothing. */

+    } else if (*scanner->curptr == '&') {

+	pj_scan_get_char(scanner);

+    } else {

+	pj_scan_get_newline(scanner);

+    }

+}

+

+/* Parse ending of header. */

+void pjsip_parse_end_hdr_imp( pj_scanner *scanner )

+{

+    parse_hdr_end(scanner);

+}

+

+/* Parse generic array header. */

+static void parse_generic_array_hdr( pjsip_generic_array_hdr *hdr,

+				     pj_scanner *scanner)

+{

+    pj_scan_get_until( scanner, &pjsip_ARRAY_ELEMENTS, &hdr->values[0]);

+    hdr->count++;

+

+    while (*scanner->curptr == ',') {

+	pj_scan_get_char(scanner);

 	pj_scan_get_until( scanner, &pjsip_ARRAY_ELEMENTS, 

-                           &hdr->values[hdr->count]);
-	hdr->count++;
-    }
-    parse_hdr_end(scanner);
-}
-
-/* Parse generic string header. */
-static void parse_generic_string_hdr( pjsip_generic_string_hdr *hdr,
-				      pj_scanner *scanner )
-{
-    pj_scan_get_until( scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &hdr->hvalue);
-    parse_hdr_end(scanner);
-}
-
-/* Parse generic integer header. */
-static void parse_generic_int_hdr( pjsip_generic_int_hdr *hdr,
-				   pj_scanner *scanner )
-{
-    pj_str_t tmp;
-    pj_scan_get_until( scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &tmp);
-    hdr->ivalue = pj_strtoul(&tmp);
-    parse_hdr_end(scanner);
-}
-
-
-/* Parse Accept header. */
-static pjsip_hdr* parse_hdr_accept(pjsip_parse_ctx *ctx)
-{
-    pjsip_accept_hdr *accept = pjsip_accept_hdr_create(ctx->pool);
-    parse_generic_array_hdr(accept, ctx->scanner);
-    return (pjsip_hdr*)accept;
-}
-
-/* Parse Allow header. */
-static pjsip_hdr* parse_hdr_allow(pjsip_parse_ctx *ctx)
-{
-    pjsip_allow_hdr *allow = pjsip_allow_hdr_create(ctx->pool);
-    parse_generic_array_hdr(allow, ctx->scanner);
-    return (pjsip_hdr*)allow;
-}
-
-/* Parse Call-ID header. */
-static pjsip_hdr* parse_hdr_call_id(pjsip_parse_ctx *ctx)
-{
-    pjsip_cid_hdr *hdr = pjsip_cid_hdr_create(ctx->pool);
-    pj_scan_get_until( ctx->scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &hdr->id);
+                           &hdr->values[hdr->count]);

+	hdr->count++;

+    }

+    parse_hdr_end(scanner);

+}

+

+/* Parse generic string header. */

+static void parse_generic_string_hdr( pjsip_generic_string_hdr *hdr,

+				      pj_scanner *scanner )

+{

+    pj_scan_get_until( scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &hdr->hvalue);

+    parse_hdr_end(scanner);

+}

+

+/* Parse generic integer header. */

+static void parse_generic_int_hdr( pjsip_generic_int_hdr *hdr,

+				   pj_scanner *scanner )

+{

+    pj_str_t tmp;

+    pj_scan_get_until( scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &tmp);

+    hdr->ivalue = pj_strtoul(&tmp);

+    parse_hdr_end(scanner);

+}

+

+

+/* Parse Accept header. */

+static pjsip_hdr* parse_hdr_accept(pjsip_parse_ctx *ctx)

+{

+    pjsip_accept_hdr *accept = pjsip_accept_hdr_create(ctx->pool);

+    parse_generic_array_hdr(accept, ctx->scanner);

+    return (pjsip_hdr*)accept;

+}

+

+/* Parse Allow header. */

+static pjsip_hdr* parse_hdr_allow(pjsip_parse_ctx *ctx)

+{

+    pjsip_allow_hdr *allow = pjsip_allow_hdr_create(ctx->pool);

+    parse_generic_array_hdr(allow, ctx->scanner);

+    return (pjsip_hdr*)allow;

+}

+

+/* Parse Call-ID header. */

+static pjsip_hdr* parse_hdr_call_id(pjsip_parse_ctx *ctx)

+{

+    pjsip_cid_hdr *hdr = pjsip_cid_hdr_create(ctx->pool);

+    pj_scan_get_until( ctx->scanner, &pjsip_NEWLINE_OR_EOF_SPEC, &hdr->id);

     parse_hdr_end(ctx->scanner);

 

     if (ctx->rdata)

         ctx->rdata->call_id = hdr->id;

-
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse and interpret Contact param. */
-static void int_parse_contact_param( pjsip_contact_hdr *hdr, 
-				     pj_scanner *scanner,
-				     pj_pool_t *pool)
-{
-    while ( *scanner->curptr == ';' ) {
-	pj_str_t pname, pvalue;
-
-	int_parse_param( scanner, &pname, &pvalue);
-	if (!parser_stricmp(pname, pjsip_Q_STR) && pvalue.slen) {
-	    char *dot_pos = memchr(pvalue.ptr, '.', pvalue.slen);
-	    if (!dot_pos) {
-		hdr->q1000 = pj_strtoul(&pvalue);
-	    } else {
-		pvalue.slen = (pvalue.ptr+pvalue.slen) - (dot_pos+1);
-		pvalue.ptr = dot_pos + 1;
-		hdr->q1000 = pj_strtoul_mindigit(&pvalue, 3);
-	    }    
-	} else if (!parser_stricmp(pname, pjsip_EXPIRES_STR) && pvalue.slen) {
-	    hdr->expires = pj_strtoul(&pvalue);
-
-	} else {
-	    concat_param(&hdr->other_param, pool, &pname, &pvalue);
-	}
-    }
-}
-
-/* Parse Contact header. */
-static pjsip_hdr* parse_hdr_contact( pjsip_parse_ctx *ctx )
-{
+

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse and interpret Contact param. */

+static void int_parse_contact_param( pjsip_contact_hdr *hdr, 

+				     pj_scanner *scanner,

+				     pj_pool_t *pool)

+{

+    while ( *scanner->curptr == ';' ) {

+	pj_str_t pname, pvalue;

+

+	int_parse_param( scanner, &pname, &pvalue);

+	if (!parser_stricmp(pname, pjsip_Q_STR) && pvalue.slen) {

+	    char *dot_pos = memchr(pvalue.ptr, '.', pvalue.slen);

+	    if (!dot_pos) {

+		hdr->q1000 = pj_strtoul(&pvalue);

+	    } else {

+		pvalue.slen = (pvalue.ptr+pvalue.slen) - (dot_pos+1);

+		pvalue.ptr = dot_pos + 1;

+		hdr->q1000 = pj_strtoul_mindigit(&pvalue, 3);

+	    }    

+	} else if (!parser_stricmp(pname, pjsip_EXPIRES_STR) && pvalue.slen) {

+	    hdr->expires = pj_strtoul(&pvalue);

+

+	} else {

+	    concat_param(&hdr->other_param, pool, &pname, &pvalue);

+	}

+    }

+}

+

+/* Parse Contact header. */

+static pjsip_hdr* parse_hdr_contact( pjsip_parse_ctx *ctx )

+{

     pjsip_contact_hdr *first = NULL;

-    pj_scanner *scanner = ctx->scanner;
-    
-    do {
-	pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(ctx->pool);
-	if (first == NULL)
-	    first = hdr;
-	else
-	    pj_list_insert_before(first, hdr);
-
-	if (*scanner->curptr == '*') {
-	    pj_scan_get_char(scanner);
-	    hdr->star = 1;
-
-	} else {
-	    hdr->star = 0;
+    pj_scanner *scanner = ctx->scanner;

+    

+    do {

+	pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(ctx->pool);

+	if (first == NULL)

+	    first = hdr;

+	else

+	    pj_list_insert_before(first, hdr);

+

+	if (*scanner->curptr == '*') {

+	    pj_scan_get_char(scanner);

+	    hdr->star = 1;

+

+	} else {

+	    hdr->star = 0;

 	    hdr->uri = int_parse_uri_or_name_addr(scanner, ctx->pool, 

-                                                  PJSIP_PARSE_URI_AS_NAMEADDR);
-
-	    int_parse_contact_param(hdr, scanner, ctx->pool);
-	}
-
-	if (*scanner->curptr != ',')
-	    break;
-
-	pj_scan_get_char(scanner);
-
-    } while (1);
-
+                                                  PJSIP_PARSE_URI_AS_NAMEADDR);

+

+	    int_parse_contact_param(hdr, scanner, ctx->pool);

+	}

+

+	if (*scanner->curptr != ',')

+	    break;

+

+	pj_scan_get_char(scanner);

+

+    } while (1);

+

     parse_hdr_end(scanner);

-
-    return (pjsip_hdr*)first;
-}
-
-/* Parse Content-Length header. */
-static pjsip_hdr* parse_hdr_content_len( pjsip_parse_ctx *ctx )
-{
-    pj_str_t digit;
-    pjsip_clen_hdr *hdr;
-
-    hdr = pjsip_clen_hdr_create(ctx->pool);
-    pj_scan_get(ctx->scanner, &pjsip_DIGIT_SPEC, &digit);
-    hdr->len = pj_strtoul(&digit);
+

+    return (pjsip_hdr*)first;

+}

+

+/* Parse Content-Length header. */

+static pjsip_hdr* parse_hdr_content_len( pjsip_parse_ctx *ctx )

+{

+    pj_str_t digit;

+    pjsip_clen_hdr *hdr;

+

+    hdr = pjsip_clen_hdr_create(ctx->pool);

+    pj_scan_get(ctx->scanner, &pjsip_DIGIT_SPEC, &digit);

+    hdr->len = pj_strtoul(&digit);

     parse_hdr_end(ctx->scanner);

 

     if (ctx->rdata)

         ctx->rdata->clen = hdr;

-
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse Content-Type header. */
-static pjsip_hdr* parse_hdr_content_type( pjsip_parse_ctx *ctx )
-{
-    pjsip_ctype_hdr *hdr;
+

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse Content-Type header. */

+static pjsip_hdr* parse_hdr_content_type( pjsip_parse_ctx *ctx )

+{

+    pjsip_ctype_hdr *hdr;

     pj_scanner *scanner = ctx->scanner;

-
-    hdr = pjsip_ctype_hdr_create(ctx->pool);
-    
-    /* Parse media type and subtype. */
-    pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->media.type);
-    pj_scan_get_char(scanner);
-    pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->media.subtype);
-
-    /* Parse media parameters */
-    while (*scanner->curptr == ';') {
-	pj_str_t pname, pvalue;
-	int_parse_param(scanner, &pname, &pvalue);
-	concat_param(&hdr->media.param, ctx->pool, &pname, &pvalue);
-    }
-
+

+    hdr = pjsip_ctype_hdr_create(ctx->pool);

+    

+    /* Parse media type and subtype. */

+    pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->media.type);

+    pj_scan_get_char(scanner);

+    pj_scan_get(scanner, &pjsip_TOKEN_SPEC, &hdr->media.subtype);

+

+    /* Parse media parameters */

+    while (*scanner->curptr == ';') {

+	pj_str_t pname, pvalue;

+	int_parse_param(scanner, &pname, &pvalue);

+	concat_param(&hdr->media.param, ctx->pool, &pname, &pvalue);

+    }

+

     parse_hdr_end(ctx->scanner);

 

     if (ctx->rdata)

         ctx->rdata->ctype = hdr;

-
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse CSeq header. */
-static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx )
-{
-    pj_str_t cseq, method;
-    pjsip_cseq_hdr *hdr;
-
-    hdr = pjsip_cseq_hdr_create(ctx->pool);
-    pj_scan_get( ctx->scanner, &pjsip_DIGIT_SPEC, &cseq);
-    hdr->cseq = pj_strtoul(&cseq);
-
-    pj_scan_get( ctx->scanner, &pjsip_TOKEN_SPEC, &method);
-    pjsip_method_init_np(&hdr->method, &method);
-
+

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse CSeq header. */

+static pjsip_hdr* parse_hdr_cseq( pjsip_parse_ctx *ctx )

+{

+    pj_str_t cseq, method;

+    pjsip_cseq_hdr *hdr;

+

+    hdr = pjsip_cseq_hdr_create(ctx->pool);

+    pj_scan_get( ctx->scanner, &pjsip_DIGIT_SPEC, &cseq);

+    hdr->cseq = pj_strtoul(&cseq);

+

+    pj_scan_get( ctx->scanner, &pjsip_TOKEN_SPEC, &method);

+    pjsip_method_init_np(&hdr->method, &method);

+

     parse_hdr_end( ctx->scanner );

 

     if (ctx->rdata)

         ctx->rdata->cseq = hdr;

-
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse Expires header. */
-static pjsip_hdr* parse_hdr_expires(pjsip_parse_ctx *ctx)
-{
-    pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(ctx->pool);
-    parse_generic_int_hdr(hdr, ctx->scanner);
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse From: or To: header. */
-static void parse_hdr_fromto( pj_scanner *scanner, 
-			      pj_pool_t *pool, 
-			      pjsip_from_hdr *hdr)
-{
-    hdr->uri = int_parse_uri_or_name_addr(scanner, pool, 
-					  PJSIP_PARSE_URI_AS_NAMEADDR |
-					  PJSIP_PARSE_URI_IN_FROM_TO_HDR);
-
-    while ( *scanner->curptr == ';' ) {
-	pj_str_t pname, pvalue;
-
-	int_parse_param( scanner, &pname, &pvalue);
-
-	if (!parser_stricmp(pname, pjsip_TAG_STR)) {
-	    hdr->tag = pvalue;
-	    
-	} else {
-	    concat_param(&hdr->other_param, pool, &pname, &pvalue);
-	}
-    }
-
-    parse_hdr_end(scanner);
-}
-
-/* Parse From: header. */
-static pjsip_hdr* parse_hdr_from( pjsip_parse_ctx *ctx )
-{
-    pjsip_from_hdr *hdr = pjsip_from_hdr_create(ctx->pool);
+

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse Expires header. */

+static pjsip_hdr* parse_hdr_expires(pjsip_parse_ctx *ctx)

+{

+    pjsip_expires_hdr *hdr = pjsip_expires_hdr_create(ctx->pool);

+    parse_generic_int_hdr(hdr, ctx->scanner);

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse From: or To: header. */

+static void parse_hdr_fromto( pj_scanner *scanner, 

+			      pj_pool_t *pool, 

+			      pjsip_from_hdr *hdr)

+{

+    hdr->uri = int_parse_uri_or_name_addr(scanner, pool, 

+					  PJSIP_PARSE_URI_AS_NAMEADDR |

+					  PJSIP_PARSE_URI_IN_FROM_TO_HDR);

+

+    while ( *scanner->curptr == ';' ) {

+	pj_str_t pname, pvalue;

+

+	int_parse_param( scanner, &pname, &pvalue);

+

+	if (!parser_stricmp(pname, pjsip_TAG_STR)) {

+	    hdr->tag = pvalue;

+	    

+	} else {

+	    concat_param(&hdr->other_param, pool, &pname, &pvalue);

+	}

+    }

+

+    parse_hdr_end(scanner);

+}

+

+/* Parse From: header. */

+static pjsip_hdr* parse_hdr_from( pjsip_parse_ctx *ctx )

+{

+    pjsip_from_hdr *hdr = pjsip_from_hdr_create(ctx->pool);

     parse_hdr_fromto(ctx->scanner, ctx->pool, hdr);

     if (ctx->rdata)

         ctx->rdata->from = hdr;

-
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse Require: header. */
-static pjsip_hdr* parse_hdr_require( pjsip_parse_ctx *ctx )
-{
-    pjsip_require_hdr *hdr = pjsip_require_hdr_create(ctx->pool);
+

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse Require: header. */

+static pjsip_hdr* parse_hdr_require( pjsip_parse_ctx *ctx )

+{

+    pjsip_require_hdr *hdr = pjsip_require_hdr_create(ctx->pool);

     parse_generic_array_hdr(hdr, ctx->scanner);

 

     if (ctx->rdata && ctx->rdata->require == NULL)

         ctx->rdata->require = hdr;

-
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse Retry-After: header. */
-static pjsip_hdr* parse_hdr_retry_after(pjsip_parse_ctx *ctx)
-{
-    pjsip_retry_after_hdr *hdr;
-    hdr = pjsip_retry_after_hdr_create(ctx->pool);
-    parse_generic_int_hdr(hdr, ctx->scanner);
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse Supported: header. */
-static pjsip_hdr* parse_hdr_supported(pjsip_parse_ctx *ctx)
-{
-    pjsip_supported_hdr *hdr = pjsip_supported_hdr_create(ctx->pool);
-    parse_generic_array_hdr(hdr, ctx->scanner);
-    return (pjsip_hdr*)hdr;
-}
-
-
-/* Parse To: header. */
-static pjsip_hdr* parse_hdr_to( pjsip_parse_ctx *ctx )
-{
-    pjsip_to_hdr *hdr = pjsip_to_hdr_create(ctx->pool);
+

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse Retry-After: header. */

+static pjsip_hdr* parse_hdr_retry_after(pjsip_parse_ctx *ctx)

+{

+    pjsip_retry_after_hdr *hdr;

+    hdr = pjsip_retry_after_hdr_create(ctx->pool);

+    parse_generic_int_hdr(hdr, ctx->scanner);

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse Supported: header. */

+static pjsip_hdr* parse_hdr_supported(pjsip_parse_ctx *ctx)

+{

+    pjsip_supported_hdr *hdr = pjsip_supported_hdr_create(ctx->pool);

+    parse_generic_array_hdr(hdr, ctx->scanner);

+    return (pjsip_hdr*)hdr;

+}

+

+

+/* Parse To: header. */

+static pjsip_hdr* parse_hdr_to( pjsip_parse_ctx *ctx )

+{

+    pjsip_to_hdr *hdr = pjsip_to_hdr_create(ctx->pool);

     parse_hdr_fromto(ctx->scanner, ctx->pool, hdr);

 

     if (ctx->rdata)

         ctx->rdata->to = hdr;

-
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse Unsupported: header. */
-static pjsip_hdr* parse_hdr_unsupported(pjsip_parse_ctx *ctx)
-{
-    pjsip_unsupported_hdr *hdr = pjsip_unsupported_hdr_create(ctx->pool);
-    parse_generic_array_hdr(hdr, ctx->scanner);
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse and interpret Via parameters. */
-static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner,
-				 pj_pool_t *pool)
-{
-    while ( *scanner->curptr == ';' ) {
-	pj_str_t pname, pvalue;
-
-	int_parse_param( scanner, &pname, &pvalue);
-
-	if (!parser_stricmp(pname, pjsip_BRANCH_STR) && pvalue.slen) {
-	    hdr->branch_param = pvalue;
-
-	} else if (!parser_stricmp(pname, pjsip_TTL_STR) && pvalue.slen) {
-	    hdr->ttl_param = pj_strtoul(&pvalue);
-	    
-	} else if (!parser_stricmp(pname, pjsip_MADDR_STR) && pvalue.slen) {
-	    hdr->maddr_param = pvalue;
-
-	} else if (!parser_stricmp(pname, pjsip_PNAME_STR) && pvalue.slen) {
-	    hdr->recvd_param = pvalue;
-
-	} else if (!parser_stricmp(pname, pjsip_RPORT_STR)) {
-	    if (pvalue.slen)
-		hdr->rport_param = pj_strtoul(&pvalue);
-	    else
-		hdr->rport_param = 0;
-	} else {
-	    concat_param( &hdr->other_param, pool, &pname, &pvalue);
-	}
-    }
-
-}
-
-/* Parse Max-Forwards header. */
-static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx )
-{
-    pjsip_max_forwards_hdr *hdr;
-    hdr = pjsip_max_forwards_hdr_create(ctx->pool);
+

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse Unsupported: header. */

+static pjsip_hdr* parse_hdr_unsupported(pjsip_parse_ctx *ctx)

+{

+    pjsip_unsupported_hdr *hdr = pjsip_unsupported_hdr_create(ctx->pool);

+    parse_generic_array_hdr(hdr, ctx->scanner);

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse and interpret Via parameters. */

+static void int_parse_via_param( pjsip_via_hdr *hdr, pj_scanner *scanner,

+				 pj_pool_t *pool)

+{

+    while ( *scanner->curptr == ';' ) {

+	pj_str_t pname, pvalue;

+

+	int_parse_param( scanner, &pname, &pvalue);

+

+	if (!parser_stricmp(pname, pjsip_BRANCH_STR) && pvalue.slen) {

+	    hdr->branch_param = pvalue;

+

+	} else if (!parser_stricmp(pname, pjsip_TTL_STR) && pvalue.slen) {

+	    hdr->ttl_param = pj_strtoul(&pvalue);

+	    

+	} else if (!parser_stricmp(pname, pjsip_MADDR_STR) && pvalue.slen) {

+	    hdr->maddr_param = pvalue;

+

+	} else if (!parser_stricmp(pname, pjsip_PNAME_STR) && pvalue.slen) {

+	    hdr->recvd_param = pvalue;

+

+	} else if (!parser_stricmp(pname, pjsip_RPORT_STR)) {

+	    if (pvalue.slen)

+		hdr->rport_param = pj_strtoul(&pvalue);

+	    else

+		hdr->rport_param = 0;

+	} else {

+	    concat_param( &hdr->other_param, pool, &pname, &pvalue);

+	}

+    }

+

+}

+

+/* Parse Max-Forwards header. */

+static pjsip_hdr* parse_hdr_max_forwards( pjsip_parse_ctx *ctx )

+{

+    pjsip_max_forwards_hdr *hdr;

+    hdr = pjsip_max_forwards_hdr_create(ctx->pool);

     parse_generic_int_hdr(hdr, ctx->scanner);

 

     if (ctx->rdata)

         ctx->rdata->max_fwd = hdr;

-
-    return (pjsip_hdr*)hdr;
-}
-
-/* Parse Min-Expires header. */
-static pjsip_hdr* parse_hdr_min_expires(pjsip_parse_ctx *ctx)
-{
-    pjsip_min_expires_hdr *hdr;
-    hdr = pjsip_min_expires_hdr_create(ctx->pool);
-    parse_generic_int_hdr(hdr, ctx->scanner);
-    return (pjsip_hdr*)hdr;
-}
-
-
-/* Parse Route: or Record-Route: header. */
-static void parse_hdr_rr_route( pj_scanner *scanner, pj_pool_t *pool,
-				pjsip_routing_hdr *hdr )
-{
-    pjsip_name_addr *temp=int_parse_name_addr(scanner, pool);
-
-    pj_memcpy(&hdr->name_addr, temp, sizeof(*temp));
-    if (*scanner->curptr == ';') {
+

+    return (pjsip_hdr*)hdr;

+}

+

+/* Parse Min-Expires header. */

+static pjsip_hdr* parse_hdr_min_expires(pjsip_parse_ctx *ctx)

+{

+    pjsip_min_expires_hdr *hdr;

+    hdr = pjsip_min_expires_hdr_create(ctx->pool);

+    parse_generic_int_hdr(hdr, ctx->scanner);

+    return (pjsip_hdr*)hdr;

+}

+

+

+/* Parse Route: or Record-Route: header. */

+static void parse_hdr_rr_route( pj_scanner *scanner, pj_pool_t *pool,

+				pjsip_routing_hdr *hdr )

+{

+    pjsip_name_addr *temp=int_parse_name_addr(scanner, pool);

+

+    pj_memcpy(&hdr->name_addr, temp, sizeof(*temp));

+    if (*scanner->curptr == ';') {

 	pj_scan_get_until(scanner, &pjsip_NEWLINE_OR_EOF_SPEC, 

-                          &hdr->other_param);
-    }
-}
-
-/* Parse Record-Route header. */
-static pjsip_hdr* parse_hdr_rr( pjsip_parse_ctx *ctx)
-{
+                          &hdr->other_param);

+    }

+}

+

+/* Parse Record-Route header. */

+static pjsip_hdr* parse_hdr_rr( pjsip_parse_ctx *ctx)

+{

     pjsip_rr_hdr *first = NULL;

-    pj_scanner *scanner = ctx->scanner;
-
-    do {
-	pjsip_rr_hdr *hdr = pjsip_rr_hdr_create(ctx->pool);
-	if (!first) {
-	    first = hdr;
-	} else {
-	    pj_list_insert_before(first, hdr);
-	}
-	parse_hdr_rr_route(scanner, ctx->pool, hdr);
-	if (*scanner->curptr == ',') {
-	    pj_scan_get_char(scanner);
-	} else {
-	    break;
-	}
-    } while (1);
+    pj_scanner *scanner = ctx->scanner;

+

+    do {

+	pjsip_rr_hdr *hdr = pjsip_rr_hdr_create(ctx->pool);

+	if (!first) {

+	    first = hdr;

+	} else {

+	    pj_list_insert_before(first, hdr);

+	}

+	parse_hdr_rr_route(scanner, ctx->pool, hdr);

+	if (*scanner->curptr == ',') {

+	    pj_scan_get_char(scanner);

+	} else {

+	    break;

+	}

+    } while (1);

     parse_hdr_end(scanner);

 

     if (ctx->rdata && ctx->rdata->record_route==NULL)

         ctx->rdata->record_route = first;

-
-    return (pjsip_hdr*)first;
-}
-
-/* Parse Route: header. */
-static pjsip_hdr* parse_hdr_route( pjsip_parse_ctx *ctx )
-{
+

+    return (pjsip_hdr*)first;

+}

+

+/* Parse Route: header. */

+static pjsip_hdr* parse_hdr_route( pjsip_parse_ctx *ctx )

+{

     pjsip_route_hdr *first = NULL;

-    pj_scanner *scanner = ctx->scanner;
-
-    do {
-	pjsip_route_hdr *hdr = pjsip_route_hdr_create(ctx->pool);
-	if (!first) {
-	    first = hdr;
-	} else {
-	    pj_list_insert_before(first, hdr);
-	}
-	parse_hdr_rr_route(scanner, ctx->pool, hdr);
-	if (*scanner->curptr == ',') {
-	    pj_scan_get_char(scanner);
-	} else {
-	    break;
-	}
-    } while (1);
+    pj_scanner *scanner = ctx->scanner;

+

+    do {

+	pjsip_route_hdr *hdr = pjsip_route_hdr_create(ctx->pool);

+	if (!first) {

+	    first = hdr;

+	} else {

+	    pj_list_insert_before(first, hdr);

+	}

+	parse_hdr_rr_route(scanner, ctx->pool, hdr);

+	if (*scanner->curptr == ',') {

+	    pj_scan_get_char(scanner);

+	} else {

+	    break;

+	}

+    } while (1);

     parse_hdr_end(scanner);

 

     if (ctx->rdata && ctx->rdata->route==NULL)

         ctx->rdata->route = first;

-
-    return (pjsip_hdr*)first;
-}
-
-/* Parse Via: header. */
-static pjsip_hdr* parse_hdr_via( pjsip_parse_ctx *ctx )
-{
+

+    return (pjsip_hdr*)first;

+}

+

+/* Parse Via: header. */

+static pjsip_hdr* parse_hdr_via( pjsip_parse_ctx *ctx )

+{

     pjsip_via_hdr *first = NULL;

-    pj_scanner *scanner = ctx->scanner;
-
-    do {
-	pjsip_via_hdr *hdr = pjsip_via_hdr_create(ctx->pool);
-	if (!first)
-	    first = hdr;
-	else
-	    pj_list_insert_before(first, hdr);
-
-	if (pj_scan_stricmp( scanner, PJSIP_VERSION "/", 8) != 0)
-	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);
-
-	pj_scan_advance_n( scanner, 8, 1);
-
-	pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &hdr->transport);
-	pj_scan_get( scanner, &pjsip_HOST_SPEC, &hdr->sent_by.host);
-
-	if (*scanner->curptr==':') {
-	    pj_str_t digit;
-	    pj_scan_get_char(scanner);
-	    pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &digit);
-	    hdr->sent_by.port = pj_strtoul(&digit);
-	} else {
-	    hdr->sent_by.port = 5060;
-	}
-	
-	int_parse_via_param(hdr, scanner, ctx->pool);
-
-	if (*scanner->curptr == '(') {
-	    pj_scan_get_char(scanner);
-	    pj_scan_get_until_ch( scanner, ')', &hdr->comment);
-	    pj_scan_get_char( scanner );
-	}
-
-	if (*scanner->curptr != ',')
-	    break;
-
-	pj_scan_get_char(scanner);
-
-    } while (1);
-
+    pj_scanner *scanner = ctx->scanner;

+

+    do {

+	pjsip_via_hdr *hdr = pjsip_via_hdr_create(ctx->pool);

+	if (!first)

+	    first = hdr;

+	else

+	    pj_list_insert_before(first, hdr);

+

+	if (pj_scan_stricmp( scanner, PJSIP_VERSION "/", 8) != 0)

+	    PJ_THROW(PJSIP_SYN_ERR_EXCEPTION);

+

+	pj_scan_advance_n( scanner, 8, 1);

+

+	pj_scan_get( scanner, &pjsip_TOKEN_SPEC, &hdr->transport);

+	pj_scan_get( scanner, &pjsip_HOST_SPEC, &hdr->sent_by.host);

+

+	if (*scanner->curptr==':') {

+	    pj_str_t digit;

+	    pj_scan_get_char(scanner);

+	    pj_scan_get(scanner, &pjsip_DIGIT_SPEC, &digit);

+	    hdr->sent_by.port = pj_strtoul(&digit);

+	} else {

+	    hdr->sent_by.port = 5060;

+	}

+	

+	int_parse_via_param(hdr, scanner, ctx->pool);

+

+	if (*scanner->curptr == '(') {

+	    pj_scan_get_char(scanner);

+	    pj_scan_get_until_ch( scanner, ')', &hdr->comment);

+	    pj_scan_get_char( scanner );

+	}

+

+	if (*scanner->curptr != ',')

+	    break;

+

+	pj_scan_get_char(scanner);

+

+    } while (1);

+

     parse_hdr_end(scanner);

 

     if (ctx->rdata && ctx->rdata->via == NULL)

         ctx->rdata->via = first;

-
-    return (pjsip_hdr*)first;
-}
-
-/* Parse generic header. */
-static pjsip_hdr* parse_hdr_generic_string( pjsip_parse_ctx *ctx )
-{
-    pjsip_generic_string_hdr *hdr;
-
-    hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL);
-    parse_generic_string_hdr(hdr, ctx->scanner);
-    return (pjsip_hdr*)hdr;
-
-}
-
-/* Public function to parse a header value. */
-PJ_DEF(void*) pjsip_parse_hdr( pj_pool_t *pool, const pj_str_t *hname,
-			       char *buf, pj_size_t size, int *parsed_len )
-{
-    pj_scanner scanner;
+

+    return (pjsip_hdr*)first;

+}

+

+/* Parse generic header. */

+static pjsip_hdr* parse_hdr_generic_string( pjsip_parse_ctx *ctx )

+{

+    pjsip_generic_string_hdr *hdr;

+

+    hdr = pjsip_generic_string_hdr_create(ctx->pool, NULL);

+    parse_generic_string_hdr(hdr, ctx->scanner);

+    return (pjsip_hdr*)hdr;

+

+}

+

+/* Public function to parse a header value. */

+PJ_DEF(void*) pjsip_parse_hdr( pj_pool_t *pool, const pj_str_t *hname,

+			       char *buf, pj_size_t size, int *parsed_len )

+{

+    pj_scanner scanner;

     pjsip_hdr *hdr = NULL;

-    pjsip_parse_ctx context;
-    PJ_USE_EXCEPTION;
-
-    init_sip_parser();
-
+    pjsip_parse_ctx context;

+    PJ_USE_EXCEPTION;

+

+    init_sip_parser();

+

     pj_scan_init(&scanner, buf, size, PJ_SCAN_AUTOSKIP_WS_HEADER, 

-                 &on_syntax_error);
+                 &on_syntax_error);

 

     context.scanner = &scanner;

     context.pool = pool;

     context.rdata = NULL;

-
-    PJ_TRY {
-	pjsip_parse_hdr_func *handler = find_handler(hname);
-	if (handler) {
-	    hdr = (*handler)(&context);
-	} else {
-	    hdr = parse_hdr_generic_string(&context);
-	    hdr->type = PJSIP_H_OTHER;
-	    pj_strdup(pool, &hdr->name, hname);
-	    hdr->sname = hdr->name;
-	}
-
-    } 
-    PJ_DEFAULT {
-	hdr = NULL;
-    }
-    PJ_END
-
-    if (parsed_len) {
-	*parsed_len = (scanner.curptr - scanner.begin);
-    }
-
-    pj_scan_fini(&scanner);
-
-    return hdr;
-}
-
+

+    PJ_TRY {

+	pjsip_parse_hdr_func *handler = find_handler(hname);

+	if (handler) {

+	    hdr = (*handler)(&context);

+	} else {

+	    hdr = parse_hdr_generic_string(&context);

+	    hdr->type = PJSIP_H_OTHER;

+	    pj_strdup(pool, &hdr->name, hname);

+	    hdr->sname = hdr->name;

+	}

+

+    } 

+    PJ_DEFAULT {

+	hdr = NULL;

+    }

+    PJ_END

+

+    if (parsed_len) {

+	*parsed_len = (scanner.curptr - scanner.begin);

+    }

+

+    pj_scan_fini(&scanner);

+

+    return hdr;

+}

+

diff --git a/pjsip/src/pjsip/sip_resolve.c b/pjsip/src/pjsip/sip_resolve.c
index b199eab..74d7e88 100644
--- a/pjsip/src/pjsip/sip_resolve.c
+++ b/pjsip/src/pjsip/sip_resolve.c
@@ -1,110 +1,132 @@
-/* $Id$
- */
-
-#include <pjsip/sip_resolve.h>
-#include <pjsip/sip_transport.h>
-#include <pj/pool.h>
-#include <pj/ctype.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+

+#include <pjsip/sip_resolve.h>

+#include <pjsip/sip_transport.h>

+#include <pj/pool.h>

+#include <pj/ctype.h>

 #include <pj/assert.h>

-
-struct pjsip_resolver_t
-{
-    void *dummy;
-};
-
-PJ_DEF(pjsip_resolver_t*) pjsip_resolver_create(pj_pool_t *pool)
-{
-    pjsip_resolver_t *resolver;
-    resolver = (pjsip_resolver_t*) pj_pool_calloc(pool, 1, sizeof(*resolver));
-    return resolver;
-}
-
-PJ_DEF(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver)
-{
-    PJ_UNUSED_ARG(resolver);
-}
-
-static int is_str_ip(const pj_str_t *host)
-{
-    const char *p = host->ptr;
-    const char *end = ((const char*)host->ptr) + host->slen;
-
-    while (p != end) {
-	if (pj_isdigit(*p) || *p=='.') {
-	    ++p;
-	} else {
-	    return 0;
-	}
-    }
-    return 1;
-}
-
-PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
-			    pj_pool_t *pool,
-			    pjsip_host_port *target,
-			    void *token,
-			    pjsip_resolver_callback *cb)
-{
-    struct pjsip_server_addresses svr_addr;
-    pj_status_t status;
-    int is_ip_addr;
-    pjsip_transport_type_e type = target->type;
-
-    PJ_UNUSED_ARG(resolver);
-    PJ_UNUSED_ARG(pool);
-
-    /* We only do synchronous resolving at this moment. */
-    PJ_TODO(SUPPORT_RFC3263_SERVER_RESOLUTION)
-
-    /* Is it IP address or hostname?. */
-    is_ip_addr = is_str_ip(&target->host);
-
-    /* Set the transport type if not explicitly specified. 
-     * RFC 3263 section 4.1 specify rules to set up this.
-     */
-    if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
-	if (is_ip_addr || (target->port != 0)) {
-#if PJ_HAS_TCP
-	    if (target->flag & PJSIP_TRANSPORT_SECURE) 
-	    {
-		type = PJSIP_TRANSPORT_TLS;
-	    } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) 
-	    {
-		type = PJSIP_TRANSPORT_TCP;
-	    } else 
-#endif
-	    {
-		type = PJSIP_TRANSPORT_UDP;
-	    }
-	} else {
-	    /* No type or explicit port is specified, and the address is
-	     * not IP address.
-	     * In this case, full resolution must be performed.
-	     * But we don't support it (yet).
-	     */
-	    type = PJSIP_TRANSPORT_UDP;
-	}
-
-    }
-
-    /* Set the port number if not specified. */
-    if (target->port == 0) {
-	target->port = pjsip_transport_get_default_port_for_type(type);
-    }
-
-    /* Resolve hostname. */
-    if (!is_ip_addr) {
+

+struct pjsip_resolver_t

+{

+    void *dummy;

+};

+

+PJ_DEF(pjsip_resolver_t*) pjsip_resolver_create(pj_pool_t *pool)

+{

+    pjsip_resolver_t *resolver;

+    resolver = (pjsip_resolver_t*) pj_pool_calloc(pool, 1, sizeof(*resolver));

+    return resolver;

+}

+

+PJ_DEF(void) pjsip_resolver_destroy(pjsip_resolver_t *resolver)

+{

+    PJ_UNUSED_ARG(resolver);

+}

+

+static int is_str_ip(const pj_str_t *host)

+{

+    const char *p = host->ptr;

+    const char *end = ((const char*)host->ptr) + host->slen;

+

+    while (p != end) {

+	if (pj_isdigit(*p) || *p=='.') {

+	    ++p;

+	} else {

+	    return 0;

+	}

+    }

+    return 1;

+}

+

+PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,

+			    pj_pool_t *pool,

+			    pjsip_host_port *target,

+			    void *token,

+			    pjsip_resolver_callback *cb)

+{

+    struct pjsip_server_addresses svr_addr;

+    pj_status_t status;

+    int is_ip_addr;

+    pjsip_transport_type_e type = target->type;

+

+    PJ_UNUSED_ARG(resolver);

+    PJ_UNUSED_ARG(pool);

+

+    /* We only do synchronous resolving at this moment. */

+    PJ_TODO(SUPPORT_RFC3263_SERVER_RESOLUTION)

+

+    /* Is it IP address or hostname?. */

+    is_ip_addr = is_str_ip(&target->host);

+

+    /* Set the transport type if not explicitly specified. 

+     * RFC 3263 section 4.1 specify rules to set up this.

+     */

+    if (type == PJSIP_TRANSPORT_UNSPECIFIED) {

+	if (is_ip_addr || (target->port != 0)) {

+#if PJ_HAS_TCP

+	    if (target->flag & PJSIP_TRANSPORT_SECURE) 

+	    {

+		type = PJSIP_TRANSPORT_TLS;

+	    } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) 

+	    {

+		type = PJSIP_TRANSPORT_TCP;

+	    } else 

+#endif

+	    {

+		type = PJSIP_TRANSPORT_UDP;

+	    }

+	} else {

+	    /* No type or explicit port is specified, and the address is

+	     * not IP address.

+	     * In this case, full resolution must be performed.

+	     * But we don't support it (yet).

+	     */

+	    type = PJSIP_TRANSPORT_UDP;

+	}

+

+    }

+

+    /* Set the port number if not specified. */

+    if (target->port == 0) {

+	target->port = pjsip_transport_get_default_port_for_type(type);

+    }

+

+    /* Resolve hostname. */

+    if (!is_ip_addr) {

 	status = pj_sockaddr_in_init(&svr_addr.entry[0].addr, &target->host, 

-				     (pj_uint16_t)target->port);
-    } else {
+				     (pj_uint16_t)target->port);

+    } else {

 	status = pj_sockaddr_in_init(&svr_addr.entry[0].addr, &target->host, 

-				     (pj_uint16_t)target->port);
-	pj_assert(status == PJ_SUCCESS);
-    }
-
-    /* Call the callback. */
-    svr_addr.count = (status == PJ_SUCCESS) ? 1 : 0;
-    svr_addr.entry[0].type = type;
-    (*cb)(status, token, &svr_addr);
-}
-
+				     (pj_uint16_t)target->port);

+	pj_assert(status == PJ_SUCCESS);

+    }

+

+    /* Call the callback. */

+    svr_addr.count = (status == PJ_SUCCESS) ? 1 : 0;

+    svr_addr.entry[0].type = type;

+    (*cb)(status, token, &svr_addr);

+}

+

diff --git a/pjsip/src/pjsip/sip_transaction.c b/pjsip/src/pjsip/sip_transaction.c
index ebc0a80..9e9b483 100644
--- a/pjsip/src/pjsip/sip_transaction.c
+++ b/pjsip/src/pjsip/sip_transaction.c
@@ -1,1966 +1,1988 @@
-/* $Id$
- */
-#include <pjsip/sip_transaction.h>
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_config.h>
-#include <pjsip/sip_misc.h>
-#include <pjsip/sip_event.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_errno.h>
-#include <pj/log.h>
-#include <pj/string.h>
-#include <pj/os.h>
-#include <pj/guid.h>
-#include <pj/pool.h>
-#include <pj/assert.h>
-
-/* Thread Local Storage ID for transaction lock (initialized by endpoint) */
-long pjsip_tsx_lock_tls_id;
-
-/* State names */
-static const char *state_str[] = 
-{
-    "Null",
-    "Calling",
-    "Trying",
-    "Proceeding",
-    "Completed",
-    "Confirmed",
-    "Terminated",
-    "Destroyed",
-};
-
-/* Role names */
-static const char *role_name[] = 
-{
-    "Client",
-    "Server"
-};
-
-/* Transaction lock. */
-typedef struct tsx_lock_data {
-    struct tsx_lock_data *prev;
-    pjsip_transaction    *tsx;
-    int			  is_alive;
-} tsx_lock_data;
-
-
-/* Timer timeout value constants */
-static const pj_time_val t1_timer_val = { PJSIP_T1_TIMEOUT/1000, 
-                                          PJSIP_T1_TIMEOUT%1000 };
-static const pj_time_val t4_timer_val = { PJSIP_T4_TIMEOUT/1000, 
-                                          PJSIP_T4_TIMEOUT%1000 };
-static const pj_time_val td_timer_val = { PJSIP_TD_TIMEOUT/1000, 
-                                          PJSIP_TD_TIMEOUT%1000 };
-static const pj_time_val timeout_timer_val = { (64*PJSIP_T1_TIMEOUT)/1000,
-					       (64*PJSIP_T1_TIMEOUT)%1000 };
-
-/* Internal timer IDs */
-enum Transaction_Timer_Id
-{
-    TSX_TIMER_RETRANSMISSION,
-    TSX_TIMER_TIMEOUT,
-};
-
-/* Function Prototypes */
-static pj_status_t pjsip_tsx_on_state_null(     pjsip_transaction *tsx, 
-				                pjsip_event *event);
-static pj_status_t pjsip_tsx_on_state_calling(  pjsip_transaction *tsx, 
-				                pjsip_event *event);
-static pj_status_t pjsip_tsx_on_state_trying(   pjsip_transaction *tsx, 
-				                pjsip_event *event);
-static pj_status_t pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, 
-					        pjsip_event *event);
-static pj_status_t pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx,
-					        pjsip_event *event);
-static pj_status_t pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, 
-					        pjsip_event *event);
-static pj_status_t pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx,
-					        pjsip_event *event);
-static pj_status_t pjsip_tsx_on_state_confirmed(pjsip_transaction *tsx, 
-					        pjsip_event *event);
-static pj_status_t pjsip_tsx_on_state_terminated(pjsip_transaction *tsx, 
-					        pjsip_event *event);
-static pj_status_t pjsip_tsx_on_state_destroyed(pjsip_transaction *tsx, 
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_transaction.h>

+#include <pjsip/sip_transport.h>

+#include <pjsip/sip_config.h>

+#include <pjsip/sip_misc.h>

+#include <pjsip/sip_event.h>

+#include <pjsip/sip_endpoint.h>

+#include <pjsip/sip_errno.h>

+#include <pj/log.h>

+#include <pj/string.h>

+#include <pj/os.h>

+#include <pj/guid.h>

+#include <pj/pool.h>

+#include <pj/assert.h>

+

+/* Thread Local Storage ID for transaction lock (initialized by endpoint) */

+long pjsip_tsx_lock_tls_id;

+

+/* State names */

+static const char *state_str[] = 

+{

+    "Null",

+    "Calling",

+    "Trying",

+    "Proceeding",

+    "Completed",

+    "Confirmed",

+    "Terminated",

+    "Destroyed",

+};

+

+/* Role names */

+static const char *role_name[] = 

+{

+    "Client",

+    "Server"

+};

+

+/* Transaction lock. */

+typedef struct tsx_lock_data {

+    struct tsx_lock_data *prev;

+    pjsip_transaction    *tsx;

+    int			  is_alive;

+} tsx_lock_data;

+

+

+/* Timer timeout value constants */

+static const pj_time_val t1_timer_val = { PJSIP_T1_TIMEOUT/1000, 

+                                          PJSIP_T1_TIMEOUT%1000 };

+static const pj_time_val t4_timer_val = { PJSIP_T4_TIMEOUT/1000, 

+                                          PJSIP_T4_TIMEOUT%1000 };

+static const pj_time_val td_timer_val = { PJSIP_TD_TIMEOUT/1000, 

+                                          PJSIP_TD_TIMEOUT%1000 };

+static const pj_time_val timeout_timer_val = { (64*PJSIP_T1_TIMEOUT)/1000,

+					       (64*PJSIP_T1_TIMEOUT)%1000 };

+

+/* Internal timer IDs */

+enum Transaction_Timer_Id

+{

+    TSX_TIMER_RETRANSMISSION,

+    TSX_TIMER_TIMEOUT,

+};

+

+/* Function Prototypes */

+static pj_status_t pjsip_tsx_on_state_null(     pjsip_transaction *tsx, 

+				                pjsip_event *event);

+static pj_status_t pjsip_tsx_on_state_calling(  pjsip_transaction *tsx, 

+				                pjsip_event *event);

+static pj_status_t pjsip_tsx_on_state_trying(   pjsip_transaction *tsx, 

+				                pjsip_event *event);

+static pj_status_t pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx, 

 					        pjsip_event *event);

-
-static void         tsx_timer_callback( pj_timer_heap_t *theap, 
-			                pj_timer_entry *entry);
+static pj_status_t pjsip_tsx_on_state_proceeding_uac( pjsip_transaction *tsx,

+					        pjsip_event *event);

+static pj_status_t pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, 

+					        pjsip_event *event);

+static pj_status_t pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx,

+					        pjsip_event *event);

+static pj_status_t pjsip_tsx_on_state_confirmed(pjsip_transaction *tsx, 

+					        pjsip_event *event);

+static pj_status_t pjsip_tsx_on_state_terminated(pjsip_transaction *tsx, 

+					        pjsip_event *event);

+static pj_status_t pjsip_tsx_on_state_destroyed(pjsip_transaction *tsx, 

+					        pjsip_event *event);

+

+static void         tsx_timer_callback( pj_timer_heap_t *theap, 

+			                pj_timer_entry *entry);

 static int          tsx_send_msg( pjsip_transaction *tsx, 

-                                  pjsip_tx_data *tdata);
+                                  pjsip_tx_data *tdata);

 static void         lock_tsx( pjsip_transaction *tsx, struct 

-                               tsx_lock_data *lck );
-static pj_status_t  unlock_tsx( pjsip_transaction *tsx, 
-                               struct tsx_lock_data *lck );
-
-/* State handlers for UAC, indexed by state */
-static int  (*tsx_state_handler_uac[PJSIP_TSX_STATE_MAX])(pjsip_transaction *,
-							  pjsip_event *) = 
-{
-    &pjsip_tsx_on_state_null,
-    &pjsip_tsx_on_state_calling,
-    &pjsip_tsx_on_state_trying,
-    &pjsip_tsx_on_state_proceeding_uac,
-    &pjsip_tsx_on_state_completed_uac,
-    &pjsip_tsx_on_state_confirmed,
-    &pjsip_tsx_on_state_terminated,
-    &pjsip_tsx_on_state_destroyed,
-};
-
-/* State handlers for UAS */
-static int  (*tsx_state_handler_uas[PJSIP_TSX_STATE_MAX])(pjsip_transaction *, 
-							  pjsip_event *) = 
-{
-    &pjsip_tsx_on_state_null,
-    &pjsip_tsx_on_state_calling,
-    &pjsip_tsx_on_state_trying,
-    &pjsip_tsx_on_state_proceeding_uas,
-    &pjsip_tsx_on_state_completed_uas,
-    &pjsip_tsx_on_state_confirmed,
-    &pjsip_tsx_on_state_terminated,
-    &pjsip_tsx_on_state_destroyed,
-};
-
-/*
- * Get transaction state name.
- */
-PJ_DEF(const char *) pjsip_tsx_state_str(pjsip_tsx_state_e state)
-{
-    return state_str[state];
-}
-
-/*
- * Get the role name.
- */
-PJ_DEF(const char *) pjsip_role_name(pjsip_role_e role)
-{
-    return role_name[role];
-}
-
-
-/*
- * Create transaction key for RFC2543 compliant messages, which don't have
- * unique branch parameter in the top most Via header.
- *
- * INVITE requests matches a transaction if the following attributes
- * match the original request:
- *	- Request-URI
- *	- To tag
- *	- From tag
- *	- Call-ID
- *	- CSeq
- *	- top Via header
- *
- * CANCEL matching is done similarly as INVITE, except:
- *	- CSeq method will differ
- *	- To tag is not matched.
- *
- * ACK matching is done similarly, except that:
- *	- method of the CSeq will differ,
- *	- To tag is matched to the response sent by the server transaction.
- *
- * The transaction key is constructed from the common components of above
- * components. Additional comparison is needed to fully match a transaction.
- */
-static pj_status_t create_tsx_key_2543( pj_pool_t *pool,
-			                pj_str_t *str,
-			                pjsip_role_e role,
-			                const pjsip_method *method,
-			                const pjsip_rx_data *rdata )
-{
-#define SEPARATOR   '$'
-    char *key, *p, *end;
-    int len;
-    pj_size_t len_required;
-    pjsip_uri *req_uri;
-    pj_str_t *host;
-
-    PJ_ASSERT_RETURN(pool && str && method && rdata, PJ_EINVAL);
-    PJ_ASSERT_RETURN(rdata->msg, PJ_EINVAL);
-    PJ_ASSERT_RETURN(rdata->via, PJSIP_EMISSINGHDR);
-    PJ_ASSERT_RETURN(rdata->cseq, PJSIP_EMISSINGHDR);
-    PJ_ASSERT_RETURN(rdata->from, PJSIP_EMISSINGHDR);
-
-    host = &rdata->via->sent_by.host;
-    req_uri = (pjsip_uri*)rdata->msg->line.req.uri;
-
-    /* Calculate length required. */
-    len_required = 9 +			    /* CSeq number */
-		   rdata->from->tag.slen +   /* From tag. */
-		   rdata->call_id.slen +    /* Call-ID */
-		   host->slen +		    /* Via host. */
-		   9 +			    /* Via port. */
-		   16;			    /* Separator+Allowance. */
-    key = p = pj_pool_alloc(pool, len_required);
-    end = p + len_required;
-
-    /* Add role. */
-    *p++ = (char)(role==PJSIP_ROLE_UAC ? 'c' : 's');
-    *p++ = SEPARATOR;
-
-    /* Add Request-URI */
-    /* This is BUG!
-     * Response doesn't have Request-URI!
-     *
-    len = req_uri->vptr->print( PJSIP_URI_IN_REQ_URI, req_uri, p, end-p );
-    p += len;
-    *p++ = SEPARATOR;
-     */
-
-    /* Add method, except when method is INVITE or ACK. */
-    if (method->id != PJSIP_INVITE_METHOD && method->id != PJSIP_ACK_METHOD) {
-	pj_memcpy(p, method->name.ptr, method->name.slen);
-	p += method->name.slen;
-	*p++ = '$';
-    }
-
-    /* Add CSeq (only the number). */
-    len = pj_utoa(rdata->cseq->cseq, p);
-    p += len;
-    *p++ = SEPARATOR;
-
-    /* Add From tag. */
-    len = rdata->from->tag.slen;
-    pj_memcpy( p, rdata->from->tag.ptr, len);
-    p += len;
-    *p++ = SEPARATOR;
-
-    /* Add Call-ID. */
-    len = rdata->call_id.slen;
-    pj_memcpy( p, rdata->call_id.ptr, len );
-    p += len;
-    *p++ = SEPARATOR;
-
-    /* Add top Via header. 
-     * We don't really care whether the port contains the real port (because
-     * it can be omited if default port is used). Anyway this function is 
-     * only used to match request retransmission, and we expect that the 
-     * request retransmissions will contain the same port.
-     */
-    pj_memcpy(p, host->ptr, host->slen);
-    p += host->slen;
-    *p++ = ':';
-
-    len = pj_utoa(rdata->via->sent_by.port, p);
-    p += len;
-    *p++ = SEPARATOR;
-    
-    *p++ = '\0';
-
-    /* Done. */
-    str->ptr = key;
-    str->slen = p-key;
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Create transaction key for RFC3161 compliant system.
- */
-static pj_status_t create_tsx_key_3261( pj_pool_t *pool,
-		                        pj_str_t *key,
-		                        pjsip_role_e role,
-		                        const pjsip_method *method,
-		                        const pj_str_t *branch)
-{
-    char *p;
-
-    PJ_ASSERT_RETURN(pool && key && method && branch, PJ_EINVAL);
-
-    p = key->ptr = pj_pool_alloc(pool, branch->slen + method->name.slen + 4 );
-    
-    /* Add role. */
-    *p++ = (char)(role==PJSIP_ROLE_UAC ? 'c' : 's');
-    *p++ = SEPARATOR;
-
-    /* Add method, except when method is INVITE or ACK. */
-    if (method->id != PJSIP_INVITE_METHOD && method->id != PJSIP_ACK_METHOD) {
-	pj_memcpy(p, method->name.ptr, method->name.slen);
-	p += method->name.slen;
-	*p++ = '$';
-    }
-
-    /* Add branch ID. */
-    pj_memcpy(p, branch->ptr, branch->slen);
-    p += branch->slen;
-
-    /* Set length */
-    key->slen = p - key->ptr;
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Create key from the incoming data, to be used to search the transaction
- * in the transaction hash table.
- */
-PJ_DEF(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key, 
-				          pjsip_role_e role, 
-				          const pjsip_method *method, 
-				          const pjsip_rx_data *rdata)
-{
-    pj_str_t rfc3261_branch = {PJSIP_RFC3261_BRANCH_ID, 
-                               PJSIP_RFC3261_BRANCH_LEN};
-
-
-    /* Get the branch parameter in the top-most Via.
-     * If branch parameter is started with "z9hG4bK", then the message was
-     * generated by agent compliant with RFC3261. Otherwise, it will be
-     * handled as RFC2543.
-     */
-    const pj_str_t *branch = &rdata->via->branch_param;
-
-    if (pj_strncmp(branch,&rfc3261_branch,PJSIP_RFC3261_BRANCH_LEN)==0) {
-
-	/* Create transaction key. */
-	return create_tsx_key_3261(pool, key, role, method, branch);
-
-    } else {
-	/* Create the key for the message. This key will be matched up 
-         * with the transaction key. For RFC2563 transactions, the 
-         * transaction key was created by the same function, so it will 
-         * match the message.
-	 */
-	return create_tsx_key_2543( pool, key, role, method, rdata );
-    }
-}
-
-
-/*
- * Create new transaction.
- */
-pj_status_t pjsip_tsx_create( pj_pool_t *pool,
-			      pjsip_endpoint *endpt,
-                              pjsip_transaction **p_tsx)
-{
-    pjsip_transaction *tsx;
-    pj_status_t status;
-
-    tsx = pj_pool_calloc(pool, 1, sizeof(pjsip_transaction));
-
-    tsx->pool = pool;
-    tsx->endpt = endpt;
-    tsx->retransmit_timer.id = TSX_TIMER_RETRANSMISSION;
-    tsx->retransmit_timer._timer_id = -1;
-    tsx->retransmit_timer.user_data = tsx;
-    tsx->retransmit_timer.cb = &tsx_timer_callback;
-    tsx->timeout_timer.id = TSX_TIMER_TIMEOUT;
-    tsx->timeout_timer._timer_id = -1;
-    tsx->timeout_timer.user_data = tsx;
-    tsx->timeout_timer.cb = &tsx_timer_callback;
-    pj_sprintf(tsx->obj_name, "tsx%p", tsx);
-    status = pj_mutex_create_recursive(pool, "mtsx%p", &tsx->mutex);
-    if (status != PJ_SUCCESS) {
-	return status;
-    }
-
-    *p_tsx = tsx;
-    return PJ_SUCCESS;
-}
-
-/*
- * Lock transaction and set the value of Thread Local Storage.
- */
-static void lock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck)
-{
-    struct tsx_lock_data *prev_data;
-
-    pj_mutex_lock(tsx->mutex);
-    prev_data = (struct tsx_lock_data *) 
-                    pj_thread_local_get(pjsip_tsx_lock_tls_id);
-    lck->prev = prev_data;
-    lck->tsx = tsx;
-    lck->is_alive = 1;
-    pj_thread_local_set(pjsip_tsx_lock_tls_id, lck);
-}
-
-
-/*
- * Unlock transaction.
- * This will selectively unlock the mutex ONLY IF the transaction has not been 
- * destroyed. The function knows whether the transaction has been destroyed
- * because when transaction is destroyed the is_alive flag for the transaction
- * will be set to zero.
- */
-static pj_status_t unlock_tsx( pjsip_transaction *tsx, 
-                               struct tsx_lock_data *lck)
-{
-    pj_assert( (void*)pj_thread_local_get(pjsip_tsx_lock_tls_id) == lck);
-    pj_assert( lck->tsx == tsx );
-    pj_thread_local_set(pjsip_tsx_lock_tls_id, lck->prev);
-    if (lck->is_alive)
-	pj_mutex_unlock(tsx->mutex);
-
-    return lck->is_alive ? PJ_SUCCESS : PJSIP_ETSXDESTROYED;
-}
-
-/*
- * Set transaction state, and inform TU about the transaction state change.
- */
-static void tsx_set_state( pjsip_transaction *tsx,
-			   pjsip_tsx_state_e state,
-			   pjsip_event_id_e event_src_type,
-                           void *event_src )
-{
-    pjsip_event e;
-
-    PJ_LOG(4, (tsx->obj_name, "STATE %s-->%s, cause = %s",
-	       state_str[tsx->state], state_str[state], 
-               pjsip_event_str(event_src_type)));
-
-    /* Change state. */
-    tsx->state = state;
-
-    /* Update the state handlers. */
-    if (tsx->role == PJSIP_ROLE_UAC) {
-	tsx->state_handler = tsx_state_handler_uac[state];
-    } else {
-	tsx->state_handler = tsx_state_handler_uas[state];
-    }
-
-    /* Inform TU */
-    PJSIP_EVENT_INIT_TSX_STATE(e, tsx, event_src_type, event_src);
-    pjsip_endpt_send_tsx_event( tsx->endpt, &e  );
-
-    /* When the transaction is terminated, release transport, and free the
-     * saved last transmitted message.
-     */
-    if (state == PJSIP_TSX_STATE_TERMINATED) {
-
-	/* Decrement transport reference counter. */
-	if (tsx->transport && 
-            tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL) 
-        {
-	    pjsip_transport_dec_ref( tsx->transport );
-	    tsx->transport = NULL;
-	}
-	/* Free last transmitted message. */
-	if (tsx->last_tx) {
-	    pjsip_tx_data_dec_ref( tsx->last_tx );
-	    tsx->last_tx = NULL;
-	}
-	/* Cancel timeout timer. */
-	if (tsx->timeout_timer._timer_id != -1) {
-	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
-	    tsx->timeout_timer._timer_id = -1;
-	}
-	/* Cancel retransmission timer. */
-	if (tsx->retransmit_timer._timer_id != -1) {
-	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-	    tsx->retransmit_timer._timer_id = -1;
-	}
-
-	/* If transport is not pending, reschedule timeout timer to
-	 * destroy this transaction.
-	 */
-	if (tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL) {
-	    pj_time_val timeout = {0, 0};
-	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-					&timeout);
-	}
-
-    } else if (state == PJSIP_TSX_STATE_DESTROYED) {
-
-	/* Clear TLS, so that mutex will not be unlocked */
-	struct tsx_lock_data *lck = pj_thread_local_get(pjsip_tsx_lock_tls_id);
-	while (lck) {
-	    if (lck->tsx == tsx) {
-		lck->is_alive = 0;
-	    }
-	    lck = lck->prev;
-	}
-    }
-}
-
-/*
- * Look-up destination address and select which transport to be used to send
- * the request message. The procedure used here follows the guidelines on 
- * sending the request in RFC3261 chapter 8.1.2.
- *
- * This function also modifies the message (request line and Route headers)
- * accordingly.
- */
-static pj_status_t tsx_process_route( pjsip_transaction *tsx,
-				      pjsip_tx_data *tdata,
-				      pjsip_host_port *send_addr )
-{
-    const pjsip_uri *new_request_uri, *target_uri;
-    const pjsip_name_addr *topmost_route_uri;
-    pjsip_route_hdr *first_route_hdr, *last_route_hdr;
-    
-    pj_assert(tdata->msg->type == PJSIP_REQUEST_MSG);
-
-    /* Get the first "Route" header from the message. If the message doesn't
-     * have any "Route" headers but the endpoint has, then copy the "Route"
-     * headers from the endpoint first.
-     */
-    last_route_hdr = first_route_hdr = 
-	pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL);
-    if (first_route_hdr) {
-	topmost_route_uri = &first_route_hdr->name_addr;
-	while (last_route_hdr->next != (void*)&tdata->msg->hdr) {
-	    pjsip_route_hdr *hdr;
-	    hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, 
-                                     last_route_hdr->next);
-	    if (!hdr)
-		break;
-	    last_route_hdr = hdr;
-	}
-    } else {
-	const pjsip_route_hdr *hdr_list;
-	hdr_list = (pjsip_route_hdr*)pjsip_endpt_get_routing(tsx->endpt);
-	if (hdr_list->next != hdr_list) {
-	    const pjsip_route_hdr *hdr = (pjsip_route_hdr*)hdr_list->next;
-	    first_route_hdr = NULL;
-	    topmost_route_uri = &hdr->name_addr;
-	    do {
-		last_route_hdr = pjsip_hdr_shallow_clone(tdata->pool, hdr);
-		if (first_route_hdr == NULL)
-		    first_route_hdr = last_route_hdr;
-		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)last_route_hdr);
-		hdr = hdr->next;
-	    } while (hdr != hdr_list);
-	} else {
-	    topmost_route_uri = NULL;
-	}
-    }
-
-    /* If Route headers exist, and the first element indicates loose-route,
-     * the URI is taken from the Request-URI, and we keep all existing Route
-     * headers intact.
-     * If Route headers exist, and the first element DOESN'T indicate loose
-     * route, the URI is taken from the first Route header, and remove the
-     * first Route header from the message.
-     * Otherwise if there's no Route headers, the URI is taken from the
-     * Request-URI.
-     */
-    if (topmost_route_uri) {
-	pj_bool_t has_lr_param;
-
-	if (PJSIP_URI_SCHEME_IS_SIP(topmost_route_uri) ||
-	    PJSIP_URI_SCHEME_IS_SIPS(topmost_route_uri))
-	{
-	    const pjsip_url *url = pjsip_uri_get_uri((void*)topmost_route_uri);
-	    has_lr_param = url->lr_param;
-	} else {
-	    has_lr_param = 0;
-	}
-
-	if (has_lr_param) {
-	    new_request_uri = tdata->msg->line.req.uri;
-	    /* We shouldn't need to delete topmost Route if it has lr param.
-	     * But seems like it breaks some proxy implementation, so we
-	     * delete it anyway.
-	     */
-	    /*
-	    pj_list_erase(first_route_hdr);
-	    if (first_route_hdr == last_route_hdr)
-		last_route_hdr = NULL;
-	    */
-	} else {
-	    new_request_uri = pjsip_uri_get_uri((void*)topmost_route_uri);
-	    pj_list_erase(first_route_hdr);
-	    if (first_route_hdr == last_route_hdr)
-		last_route_hdr = NULL;
-	}
-
-	target_uri = (pjsip_uri*)topmost_route_uri;
-
-    } else {
-	target_uri = new_request_uri = tdata->msg->line.req.uri;
-    }
-
-    /* The target URI must be a SIP/SIPS URL so we can resolve it's address.
-     * Otherwise we're in trouble (i.e. there's no host part in tel: URL).
-     */
-    pj_memset(send_addr, 0, sizeof(*send_addr));
-
-    if (PJSIP_URI_SCHEME_IS_SIPS(target_uri)) {
-	pjsip_uri *uri = (pjsip_uri*) target_uri;
-	const pjsip_url *url = (const pjsip_url*)pjsip_uri_get_uri(uri);
-	send_addr->flag |= (PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_RELIABLE);
-	pj_strdup(tdata->pool, &send_addr->host, &url->host);
-        send_addr->port = url->port;
-	send_addr->type = 
-            pjsip_transport_get_type_from_name(&url->transport_param);
-
-    } else if (PJSIP_URI_SCHEME_IS_SIP(target_uri)) {
-	pjsip_uri *uri = (pjsip_uri*) target_uri;
-	const pjsip_url *url = (const pjsip_url*)pjsip_uri_get_uri(uri);
-	pj_strdup(tdata->pool, &send_addr->host, &url->host);
-	send_addr->port = url->port;
-	send_addr->type = 
-            pjsip_transport_get_type_from_name(&url->transport_param);
-#if PJ_HAS_TCP
-	if (send_addr->type == PJSIP_TRANSPORT_TCP || 
-	    send_addr->type == PJSIP_TRANSPORT_SCTP) 
-	{
-	    send_addr->flag |= PJSIP_TRANSPORT_RELIABLE;
-	}
-#endif
-    } else {
-        pj_assert(!"Unsupported URI scheme!");
-	return PJSIP_EINVALIDSCHEME;
-    }
-
-    /* If target URI is different than request URI, replace 
-     * request URI add put the original URI in the last Route header.
-     */
-    if (new_request_uri && new_request_uri!=tdata->msg->line.req.uri) {
-	pjsip_route_hdr *route = pjsip_route_hdr_create(tdata->pool);
-	route->name_addr.uri = tdata->msg->line.req.uri;
-	if (last_route_hdr)
-	    pj_list_insert_after(last_route_hdr, route);
-	else
-	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)route);
-	tdata->msg->line.req.uri = (pjsip_uri*)new_request_uri;
-    }
-
-    /* Success. */
-    return PJ_SUCCESS;  
-}
-
-
-/*
- * Callback from the transport job.
- * This callback is called when asychronous transport connect() operation
- * has completed, with or without error.
- */
-static void tsx_transport_callback(pjsip_transport_t *tr, 
-				   void *token, 
-				   pj_status_t status)
-{
-    char addr[PJ_MAX_HOSTNAME];
-    pjsip_transaction *tsx = token;
-    struct tsx_lock_data lck;
-
-    pj_memcpy(addr, tsx->dest_name.host.ptr, tsx->dest_name.host.slen);
-    addr[tsx->dest_name.host.slen] = '\0';
-
-
-    if (status == PJ_SUCCESS) {
-	PJ_LOG(4, (tsx->obj_name, "%s connected to %s:%d",
-				  pjsip_transport_get_type_name(tr),
-				  addr, tsx->dest_name.port));
-    } else {
-	PJ_LOG(4, (tsx->obj_name, "%s unable to connect to %s:%d, status=%d", 
-				  pjsip_transport_get_type_name(tr),
-				  addr, tsx->dest_name.port, status));
-    }
-
-    /* Lock transaction. */
-    lock_tsx(tsx, &lck);
-
-    if (status != PJ_SUCCESS) {
-	tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;
-	tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;
-
-	tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED,
-                      PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);
-
-	/* Unlock transaction. */
-	unlock_tsx(tsx, &lck);
-	return;
-    }
-
-    /* See if transaction has already been terminated. 
-     * If so, schedule to destroy the transaction.
-     */
-    if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
-	pj_time_val timeout = {0, 0};
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-				    &timeout);
-
-	/* Unlock transaction. */
-	unlock_tsx(tsx, &lck);
-	return;
-    }
-
-    /* Add reference counter to the transport. */
-    pjsip_transport_add_ref(tr);
-
-    /* Mark transport as ready. */
-    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;
-    tsx->transport = tr;
-
-    /* If there's a pending message to send, send it now. */
-    if (tsx->has_unsent_msg) {
-	tsx_send_msg( tsx, tsx->last_tx );
-    }
-
-    /* Unlock transaction. */
-    unlock_tsx(tsx, &lck);
-}
-
-/*
- * Callback from the resolver job.
- */
-static void tsx_resolver_callback(pj_status_t status,
-				  void *token,
-				  const struct pjsip_server_addresses *addr)
-{
-    pjsip_transaction *tsx = token;
-    struct tsx_lock_data lck;
-
-    PJ_LOG(4, (tsx->obj_name, "resolver job complete, status=%d", status));
-
-    if (status != PJ_SUCCESS || addr->count == 0) {
-	lock_tsx(tsx, &lck);
-	tsx->status_code = PJSIP_SC_TSX_RESOLVE_ERROR;
-	tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, 
-                      PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);
-	unlock_tsx(tsx, &lck);
-	return;
-    }
-
-    /* Lock transaction. */
-    lock_tsx(tsx, &lck);
-
-    /* Copy server addresses. */
-    pj_memcpy(&tsx->remote_addr, addr, sizeof(*addr));
-
-    /* Create/find the transport for the remote address. */
-    PJ_LOG(5,(tsx->obj_name, "tsx getting transport for %s:%d",
-			     pj_inet_ntoa(addr->entry[0].addr.sin_addr),
-			     pj_ntohs(addr->entry[0].addr.sin_port)));
-
-    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_CONNECTING;
-    pjsip_endpt_get_transport(tsx->endpt, tsx->pool,
-			      addr->entry[0].type, &addr->entry[0].addr,
-			      tsx,
-			      &tsx_transport_callback);
-
-    /* Unlock transaction */
-    unlock_tsx(tsx, &lck);
-
-    /* There should be nothing to do after this point.
-     * Execution for the transaction will resume when the callback for the 
-     * transport is called.
-     */
-}
-
-/*
- * Initialize the transaction as UAC transaction.
- */
-PJ_DEF(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, 
-					pjsip_tx_data *tdata)
-{
-    pjsip_msg *msg;
-    pjsip_cseq_hdr *cseq;
-    pjsip_via_hdr *via;
-    pj_status_t status;
-    struct tsx_lock_data lck;
-
-    PJ_LOG(4,(tsx->obj_name, "initializing tsx as UAC (tdata=%p)", tdata));
-
-    /* Lock transaction. */
-    lock_tsx(tsx, &lck);
-
-    /* Keep shortcut */
-    msg = tdata->msg;
-
-    /* Role is UAC. */
-    tsx->role = PJSIP_ROLE_UAC;
-
-    /* Save method. */
-    pjsip_method_copy( tsx->pool, &tsx->method, &msg->line.req.method);
-
-    /* Generate Via header if it doesn't exist. */
-    via = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, NULL);
-    if (via == NULL) {
-	via = pjsip_via_hdr_create(tdata->pool);
-	pjsip_msg_insert_first_hdr(msg, (pjsip_hdr*) via);
-    }
-
-    if (via->branch_param.slen == 0) {
-	pj_str_t tmp;
-	via->branch_param.ptr = pj_pool_alloc(tsx->pool, PJSIP_MAX_BRANCH_LEN);
-	via->branch_param.slen = PJSIP_MAX_BRANCH_LEN;
-	pj_memcpy(via->branch_param.ptr, PJSIP_RFC3261_BRANCH_ID, 
-		  PJSIP_RFC3261_BRANCH_LEN);
-
-	tmp.ptr = via->branch_param.ptr + PJSIP_RFC3261_BRANCH_LEN;
-	pj_generate_unique_string( &tmp );
-
-        /* Save branch parameter. */
-        tsx->branch = via->branch_param;
-    } else {
-        /* Copy branch parameter. */
-        pj_strdup(tsx->pool, &tsx->branch, &via->branch_param);
-    }
-
-
-    /* Generate transaction key. */
-    status = create_tsx_key_3261( tsx->pool, &tsx->transaction_key,
-			          PJSIP_ROLE_UAC, &tsx->method, 
-			          &via->branch_param);
-    if (status != PJ_SUCCESS) {
-        unlock_tsx(tsx, &lck);
-        return status;
-    }
-
-    PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen,
-	       tsx->transaction_key.ptr));
-
-    /* Save CSeq. */
-    cseq = pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL);
-    if (!cseq) {
-	pj_assert(!"CSeq header not present in outgoing message!");
-        unlock_tsx(tsx, &lck);
-	return PJSIP_EMISSINGHDR;
-    }
-    tsx->cseq = cseq->cseq;
-
-
-    /* Begin with State_Null.
-     * Manually set-up the state becase we don't want to call the callback.
-     */
-    tsx->state = PJSIP_TSX_STATE_NULL;
-    tsx->state_handler = &pjsip_tsx_on_state_null;
-
-    /* Get destination name from the message. */
-    status = tsx_process_route(tsx, tdata, &tsx->dest_name);
-    if (status != PJ_SUCCESS) {
-	tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;
-	tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;
-	tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, 
-                      PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);
-	unlock_tsx(tsx, &lck);
-	return status;
-    }
-
-    /* Resolve destination.
-     * This will start asynchronous resolver job, and when it finishes, 
-     * the callback will be called.
-     */
-    PJ_LOG(5,(tsx->obj_name, "tsx resolving destination %.*s:%d",
-			     tsx->dest_name.host.slen, 
-			     tsx->dest_name.host.ptr,
-			     tsx->dest_name.port));
-
-    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_RESOLVING;
-    pjsip_endpt_resolve( tsx->endpt, tsx->pool, &tsx->dest_name, 
-			 tsx, &tsx_resolver_callback);
-
-    /* There should be nothing to do after this point. 
-     * Execution for the transaction will resume when the resolver callback is
-     * called.
-     */
-
-    /* Unlock transaction and return.
-     * If transaction has been destroyed WITHIN the current thread, the 
-     * unlock_tsx() function will return -1.
-     */
-    return unlock_tsx(tsx, &lck);
-}
-
-
-/*
- * Initialize the transaction as UAS transaction.
- */
-PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx, 
-					pjsip_rx_data *rdata)
-{
-    pjsip_msg *msg = rdata->msg;
-    pj_str_t *branch;
-    pjsip_cseq_hdr *cseq;
-    pj_status_t status;
-    struct tsx_lock_data lck;
-
-    PJ_LOG(4,(tsx->obj_name, "initializing tsx as UAS (rdata=%p)", rdata));
-
-    /* Lock transaction. */
-    lock_tsx(tsx, &lck);
-
-    /* Keep shortcut to message */
-    msg = rdata->msg;
-
-    /* Role is UAS */
-    tsx->role = PJSIP_ROLE_UAS;
-
-    /* Save method. */
-    pjsip_method_copy( tsx->pool, &tsx->method, &msg->line.req.method);
-
-    /* Get transaction key either from branch for RFC3261 message, or
-     * create transaction key.
-     */
-    status = pjsip_tsx_create_key(tsx->pool, &tsx->transaction_key, 
-                                  PJSIP_ROLE_UAS, &tsx->method, rdata);
-    if (status != PJ_SUCCESS) {
-        unlock_tsx(tsx, &lck);
-        return status;
-    }
-
-    /* Duplicate branch parameter for transaction. */
-    branch = &rdata->via->branch_param;
-    pj_strdup(tsx->pool, &tsx->branch, branch);
-
-    PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen,
-	       tsx->transaction_key.ptr));
-
-    /* Save CSeq */
-    cseq = rdata->cseq;
-    tsx->cseq = cseq->cseq;
-
-    /* Begin with state NULL
-     * Manually set-up the state becase we don't want to call the callback.
-     */
-    tsx->state = PJSIP_TSX_STATE_NULL; 
-    tsx->state_handler = &pjsip_tsx_on_state_null;
-
-    /* Get the transport to send the response. 
-     * According to section 18.2.2 of RFC3261, if the transport is reliable
-     * then the response must be sent using that transport.
-     */
-    /* In addition, RFC 3581 says, if Via has "rport" parameter specified,
-     * then return the response using the same transport.
-     */
-    if (PJSIP_TRANSPORT_IS_RELIABLE(rdata->transport) || 
-	rdata->via->rport_param >= 0) 
-    {
-	tsx->transport = rdata->transport;
-	pjsip_transport_add_ref(tsx->transport);
-	tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;
-
-	tsx->current_addr = 0;
-	tsx->remote_addr.count = 1;
-	tsx->remote_addr.entry[0].type = 
-		pjsip_transport_get_type(tsx->transport);
-	pj_memcpy(&tsx->remote_addr.entry[0].addr, 
-		  &rdata->addr, rdata->addr_len);
-	
-    } else {
-	pj_status_t status;
-
-	status = pjsip_get_response_addr(tsx->pool, rdata->transport,
-					 rdata->via, &tsx->dest_name);
-	if (status != PJ_SUCCESS) {
-	    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;
-	    tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;
-	    tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, 
-                          PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);
-	    unlock_tsx(tsx, &lck);
-	    return status;
-	}
-
-	/* Resolve destination.
-	 * This will start asynchronous resolver job, and when it finishes, 
-	 * the callback will be called.
-	 */
-	PJ_LOG(5,(tsx->obj_name, "tsx resolving destination %.*s:%d",
-				 tsx->dest_name.host.slen, 
-				 tsx->dest_name.host.ptr,
-				 tsx->dest_name.port));
-
-	tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_RESOLVING;
-	pjsip_endpt_resolve( tsx->endpt, tsx->pool, &tsx->dest_name, 
-			     tsx, &tsx_resolver_callback);
-    }
-    
-    /* There should be nothing to do after this point. 
-     * Execution for the transaction will resume when the resolver callback is
-     * called.
-     */
-
-    /* Unlock transaction and return.
-     * If transaction has been destroyed WITHIN the current thread, the 
-     * unlock_tsx() function will return -1.
-     */
-    return unlock_tsx(tsx, &lck);
-}
-
-/*
- * Callback when timer expires.
- */
-static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry)
-{
-    pjsip_event event;
-    pjsip_transaction *tsx = entry->user_data;
-    struct tsx_lock_data lck;
-
-    PJ_UNUSED_ARG(theap);
-
-    PJ_LOG(5,(tsx->obj_name, "got timer event (%s timer)", 
-	     (entry->id==TSX_TIMER_RETRANSMISSION ? "Retransmit" : "Timeout")));
-
-
-    if (entry->id == TSX_TIMER_RETRANSMISSION) {
-        PJSIP_EVENT_INIT_TIMER(event, &tsx->retransmit_timer);
-    } else {
-        PJSIP_EVENT_INIT_TIMER(event, &tsx->timeout_timer);
-    }
-
-    /* Dispatch event to transaction. */
-    lock_tsx(tsx, &lck);
-    (*tsx->state_handler)(tsx, &event);
-    unlock_tsx(tsx, &lck);
-}
-
-/*
- * Transmit ACK message for 2xx/INVITE with this transaction. The ACK for
- * non-2xx/INVITE is automatically sent by the transaction.
- * This operation is only valid if the transaction is configured to handle ACK
- * (tsx->handle_ack is non-zero). If this attribute is not set, then the
- * transaction will comply with RFC-3261, i.e. it will set itself to 
- * TERMINATED state when it receives 2xx/INVITE.
- */
-PJ_DEF(void) pjsip_tsx_on_tx_ack( pjsip_transaction *tsx, pjsip_tx_data *tdata)
-{
-    pjsip_msg *msg;
-    pjsip_host_port dest_addr;
-    pjsip_via_hdr *via;
-    struct tsx_lock_data lck;
-    pj_status_t status = PJ_SUCCESS;
-
-    /* Lock tsx. */
-    lock_tsx(tsx, &lck);
-
-    pj_assert(tsx->handle_ack != 0);
-    
-    msg = tdata->msg;
-
-    /* Generate branch parameter if it doesn't exist. */
-    via = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, NULL);
-    if (via == NULL) {
-	via = pjsip_via_hdr_create(tdata->pool);
-	pjsip_msg_add_hdr(msg, (pjsip_hdr*) via);
-    }
-
-    if (via->branch_param.slen == 0) {
-	via->branch_param = tsx->branch;
-    } else {
-	pj_assert( pj_strcmp(&via->branch_param, &tsx->branch) == 0 );
-    }
-
-    /* Get destination name from the message. */
-    status = tsx_process_route(tsx, tdata, &dest_addr);
-    if (status != 0){
-	goto on_error;
-    }
-
-    /* Compare message's destination name with transaction's destination name.
-     * If NOT equal, then we'll have to resolve the destination.
-     */
-    if (dest_addr.type == tsx->dest_name.type &&
-	dest_addr.flag == tsx->dest_name.flag &&
-	dest_addr.port == tsx->dest_name.port &&
-	pj_stricmp(&dest_addr.host, &tsx->dest_name.host) == 0)
-    {
-	/* Equal destination. We can use current transport. */
-	pjsip_tsx_on_tx_msg(tsx, tdata);
-	unlock_tsx(tsx, &lck);
-	return;
-
-    }
-
-    /* New destination; we'll have to resolve host and create new transport. */
-    pj_memcpy(&tsx->dest_name, &dest_addr, sizeof(dest_addr));
-    pj_strdup(tsx->pool, &tsx->dest_name.host, &dest_addr.host);
-
-    PJ_LOG(5,(tsx->obj_name, "tsx resolving destination %.*s:%d",
-			     tsx->dest_name.host.slen, 
-			     tsx->dest_name.host.ptr,
-			     tsx->dest_name.port));
-
-    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_RESOLVING;
-    pjsip_transport_dec_ref(tsx->transport);
-    tsx->transport = NULL;
-
-    /* Put the message in queue. */
-    pjsip_tsx_on_tx_msg(tsx, tdata);
-
-    /* This is a bug!
-     * We shouldn't change transaction's state before actually sending the
-     * message. Otherwise transaction will terminate before message is sent,
-     * and timeout timer will be scheduled.
-     */
-    PJ_TODO(TSX_DONT_CHANGE_STATE_BEFORE_SENDING_ACK)
-
-    /* 
-     * This will start asynchronous resolver job, and when it finishes, 
-     * the callback will be called.
-     */
-
-    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_RESOLVING;
-    pjsip_endpt_resolve( tsx->endpt, tsx->pool, &tsx->dest_name, 
-			 tsx, &tsx_resolver_callback);
-
-    unlock_tsx(tsx, &lck);
-
-    /* There should be nothing to do after this point. 
-     * Execution for the transaction will resume when the resolver callback is
-     * called.
-     */
-    return;
-
-on_error:
-    /* Failure condition. 
-     * Send TERMINATED event.
-     */
-    tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;
-
-    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                   PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);
-
-    unlock_tsx(tsx, &lck);
-}
-
-
-/*
- * This function is called by TU to send a message.
- */
-PJ_DEF(void) pjsip_tsx_on_tx_msg( pjsip_transaction *tsx,
-				  pjsip_tx_data *tdata )
-{
-    pjsip_event event;
-    struct tsx_lock_data lck;
-    pj_status_t status;
-
-    PJ_LOG(5,(tsx->obj_name, "Request to transmit msg on state %s (tdata=%p)",
-                             state_str[tsx->state], tdata));
-
-    PJSIP_EVENT_INIT_TX_MSG(event, tsx, tdata);
-
-    /* Dispatch to transaction. */
-    lock_tsx(tsx, &lck);
-    status = (*tsx->state_handler)(tsx, &event);
-    unlock_tsx(tsx, &lck);
-}
-
-/*
- * This function is called by endpoint when incoming message for the 
- * transaction is received.
- */
-PJ_DEF(void) pjsip_tsx_on_rx_msg( pjsip_transaction *tsx,
-				  pjsip_rx_data *rdata)
-{
-    pjsip_event event;
-    struct tsx_lock_data lck;
-    pj_status_t status;
-
-    PJ_LOG(5,(tsx->obj_name, "Incoming msg on state %s (rdata=%p)", 
-	      state_str[tsx->state], rdata));
-
-    PJSIP_EVENT_INIT_RX_MSG(event, tsx, rdata);
-
-    /* Dispatch to transaction. */
-    lock_tsx(tsx, &lck);
-    status = (*tsx->state_handler)(tsx, &event);
-    unlock_tsx(tsx, &lck);
-}
-
-/*
- * Forcely terminate transaction.
- */
-PJ_DEF(void) pjsip_tsx_terminate( pjsip_transaction *tsx, int code )
-{
-    struct tsx_lock_data lck;
-
-    lock_tsx(tsx, &lck);
-    tsx->status_code = code;
-    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                   PJSIP_EVENT_USER, NULL);
-
-    unlock_tsx(tsx, &lck);
-}
-
-/*
- * Send message to the transport.
- * If transport is not yet available, then do nothing. The message will be
- * transmitted when transport connection completion callback is called.
- */
-static pj_status_t tsx_send_msg( pjsip_transaction *tsx, 
-                                 pjsip_tx_data *tdata)
-{
-    pj_status_t status = PJ_SUCCESS;
-
-    PJ_LOG(5,(tsx->obj_name, "sending msg (tdata=%p)", tdata));
-
-    if (tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL) {
-	pj_ssize_t sent;
-	pjsip_event before_tx_event;
-
-	pj_assert(tsx->transport != NULL);
-
-	/* Make sure Via transport info is filled up properly for
-	 * requests. 
-	 */
-	if (tdata->msg->type == PJSIP_REQUEST_MSG) {
-	    const pj_sockaddr_in *addr_name;
-	    pjsip_via_hdr *via = (pjsip_via_hdr*) 
-		pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
-
-	    /* For request message, set "rport" parameter by default. */
-	    if (tdata->msg->type == PJSIP_REQUEST_MSG)
-		via->rport_param = 0;
-
-	    /* Don't update Via sent-by on retransmission. */
-	    if (via->sent_by.host.slen == 0) {
-		addr_name = pjsip_transport_get_addr_name(tsx->transport);
-		pj_strdup2(tdata->pool, &via->transport, 
-			pjsip_transport_get_type_name(tsx->transport));
-		pj_strdup2(tdata->pool, &via->sent_by.host, 
-			   pj_inet_ntoa(addr_name->sin_addr));
-		via->sent_by.port = pj_ntohs(addr_name->sin_port);
-	    }
-	}
-
-	/* Notify everybody we're about to send message. */
-        PJSIP_EVENT_INIT_PRE_TX_MSG(before_tx_event, tsx, tdata, 
-                                    tsx->retransmit_count);
-	pjsip_endpt_send_tsx_event( tsx->endpt, &before_tx_event );
-
-	tsx->has_unsent_msg = 0;
-	status = pjsip_transport_send_msg(
-		        tsx->transport, tdata,
-		        &tsx->remote_addr.entry[tsx->current_addr].addr,
-                        &sent);
-	if (status != PJ_SUCCESS) {
-	    goto on_error;
-	}
-    } else {
-	tsx->has_unsent_msg = 1;
-    }
-
-    return 0;
-
-on_error:
-    tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;
-    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                   PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);
-    return status;
-}
-
-/*
- * Retransmit last message sent.
- */
-static pj_status_t pjsip_tsx_retransmit( pjsip_transaction *tsx,
-					 int should_restart_timer)
-{
-    pj_status_t status;
-
-    PJ_LOG(4,(tsx->obj_name, "retransmiting (tdata=%p, count=%d, restart?=%d)", 
-	      tsx->last_tx, tsx->retransmit_count, should_restart_timer));
-
-    pj_assert(tsx->last_tx != NULL);
-
-    ++tsx->retransmit_count;
-
-    status = tsx_send_msg( tsx, tsx->last_tx);
-    if (status != PJ_SUCCESS) {
-	return status;
-    }
-    
-    /* Restart timer T1. */
-    if (should_restart_timer) {
-	pj_time_val timeout;
-	int msec_time = (1 << (tsx->retransmit_count)) * PJSIP_T1_TIMEOUT;
-
-	if (tsx->method.id!=PJSIP_INVITE_METHOD && msec_time>PJSIP_T2_TIMEOUT) 
-	    msec_time = PJSIP_T2_TIMEOUT;
-
-	timeout.sec = msec_time / 1000;
-	timeout.msec = msec_time % 1000;
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer, 
-				    &timeout);
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Handler for events in state Null.
- */
-static pj_status_t pjsip_tsx_on_state_null( pjsip_transaction *tsx, 
-                                            pjsip_event *event )
-{
-    pj_status_t status;
-
-    pj_assert( tsx->state == PJSIP_TSX_STATE_NULL);
-    pj_assert( tsx->last_tx == NULL );
-    pj_assert( tsx->has_unsent_msg == 0);
-
-    if (tsx->role == PJSIP_ROLE_UAS) {
-
-	/* Set state to Trying. */
-	pj_assert(event->type == PJSIP_EVENT_RX_MSG);
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, 
-                       PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
-
-    } else {
-	pjsip_tx_data *tdata = event->body.tx_msg.tdata;
-
-	/* Save the message for retransmission. */
-	tsx->last_tx = tdata;
-	pjsip_tx_data_add_ref(tdata);
-
-	/* Send the message. */
-        status = tsx_send_msg( tsx, tdata);
-	if (status != PJ_SUCCESS) {
-	    return status;
-	}
-
-	/* Start Timer B (or called timer F for non-INVITE) for transaction 
-	 * timeout.
-	 */
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-                                    &timeout_timer_val);
-
-	/* Start Timer A (or timer E) for retransmission only if unreliable 
-	 * transport is being used.
-	 */
-	if (tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL &&
-	    PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) 
-	{
-	    pjsip_endpt_schedule_timer(tsx->endpt, &tsx->retransmit_timer, 
-                                       &t1_timer_val);
-	    tsx->retransmit_count = 0;
-	}
-
-	/* Move state. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_CALLING, 
-                       PJSIP_EVENT_TX_MSG, tdata);
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * State Calling is for UAC after it sends request but before any responses
- * is received.
- */
-static pj_status_t pjsip_tsx_on_state_calling( pjsip_transaction *tsx, 
-				               pjsip_event *event )
-{
-    pj_assert(tsx->state == PJSIP_TSX_STATE_CALLING);
-    pj_assert(tsx->role == PJSIP_ROLE_UAC);
-
-    if (event->type == PJSIP_EVENT_TIMER && 
-	event->body.timer.entry == &tsx->retransmit_timer) 
-    {
-        pj_status_t status;
-
-	/* Retransmit the request. */
-        status = pjsip_tsx_retransmit( tsx, 1 );
-	if (status != PJ_SUCCESS) {
-	    return status;
-	}
-
-    } else if (event->type == PJSIP_EVENT_TIMER && 
-	       event->body.timer.entry == &tsx->timeout_timer) 
-    {
-
-	/* Cancel retransmission timer. */
-	if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {
-	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-	}
-
-	/* Set status code */
-	tsx->status_code = PJSIP_SC_TSX_TIMEOUT;
-
-	/* Inform TU. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                       PJSIP_EVENT_TIMER, &tsx->timeout_timer);
-
-	/* Transaction is destroyed */
-	return PJSIP_ETSXDESTROYED;
-
-    } else if (event->type == PJSIP_EVENT_RX_MSG) {
-	int code;
-
-	/* Cancel retransmission timer A. */
-	if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0)
-	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);
-
-	/* Cancel timer B (transaction timeout) */
-	pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
-
-	/* Discard retransmission message if it is not INVITE.
-	 * The INVITE tdata is needed in case we have to generate ACK for
-	 * the final response.
-	 */
-	/* Keep last_tx for authorization. */
-	code = event->body.rx_msg.rdata->msg->line.status.code;
-	if (tsx->method.id != PJSIP_INVITE_METHOD && code!=401 && code!=407) {
-	    pjsip_tx_data_dec_ref(tsx->last_tx);
-	    tsx->last_tx = NULL;
-	}
-
-	/* Processing is similar to state Proceeding. */
-	pjsip_tsx_on_state_proceeding_uac( tsx, event);
-
-    } else {
-	pj_assert(0);
-        return PJ_EBUG;
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * State Trying is for UAS after it received request but before any responses
- * is sent.
- * Note: this is different than RFC3261, which can use Trying state for
- *	 non-INVITE client transaction (bug in RFC?).
- */
-static pj_status_t pjsip_tsx_on_state_trying( pjsip_transaction *tsx, 
-                                              pjsip_event *event)
-{
-    pj_status_t status;
-
-    pj_assert(tsx->state == PJSIP_TSX_STATE_TRYING);
-
-    /* This state is only for UAS */
-    pj_assert(tsx->role == PJSIP_ROLE_UAS);
-
-    /* Better be transmission of response message.
-     * If we've got request retransmission, this means that the TU hasn't
-     * transmitted any responses within 500 ms, which is not allowed. If
-     * this happens, just ignore the event (we couldn't retransmit last
-     * response because we haven't sent any!).
-     */
-    //pj_assert(event->type == PJSIP_EVENT_TX_MSG);
-    if (event->type != PJSIP_EVENT_TX_MSG) {
-	return PJ_SUCCESS;
-    }
-
-    /* The rest of the processing of the event is exactly the same as in
-     * "Proceeding" state.
-     */
-    status = pjsip_tsx_on_state_proceeding_uas( tsx, event);
-
-    /* Inform the TU of the state transision if state is still State_Trying */
-    if (status==PJ_SUCCESS && tsx->state == PJSIP_TSX_STATE_TRYING) {
-	tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, 
-                       PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata);
-    }
-
-    return status;
-}
-
-/*
- * Handler for events in Proceeding for UAS
- * This state happens after the TU sends provisional response.
- */
-static pj_status_t pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx,
-                                                      pjsip_event *event)
-{
-    pj_assert(tsx->state == PJSIP_TSX_STATE_PROCEEDING || 
-	      tsx->state == PJSIP_TSX_STATE_TRYING);
-
-    /* This state is only for UAS. */
-    pj_assert(tsx->role == PJSIP_ROLE_UAS);
-
-    /* Receive request retransmission. */
-    if (event->type == PJSIP_EVENT_RX_MSG) {
-
-        pj_status_t status;
-
-	/* Send last response. */
-        status = pjsip_tsx_retransmit( tsx, 0 );
-	if (status != PJ_SUCCESS) {
-	    return status;
-	}
-	
-    } else if (event->type == PJSIP_EVENT_TX_MSG ) {
-	pjsip_tx_data *tdata = event->body.tx_msg.tdata;
-        pj_status_t status;
-
-	/* The TU sends response message to the request. Save this message so
-	 * that we can retransmit the last response in case we receive request
-	 * retransmission.
-	 */
-	pjsip_msg *msg = tdata->msg;
-
-	/* This can only be a response message. */
-	pj_assert(msg->type == PJSIP_RESPONSE_MSG);
-
-	/* Status code must be higher than last sent. */
-	pj_assert(msg->line.status.code >= tsx->status_code);
-
-	/* Update last status */
-	tsx->status_code = msg->line.status.code;
-
-	/* Discard the saved last response (it will be updated later as
-	 * necessary).
-	 */
-	if (tsx->last_tx && tsx->last_tx != tdata) {
-	    pjsip_tx_data_dec_ref( tsx->last_tx );
-	    tsx->last_tx = NULL;
-	}
-
-	/* Send the message. */
-        status = tsx_send_msg(tsx, tdata);
-	if (status != PJ_SUCCESS) {
-	    return status;
-	}
-
-	// Update To tag header for RFC2543 transaction.
-	// TODO:
-
-	/* Update transaction state */
-	if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 100)) {
-
-	    if (tsx->last_tx != tdata) {
-		tsx->last_tx = tdata;
-		pjsip_tx_data_add_ref( tdata );
-	    }
-	    tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, 
-                           PJSIP_EVENT_TX_MSG, tdata );
-
-	} else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {
-
-	    if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->handle_ack==0) {
-
-		/* 2xx class message is not saved, because retransmission 
-                 * is handled by TU.
-		 */
-		tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                               PJSIP_EVENT_TX_MSG, tdata );
-
-		/* Transaction is destroyed. */
-		return PJSIP_ETSXDESTROYED;
-
-	    } else {
-		pj_time_val timeout;
-
-		if (tsx->method.id == PJSIP_INVITE_METHOD) {
-		    tsx->retransmit_count = 0;
-		    pjsip_endpt_schedule_timer( tsx->endpt, 
-                                                &tsx->retransmit_timer, 
-						&t1_timer_val);
-		}
-
-		/* Save last response sent for retransmission when request 
-		 * retransmission is received.
-		 */
-		if (tsx->last_tx != tdata) {
-		    tsx->last_tx = tdata;
-		    pjsip_tx_data_add_ref(tdata);
-		}
-
-		/* Start timer J at 64*T1 for unreliable transport or zero for
-		 * reliable transport.
-		 */
-		if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {
-		    timeout = timeout_timer_val;
-		} else {
-		    timeout.sec = timeout.msec = 0;
-		}
-
-		pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-                                            &timeout);
-
-		/* Set state to "Completed" */
-		tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 
-                               PJSIP_EVENT_TX_MSG, tdata );
-	    }
-
-	} else if (tsx->status_code >= 300) {
-
-	    /* 3xx-6xx class message causes transaction to move to 
-             * "Completed" state. 
-             */
-	    if (tsx->last_tx != tdata) {
-		tsx->last_tx = tdata;
-		pjsip_tx_data_add_ref( tdata );
-	    }
-
-	    /* Start timer H for transaction termination */
-	    pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,
-                                       &timeout_timer_val);
-
-	    /* For INVITE, if unreliable transport is used, retransmission 
-	     * timer G will be scheduled (retransmission).
-	     */
-	    if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {
-		pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ,
-                                                           NULL);
-		if (cseq->method.id == PJSIP_INVITE_METHOD) {
-		    tsx->retransmit_count = 0;
-		    pjsip_endpt_schedule_timer(tsx->endpt, 
-                                               &tsx->retransmit_timer, 
-					       &t1_timer_val);
-		}
-	    }
-
-	    /* Inform TU */
-	    tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 
-                           PJSIP_EVENT_TX_MSG, tdata );
-
-	} else {
-	    pj_assert(0);
-	}
-
-
-    } else if (event->type == PJSIP_EVENT_TIMER && 
-	       event->body.timer.entry == &tsx->retransmit_timer) {
-	/* Retransmission timer elapsed. */
-        pj_status_t status;
-
-	/* Must have last response to retransmit. */
-	pj_assert(tsx->last_tx != NULL);
-
-	/* Retransmit the last response. */
-        status = pjsip_tsx_retransmit( tsx, 1 );
-	if (status != PJ_SUCCESS) {
-	    return status;
-	}
-
-    } else if (event->type == PJSIP_EVENT_TIMER && 
-	       event->body.timer.entry == &tsx->timeout_timer) {
-
-	/* Timeout timer. should not happen? */
-	pj_assert(0);
-
-	tsx->status_code = PJSIP_SC_TSX_TIMEOUT;
-
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                       PJSIP_EVENT_TIMER, &tsx->timeout_timer);
-
-	return PJ_EBUG;
-
-    } else {
-	pj_assert(0);
-        return PJ_EBUG;
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Handler for events in Proceeding for UAC
- * This state happens after provisional response(s) has been received from
- * UAS.
- */
-static pj_status_t pjsip_tsx_on_state_proceeding_uac(pjsip_transaction *tsx, 
-                                                     pjsip_event *event)
-{
-
-    pj_assert(tsx->state == PJSIP_TSX_STATE_PROCEEDING || 
-	      tsx->state == PJSIP_TSX_STATE_CALLING);
-
-    if (event->type != PJSIP_EVENT_TIMER) {
-	/* Must be incoming response, because we should not retransmit
-	 * request once response has been received.
-	 */
-	pj_assert(event->type == PJSIP_EVENT_RX_MSG);
-	if (event->type != PJSIP_EVENT_RX_MSG) {
-	    return PJ_EINVALIDOP;
-	}
-
-	tsx->status_code = event->body.rx_msg.rdata->msg->line.status.code;
-    } else {
-	tsx->status_code = PJSIP_SC_TSX_TIMEOUT;
-    }
-
-    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 100)) {
-
-	/* Inform the message to TU. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, 
-                       PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
-
-    } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code,200)) {
-
-	/* Stop timeout timer B/F. */
-	pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
-
-	/* For INVITE, the state moves to Terminated state (because ACK is
-	 * handled in TU). For non-INVITE, state moves to Completed.
-	 */
-	if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->handle_ack == 0) {
-	    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                           PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
-	    return PJSIP_ETSXDESTROYED;
-
-	} else {
-	    pj_time_val timeout;
-
-	    /* For unreliable transport, start timer D (for INVITE) or 
-	     * timer K for non-INVITE. */
-	    if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport) == 0) {
-		if (tsx->method.id == PJSIP_INVITE_METHOD) {
-		    timeout = td_timer_val;
-		} else {
-		    timeout = t4_timer_val;
-		}
-	    } else {
-		timeout.sec = timeout.msec = 0;
-	    }
-	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-					&timeout);
-
-	    /* Move state to Completed, inform TU. */
-	    tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 
-                           PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
-	}
-
-    } else if (tsx->status_code >= 300 && tsx->status_code <= 699) {
-	pj_time_val timeout;
-        pj_status_t status;
-
-	/* Stop timer B. */
-	pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
-
-	/* Generate and send ACK for INVITE. */
-	if (tsx->method.id == PJSIP_INVITE_METHOD) {
-	    pjsip_endpt_create_ack( tsx->endpt, tsx->last_tx, 
-                                    event->body.rx_msg.rdata );
-            status = tsx_send_msg( tsx, tsx->last_tx);
-	    if (status != PJ_SUCCESS) {
-		return status;
-	    }
-	}
-
-	/* Start Timer D with TD/T4 timer if unreliable transport is used. */
-	if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport) == 0) {
-	    if (tsx->method.id == PJSIP_INVITE_METHOD) {
-		timeout = td_timer_val;
-	    } else {
-		timeout = t4_timer_val;
-	    }
-	} else {
-	    timeout.sec = timeout.msec = 0;
-	}
-	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout);
-
-	/* Inform TU. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 
-                       PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
-
-    } else {
-	// Shouldn't happen because there's no timer for this state.
-	pj_assert(0);
-        return PJ_EBUG;
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Handler for events in Completed state for UAS
- */
-static pj_status_t pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, 
-                                                     pjsip_event *event)
-{
-    pj_assert(tsx->state == PJSIP_TSX_STATE_COMPLETED);
-
-    if (event->type == PJSIP_EVENT_RX_MSG) {
-	pjsip_msg *msg = event->body.rx_msg.rdata->msg;
-	pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ, NULL );
-
-	/* On receive request retransmission, retransmit last response. */
-	if (cseq->method.id != PJSIP_ACK_METHOD) {
-            pj_status_t status;
-
-            status = pjsip_tsx_retransmit( tsx, 0 );
-	    if (status != PJ_SUCCESS) {
-		return status;
-	    }
-
-	} else {
-	    /* Process incoming ACK request. */
-
-	    /* Cease retransmission. */
-	    pjsip_endpt_cancel_timer( tsx->endpt, &tsx->retransmit_timer );
-
-	    /* Start timer I in T4 interval (transaction termination). */
-	    pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
-	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
-					&t4_timer_val);
-
-	    /* Move state to "Confirmed" */
-	    tsx_set_state( tsx, PJSIP_TSX_STATE_CONFIRMED, 
-                           PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );
-	}	
-
-    } else if (event->type == PJSIP_EVENT_TIMER) {
-
-	if (event->body.timer.entry == &tsx->retransmit_timer) {
-	    /* Retransmit message. */
-            pj_status_t status;
-
-            status = pjsip_tsx_retransmit( tsx, 1 );
-	    if (status != PJ_SUCCESS) {
-		return status;
-	    }
-
-	} else {
-	    if (tsx->method.id == PJSIP_INVITE_METHOD) {
-
-		/* For INVITE, this means that ACK was never received.
-		 * Set state to Terminated, and inform TU.
-		 */
-
-		tsx->status_code = PJSIP_SC_TSX_TIMEOUT;
-
-		tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                               PJSIP_EVENT_TIMER, &tsx->timeout_timer );
-
-		return PJSIP_ETSXDESTROYED;
-
-	    } else {
-		/* Transaction terminated, it can now be deleted. */
-		tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                               PJSIP_EVENT_TIMER, &tsx->timeout_timer );
-		return PJSIP_ETSXDESTROYED;
-	    }
-	}
-
-    } else {
-	/* Ignore request to transmit. */
-	pj_assert(event->body.tx_msg.tdata == tsx->last_tx);
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Handler for events in Completed state for UAC transaction.
- */
-static pj_status_t pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx,
-                                                     pjsip_event *event)
-{
-    pj_assert(tsx->state == PJSIP_TSX_STATE_COMPLETED);
-
-    if (event->type == PJSIP_EVENT_TIMER) {
-	/* Must be the timeout timer. */
-	pj_assert(event->body.timer.entry == &tsx->timeout_timer);
-
-	/* Move to Terminated state. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                       PJSIP_EVENT_TIMER, event->body.timer.entry );
-
-	/* Transaction has been destroyed. */
-	return PJSIP_ETSXDESTROYED;
-
-    } else if (event->type == PJSIP_EVENT_RX_MSG) {
-	if (tsx->method.id == PJSIP_INVITE_METHOD) {
-	    /* On received of final response retransmission, retransmit the ACK.
-	     * TU doesn't need to be informed.
-	     */
-	    pjsip_msg *msg = event->body.rx_msg.rdata->msg;
-	    pj_assert(msg->type == PJSIP_RESPONSE_MSG);
-	    if (msg->type==PJSIP_RESPONSE_MSG &&
-		msg->line.status.code >= 200)
-	    {
-                pj_status_t status;
-
-                status = pjsip_tsx_retransmit( tsx, 0 );
-		if (status != PJ_SUCCESS) {
-		    return status;
-		}
-	    } else {
-		/* Very late retransmission of privisional response. */
-		pj_assert( msg->type == PJSIP_RESPONSE_MSG );
-	    }
-	} else {
-	    /* Just drop the response. */
-	}
-    } else if (tsx->method.id == PJSIP_INVITE_METHOD &&
-	       event->type == PJSIP_EVENT_TX_MSG &&
-	       event->body.tx_msg.tdata->msg->line.req.method.id==PJSIP_ACK_METHOD) {
-
-        pj_status_t status;
-
-	/* Set last transmitted message. */
-	if (tsx->last_tx != event->body.tx_msg.tdata) {
-	    pjsip_tx_data_dec_ref( tsx->last_tx );
-	    tsx->last_tx = event->body.tx_msg.tdata;
-	    pjsip_tx_data_add_ref( tsx->last_tx );
-	}
-
-	/* No state changed, but notify app. 
-	 * Must notify now, so app has chance to put SDP in outgoing ACK msg.
-	 */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 
-                       PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata );
-
-	/* Send msg */
-	status = tsx_send_msg(tsx, event->body.tx_msg.tdata);
-        if (status != PJ_SUCCESS)
-            return status;
-
-    } else {
-	pj_assert(0);
-        return PJ_EBUG;
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Handler for events in state Confirmed.
- */
-static pj_status_t pjsip_tsx_on_state_confirmed( pjsip_transaction *tsx,
-                                                 pjsip_event *event)
-{
-    pj_assert(tsx->state == PJSIP_TSX_STATE_CONFIRMED);
-
-    /* This state is only for UAS for INVITE. */
-    pj_assert(tsx->role == PJSIP_ROLE_UAS);
-    pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);
-
-    /* Absorb any ACK received. */
-    if (event->type == PJSIP_EVENT_RX_MSG) {
-
-        pjsip_method_e method_id = 
-            event->body.rx_msg.rdata->msg->line.req.method.id;
-
-	/* Must be a request message. */
-	pj_assert(event->body.rx_msg.rdata->msg->type == PJSIP_REQUEST_MSG);
-
-	/* Must be an ACK request or a late INVITE retransmission. */
-	pj_assert(method_id == PJSIP_ACK_METHOD ||
-		  method_id == PJSIP_INVITE_METHOD);
-
-        /* Just so that compiler won't complain about unused vars when
-         * building release code.
-         */
-        PJ_UNUSED_ARG(method_id);
-
-    } else if (event->type == PJSIP_EVENT_TIMER) {
-	/* Must be from timeout_timer_. */
-	pj_assert(event->body.timer.entry == &tsx->timeout_timer);
-
-	/* Move to Terminated state. */
-	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 
-                       PJSIP_EVENT_TIMER, &tsx->timeout_timer );
-
-	/* Transaction has been destroyed. */
-	return PJSIP_ETSXDESTROYED;
-
-    } else {
-	pj_assert(0);
-        return PJ_EBUG;
-    }
-
-    return PJ_SUCCESS;
-}
-
-/*
- * Handler for events in state Terminated.
- */
-static pj_status_t pjsip_tsx_on_state_terminated( pjsip_transaction *tsx,
-                                                  pjsip_event *event)
-{
-    pj_assert(tsx->state == PJSIP_TSX_STATE_TERMINATED);
-
-    PJ_UNUSED_ARG(event);
-
-    /* Destroy this transaction */
-    tsx_set_state(tsx, PJSIP_TSX_STATE_DESTROYED, 
-                  event->type, event->body.user.user1 );
-
-    return PJ_SUCCESS;
-}
-
-
-static pj_status_t pjsip_tsx_on_state_destroyed(pjsip_transaction *tsx,
-                                                pjsip_event *event)
-{
-    PJ_UNUSED_ARG(tsx);
-    PJ_UNUSED_ARG(event);
-    return PJ_SUCCESS;
-}
-
+                               tsx_lock_data *lck );

+static pj_status_t  unlock_tsx( pjsip_transaction *tsx, 

+                               struct tsx_lock_data *lck );

+

+/* State handlers for UAC, indexed by state */

+static int  (*tsx_state_handler_uac[PJSIP_TSX_STATE_MAX])(pjsip_transaction *,

+							  pjsip_event *) = 

+{

+    &pjsip_tsx_on_state_null,

+    &pjsip_tsx_on_state_calling,

+    &pjsip_tsx_on_state_trying,

+    &pjsip_tsx_on_state_proceeding_uac,

+    &pjsip_tsx_on_state_completed_uac,

+    &pjsip_tsx_on_state_confirmed,

+    &pjsip_tsx_on_state_terminated,

+    &pjsip_tsx_on_state_destroyed,

+};

+

+/* State handlers for UAS */

+static int  (*tsx_state_handler_uas[PJSIP_TSX_STATE_MAX])(pjsip_transaction *, 

+							  pjsip_event *) = 

+{

+    &pjsip_tsx_on_state_null,

+    &pjsip_tsx_on_state_calling,

+    &pjsip_tsx_on_state_trying,

+    &pjsip_tsx_on_state_proceeding_uas,

+    &pjsip_tsx_on_state_completed_uas,

+    &pjsip_tsx_on_state_confirmed,

+    &pjsip_tsx_on_state_terminated,

+    &pjsip_tsx_on_state_destroyed,

+};

+

+/*

+ * Get transaction state name.

+ */

+PJ_DEF(const char *) pjsip_tsx_state_str(pjsip_tsx_state_e state)

+{

+    return state_str[state];

+}

+

+/*

+ * Get the role name.

+ */

+PJ_DEF(const char *) pjsip_role_name(pjsip_role_e role)

+{

+    return role_name[role];

+}

+

+

+/*

+ * Create transaction key for RFC2543 compliant messages, which don't have

+ * unique branch parameter in the top most Via header.

+ *

+ * INVITE requests matches a transaction if the following attributes

+ * match the original request:

+ *	- Request-URI

+ *	- To tag

+ *	- From tag

+ *	- Call-ID

+ *	- CSeq

+ *	- top Via header

+ *

+ * CANCEL matching is done similarly as INVITE, except:

+ *	- CSeq method will differ

+ *	- To tag is not matched.

+ *

+ * ACK matching is done similarly, except that:

+ *	- method of the CSeq will differ,

+ *	- To tag is matched to the response sent by the server transaction.

+ *

+ * The transaction key is constructed from the common components of above

+ * components. Additional comparison is needed to fully match a transaction.

+ */

+static pj_status_t create_tsx_key_2543( pj_pool_t *pool,

+			                pj_str_t *str,

+			                pjsip_role_e role,

+			                const pjsip_method *method,

+			                const pjsip_rx_data *rdata )

+{

+#define SEPARATOR   '$'

+    char *key, *p, *end;

+    int len;

+    pj_size_t len_required;

+    pjsip_uri *req_uri;

+    pj_str_t *host;

+

+    PJ_ASSERT_RETURN(pool && str && method && rdata, PJ_EINVAL);

+    PJ_ASSERT_RETURN(rdata->msg, PJ_EINVAL);

+    PJ_ASSERT_RETURN(rdata->via, PJSIP_EMISSINGHDR);

+    PJ_ASSERT_RETURN(rdata->cseq, PJSIP_EMISSINGHDR);

+    PJ_ASSERT_RETURN(rdata->from, PJSIP_EMISSINGHDR);

+

+    host = &rdata->via->sent_by.host;

+    req_uri = (pjsip_uri*)rdata->msg->line.req.uri;

+

+    /* Calculate length required. */

+    len_required = 9 +			    /* CSeq number */

+		   rdata->from->tag.slen +   /* From tag. */

+		   rdata->call_id.slen +    /* Call-ID */

+		   host->slen +		    /* Via host. */

+		   9 +			    /* Via port. */

+		   16;			    /* Separator+Allowance. */

+    key = p = pj_pool_alloc(pool, len_required);

+    end = p + len_required;

+

+    /* Add role. */

+    *p++ = (char)(role==PJSIP_ROLE_UAC ? 'c' : 's');

+    *p++ = SEPARATOR;

+

+    /* Add Request-URI */

+    /* This is BUG!

+     * Response doesn't have Request-URI!

+     *

+    len = req_uri->vptr->print( PJSIP_URI_IN_REQ_URI, req_uri, p, end-p );

+    p += len;

+    *p++ = SEPARATOR;

+     */

+

+    /* Add method, except when method is INVITE or ACK. */

+    if (method->id != PJSIP_INVITE_METHOD && method->id != PJSIP_ACK_METHOD) {

+	pj_memcpy(p, method->name.ptr, method->name.slen);

+	p += method->name.slen;

+	*p++ = '$';

+    }

+

+    /* Add CSeq (only the number). */

+    len = pj_utoa(rdata->cseq->cseq, p);

+    p += len;

+    *p++ = SEPARATOR;

+

+    /* Add From tag. */

+    len = rdata->from->tag.slen;

+    pj_memcpy( p, rdata->from->tag.ptr, len);

+    p += len;

+    *p++ = SEPARATOR;

+

+    /* Add Call-ID. */

+    len = rdata->call_id.slen;

+    pj_memcpy( p, rdata->call_id.ptr, len );

+    p += len;

+    *p++ = SEPARATOR;

+

+    /* Add top Via header. 

+     * We don't really care whether the port contains the real port (because

+     * it can be omited if default port is used). Anyway this function is 

+     * only used to match request retransmission, and we expect that the 

+     * request retransmissions will contain the same port.

+     */

+    pj_memcpy(p, host->ptr, host->slen);

+    p += host->slen;

+    *p++ = ':';

+

+    len = pj_utoa(rdata->via->sent_by.port, p);

+    p += len;

+    *p++ = SEPARATOR;

+    

+    *p++ = '\0';

+

+    /* Done. */

+    str->ptr = key;

+    str->slen = p-key;

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Create transaction key for RFC3161 compliant system.

+ */

+static pj_status_t create_tsx_key_3261( pj_pool_t *pool,

+		                        pj_str_t *key,

+		                        pjsip_role_e role,

+		                        const pjsip_method *method,

+		                        const pj_str_t *branch)

+{

+    char *p;

+

+    PJ_ASSERT_RETURN(pool && key && method && branch, PJ_EINVAL);

+

+    p = key->ptr = pj_pool_alloc(pool, branch->slen + method->name.slen + 4 );

+    

+    /* Add role. */

+    *p++ = (char)(role==PJSIP_ROLE_UAC ? 'c' : 's');

+    *p++ = SEPARATOR;

+

+    /* Add method, except when method is INVITE or ACK. */

+    if (method->id != PJSIP_INVITE_METHOD && method->id != PJSIP_ACK_METHOD) {

+	pj_memcpy(p, method->name.ptr, method->name.slen);

+	p += method->name.slen;

+	*p++ = '$';

+    }

+

+    /* Add branch ID. */

+    pj_memcpy(p, branch->ptr, branch->slen);

+    p += branch->slen;

+

+    /* Set length */

+    key->slen = p - key->ptr;

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Create key from the incoming data, to be used to search the transaction

+ * in the transaction hash table.

+ */

+PJ_DEF(pj_status_t) pjsip_tsx_create_key( pj_pool_t *pool, pj_str_t *key, 

+				          pjsip_role_e role, 

+				          const pjsip_method *method, 

+				          const pjsip_rx_data *rdata)

+{

+    pj_str_t rfc3261_branch = {PJSIP_RFC3261_BRANCH_ID, 

+                               PJSIP_RFC3261_BRANCH_LEN};

+

+

+    /* Get the branch parameter in the top-most Via.

+     * If branch parameter is started with "z9hG4bK", then the message was

+     * generated by agent compliant with RFC3261. Otherwise, it will be

+     * handled as RFC2543.

+     */

+    const pj_str_t *branch = &rdata->via->branch_param;

+

+    if (pj_strncmp(branch,&rfc3261_branch,PJSIP_RFC3261_BRANCH_LEN)==0) {

+

+	/* Create transaction key. */

+	return create_tsx_key_3261(pool, key, role, method, branch);

+

+    } else {

+	/* Create the key for the message. This key will be matched up 

+         * with the transaction key. For RFC2563 transactions, the 

+         * transaction key was created by the same function, so it will 

+         * match the message.

+	 */

+	return create_tsx_key_2543( pool, key, role, method, rdata );

+    }

+}

+

+

+/*

+ * Create new transaction.

+ */

+pj_status_t pjsip_tsx_create( pj_pool_t *pool,

+			      pjsip_endpoint *endpt,

+                              pjsip_transaction **p_tsx)

+{

+    pjsip_transaction *tsx;

+    pj_status_t status;

+

+    tsx = pj_pool_calloc(pool, 1, sizeof(pjsip_transaction));

+

+    tsx->pool = pool;

+    tsx->endpt = endpt;

+    tsx->retransmit_timer.id = TSX_TIMER_RETRANSMISSION;

+    tsx->retransmit_timer._timer_id = -1;

+    tsx->retransmit_timer.user_data = tsx;

+    tsx->retransmit_timer.cb = &tsx_timer_callback;

+    tsx->timeout_timer.id = TSX_TIMER_TIMEOUT;

+    tsx->timeout_timer._timer_id = -1;

+    tsx->timeout_timer.user_data = tsx;

+    tsx->timeout_timer.cb = &tsx_timer_callback;

+    pj_sprintf(tsx->obj_name, "tsx%p", tsx);

+    status = pj_mutex_create_recursive(pool, "mtsx%p", &tsx->mutex);

+    if (status != PJ_SUCCESS) {

+	return status;

+    }

+

+    *p_tsx = tsx;

+    return PJ_SUCCESS;

+}

+

+/*

+ * Lock transaction and set the value of Thread Local Storage.

+ */

+static void lock_tsx(pjsip_transaction *tsx, struct tsx_lock_data *lck)

+{

+    struct tsx_lock_data *prev_data;

+

+    pj_mutex_lock(tsx->mutex);

+    prev_data = (struct tsx_lock_data *) 

+                    pj_thread_local_get(pjsip_tsx_lock_tls_id);

+    lck->prev = prev_data;

+    lck->tsx = tsx;

+    lck->is_alive = 1;

+    pj_thread_local_set(pjsip_tsx_lock_tls_id, lck);

+}

+

+

+/*

+ * Unlock transaction.

+ * This will selectively unlock the mutex ONLY IF the transaction has not been 

+ * destroyed. The function knows whether the transaction has been destroyed

+ * because when transaction is destroyed the is_alive flag for the transaction

+ * will be set to zero.

+ */

+static pj_status_t unlock_tsx( pjsip_transaction *tsx, 

+                               struct tsx_lock_data *lck)

+{

+    pj_assert( (void*)pj_thread_local_get(pjsip_tsx_lock_tls_id) == lck);

+    pj_assert( lck->tsx == tsx );

+    pj_thread_local_set(pjsip_tsx_lock_tls_id, lck->prev);

+    if (lck->is_alive)

+	pj_mutex_unlock(tsx->mutex);

+

+    return lck->is_alive ? PJ_SUCCESS : PJSIP_ETSXDESTROYED;

+}

+

+/*

+ * Set transaction state, and inform TU about the transaction state change.

+ */

+static void tsx_set_state( pjsip_transaction *tsx,

+			   pjsip_tsx_state_e state,

+			   pjsip_event_id_e event_src_type,

+                           void *event_src )

+{

+    pjsip_event e;

+

+    PJ_LOG(4, (tsx->obj_name, "STATE %s-->%s, cause = %s",

+	       state_str[tsx->state], state_str[state], 

+               pjsip_event_str(event_src_type)));

+

+    /* Change state. */

+    tsx->state = state;

+

+    /* Update the state handlers. */

+    if (tsx->role == PJSIP_ROLE_UAC) {

+	tsx->state_handler = tsx_state_handler_uac[state];

+    } else {

+	tsx->state_handler = tsx_state_handler_uas[state];

+    }

+

+    /* Inform TU */

+    PJSIP_EVENT_INIT_TSX_STATE(e, tsx, event_src_type, event_src);

+    pjsip_endpt_send_tsx_event( tsx->endpt, &e  );

+

+    /* When the transaction is terminated, release transport, and free the

+     * saved last transmitted message.

+     */

+    if (state == PJSIP_TSX_STATE_TERMINATED) {

+

+	/* Decrement transport reference counter. */

+	if (tsx->transport && 

+            tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL) 

+        {

+	    pjsip_transport_dec_ref( tsx->transport );

+	    tsx->transport = NULL;

+	}

+	/* Free last transmitted message. */

+	if (tsx->last_tx) {

+	    pjsip_tx_data_dec_ref( tsx->last_tx );

+	    tsx->last_tx = NULL;

+	}

+	/* Cancel timeout timer. */

+	if (tsx->timeout_timer._timer_id != -1) {

+	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);

+	    tsx->timeout_timer._timer_id = -1;

+	}

+	/* Cancel retransmission timer. */

+	if (tsx->retransmit_timer._timer_id != -1) {

+	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);

+	    tsx->retransmit_timer._timer_id = -1;

+	}

+

+	/* If transport is not pending, reschedule timeout timer to

+	 * destroy this transaction.

+	 */

+	if (tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL) {

+	    pj_time_val timeout = {0, 0};

+	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 

+					&timeout);

+	}

+

+    } else if (state == PJSIP_TSX_STATE_DESTROYED) {

+

+	/* Clear TLS, so that mutex will not be unlocked */

+	struct tsx_lock_data *lck = pj_thread_local_get(pjsip_tsx_lock_tls_id);

+	while (lck) {

+	    if (lck->tsx == tsx) {

+		lck->is_alive = 0;

+	    }

+	    lck = lck->prev;

+	}

+    }

+}

+

+/*

+ * Look-up destination address and select which transport to be used to send

+ * the request message. The procedure used here follows the guidelines on 

+ * sending the request in RFC3261 chapter 8.1.2.

+ *

+ * This function also modifies the message (request line and Route headers)

+ * accordingly.

+ */

+static pj_status_t tsx_process_route( pjsip_transaction *tsx,

+				      pjsip_tx_data *tdata,

+				      pjsip_host_port *send_addr )

+{

+    const pjsip_uri *new_request_uri, *target_uri;

+    const pjsip_name_addr *topmost_route_uri;

+    pjsip_route_hdr *first_route_hdr, *last_route_hdr;

+    

+    pj_assert(tdata->msg->type == PJSIP_REQUEST_MSG);

+

+    /* Get the first "Route" header from the message. If the message doesn't

+     * have any "Route" headers but the endpoint has, then copy the "Route"

+     * headers from the endpoint first.

+     */

+    last_route_hdr = first_route_hdr = 

+	pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL);

+    if (first_route_hdr) {

+	topmost_route_uri = &first_route_hdr->name_addr;

+	while (last_route_hdr->next != (void*)&tdata->msg->hdr) {

+	    pjsip_route_hdr *hdr;

+	    hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, 

+                                     last_route_hdr->next);

+	    if (!hdr)

+		break;

+	    last_route_hdr = hdr;

+	}

+    } else {

+	const pjsip_route_hdr *hdr_list;

+	hdr_list = (pjsip_route_hdr*)pjsip_endpt_get_routing(tsx->endpt);

+	if (hdr_list->next != hdr_list) {

+	    const pjsip_route_hdr *hdr = (pjsip_route_hdr*)hdr_list->next;

+	    first_route_hdr = NULL;

+	    topmost_route_uri = &hdr->name_addr;

+	    do {

+		last_route_hdr = pjsip_hdr_shallow_clone(tdata->pool, hdr);

+		if (first_route_hdr == NULL)

+		    first_route_hdr = last_route_hdr;

+		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)last_route_hdr);

+		hdr = hdr->next;

+	    } while (hdr != hdr_list);

+	} else {

+	    topmost_route_uri = NULL;

+	}

+    }

+

+    /* If Route headers exist, and the first element indicates loose-route,

+     * the URI is taken from the Request-URI, and we keep all existing Route

+     * headers intact.

+     * If Route headers exist, and the first element DOESN'T indicate loose

+     * route, the URI is taken from the first Route header, and remove the

+     * first Route header from the message.

+     * Otherwise if there's no Route headers, the URI is taken from the

+     * Request-URI.

+     */

+    if (topmost_route_uri) {

+	pj_bool_t has_lr_param;

+

+	if (PJSIP_URI_SCHEME_IS_SIP(topmost_route_uri) ||

+	    PJSIP_URI_SCHEME_IS_SIPS(topmost_route_uri))

+	{

+	    const pjsip_url *url = pjsip_uri_get_uri((void*)topmost_route_uri);

+	    has_lr_param = url->lr_param;

+	} else {

+	    has_lr_param = 0;

+	}

+

+	if (has_lr_param) {

+	    new_request_uri = tdata->msg->line.req.uri;

+	    /* We shouldn't need to delete topmost Route if it has lr param.

+	     * But seems like it breaks some proxy implementation, so we

+	     * delete it anyway.

+	     */

+	    /*

+	    pj_list_erase(first_route_hdr);

+	    if (first_route_hdr == last_route_hdr)

+		last_route_hdr = NULL;

+	    */

+	} else {

+	    new_request_uri = pjsip_uri_get_uri((void*)topmost_route_uri);

+	    pj_list_erase(first_route_hdr);

+	    if (first_route_hdr == last_route_hdr)

+		last_route_hdr = NULL;

+	}

+

+	target_uri = (pjsip_uri*)topmost_route_uri;

+

+    } else {

+	target_uri = new_request_uri = tdata->msg->line.req.uri;

+    }

+

+    /* The target URI must be a SIP/SIPS URL so we can resolve it's address.

+     * Otherwise we're in trouble (i.e. there's no host part in tel: URL).

+     */

+    pj_memset(send_addr, 0, sizeof(*send_addr));

+

+    if (PJSIP_URI_SCHEME_IS_SIPS(target_uri)) {

+	pjsip_uri *uri = (pjsip_uri*) target_uri;

+	const pjsip_url *url = (const pjsip_url*)pjsip_uri_get_uri(uri);

+	send_addr->flag |= (PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_RELIABLE);

+	pj_strdup(tdata->pool, &send_addr->host, &url->host);

+        send_addr->port = url->port;

+	send_addr->type = 

+            pjsip_transport_get_type_from_name(&url->transport_param);

+

+    } else if (PJSIP_URI_SCHEME_IS_SIP(target_uri)) {

+	pjsip_uri *uri = (pjsip_uri*) target_uri;

+	const pjsip_url *url = (const pjsip_url*)pjsip_uri_get_uri(uri);

+	pj_strdup(tdata->pool, &send_addr->host, &url->host);

+	send_addr->port = url->port;

+	send_addr->type = 

+            pjsip_transport_get_type_from_name(&url->transport_param);

+#if PJ_HAS_TCP

+	if (send_addr->type == PJSIP_TRANSPORT_TCP || 

+	    send_addr->type == PJSIP_TRANSPORT_SCTP) 

+	{

+	    send_addr->flag |= PJSIP_TRANSPORT_RELIABLE;

+	}

+#endif

+    } else {

+        pj_assert(!"Unsupported URI scheme!");

+	return PJSIP_EINVALIDSCHEME;

+    }

+

+    /* If target URI is different than request URI, replace 

+     * request URI add put the original URI in the last Route header.

+     */

+    if (new_request_uri && new_request_uri!=tdata->msg->line.req.uri) {

+	pjsip_route_hdr *route = pjsip_route_hdr_create(tdata->pool);

+	route->name_addr.uri = tdata->msg->line.req.uri;

+	if (last_route_hdr)

+	    pj_list_insert_after(last_route_hdr, route);

+	else

+	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)route);

+	tdata->msg->line.req.uri = (pjsip_uri*)new_request_uri;

+    }

+

+    /* Success. */

+    return PJ_SUCCESS;  

+}

+

+

+/*

+ * Callback from the transport job.

+ * This callback is called when asychronous transport connect() operation

+ * has completed, with or without error.

+ */

+static void tsx_transport_callback(pjsip_transport_t *tr, 

+				   void *token, 

+				   pj_status_t status)

+{

+    char addr[PJ_MAX_HOSTNAME];

+    pjsip_transaction *tsx = token;

+    struct tsx_lock_data lck;

+

+    pj_memcpy(addr, tsx->dest_name.host.ptr, tsx->dest_name.host.slen);

+    addr[tsx->dest_name.host.slen] = '\0';

+

+

+    if (status == PJ_SUCCESS) {

+	PJ_LOG(4, (tsx->obj_name, "%s connected to %s:%d",

+				  pjsip_transport_get_type_name(tr),

+				  addr, tsx->dest_name.port));

+    } else {

+	PJ_LOG(4, (tsx->obj_name, "%s unable to connect to %s:%d, status=%d", 

+				  pjsip_transport_get_type_name(tr),

+				  addr, tsx->dest_name.port, status));

+    }

+

+    /* Lock transaction. */

+    lock_tsx(tsx, &lck);

+

+    if (status != PJ_SUCCESS) {

+	tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;

+	tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;

+

+	tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED,

+                      PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);

+

+	/* Unlock transaction. */

+	unlock_tsx(tsx, &lck);

+	return;

+    }

+

+    /* See if transaction has already been terminated. 

+     * If so, schedule to destroy the transaction.

+     */

+    if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {

+	pj_time_val timeout = {0, 0};

+	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 

+				    &timeout);

+

+	/* Unlock transaction. */

+	unlock_tsx(tsx, &lck);

+	return;

+    }

+

+    /* Add reference counter to the transport. */

+    pjsip_transport_add_ref(tr);

+

+    /* Mark transport as ready. */

+    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;

+    tsx->transport = tr;

+

+    /* If there's a pending message to send, send it now. */

+    if (tsx->has_unsent_msg) {

+	tsx_send_msg( tsx, tsx->last_tx );

+    }

+

+    /* Unlock transaction. */

+    unlock_tsx(tsx, &lck);

+}

+

+/*

+ * Callback from the resolver job.

+ */

+static void tsx_resolver_callback(pj_status_t status,

+				  void *token,

+				  const struct pjsip_server_addresses *addr)

+{

+    pjsip_transaction *tsx = token;

+    struct tsx_lock_data lck;

+

+    PJ_LOG(4, (tsx->obj_name, "resolver job complete, status=%d", status));

+

+    if (status != PJ_SUCCESS || addr->count == 0) {

+	lock_tsx(tsx, &lck);

+	tsx->status_code = PJSIP_SC_TSX_RESOLVE_ERROR;

+	tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, 

+                      PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);

+	unlock_tsx(tsx, &lck);

+	return;

+    }

+

+    /* Lock transaction. */

+    lock_tsx(tsx, &lck);

+

+    /* Copy server addresses. */

+    pj_memcpy(&tsx->remote_addr, addr, sizeof(*addr));

+

+    /* Create/find the transport for the remote address. */

+    PJ_LOG(5,(tsx->obj_name, "tsx getting transport for %s:%d",

+			     pj_inet_ntoa(addr->entry[0].addr.sin_addr),

+			     pj_ntohs(addr->entry[0].addr.sin_port)));

+

+    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_CONNECTING;

+    pjsip_endpt_get_transport(tsx->endpt, tsx->pool,

+			      addr->entry[0].type, &addr->entry[0].addr,

+			      tsx,

+			      &tsx_transport_callback);

+

+    /* Unlock transaction */

+    unlock_tsx(tsx, &lck);

+

+    /* There should be nothing to do after this point.

+     * Execution for the transaction will resume when the callback for the 

+     * transport is called.

+     */

+}

+

+/*

+ * Initialize the transaction as UAC transaction.

+ */

+PJ_DEF(pj_status_t) pjsip_tsx_init_uac( pjsip_transaction *tsx, 

+					pjsip_tx_data *tdata)

+{

+    pjsip_msg *msg;

+    pjsip_cseq_hdr *cseq;

+    pjsip_via_hdr *via;

+    pj_status_t status;

+    struct tsx_lock_data lck;

+

+    PJ_LOG(4,(tsx->obj_name, "initializing tsx as UAC (tdata=%p)", tdata));

+

+    /* Lock transaction. */

+    lock_tsx(tsx, &lck);

+

+    /* Keep shortcut */

+    msg = tdata->msg;

+

+    /* Role is UAC. */

+    tsx->role = PJSIP_ROLE_UAC;

+

+    /* Save method. */

+    pjsip_method_copy( tsx->pool, &tsx->method, &msg->line.req.method);

+

+    /* Generate Via header if it doesn't exist. */

+    via = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, NULL);

+    if (via == NULL) {

+	via = pjsip_via_hdr_create(tdata->pool);

+	pjsip_msg_insert_first_hdr(msg, (pjsip_hdr*) via);

+    }

+

+    if (via->branch_param.slen == 0) {

+	pj_str_t tmp;

+	via->branch_param.ptr = pj_pool_alloc(tsx->pool, PJSIP_MAX_BRANCH_LEN);

+	via->branch_param.slen = PJSIP_MAX_BRANCH_LEN;

+	pj_memcpy(via->branch_param.ptr, PJSIP_RFC3261_BRANCH_ID, 

+		  PJSIP_RFC3261_BRANCH_LEN);

+

+	tmp.ptr = via->branch_param.ptr + PJSIP_RFC3261_BRANCH_LEN;

+	pj_generate_unique_string( &tmp );

+

+        /* Save branch parameter. */

+        tsx->branch = via->branch_param;

+    } else {

+        /* Copy branch parameter. */

+        pj_strdup(tsx->pool, &tsx->branch, &via->branch_param);

+    }

+

+

+    /* Generate transaction key. */

+    status = create_tsx_key_3261( tsx->pool, &tsx->transaction_key,

+			          PJSIP_ROLE_UAC, &tsx->method, 

+			          &via->branch_param);

+    if (status != PJ_SUCCESS) {

+        unlock_tsx(tsx, &lck);

+        return status;

+    }

+

+    PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen,

+	       tsx->transaction_key.ptr));

+

+    /* Save CSeq. */

+    cseq = pjsip_msg_find_hdr(msg, PJSIP_H_CSEQ, NULL);

+    if (!cseq) {

+	pj_assert(!"CSeq header not present in outgoing message!");

+        unlock_tsx(tsx, &lck);

+	return PJSIP_EMISSINGHDR;

+    }

+    tsx->cseq = cseq->cseq;

+

+

+    /* Begin with State_Null.

+     * Manually set-up the state becase we don't want to call the callback.

+     */

+    tsx->state = PJSIP_TSX_STATE_NULL;

+    tsx->state_handler = &pjsip_tsx_on_state_null;

+

+    /* Get destination name from the message. */

+    status = tsx_process_route(tsx, tdata, &tsx->dest_name);

+    if (status != PJ_SUCCESS) {

+	tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;

+	tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;

+	tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, 

+                      PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);

+	unlock_tsx(tsx, &lck);

+	return status;

+    }

+

+    /* Resolve destination.

+     * This will start asynchronous resolver job, and when it finishes, 

+     * the callback will be called.

+     */

+    PJ_LOG(5,(tsx->obj_name, "tsx resolving destination %.*s:%d",

+			     tsx->dest_name.host.slen, 

+			     tsx->dest_name.host.ptr,

+			     tsx->dest_name.port));

+

+    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_RESOLVING;

+    pjsip_endpt_resolve( tsx->endpt, tsx->pool, &tsx->dest_name, 

+			 tsx, &tsx_resolver_callback);

+

+    /* There should be nothing to do after this point. 

+     * Execution for the transaction will resume when the resolver callback is

+     * called.

+     */

+

+    /* Unlock transaction and return.

+     * If transaction has been destroyed WITHIN the current thread, the 

+     * unlock_tsx() function will return -1.

+     */

+    return unlock_tsx(tsx, &lck);

+}

+

+

+/*

+ * Initialize the transaction as UAS transaction.

+ */

+PJ_DEF(pj_status_t) pjsip_tsx_init_uas( pjsip_transaction *tsx, 

+					pjsip_rx_data *rdata)

+{

+    pjsip_msg *msg = rdata->msg;

+    pj_str_t *branch;

+    pjsip_cseq_hdr *cseq;

+    pj_status_t status;

+    struct tsx_lock_data lck;

+

+    PJ_LOG(4,(tsx->obj_name, "initializing tsx as UAS (rdata=%p)", rdata));

+

+    /* Lock transaction. */

+    lock_tsx(tsx, &lck);

+

+    /* Keep shortcut to message */

+    msg = rdata->msg;

+

+    /* Role is UAS */

+    tsx->role = PJSIP_ROLE_UAS;

+

+    /* Save method. */

+    pjsip_method_copy( tsx->pool, &tsx->method, &msg->line.req.method);

+

+    /* Get transaction key either from branch for RFC3261 message, or

+     * create transaction key.

+     */

+    status = pjsip_tsx_create_key(tsx->pool, &tsx->transaction_key, 

+                                  PJSIP_ROLE_UAS, &tsx->method, rdata);

+    if (status != PJ_SUCCESS) {

+        unlock_tsx(tsx, &lck);

+        return status;

+    }

+

+    /* Duplicate branch parameter for transaction. */

+    branch = &rdata->via->branch_param;

+    pj_strdup(tsx->pool, &tsx->branch, branch);

+

+    PJ_LOG(6, (tsx->obj_name, "tsx_key=%.*s", tsx->transaction_key.slen,

+	       tsx->transaction_key.ptr));

+

+    /* Save CSeq */

+    cseq = rdata->cseq;

+    tsx->cseq = cseq->cseq;

+

+    /* Begin with state NULL

+     * Manually set-up the state becase we don't want to call the callback.

+     */

+    tsx->state = PJSIP_TSX_STATE_NULL; 

+    tsx->state_handler = &pjsip_tsx_on_state_null;

+

+    /* Get the transport to send the response. 

+     * According to section 18.2.2 of RFC3261, if the transport is reliable

+     * then the response must be sent using that transport.

+     */

+    /* In addition, RFC 3581 says, if Via has "rport" parameter specified,

+     * then return the response using the same transport.

+     */

+    if (PJSIP_TRANSPORT_IS_RELIABLE(rdata->transport) || 

+	rdata->via->rport_param >= 0) 

+    {

+	tsx->transport = rdata->transport;

+	pjsip_transport_add_ref(tsx->transport);

+	tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;

+

+	tsx->current_addr = 0;

+	tsx->remote_addr.count = 1;

+	tsx->remote_addr.entry[0].type = 

+		pjsip_transport_get_type(tsx->transport);

+	pj_memcpy(&tsx->remote_addr.entry[0].addr, 

+		  &rdata->addr, rdata->addr_len);

+	

+    } else {

+	pj_status_t status;

+

+	status = pjsip_get_response_addr(tsx->pool, rdata->transport,

+					 rdata->via, &tsx->dest_name);

+	if (status != PJ_SUCCESS) {

+	    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_FINAL;

+	    tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;

+	    tsx_set_state(tsx, PJSIP_TSX_STATE_TERMINATED, 

+                          PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);

+	    unlock_tsx(tsx, &lck);

+	    return status;

+	}

+

+	/* Resolve destination.

+	 * This will start asynchronous resolver job, and when it finishes, 

+	 * the callback will be called.

+	 */

+	PJ_LOG(5,(tsx->obj_name, "tsx resolving destination %.*s:%d",

+				 tsx->dest_name.host.slen, 

+				 tsx->dest_name.host.ptr,

+				 tsx->dest_name.port));

+

+	tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_RESOLVING;

+	pjsip_endpt_resolve( tsx->endpt, tsx->pool, &tsx->dest_name, 

+			     tsx, &tsx_resolver_callback);

+    }

+    

+    /* There should be nothing to do after this point. 

+     * Execution for the transaction will resume when the resolver callback is

+     * called.

+     */

+

+    /* Unlock transaction and return.

+     * If transaction has been destroyed WITHIN the current thread, the 

+     * unlock_tsx() function will return -1.

+     */

+    return unlock_tsx(tsx, &lck);

+}

+

+/*

+ * Callback when timer expires.

+ */

+static void tsx_timer_callback( pj_timer_heap_t *theap, pj_timer_entry *entry)

+{

+    pjsip_event event;

+    pjsip_transaction *tsx = entry->user_data;

+    struct tsx_lock_data lck;

+

+    PJ_UNUSED_ARG(theap);

+

+    PJ_LOG(5,(tsx->obj_name, "got timer event (%s timer)", 

+	     (entry->id==TSX_TIMER_RETRANSMISSION ? "Retransmit" : "Timeout")));

+

+

+    if (entry->id == TSX_TIMER_RETRANSMISSION) {

+        PJSIP_EVENT_INIT_TIMER(event, &tsx->retransmit_timer);

+    } else {

+        PJSIP_EVENT_INIT_TIMER(event, &tsx->timeout_timer);

+    }

+

+    /* Dispatch event to transaction. */

+    lock_tsx(tsx, &lck);

+    (*tsx->state_handler)(tsx, &event);

+    unlock_tsx(tsx, &lck);

+}

+

+/*

+ * Transmit ACK message for 2xx/INVITE with this transaction. The ACK for

+ * non-2xx/INVITE is automatically sent by the transaction.

+ * This operation is only valid if the transaction is configured to handle ACK

+ * (tsx->handle_ack is non-zero). If this attribute is not set, then the

+ * transaction will comply with RFC-3261, i.e. it will set itself to 

+ * TERMINATED state when it receives 2xx/INVITE.

+ */

+PJ_DEF(void) pjsip_tsx_on_tx_ack( pjsip_transaction *tsx, pjsip_tx_data *tdata)

+{

+    pjsip_msg *msg;

+    pjsip_host_port dest_addr;

+    pjsip_via_hdr *via;

+    struct tsx_lock_data lck;

+    pj_status_t status = PJ_SUCCESS;

+

+    /* Lock tsx. */

+    lock_tsx(tsx, &lck);

+

+    pj_assert(tsx->handle_ack != 0);

+    

+    msg = tdata->msg;

+

+    /* Generate branch parameter if it doesn't exist. */

+    via = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, NULL);

+    if (via == NULL) {

+	via = pjsip_via_hdr_create(tdata->pool);

+	pjsip_msg_add_hdr(msg, (pjsip_hdr*) via);

+    }

+

+    if (via->branch_param.slen == 0) {

+	via->branch_param = tsx->branch;

+    } else {

+	pj_assert( pj_strcmp(&via->branch_param, &tsx->branch) == 0 );

+    }

+

+    /* Get destination name from the message. */

+    status = tsx_process_route(tsx, tdata, &dest_addr);

+    if (status != 0){

+	goto on_error;

+    }

+

+    /* Compare message's destination name with transaction's destination name.

+     * If NOT equal, then we'll have to resolve the destination.

+     */

+    if (dest_addr.type == tsx->dest_name.type &&

+	dest_addr.flag == tsx->dest_name.flag &&

+	dest_addr.port == tsx->dest_name.port &&

+	pj_stricmp(&dest_addr.host, &tsx->dest_name.host) == 0)

+    {

+	/* Equal destination. We can use current transport. */

+	pjsip_tsx_on_tx_msg(tsx, tdata);

+	unlock_tsx(tsx, &lck);

+	return;

+

+    }

+

+    /* New destination; we'll have to resolve host and create new transport. */

+    pj_memcpy(&tsx->dest_name, &dest_addr, sizeof(dest_addr));

+    pj_strdup(tsx->pool, &tsx->dest_name.host, &dest_addr.host);

+

+    PJ_LOG(5,(tsx->obj_name, "tsx resolving destination %.*s:%d",

+			     tsx->dest_name.host.slen, 

+			     tsx->dest_name.host.ptr,

+			     tsx->dest_name.port));

+

+    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_RESOLVING;

+    pjsip_transport_dec_ref(tsx->transport);

+    tsx->transport = NULL;

+

+    /* Put the message in queue. */

+    pjsip_tsx_on_tx_msg(tsx, tdata);

+

+    /* This is a bug!

+     * We shouldn't change transaction's state before actually sending the

+     * message. Otherwise transaction will terminate before message is sent,

+     * and timeout timer will be scheduled.

+     */

+    PJ_TODO(TSX_DONT_CHANGE_STATE_BEFORE_SENDING_ACK)

+

+    /* 

+     * This will start asynchronous resolver job, and when it finishes, 

+     * the callback will be called.

+     */

+

+    tsx->transport_state = PJSIP_TSX_TRANSPORT_STATE_RESOLVING;

+    pjsip_endpt_resolve( tsx->endpt, tsx->pool, &tsx->dest_name, 

+			 tsx, &tsx_resolver_callback);

+

+    unlock_tsx(tsx, &lck);

+

+    /* There should be nothing to do after this point. 

+     * Execution for the transaction will resume when the resolver callback is

+     * called.

+     */

+    return;

+

+on_error:

+    /* Failure condition. 

+     * Send TERMINATED event.

+     */

+    tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;

+

+    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                   PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);

+

+    unlock_tsx(tsx, &lck);

+}

+

+

+/*

+ * This function is called by TU to send a message.

+ */

+PJ_DEF(void) pjsip_tsx_on_tx_msg( pjsip_transaction *tsx,

+				  pjsip_tx_data *tdata )

+{

+    pjsip_event event;

+    struct tsx_lock_data lck;

+    pj_status_t status;

+

+    PJ_LOG(5,(tsx->obj_name, "Request to transmit msg on state %s (tdata=%p)",

+                             state_str[tsx->state], tdata));

+

+    PJSIP_EVENT_INIT_TX_MSG(event, tsx, tdata);

+

+    /* Dispatch to transaction. */

+    lock_tsx(tsx, &lck);

+    status = (*tsx->state_handler)(tsx, &event);

+    unlock_tsx(tsx, &lck);

+}

+

+/*

+ * This function is called by endpoint when incoming message for the 

+ * transaction is received.

+ */

+PJ_DEF(void) pjsip_tsx_on_rx_msg( pjsip_transaction *tsx,

+				  pjsip_rx_data *rdata)

+{

+    pjsip_event event;

+    struct tsx_lock_data lck;

+    pj_status_t status;

+

+    PJ_LOG(5,(tsx->obj_name, "Incoming msg on state %s (rdata=%p)", 

+	      state_str[tsx->state], rdata));

+

+    PJSIP_EVENT_INIT_RX_MSG(event, tsx, rdata);

+

+    /* Dispatch to transaction. */

+    lock_tsx(tsx, &lck);

+    status = (*tsx->state_handler)(tsx, &event);

+    unlock_tsx(tsx, &lck);

+}

+

+/*

+ * Forcely terminate transaction.

+ */

+PJ_DEF(void) pjsip_tsx_terminate( pjsip_transaction *tsx, int code )

+{

+    struct tsx_lock_data lck;

+

+    lock_tsx(tsx, &lck);

+    tsx->status_code = code;

+    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                   PJSIP_EVENT_USER, NULL);

+

+    unlock_tsx(tsx, &lck);

+}

+

+/*

+ * Send message to the transport.

+ * If transport is not yet available, then do nothing. The message will be

+ * transmitted when transport connection completion callback is called.

+ */

+static pj_status_t tsx_send_msg( pjsip_transaction *tsx, 

+                                 pjsip_tx_data *tdata)

+{

+    pj_status_t status = PJ_SUCCESS;

+

+    PJ_LOG(5,(tsx->obj_name, "sending msg (tdata=%p)", tdata));

+

+    if (tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL) {

+	pj_ssize_t sent;

+	pjsip_event before_tx_event;

+

+	pj_assert(tsx->transport != NULL);

+

+	/* Make sure Via transport info is filled up properly for

+	 * requests. 

+	 */

+	if (tdata->msg->type == PJSIP_REQUEST_MSG) {

+	    const pj_sockaddr_in *addr_name;

+	    pjsip_via_hdr *via = (pjsip_via_hdr*) 

+		pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);

+

+	    /* For request message, set "rport" parameter by default. */

+	    if (tdata->msg->type == PJSIP_REQUEST_MSG)

+		via->rport_param = 0;

+

+	    /* Don't update Via sent-by on retransmission. */

+	    if (via->sent_by.host.slen == 0) {

+		addr_name = pjsip_transport_get_addr_name(tsx->transport);

+		pj_strdup2(tdata->pool, &via->transport, 

+			pjsip_transport_get_type_name(tsx->transport));

+		pj_strdup2(tdata->pool, &via->sent_by.host, 

+			   pj_inet_ntoa(addr_name->sin_addr));

+		via->sent_by.port = pj_ntohs(addr_name->sin_port);

+	    }

+	}

+

+	/* Notify everybody we're about to send message. */

+        PJSIP_EVENT_INIT_PRE_TX_MSG(before_tx_event, tsx, tdata, 

+                                    tsx->retransmit_count);

+	pjsip_endpt_send_tsx_event( tsx->endpt, &before_tx_event );

+

+	tsx->has_unsent_msg = 0;

+	status = pjsip_transport_send_msg(

+		        tsx->transport, tdata,

+		        &tsx->remote_addr.entry[tsx->current_addr].addr,

+                        &sent);

+	if (status != PJ_SUCCESS) {

+	    goto on_error;

+	}

+    } else {

+	tsx->has_unsent_msg = 1;

+    }

+

+    return 0;

+

+on_error:

+    tsx->status_code = PJSIP_SC_TSX_TRANSPORT_ERROR;

+    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                   PJSIP_EVENT_TRANSPORT_ERROR, (void*)status);

+    return status;

+}

+

+/*

+ * Retransmit last message sent.

+ */

+static pj_status_t pjsip_tsx_retransmit( pjsip_transaction *tsx,

+					 int should_restart_timer)

+{

+    pj_status_t status;

+

+    PJ_LOG(4,(tsx->obj_name, "retransmiting (tdata=%p, count=%d, restart?=%d)", 

+	      tsx->last_tx, tsx->retransmit_count, should_restart_timer));

+

+    pj_assert(tsx->last_tx != NULL);

+

+    ++tsx->retransmit_count;

+

+    status = tsx_send_msg( tsx, tsx->last_tx);

+    if (status != PJ_SUCCESS) {

+	return status;

+    }

+    

+    /* Restart timer T1. */

+    if (should_restart_timer) {

+	pj_time_val timeout;

+	int msec_time = (1 << (tsx->retransmit_count)) * PJSIP_T1_TIMEOUT;

+

+	if (tsx->method.id!=PJSIP_INVITE_METHOD && msec_time>PJSIP_T2_TIMEOUT) 

+	    msec_time = PJSIP_T2_TIMEOUT;

+

+	timeout.sec = msec_time / 1000;

+	timeout.msec = msec_time % 1000;

+	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->retransmit_timer, 

+				    &timeout);

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Handler for events in state Null.

+ */

+static pj_status_t pjsip_tsx_on_state_null( pjsip_transaction *tsx, 

+                                            pjsip_event *event )

+{

+    pj_status_t status;

+

+    pj_assert( tsx->state == PJSIP_TSX_STATE_NULL);

+    pj_assert( tsx->last_tx == NULL );

+    pj_assert( tsx->has_unsent_msg == 0);

+

+    if (tsx->role == PJSIP_ROLE_UAS) {

+

+	/* Set state to Trying. */

+	pj_assert(event->type == PJSIP_EVENT_RX_MSG);

+	tsx_set_state( tsx, PJSIP_TSX_STATE_TRYING, 

+                       PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );

+

+    } else {

+	pjsip_tx_data *tdata = event->body.tx_msg.tdata;

+

+	/* Save the message for retransmission. */

+	tsx->last_tx = tdata;

+	pjsip_tx_data_add_ref(tdata);

+

+	/* Send the message. */

+        status = tsx_send_msg( tsx, tdata);

+	if (status != PJ_SUCCESS) {

+	    return status;

+	}

+

+	/* Start Timer B (or called timer F for non-INVITE) for transaction 

+	 * timeout.

+	 */

+	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 

+                                    &timeout_timer_val);

+

+	/* Start Timer A (or timer E) for retransmission only if unreliable 

+	 * transport is being used.

+	 */

+	if (tsx->transport_state == PJSIP_TSX_TRANSPORT_STATE_FINAL &&

+	    PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) 

+	{

+	    pjsip_endpt_schedule_timer(tsx->endpt, &tsx->retransmit_timer, 

+                                       &t1_timer_val);

+	    tsx->retransmit_count = 0;

+	}

+

+	/* Move state. */

+	tsx_set_state( tsx, PJSIP_TSX_STATE_CALLING, 

+                       PJSIP_EVENT_TX_MSG, tdata);

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * State Calling is for UAC after it sends request but before any responses

+ * is received.

+ */

+static pj_status_t pjsip_tsx_on_state_calling( pjsip_transaction *tsx, 

+				               pjsip_event *event )

+{

+    pj_assert(tsx->state == PJSIP_TSX_STATE_CALLING);

+    pj_assert(tsx->role == PJSIP_ROLE_UAC);

+

+    if (event->type == PJSIP_EVENT_TIMER && 

+	event->body.timer.entry == &tsx->retransmit_timer) 

+    {

+        pj_status_t status;

+

+	/* Retransmit the request. */

+        status = pjsip_tsx_retransmit( tsx, 1 );

+	if (status != PJ_SUCCESS) {

+	    return status;

+	}

+

+    } else if (event->type == PJSIP_EVENT_TIMER && 

+	       event->body.timer.entry == &tsx->timeout_timer) 

+    {

+

+	/* Cancel retransmission timer. */

+	if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {

+	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);

+	}

+

+	/* Set status code */

+	tsx->status_code = PJSIP_SC_TSX_TIMEOUT;

+

+	/* Inform TU. */

+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                       PJSIP_EVENT_TIMER, &tsx->timeout_timer);

+

+	/* Transaction is destroyed */

+	return PJSIP_ETSXDESTROYED;

+

+    } else if (event->type == PJSIP_EVENT_RX_MSG) {

+	int code;

+

+	/* Cancel retransmission timer A. */

+	if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0)

+	    pjsip_endpt_cancel_timer(tsx->endpt, &tsx->retransmit_timer);

+

+	/* Cancel timer B (transaction timeout) */

+	pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);

+

+	/* Discard retransmission message if it is not INVITE.

+	 * The INVITE tdata is needed in case we have to generate ACK for

+	 * the final response.

+	 */

+	/* Keep last_tx for authorization. */

+	code = event->body.rx_msg.rdata->msg->line.status.code;

+	if (tsx->method.id != PJSIP_INVITE_METHOD && code!=401 && code!=407) {

+	    pjsip_tx_data_dec_ref(tsx->last_tx);

+	    tsx->last_tx = NULL;

+	}

+

+	/* Processing is similar to state Proceeding. */

+	pjsip_tsx_on_state_proceeding_uac( tsx, event);

+

+    } else {

+	pj_assert(0);

+        return PJ_EBUG;

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * State Trying is for UAS after it received request but before any responses

+ * is sent.

+ * Note: this is different than RFC3261, which can use Trying state for

+ *	 non-INVITE client transaction (bug in RFC?).

+ */

+static pj_status_t pjsip_tsx_on_state_trying( pjsip_transaction *tsx, 

+                                              pjsip_event *event)

+{

+    pj_status_t status;

+

+    pj_assert(tsx->state == PJSIP_TSX_STATE_TRYING);

+

+    /* This state is only for UAS */

+    pj_assert(tsx->role == PJSIP_ROLE_UAS);

+

+    /* Better be transmission of response message.

+     * If we've got request retransmission, this means that the TU hasn't

+     * transmitted any responses within 500 ms, which is not allowed. If

+     * this happens, just ignore the event (we couldn't retransmit last

+     * response because we haven't sent any!).

+     */

+    //pj_assert(event->type == PJSIP_EVENT_TX_MSG);

+    if (event->type != PJSIP_EVENT_TX_MSG) {

+	return PJ_SUCCESS;

+    }

+

+    /* The rest of the processing of the event is exactly the same as in

+     * "Proceeding" state.

+     */

+    status = pjsip_tsx_on_state_proceeding_uas( tsx, event);

+

+    /* Inform the TU of the state transision if state is still State_Trying */

+    if (status==PJ_SUCCESS && tsx->state == PJSIP_TSX_STATE_TRYING) {

+	tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, 

+                       PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata);

+    }

+

+    return status;

+}

+

+/*

+ * Handler for events in Proceeding for UAS

+ * This state happens after the TU sends provisional response.

+ */

+static pj_status_t pjsip_tsx_on_state_proceeding_uas( pjsip_transaction *tsx,

+                                                      pjsip_event *event)

+{

+    pj_assert(tsx->state == PJSIP_TSX_STATE_PROCEEDING || 

+	      tsx->state == PJSIP_TSX_STATE_TRYING);

+

+    /* This state is only for UAS. */

+    pj_assert(tsx->role == PJSIP_ROLE_UAS);

+

+    /* Receive request retransmission. */

+    if (event->type == PJSIP_EVENT_RX_MSG) {

+

+        pj_status_t status;

+

+	/* Send last response. */

+        status = pjsip_tsx_retransmit( tsx, 0 );

+	if (status != PJ_SUCCESS) {

+	    return status;

+	}

+	

+    } else if (event->type == PJSIP_EVENT_TX_MSG ) {

+	pjsip_tx_data *tdata = event->body.tx_msg.tdata;

+        pj_status_t status;

+

+	/* The TU sends response message to the request. Save this message so

+	 * that we can retransmit the last response in case we receive request

+	 * retransmission.

+	 */

+	pjsip_msg *msg = tdata->msg;

+

+	/* This can only be a response message. */

+	pj_assert(msg->type == PJSIP_RESPONSE_MSG);

+

+	/* Status code must be higher than last sent. */

+	pj_assert(msg->line.status.code >= tsx->status_code);

+

+	/* Update last status */

+	tsx->status_code = msg->line.status.code;

+

+	/* Discard the saved last response (it will be updated later as

+	 * necessary).

+	 */

+	if (tsx->last_tx && tsx->last_tx != tdata) {

+	    pjsip_tx_data_dec_ref( tsx->last_tx );

+	    tsx->last_tx = NULL;

+	}

+

+	/* Send the message. */

+        status = tsx_send_msg(tsx, tdata);

+	if (status != PJ_SUCCESS) {

+	    return status;

+	}

+

+	// Update To tag header for RFC2543 transaction.

+	// TODO:

+

+	/* Update transaction state */

+	if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 100)) {

+

+	    if (tsx->last_tx != tdata) {

+		tsx->last_tx = tdata;

+		pjsip_tx_data_add_ref( tdata );

+	    }

+	    tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, 

+                           PJSIP_EVENT_TX_MSG, tdata );

+

+	} else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 200)) {

+

+	    if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->handle_ack==0) {

+

+		/* 2xx class message is not saved, because retransmission 

+                 * is handled by TU.

+		 */

+		tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                               PJSIP_EVENT_TX_MSG, tdata );

+

+		/* Transaction is destroyed. */

+		return PJSIP_ETSXDESTROYED;

+

+	    } else {

+		pj_time_val timeout;

+

+		if (tsx->method.id == PJSIP_INVITE_METHOD) {

+		    tsx->retransmit_count = 0;

+		    pjsip_endpt_schedule_timer( tsx->endpt, 

+                                                &tsx->retransmit_timer, 

+						&t1_timer_val);

+		}

+

+		/* Save last response sent for retransmission when request 

+		 * retransmission is received.

+		 */

+		if (tsx->last_tx != tdata) {

+		    tsx->last_tx = tdata;

+		    pjsip_tx_data_add_ref(tdata);

+		}

+

+		/* Start timer J at 64*T1 for unreliable transport or zero for

+		 * reliable transport.

+		 */

+		if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {

+		    timeout = timeout_timer_val;

+		} else {

+		    timeout.sec = timeout.msec = 0;

+		}

+

+		pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 

+                                            &timeout);

+

+		/* Set state to "Completed" */

+		tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 

+                               PJSIP_EVENT_TX_MSG, tdata );

+	    }

+

+	} else if (tsx->status_code >= 300) {

+

+	    /* 3xx-6xx class message causes transaction to move to 

+             * "Completed" state. 

+             */

+	    if (tsx->last_tx != tdata) {

+		tsx->last_tx = tdata;

+		pjsip_tx_data_add_ref( tdata );

+	    }

+

+	    /* Start timer H for transaction termination */

+	    pjsip_endpt_schedule_timer(tsx->endpt,&tsx->timeout_timer,

+                                       &timeout_timer_val);

+

+	    /* For INVITE, if unreliable transport is used, retransmission 

+	     * timer G will be scheduled (retransmission).

+	     */

+	    if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport)==0) {

+		pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ,

+                                                           NULL);

+		if (cseq->method.id == PJSIP_INVITE_METHOD) {

+		    tsx->retransmit_count = 0;

+		    pjsip_endpt_schedule_timer(tsx->endpt, 

+                                               &tsx->retransmit_timer, 

+					       &t1_timer_val);

+		}

+	    }

+

+	    /* Inform TU */

+	    tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 

+                           PJSIP_EVENT_TX_MSG, tdata );

+

+	} else {

+	    pj_assert(0);

+	}

+

+

+    } else if (event->type == PJSIP_EVENT_TIMER && 

+	       event->body.timer.entry == &tsx->retransmit_timer) {

+	/* Retransmission timer elapsed. */

+        pj_status_t status;

+

+	/* Must have last response to retransmit. */

+	pj_assert(tsx->last_tx != NULL);

+

+	/* Retransmit the last response. */

+        status = pjsip_tsx_retransmit( tsx, 1 );

+	if (status != PJ_SUCCESS) {

+	    return status;

+	}

+

+    } else if (event->type == PJSIP_EVENT_TIMER && 

+	       event->body.timer.entry == &tsx->timeout_timer) {

+

+	/* Timeout timer. should not happen? */

+	pj_assert(0);

+

+	tsx->status_code = PJSIP_SC_TSX_TIMEOUT;

+

+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                       PJSIP_EVENT_TIMER, &tsx->timeout_timer);

+

+	return PJ_EBUG;

+

+    } else {

+	pj_assert(0);

+        return PJ_EBUG;

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Handler for events in Proceeding for UAC

+ * This state happens after provisional response(s) has been received from

+ * UAS.

+ */

+static pj_status_t pjsip_tsx_on_state_proceeding_uac(pjsip_transaction *tsx, 

+                                                     pjsip_event *event)

+{

+

+    pj_assert(tsx->state == PJSIP_TSX_STATE_PROCEEDING || 

+	      tsx->state == PJSIP_TSX_STATE_CALLING);

+

+    if (event->type != PJSIP_EVENT_TIMER) {

+	/* Must be incoming response, because we should not retransmit

+	 * request once response has been received.

+	 */

+	pj_assert(event->type == PJSIP_EVENT_RX_MSG);

+	if (event->type != PJSIP_EVENT_RX_MSG) {

+	    return PJ_EINVALIDOP;

+	}

+

+	tsx->status_code = event->body.rx_msg.rdata->msg->line.status.code;

+    } else {

+	tsx->status_code = PJSIP_SC_TSX_TIMEOUT;

+    }

+

+    if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code, 100)) {

+

+	/* Inform the message to TU. */

+	tsx_set_state( tsx, PJSIP_TSX_STATE_PROCEEDING, 

+                       PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );

+

+    } else if (PJSIP_IS_STATUS_IN_CLASS(tsx->status_code,200)) {

+

+	/* Stop timeout timer B/F. */

+	pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );

+

+	/* For INVITE, the state moves to Terminated state (because ACK is

+	 * handled in TU). For non-INVITE, state moves to Completed.

+	 */

+	if (tsx->method.id == PJSIP_INVITE_METHOD && tsx->handle_ack == 0) {

+	    tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                           PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );

+	    return PJSIP_ETSXDESTROYED;

+

+	} else {

+	    pj_time_val timeout;

+

+	    /* For unreliable transport, start timer D (for INVITE) or 

+	     * timer K for non-INVITE. */

+	    if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport) == 0) {

+		if (tsx->method.id == PJSIP_INVITE_METHOD) {

+		    timeout = td_timer_val;

+		} else {

+		    timeout = t4_timer_val;

+		}

+	    } else {

+		timeout.sec = timeout.msec = 0;

+	    }

+	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 

+					&timeout);

+

+	    /* Move state to Completed, inform TU. */

+	    tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 

+                           PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );

+	}

+

+    } else if (tsx->status_code >= 300 && tsx->status_code <= 699) {

+	pj_time_val timeout;

+        pj_status_t status;

+

+	/* Stop timer B. */

+	pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );

+

+	/* Generate and send ACK for INVITE. */

+	if (tsx->method.id == PJSIP_INVITE_METHOD) {

+	    pjsip_endpt_create_ack( tsx->endpt, tsx->last_tx, 

+                                    event->body.rx_msg.rdata );

+            status = tsx_send_msg( tsx, tsx->last_tx);

+	    if (status != PJ_SUCCESS) {

+		return status;

+	    }

+	}

+

+	/* Start Timer D with TD/T4 timer if unreliable transport is used. */

+	if (PJSIP_TRANSPORT_IS_RELIABLE(tsx->transport) == 0) {

+	    if (tsx->method.id == PJSIP_INVITE_METHOD) {

+		timeout = td_timer_val;

+	    } else {

+		timeout = t4_timer_val;

+	    }

+	} else {

+	    timeout.sec = timeout.msec = 0;

+	}

+	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout);

+

+	/* Inform TU. */

+	tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 

+                       PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );

+

+    } else {

+	// Shouldn't happen because there's no timer for this state.

+	pj_assert(0);

+        return PJ_EBUG;

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Handler for events in Completed state for UAS

+ */

+static pj_status_t pjsip_tsx_on_state_completed_uas( pjsip_transaction *tsx, 

+                                                     pjsip_event *event)

+{

+    pj_assert(tsx->state == PJSIP_TSX_STATE_COMPLETED);

+

+    if (event->type == PJSIP_EVENT_RX_MSG) {

+	pjsip_msg *msg = event->body.rx_msg.rdata->msg;

+	pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr( msg, PJSIP_H_CSEQ, NULL );

+

+	/* On receive request retransmission, retransmit last response. */

+	if (cseq->method.id != PJSIP_ACK_METHOD) {

+            pj_status_t status;

+

+            status = pjsip_tsx_retransmit( tsx, 0 );

+	    if (status != PJ_SUCCESS) {

+		return status;

+	    }

+

+	} else {

+	    /* Process incoming ACK request. */

+

+	    /* Cease retransmission. */

+	    pjsip_endpt_cancel_timer( tsx->endpt, &tsx->retransmit_timer );

+

+	    /* Start timer I in T4 interval (transaction termination). */

+	    pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );

+	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 

+					&t4_timer_val);

+

+	    /* Move state to "Confirmed" */

+	    tsx_set_state( tsx, PJSIP_TSX_STATE_CONFIRMED, 

+                           PJSIP_EVENT_RX_MSG, event->body.rx_msg.rdata );

+	}	

+

+    } else if (event->type == PJSIP_EVENT_TIMER) {

+

+	if (event->body.timer.entry == &tsx->retransmit_timer) {

+	    /* Retransmit message. */

+            pj_status_t status;

+

+            status = pjsip_tsx_retransmit( tsx, 1 );

+	    if (status != PJ_SUCCESS) {

+		return status;

+	    }

+

+	} else {

+	    if (tsx->method.id == PJSIP_INVITE_METHOD) {

+

+		/* For INVITE, this means that ACK was never received.

+		 * Set state to Terminated, and inform TU.

+		 */

+

+		tsx->status_code = PJSIP_SC_TSX_TIMEOUT;

+

+		tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                               PJSIP_EVENT_TIMER, &tsx->timeout_timer );

+

+		return PJSIP_ETSXDESTROYED;

+

+	    } else {

+		/* Transaction terminated, it can now be deleted. */

+		tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                               PJSIP_EVENT_TIMER, &tsx->timeout_timer );

+		return PJSIP_ETSXDESTROYED;

+	    }

+	}

+

+    } else {

+	/* Ignore request to transmit. */

+	pj_assert(event->body.tx_msg.tdata == tsx->last_tx);

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Handler for events in Completed state for UAC transaction.

+ */

+static pj_status_t pjsip_tsx_on_state_completed_uac( pjsip_transaction *tsx,

+                                                     pjsip_event *event)

+{

+    pj_assert(tsx->state == PJSIP_TSX_STATE_COMPLETED);

+

+    if (event->type == PJSIP_EVENT_TIMER) {

+	/* Must be the timeout timer. */

+	pj_assert(event->body.timer.entry == &tsx->timeout_timer);

+

+	/* Move to Terminated state. */

+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                       PJSIP_EVENT_TIMER, event->body.timer.entry );

+

+	/* Transaction has been destroyed. */

+	return PJSIP_ETSXDESTROYED;

+

+    } else if (event->type == PJSIP_EVENT_RX_MSG) {

+	if (tsx->method.id == PJSIP_INVITE_METHOD) {

+	    /* On received of final response retransmission, retransmit the ACK.

+	     * TU doesn't need to be informed.

+	     */

+	    pjsip_msg *msg = event->body.rx_msg.rdata->msg;

+	    pj_assert(msg->type == PJSIP_RESPONSE_MSG);

+	    if (msg->type==PJSIP_RESPONSE_MSG &&

+		msg->line.status.code >= 200)

+	    {

+                pj_status_t status;

+

+                status = pjsip_tsx_retransmit( tsx, 0 );

+		if (status != PJ_SUCCESS) {

+		    return status;

+		}

+	    } else {

+		/* Very late retransmission of privisional response. */

+		pj_assert( msg->type == PJSIP_RESPONSE_MSG );

+	    }

+	} else {

+	    /* Just drop the response. */

+	}

+    } else if (tsx->method.id == PJSIP_INVITE_METHOD &&

+	       event->type == PJSIP_EVENT_TX_MSG &&

+	       event->body.tx_msg.tdata->msg->line.req.method.id==PJSIP_ACK_METHOD) {

+

+        pj_status_t status;

+

+	/* Set last transmitted message. */

+	if (tsx->last_tx != event->body.tx_msg.tdata) {

+	    pjsip_tx_data_dec_ref( tsx->last_tx );

+	    tsx->last_tx = event->body.tx_msg.tdata;

+	    pjsip_tx_data_add_ref( tsx->last_tx );

+	}

+

+	/* No state changed, but notify app. 

+	 * Must notify now, so app has chance to put SDP in outgoing ACK msg.

+	 */

+	tsx_set_state( tsx, PJSIP_TSX_STATE_COMPLETED, 

+                       PJSIP_EVENT_TX_MSG, event->body.tx_msg.tdata );

+

+	/* Send msg */

+	status = tsx_send_msg(tsx, event->body.tx_msg.tdata);

+        if (status != PJ_SUCCESS)

+            return status;

+

+    } else {

+	pj_assert(0);

+        return PJ_EBUG;

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Handler for events in state Confirmed.

+ */

+static pj_status_t pjsip_tsx_on_state_confirmed( pjsip_transaction *tsx,

+                                                 pjsip_event *event)

+{

+    pj_assert(tsx->state == PJSIP_TSX_STATE_CONFIRMED);

+

+    /* This state is only for UAS for INVITE. */

+    pj_assert(tsx->role == PJSIP_ROLE_UAS);

+    pj_assert(tsx->method.id == PJSIP_INVITE_METHOD);

+

+    /* Absorb any ACK received. */

+    if (event->type == PJSIP_EVENT_RX_MSG) {

+

+        pjsip_method_e method_id = 

+            event->body.rx_msg.rdata->msg->line.req.method.id;

+

+	/* Must be a request message. */

+	pj_assert(event->body.rx_msg.rdata->msg->type == PJSIP_REQUEST_MSG);

+

+	/* Must be an ACK request or a late INVITE retransmission. */

+	pj_assert(method_id == PJSIP_ACK_METHOD ||

+		  method_id == PJSIP_INVITE_METHOD);

+

+        /* Just so that compiler won't complain about unused vars when

+         * building release code.

+         */

+        PJ_UNUSED_ARG(method_id);

+

+    } else if (event->type == PJSIP_EVENT_TIMER) {

+	/* Must be from timeout_timer_. */

+	pj_assert(event->body.timer.entry == &tsx->timeout_timer);

+

+	/* Move to Terminated state. */

+	tsx_set_state( tsx, PJSIP_TSX_STATE_TERMINATED, 

+                       PJSIP_EVENT_TIMER, &tsx->timeout_timer );

+

+	/* Transaction has been destroyed. */

+	return PJSIP_ETSXDESTROYED;

+

+    } else {

+	pj_assert(0);

+        return PJ_EBUG;

+    }

+

+    return PJ_SUCCESS;

+}

+

+/*

+ * Handler for events in state Terminated.

+ */

+static pj_status_t pjsip_tsx_on_state_terminated( pjsip_transaction *tsx,

+                                                  pjsip_event *event)

+{

+    pj_assert(tsx->state == PJSIP_TSX_STATE_TERMINATED);

+

+    PJ_UNUSED_ARG(event);

+

+    /* Destroy this transaction */

+    tsx_set_state(tsx, PJSIP_TSX_STATE_DESTROYED, 

+                  event->type, event->body.user.user1 );

+

+    return PJ_SUCCESS;

+}

+

+

+static pj_status_t pjsip_tsx_on_state_destroyed(pjsip_transaction *tsx,

+                                                pjsip_event *event)

+{

+    PJ_UNUSED_ARG(tsx);

+    PJ_UNUSED_ARG(event);

+    return PJ_SUCCESS;

+}

+

diff --git a/pjsip/src/pjsip/sip_transport.c b/pjsip/src/pjsip/sip_transport.c
index 09eb6cf..477ddf2 100644
--- a/pjsip/src/pjsip/sip_transport.c
+++ b/pjsip/src/pjsip/sip_transport.c
@@ -1,1667 +1,1689 @@
-/* $Id$
- */
-#include <pjsip/sip_transport.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_parser.h>
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_private.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_transport.h>

+#include <pjsip/sip_endpoint.h>

+#include <pjsip/sip_parser.h>

+#include <pjsip/sip_msg.h>

+#include <pjsip/sip_private.h>

 #include <pjsip/sip_errno.h>

-#include <pj/os.h>
-#include <pj/log.h>
-#include <pj/ioqueue.h>
-#include <pj/hash.h>
-#include <pj/string.h>
-#include <pj/pool.h>
+#include <pj/os.h>

+#include <pj/log.h>

+#include <pj/ioqueue.h>

+#include <pj/hash.h>

+#include <pj/string.h>

+#include <pj/pool.h>

 #include <pj/assert.h>

-
-#define MGR_IDLE_CHECK_INTERVAL	30
-#define MGR_HASH_TABLE_SIZE	PJSIP_MAX_DIALOG_COUNT
-#define BACKLOG			5
-#define DEFAULT_SO_SNDBUF	(8 * 1024 * 1024)
-#define DEFAULT_SO_RCVBUF	(8 * 1024 * 1024)
-
-#define LOG_TRANSPORT_MGR	"trmgr"	
-#define THIS_FILE		"sip_transport"
-
-static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr );
-
-
-/**
- * New TCP socket for accept.
- */
-typedef struct incoming_socket_rec
-{
-    pj_sock_t		sock;
-    pj_sockaddr_in	remote;
-    pj_sockaddr_in	local;
-    int			addrlen;
-} incoming_socket_rec;
-
-/**
- * SIP Transport.
- */
-struct pjsip_transport_t
-{
-    /** Standard list members, for chaining the transport in the 
-     *  listener list. 
-     */
-    PJ_DECL_LIST_MEMBER(struct pjsip_transport_t);
-
-    /** Transport's pool. */
-    pj_pool_t		*pool;
-
-    /** Mutex */
-    pj_mutex_t		*tr_mutex;
-
-    /** Transport name for logging purpose */
-    char		 obj_name[PJ_MAX_OBJ_NAME];
-
-    /** Socket handle */
-    pj_sock_t		 sock;
-
-    /** Transport type. */
-    pjsip_transport_type_e type;
-
-    /** Flags to keep various states (see pjsip_transport_flags_e). */
-    pj_uint32_t		 flag;
-
-    /** I/O Queue key */
-    pj_ioqueue_key_t	*key;
+

+#define MGR_IDLE_CHECK_INTERVAL	30

+#define MGR_HASH_TABLE_SIZE	PJSIP_MAX_DIALOG_COUNT

+#define BACKLOG			5

+#define DEFAULT_SO_SNDBUF	(8 * 1024 * 1024)

+#define DEFAULT_SO_RCVBUF	(8 * 1024 * 1024)

+

+#define LOG_TRANSPORT_MGR	"trmgr"	

+#define THIS_FILE		"sip_transport"

+

+static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr );

+

+

+/**

+ * New TCP socket for accept.

+ */

+typedef struct incoming_socket_rec

+{

+    pj_sock_t		sock;

+    pj_sockaddr_in	remote;

+    pj_sockaddr_in	local;

+    int			addrlen;

+} incoming_socket_rec;

+

+/**

+ * SIP Transport.

+ */

+struct pjsip_transport_t

+{

+    /** Standard list members, for chaining the transport in the 

+     *  listener list. 

+     */

+    PJ_DECL_LIST_MEMBER(struct pjsip_transport_t);

+

+    /** Transport's pool. */

+    pj_pool_t		*pool;

+

+    /** Mutex */

+    pj_mutex_t		*tr_mutex;

+

+    /** Transport name for logging purpose */

+    char		 obj_name[PJ_MAX_OBJ_NAME];

+

+    /** Socket handle */

+    pj_sock_t		 sock;

+

+    /** Transport type. */

+    pjsip_transport_type_e type;

+

+    /** Flags to keep various states (see pjsip_transport_flags_e). */

+    pj_uint32_t		 flag;

+

+    /** I/O Queue key */

+    pj_ioqueue_key_t	*key;

 

     /** Accept key. */

     pj_ioqueue_op_key_t	 accept_op;

 

-    /** Receive data buffer */
-    pjsip_rx_data	*rdata;
+    /** Receive data buffer */

+    pjsip_rx_data	*rdata;

 

-    /** Pointer to transport manager */
-    pjsip_transport_mgr *mgr;
-
-    /** Reference counter, to prevent this transport from being closed while
-     *  it's being used. 
-     */
-    pj_atomic_t		 *ref_cnt;
-
-    /** Local address. */
-    pj_sockaddr_in	 local_addr;
-
-    /** Address name (what to put in Via address field). */
-    pj_sockaddr_in	 addr_name;
-
-    /** Remote address (can be zero for UDP and for listeners). UDP listener
-     *  bound to local loopback interface (127.0.0.1) has remote address set
-     *  to 127.0.0.1 to prevent client from using it to send to remote hosts,
-     *  because remote host then will receive 127.0.0.1 as the packet's 
-     *  source address.
-     */
-    pj_sockaddr_in	 remote_addr;
-
-    /** Struct to save incoming socket information. */
-    incoming_socket_rec	 accept_data;
-
-    /** When this transport should be closed. */
-    pj_time_val		 close_time;
-
-    /** List of callbacks to be called when client attempt to use this 
-     *  transport while it's not connected (i.e. still connecting). 
-     */
-    pj_list		 cb_list;
-};
-
-
-/*
- * Transport manager.
- */
-struct pjsip_transport_mgr 
-{
-    pj_hash_table_t *transport_table;
-    pj_mutex_t	    *mutex;
-    pjsip_endpoint  *endpt;
-    pj_ioqueue_t    *ioqueue;
+    /** Pointer to transport manager */

+    pjsip_transport_mgr *mgr;

+

+    /** Reference counter, to prevent this transport from being closed while

+     *  it's being used. 

+     */

+    pj_atomic_t		 *ref_cnt;

+

+    /** Local address. */

+    pj_sockaddr_in	 local_addr;

+

+    /** Address name (what to put in Via address field). */

+    pj_sockaddr_in	 addr_name;

+

+    /** Remote address (can be zero for UDP and for listeners). UDP listener

+     *  bound to local loopback interface (127.0.0.1) has remote address set

+     *  to 127.0.0.1 to prevent client from using it to send to remote hosts,

+     *  because remote host then will receive 127.0.0.1 as the packet's 

+     *  source address.

+     */

+    pj_sockaddr_in	 remote_addr;

+

+    /** Struct to save incoming socket information. */

+    incoming_socket_rec	 accept_data;

+

+    /** When this transport should be closed. */

+    pj_time_val		 close_time;

+

+    /** List of callbacks to be called when client attempt to use this 

+     *  transport while it's not connected (i.e. still connecting). 

+     */

+    pj_list		 cb_list;

+};

+

+

+/*

+ * Transport manager.

+ */

+struct pjsip_transport_mgr 

+{

+    pj_hash_table_t *transport_table;

+    pj_mutex_t	    *mutex;

+    pjsip_endpoint  *endpt;

+    pj_ioqueue_t    *ioqueue;

     pj_time_val	     next_idle_check;

     pj_size_t        send_buf_size;

-    pj_size_t        recv_buf_size;
-    void           (*message_callback)(pjsip_endpoint*, pjsip_rx_data *rdata);
-};
-
-/*
- * Transport role.
- */
-typedef enum transport_role_e
-{
-    TRANSPORT_ROLE_LISTENER,
-    TRANSPORT_ROLE_TRANSPORT,
-} transport_role_e;
-
-/*
- * Transport key for indexing in the hash table.
- * WATCH OUT FOR ALIGNMENT PROBLEM HERE!
- */
-typedef struct transport_key
-{
-    pj_uint8_t	type;
-    pj_uint8_t	zero;
-    pj_uint16_t	port;
-    pj_uint32_t	addr;
-} transport_key;
-
-/*
- * Transport callback.
- */
-struct transport_callback
-{
-    PJ_DECL_LIST_MEMBER(struct transport_callback);
-
-    /** User defined token to be passed to the callback. */
-    void *token;
-
-    /** The callback function. */
-    void (*cb)(pjsip_transport_t *tr, void *token, pj_status_t status);
-
-};
-
-/*
- * Transport names.
- */
-const struct
-{
-    pjsip_transport_type_e type;
-    pj_uint16_t		   port;
-    pj_str_t		   name;
-} transport_names[] = 
-{
-    { PJSIP_TRANSPORT_UNSPECIFIED, 0, {NULL, 0}},
-    { PJSIP_TRANSPORT_UDP, 5060, {"UDP", 3}},
-#if PJ_HAS_TCP
-    { PJSIP_TRANSPORT_TCP, 5060, {"TCP", 3}},
-    { PJSIP_TRANSPORT_TLS, 5061, {"TLS", 3}},
-    { PJSIP_TRANSPORT_SCTP, 5060, {"SCTP", 4}}
-#endif
-};
-
+    pj_size_t        recv_buf_size;

+    void           (*message_callback)(pjsip_endpoint*, pjsip_rx_data *rdata);

+};

+

+/*

+ * Transport role.

+ */

+typedef enum transport_role_e

+{

+    TRANSPORT_ROLE_LISTENER,

+    TRANSPORT_ROLE_TRANSPORT,

+} transport_role_e;

+

+/*

+ * Transport key for indexing in the hash table.

+ * WATCH OUT FOR ALIGNMENT PROBLEM HERE!

+ */

+typedef struct transport_key

+{

+    pj_uint8_t	type;

+    pj_uint8_t	zero;

+    pj_uint16_t	port;

+    pj_uint32_t	addr;

+} transport_key;

+

+/*

+ * Transport callback.

+ */

+struct transport_callback

+{

+    PJ_DECL_LIST_MEMBER(struct transport_callback);

+

+    /** User defined token to be passed to the callback. */

+    void *token;

+

+    /** The callback function. */

+    void (*cb)(pjsip_transport_t *tr, void *token, pj_status_t status);

+

+};

+

+/*

+ * Transport names.

+ */

+const struct

+{

+    pjsip_transport_type_e type;

+    pj_uint16_t		   port;

+    pj_str_t		   name;

+} transport_names[] = 

+{

+    { PJSIP_TRANSPORT_UNSPECIFIED, 0, {NULL, 0}},

+    { PJSIP_TRANSPORT_UDP, 5060, {"UDP", 3}},

+#if PJ_HAS_TCP

+    { PJSIP_TRANSPORT_TCP, 5060, {"TCP", 3}},

+    { PJSIP_TRANSPORT_TLS, 5061, {"TLS", 3}},

+    { PJSIP_TRANSPORT_SCTP, 5060, {"SCTP", 4}}

+#endif

+};

+

 static void on_ioqueue_read(pj_ioqueue_key_t *key, 

                             pj_ioqueue_op_key_t *op_key, 

-                            pj_ssize_t bytes_read);
+                            pj_ssize_t bytes_read);

 static void on_ioqueue_write(pj_ioqueue_key_t *key, 

                              pj_ioqueue_op_key_t *op_key, 

-                             pj_ssize_t bytes_sent);
+                             pj_ssize_t bytes_sent);

 static void on_ioqueue_accept(pj_ioqueue_key_t *key, 

                               pj_ioqueue_op_key_t *op_key, 

 			      pj_sock_t newsock,

-                              int status);
+                              int status);

 static void on_ioqueue_connect(pj_ioqueue_key_t *key, 

-                               int status);
-
-static pj_ioqueue_callback ioqueue_transport_callback = 
-{
-    &on_ioqueue_read,
-    &on_ioqueue_write,
-    &on_ioqueue_accept,
-    &on_ioqueue_connect
-};
-
-static void init_key_from_transport(transport_key *key, 
-				    const pjsip_transport_t *tr)
-{
-    /* This is to detect alignment problems. */
-    pj_assert(sizeof(transport_key) == 8);
-
-    key->type = (pj_uint8_t)tr->type;
-    key->zero = 0;
-    key->addr = pj_sockaddr_in_get_addr(&tr->remote_addr).s_addr;
-    key->port = pj_sockaddr_in_get_port(&tr->remote_addr);
-    /*
-    if (key->port == 0) {
-	key->port = pj_sockaddr_in_get_port(&tr->local_addr);
-    }
-    */
-}
-
-#if PJ_HAS_TCP
-static void init_tcp_key(transport_key *key, pjsip_transport_type_e type,
-			 const pj_sockaddr_in *addr)
-{
-    /* This is to detect alignment problems. */
-    pj_assert(sizeof(transport_key) == 8);
-
-    key->type = (pj_uint8_t)type;
-    key->zero = 0;
-    key->addr = pj_sockaddr_in_get_addr(addr).s_addr;
-    key->port = pj_sockaddr_in_get_port(addr);
-}
-#endif
-
-static void init_udp_key(transport_key *key, pjsip_transport_type_e type,
-			  const pj_sockaddr_in *addr)
-{
-    PJ_UNUSED_ARG(addr);
-
-    /* This is to detect alignment problems. */
-    pj_assert(sizeof(transport_key) == 8);
-
-    pj_memset(key, 0, sizeof(*key));
-    key->type = (pj_uint8_t)type;
-
-#if 0	/* Not sure why we need to make 127.0.0.1 a special case */
-    if (addr->sin_addr.s_addr == inet_addr("127.0.0.1")) {
-	/* This looks more complicated than it is because key->addr uses
-	 * the host version of the address (i.e. converted with ntohl()).
-	 */
-	pj_str_t localaddr = pj_str("127.0.0.1");
-	pj_sockaddr_in addr;
-	pj_sockaddr_set_str_addr(&addr, &localaddr);
-	key->addr = pj_sockaddr_in_get_addr(&addr);
-    }
-#endif
-}
-
-/*
- * Get type format name (for pool name).
- */
-static const char *transport_get_name_format( int type )
-{
-    switch (type) {
-    case PJSIP_TRANSPORT_UDP:
-	return " udp%p";
-#if PJ_HAS_TCP
-    case PJSIP_TRANSPORT_TCP:
-	return " tcp%p";
-    case PJSIP_TRANSPORT_TLS:
-	return " tls%p";
-    case PJSIP_TRANSPORT_SCTP:
-	return "sctp%p";
-#endif
-    }
-    pj_assert(0);
-    return 0;
-}
-
-/*
- * Get the default SIP port number for the specified type.
- */
-PJ_DEF(int) pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type)
-{
-    return transport_names[type].port;
-}
-
-/*
- * Get transport name.
- */
-static const char *get_type_name(int type)
-{
-    return transport_names[type].name.ptr;
-}
-
-/*
- * Get transport type from name.
- */
-PJ_DEF(pjsip_transport_type_e) 
-pjsip_transport_get_type_from_name(const pj_str_t *name)
-{
-    unsigned i;
-
-    for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) {
-	if (pj_stricmp(name, &transport_names[i].name) == 0) {
-	    return transport_names[i].type;
-	}
-    }
-    return PJSIP_TRANSPORT_UNSPECIFIED;
-}
-
-/*
- * Create new transmit buffer.
- */
+                               int status);

+

+static pj_ioqueue_callback ioqueue_transport_callback = 

+{

+    &on_ioqueue_read,

+    &on_ioqueue_write,

+    &on_ioqueue_accept,

+    &on_ioqueue_connect

+};

+

+static void init_key_from_transport(transport_key *key, 

+				    const pjsip_transport_t *tr)

+{

+    /* This is to detect alignment problems. */

+    pj_assert(sizeof(transport_key) == 8);

+

+    key->type = (pj_uint8_t)tr->type;

+    key->zero = 0;

+    key->addr = pj_sockaddr_in_get_addr(&tr->remote_addr).s_addr;

+    key->port = pj_sockaddr_in_get_port(&tr->remote_addr);

+    /*

+    if (key->port == 0) {

+	key->port = pj_sockaddr_in_get_port(&tr->local_addr);

+    }

+    */

+}

+

+#if PJ_HAS_TCP

+static void init_tcp_key(transport_key *key, pjsip_transport_type_e type,

+			 const pj_sockaddr_in *addr)

+{

+    /* This is to detect alignment problems. */

+    pj_assert(sizeof(transport_key) == 8);

+

+    key->type = (pj_uint8_t)type;

+    key->zero = 0;

+    key->addr = pj_sockaddr_in_get_addr(addr).s_addr;

+    key->port = pj_sockaddr_in_get_port(addr);

+}

+#endif

+

+static void init_udp_key(transport_key *key, pjsip_transport_type_e type,

+			  const pj_sockaddr_in *addr)

+{

+    PJ_UNUSED_ARG(addr);

+

+    /* This is to detect alignment problems. */

+    pj_assert(sizeof(transport_key) == 8);

+

+    pj_memset(key, 0, sizeof(*key));

+    key->type = (pj_uint8_t)type;

+

+#if 0	/* Not sure why we need to make 127.0.0.1 a special case */

+    if (addr->sin_addr.s_addr == inet_addr("127.0.0.1")) {

+	/* This looks more complicated than it is because key->addr uses

+	 * the host version of the address (i.e. converted with ntohl()).

+	 */

+	pj_str_t localaddr = pj_str("127.0.0.1");

+	pj_sockaddr_in addr;

+	pj_sockaddr_set_str_addr(&addr, &localaddr);

+	key->addr = pj_sockaddr_in_get_addr(&addr);

+    }

+#endif

+}

+

+/*

+ * Get type format name (for pool name).

+ */

+static const char *transport_get_name_format( int type )

+{

+    switch (type) {

+    case PJSIP_TRANSPORT_UDP:

+	return " udp%p";

+#if PJ_HAS_TCP

+    case PJSIP_TRANSPORT_TCP:

+	return " tcp%p";

+    case PJSIP_TRANSPORT_TLS:

+	return " tls%p";

+    case PJSIP_TRANSPORT_SCTP:

+	return "sctp%p";

+#endif

+    }

+    pj_assert(0);

+    return 0;

+}

+

+/*

+ * Get the default SIP port number for the specified type.

+ */

+PJ_DEF(int) pjsip_transport_get_default_port_for_type(pjsip_transport_type_e type)

+{

+    return transport_names[type].port;

+}

+

+/*

+ * Get transport name.

+ */

+static const char *get_type_name(int type)

+{

+    return transport_names[type].name.ptr;

+}

+

+/*

+ * Get transport type from name.

+ */

+PJ_DEF(pjsip_transport_type_e) 

+pjsip_transport_get_type_from_name(const pj_str_t *name)

+{

+    unsigned i;

+

+    for (i=0; i<PJ_ARRAY_SIZE(transport_names); ++i) {

+	if (pj_stricmp(name, &transport_names[i].name) == 0) {

+	    return transport_names[i].type;

+	}

+    }

+    return PJSIP_TRANSPORT_UNSPECIFIED;

+}

+

+/*

+ * Create new transmit buffer.

+ */

 pj_status_t pjsip_tx_data_create( pjsip_transport_mgr *mgr,

-                                  pjsip_tx_data **p_tdata )
-{
-    pj_pool_t *pool;
-    pjsip_tx_data *tdata;
+                                  pjsip_tx_data **p_tdata )

+{

+    pj_pool_t *pool;

+    pjsip_tx_data *tdata;

     pj_status_t status;

-
-    PJ_LOG(5, ("", "pjsip_tx_data_create"));
+

+    PJ_LOG(5, ("", "pjsip_tx_data_create"));

 

     PJ_ASSERT_RETURN(mgr && p_tdata, PJ_EINVAL);

-
-    pool = pjsip_endpt_create_pool( mgr->endpt, "ptdt%p",
-				    PJSIP_POOL_LEN_TDATA,
-				    PJSIP_POOL_INC_TDATA );
-    if (!pool) {
-	return PJ_ENOMEM;
-    }
-    tdata = pj_pool_calloc(pool, 1, sizeof(pjsip_tx_data));
-    tdata->pool = pool;
-    tdata->mgr = mgr;
-    pj_sprintf(tdata->obj_name,"txd%p", tdata);
-
-    status = pj_atomic_create(tdata->pool, 0, &tdata->ref_cnt);
-    if (status != PJ_SUCCESS) {
-	pjsip_endpt_destroy_pool( mgr->endpt, tdata->pool );
-	return status;
-    }
+

+    pool = pjsip_endpt_create_pool( mgr->endpt, "ptdt%p",

+				    PJSIP_POOL_LEN_TDATA,

+				    PJSIP_POOL_INC_TDATA );

+    if (!pool) {

+	return PJ_ENOMEM;

+    }

+    tdata = pj_pool_calloc(pool, 1, sizeof(pjsip_tx_data));

+    tdata->pool = pool;

+    tdata->mgr = mgr;

+    pj_sprintf(tdata->obj_name,"txd%p", tdata);

+

+    status = pj_atomic_create(tdata->pool, 0, &tdata->ref_cnt);

+    if (status != PJ_SUCCESS) {

+	pjsip_endpt_destroy_pool( mgr->endpt, tdata->pool );

+	return status;

+    }

     

-    *p_tdata = tdata;
-    return PJ_SUCCESS;
-}
-
-/*
- * Add reference to tx buffer.
- */
-PJ_DEF(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata )
-{
-    pj_atomic_inc(tdata->ref_cnt);
-}
-
-/*
- * Decrease transport data reference, destroy it when the reference count
- * reaches zero.
- */
-PJ_DEF(void) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata )
-{
-    pj_assert( pj_atomic_get(tdata->ref_cnt) > 0);
-    if (pj_atomic_dec_and_get(tdata->ref_cnt) <= 0) {
-	PJ_LOG(6,(tdata->obj_name, "destroying txdata"));
-	pj_atomic_destroy( tdata->ref_cnt );
-	pjsip_endpt_destroy_pool( tdata->mgr->endpt, tdata->pool );
-    }
-}
-
-/*
- * Invalidate the content of the print buffer to force the message to be
- * re-printed when sent.
- */
-PJ_DEF(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata )
-{
-    tdata->buf.cur = tdata->buf.start;
-}
-
-/*
- * Get the transport type.
- */
-PJ_DEF(pjsip_transport_type_e) pjsip_transport_get_type( const pjsip_transport_t * tr)
-{
-    return tr->type;
-}
-
-/*
- * Get transport type from transport flag.
- */
-PJ_DEF(pjsip_transport_type_e) pjsip_get_transport_type_from_flag(unsigned flag)
-{
-#if PJ_HAS_TCP
-    if (flag & PJSIP_TRANSPORT_SECURE) {
-	return PJSIP_TRANSPORT_TLS;
-    } else if (flag & PJSIP_TRANSPORT_RELIABLE) {
-	return PJSIP_TRANSPORT_TCP;
-    } else 
-#else
-    PJ_UNUSED_ARG(flag);
-#endif
-    {
-	return PJSIP_TRANSPORT_UDP;
-    }
-}
-
-/*
- * Get the transport type name.
- */
-PJ_DEF(const char *) pjsip_transport_get_type_name( const pjsip_transport_t * tr)
-{
-    return get_type_name(tr->type);
-}
-
-/*
- * Get the transport's object name.
- */
-PJ_DEF(const char*) pjsip_transport_get_obj_name( const pjsip_transport_t *tr )
-{
-    return tr->obj_name;
-}
-
-/*
- * Get the transport's reference counter.
- */
-PJ_DEF(int) pjsip_transport_get_ref_cnt( const pjsip_transport_t *tr )
-{
-    return pj_atomic_get(tr->ref_cnt);
-}
-
-/*
- * Get transport local address.
- */
-PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_local_addr( pjsip_transport_t *tr )
-{
-    return &tr->local_addr;
-}
-
-/*
- * Get address name.
- */
-PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_addr_name (pjsip_transport_t *tr)
-{
-    return &tr->addr_name;
-}
-
-/*
- * Get transport remote address.
- */
-PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_remote_addr( const pjsip_transport_t *tr )
-{
-    return &tr->remote_addr;
-}
-
-/*
- * Get transport flag.
- */
-PJ_DEF(unsigned) pjsip_transport_get_flag( const pjsip_transport_t * tr )
-{
-    return tr->flag;
-}
-
-/*
- * Add reference to the specified transport.
- */
-PJ_DEF(void) pjsip_transport_add_ref( pjsip_transport_t * tr )
-{
-    pj_atomic_inc(tr->ref_cnt);
-}
-
-/*
- * Decrease the reference time of the transport.
- */
-PJ_DEF(void) pjsip_transport_dec_ref( pjsip_transport_t *tr )
-{
-    pj_assert(tr->ref_cnt > 0);
-    if (pj_atomic_dec_and_get(tr->ref_cnt) == 0) {
-	pj_gettimeofday(&tr->close_time);
-	tr->close_time.sec += PJSIP_TRANSPORT_CLOSE_TIMEOUT;
-    }
-}
-
-/*
- * Open the underlying transport.
- */
-static pj_status_t create_socket( pjsip_transport_type_e type,
+    *p_tdata = tdata;

+    return PJ_SUCCESS;

+}

+

+/*

+ * Add reference to tx buffer.

+ */

+PJ_DEF(void) pjsip_tx_data_add_ref( pjsip_tx_data *tdata )

+{

+    pj_atomic_inc(tdata->ref_cnt);

+}

+

+/*

+ * Decrease transport data reference, destroy it when the reference count

+ * reaches zero.

+ */

+PJ_DEF(void) pjsip_tx_data_dec_ref( pjsip_tx_data *tdata )

+{

+    pj_assert( pj_atomic_get(tdata->ref_cnt) > 0);

+    if (pj_atomic_dec_and_get(tdata->ref_cnt) <= 0) {

+	PJ_LOG(6,(tdata->obj_name, "destroying txdata"));

+	pj_atomic_destroy( tdata->ref_cnt );

+	pjsip_endpt_destroy_pool( tdata->mgr->endpt, tdata->pool );

+    }

+}

+

+/*

+ * Invalidate the content of the print buffer to force the message to be

+ * re-printed when sent.

+ */

+PJ_DEF(void) pjsip_tx_data_invalidate_msg( pjsip_tx_data *tdata )

+{

+    tdata->buf.cur = tdata->buf.start;

+}

+

+/*

+ * Get the transport type.

+ */

+PJ_DEF(pjsip_transport_type_e) pjsip_transport_get_type( const pjsip_transport_t * tr)

+{

+    return tr->type;

+}

+

+/*

+ * Get transport type from transport flag.

+ */

+PJ_DEF(pjsip_transport_type_e) pjsip_get_transport_type_from_flag(unsigned flag)

+{

+#if PJ_HAS_TCP

+    if (flag & PJSIP_TRANSPORT_SECURE) {

+	return PJSIP_TRANSPORT_TLS;

+    } else if (flag & PJSIP_TRANSPORT_RELIABLE) {

+	return PJSIP_TRANSPORT_TCP;

+    } else 

+#else

+    PJ_UNUSED_ARG(flag);

+#endif

+    {

+	return PJSIP_TRANSPORT_UDP;

+    }

+}

+

+/*

+ * Get the transport type name.

+ */

+PJ_DEF(const char *) pjsip_transport_get_type_name( const pjsip_transport_t * tr)

+{

+    return get_type_name(tr->type);

+}

+

+/*

+ * Get the transport's object name.

+ */

+PJ_DEF(const char*) pjsip_transport_get_obj_name( const pjsip_transport_t *tr )

+{

+    return tr->obj_name;

+}

+

+/*

+ * Get the transport's reference counter.

+ */

+PJ_DEF(int) pjsip_transport_get_ref_cnt( const pjsip_transport_t *tr )

+{

+    return pj_atomic_get(tr->ref_cnt);

+}

+

+/*

+ * Get transport local address.

+ */

+PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_local_addr( pjsip_transport_t *tr )

+{

+    return &tr->local_addr;

+}

+

+/*

+ * Get address name.

+ */

+PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_addr_name (pjsip_transport_t *tr)

+{

+    return &tr->addr_name;

+}

+

+/*

+ * Get transport remote address.

+ */

+PJ_DEF(const pj_sockaddr_in*) pjsip_transport_get_remote_addr( const pjsip_transport_t *tr )

+{

+    return &tr->remote_addr;

+}

+

+/*

+ * Get transport flag.

+ */

+PJ_DEF(unsigned) pjsip_transport_get_flag( const pjsip_transport_t * tr )

+{

+    return tr->flag;

+}

+

+/*

+ * Add reference to the specified transport.

+ */

+PJ_DEF(void) pjsip_transport_add_ref( pjsip_transport_t * tr )

+{

+    pj_atomic_inc(tr->ref_cnt);

+}

+

+/*

+ * Decrease the reference time of the transport.

+ */

+PJ_DEF(void) pjsip_transport_dec_ref( pjsip_transport_t *tr )

+{

+    pj_assert(tr->ref_cnt > 0);

+    if (pj_atomic_dec_and_get(tr->ref_cnt) == 0) {

+	pj_gettimeofday(&tr->close_time);

+	tr->close_time.sec += PJSIP_TRANSPORT_CLOSE_TIMEOUT;

+    }

+}

+

+/*

+ * Open the underlying transport.

+ */

+static pj_status_t create_socket( pjsip_transport_type_e type,

 				  pj_sockaddr_in *local,

-                                  pj_sock_t *p_sock)
-{
-    int sock_family;
-    int sock_type;
-    int sock_proto;
+                                  pj_sock_t *p_sock)

+{

+    int sock_family;

+    int sock_type;

+    int sock_proto;

     int len;

-    pj_status_t status;
-    pj_sock_t sock;
-
-    /* Set socket parameters */
-    if (type == PJSIP_TRANSPORT_UDP) {
-	sock_family = PJ_AF_INET;
-	sock_type = PJ_SOCK_DGRAM;
-	sock_proto = 0;
-
-#if PJ_HAS_TCP
-    } else if (type == PJSIP_TRANSPORT_TCP) {
-	sock_family = PJ_AF_INET;
-	sock_type = PJ_SOCK_STREAM;
-	sock_proto = 0;
-#endif
-    } else {
-	return PJ_EINVAL;
-    }
-
-    /* Create socket. */
-    status = pj_sock_socket( sock_family, sock_type, sock_proto, &sock);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Bind the socket to the requested address, or if no address is
-     * specified, let the operating system chooses the address.
-     */
-    if (/*local->sin_addr.s_addr != 0 &&*/ local->sin_port != 0) {
+    pj_status_t status;

+    pj_sock_t sock;

+

+    /* Set socket parameters */

+    if (type == PJSIP_TRANSPORT_UDP) {

+	sock_family = PJ_AF_INET;

+	sock_type = PJ_SOCK_DGRAM;

+	sock_proto = 0;

+

+#if PJ_HAS_TCP

+    } else if (type == PJSIP_TRANSPORT_TCP) {

+	sock_family = PJ_AF_INET;

+	sock_type = PJ_SOCK_STREAM;

+	sock_proto = 0;

+#endif

+    } else {

+	return PJ_EINVAL;

+    }

+

+    /* Create socket. */

+    status = pj_sock_socket( sock_family, sock_type, sock_proto, &sock);

+    if (status != PJ_SUCCESS)

+	return status;

+

+    /* Bind the socket to the requested address, or if no address is

+     * specified, let the operating system chooses the address.

+     */

+    if (/*local->sin_addr.s_addr != 0 &&*/ local->sin_port != 0) {

 	/* Bind to the requested address. */

-        status = pj_sock_bind(sock, local, sizeof(*local));
-	if (status != PJ_SUCCESS) {
-	    pj_sock_close(sock);
-	    return status;
-	}
-    } else if (type == PJSIP_TRANSPORT_UDP) {
-	/* Only for UDP sockets: bind to any address so that the operating 
-	 * system allocates the port for us. For TCP, let the OS implicitly
-	 * bind the socket with connect() syscall (if we bind now, then we'll
-	 * get 0.0.0.0 as local address).
-	 */
-	pj_memset(local, 0, sizeof(*local));
+        status = pj_sock_bind(sock, local, sizeof(*local));

+	if (status != PJ_SUCCESS) {

+	    pj_sock_close(sock);

+	    return status;

+	}

+    } else if (type == PJSIP_TRANSPORT_UDP) {

+	/* Only for UDP sockets: bind to any address so that the operating 

+	 * system allocates the port for us. For TCP, let the OS implicitly

+	 * bind the socket with connect() syscall (if we bind now, then we'll

+	 * get 0.0.0.0 as local address).

+	 */

+	pj_memset(local, 0, sizeof(*local));

 	local->sin_family = PJ_AF_INET;

-        status = pj_sock_bind(sock, local, sizeof(*local));
-	if (status != PJ_SUCCESS) {
-	    pj_sock_close(sock);
-	    return status;
-	}
-
-	/* Get the local address. */
+        status = pj_sock_bind(sock, local, sizeof(*local));

+	if (status != PJ_SUCCESS) {

+	    pj_sock_close(sock);

+	    return status;

+	}

+

+	/* Get the local address. */

 	len = sizeof(pj_sockaddr_in);

-        status = pj_sock_getsockname(sock, local, &len);
-	if (status != PJ_SUCCESS) {
-	    pj_sock_close(sock);
-	    return status;
-	}
-    }
+        status = pj_sock_getsockname(sock, local, &len);

+	if (status != PJ_SUCCESS) {

+	    pj_sock_close(sock);

+	    return status;

+	}

+    }

 

-    *p_sock = sock;
-    return PJ_SUCCESS;
-}
-
-/*
- * Close the transport.
- */
-static void destroy_socket( pjsip_transport_t * tr)
-{
-    pj_assert( pj_atomic_get(tr->ref_cnt) == 0);
-    pj_sock_close(tr->sock);
-    tr->sock = -1;
-}
-
-/*
- * Create a new transport object.
- */
-static pj_status_t create_transport( pjsip_transport_mgr *mgr,
-				     pjsip_transport_type_e type,
-				     pj_sock_t sock_hnd,
-				     const pj_sockaddr_in *local_addr,
+    *p_sock = sock;

+    return PJ_SUCCESS;

+}

+

+/*

+ * Close the transport.

+ */

+static void destroy_socket( pjsip_transport_t * tr)

+{

+    pj_assert( pj_atomic_get(tr->ref_cnt) == 0);

+    pj_sock_close(tr->sock);

+    tr->sock = -1;

+}

+

+/*

+ * Create a new transport object.

+ */

+static pj_status_t create_transport( pjsip_transport_mgr *mgr,

+				     pjsip_transport_type_e type,

+				     pj_sock_t sock_hnd,

+				     const pj_sockaddr_in *local_addr,

 				     const pj_sockaddr_in *addr_name,

-				     pjsip_transport_t **p_transport )
-{
-    pj_pool_t *tr_pool=NULL, *rdata_pool=NULL;
+				     pjsip_transport_t **p_transport )

+{

+    pj_pool_t *tr_pool=NULL, *rdata_pool=NULL;

     pjsip_transport_t *tr = NULL;

-    pj_status_t status;
-
-    /* Allocate pool for transport from endpoint. */
-    tr_pool = pjsip_endpt_create_pool( mgr->endpt,
-				       transport_get_name_format(type),
-				       PJSIP_POOL_LEN_TRANSPORT,
-				       PJSIP_POOL_INC_TRANSPORT );
-    if (!tr_pool) {

-	status = PJ_ENOMEM;
-	goto on_error;
-    }
-
-    /* Allocate pool for rdata from endpoint. */
-    rdata_pool = pjsip_endpt_create_pool( mgr->endpt,
-					     "prdt%p",
-					     PJSIP_POOL_LEN_RDATA,
-					     PJSIP_POOL_INC_RDATA );
-    if (!rdata_pool) {

-	status = PJ_ENOMEM;
-	goto on_error;
-    }
-
-    /* Allocate and initialize the transport. */
-    tr = pj_pool_calloc(tr_pool, 1, sizeof(*tr));
-    tr->pool = tr_pool;
-    tr->type = type;
-    tr->mgr = mgr;
-    tr->sock = sock_hnd;
-    pj_memcpy(&tr->local_addr, local_addr, sizeof(pj_sockaddr_in));
-    pj_list_init(&tr->cb_list);
-    pj_sprintf(tr->obj_name, transport_get_name_format(type), tr);
-
-    if (type != PJSIP_TRANSPORT_UDP) {
-	tr->flag |= PJSIP_TRANSPORT_RELIABLE;
-    }
-
-    /* Address name. */
-    if (addr_name == NULL) {
-	addr_name = &tr->local_addr;
-    } 
-    pj_memcpy(&tr->addr_name, addr_name, sizeof(*addr_name));
-
-    /* Create atomic */

-    status = pj_atomic_create(tr_pool, 0, &tr->ref_cnt);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-    
-    /* Init rdata in the transport. */
-    tr->rdata = pj_pool_alloc(rdata_pool, sizeof(*tr->rdata));
-    tr->rdata->pool = rdata_pool;
-    tr->rdata->len = 0;
-    tr->rdata->transport = tr;
-    
-    /* Init transport mutex. */
-    status = pj_mutex_create_recursive(tr_pool, "mtr%p", &tr->tr_mutex);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* Register to I/O Queue */
-    status = pj_ioqueue_register_sock( tr_pool, mgr->ioqueue, 
-				       tr->sock, tr,
-				       &ioqueue_transport_callback,

-				       &tr->key);
-    if (status != PJ_SUCCESS)
-	goto on_error;
+    pj_status_t status;

 

-    *p_transport = tr;
-    return PJ_SUCCESS;
-
-on_error:
-    if (tr && tr->tr_mutex) {
-	pj_mutex_destroy(tr->tr_mutex);
-    }
-    if (tr_pool) {
-	pjsip_endpt_destroy_pool(mgr->endpt, tr_pool);
-    }
-    if (rdata_pool) {
-	pjsip_endpt_destroy_pool(mgr->endpt, rdata_pool);
-    }
-    return status;
-}
-
-/*
- * Destroy transport.
- */
-static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr)
-{
-    transport_key hash_key;
-
-    /* Remove from I/O queue. */
-    pj_ioqueue_unregister( tr->key );
-
-    /* Remove from hash table */
-    init_key_from_transport(&hash_key, tr);
-    pj_hash_set(NULL, mgr->transport_table, &hash_key, sizeof(hash_key), NULL);
-
-    /* Close transport. */
-    destroy_socket(tr);
-
-    /* Destroy the transport mutex. */
-    pj_mutex_destroy(tr->tr_mutex);
-
-    /* Destroy atomic */
-    pj_atomic_destroy( tr->ref_cnt );
-
-    /* Release the pool associated with the rdata. */
-    pjsip_endpt_destroy_pool(mgr->endpt, tr->rdata->pool );
-
-    /* Release the pool associated with the transport. */
-    pjsip_endpt_destroy_pool(mgr->endpt, tr->pool );
-}
-
-
+    /* Allocate pool for transport from endpoint. */

+    tr_pool = pjsip_endpt_create_pool( mgr->endpt,

+				       transport_get_name_format(type),

+				       PJSIP_POOL_LEN_TRANSPORT,

+				       PJSIP_POOL_INC_TRANSPORT );

+    if (!tr_pool) {

+	status = PJ_ENOMEM;

+	goto on_error;

+    }

+

+    /* Allocate pool for rdata from endpoint. */

+    rdata_pool = pjsip_endpt_create_pool( mgr->endpt,

+					     "prdt%p",

+					     PJSIP_POOL_LEN_RDATA,

+					     PJSIP_POOL_INC_RDATA );

+    if (!rdata_pool) {

+	status = PJ_ENOMEM;

+	goto on_error;

+    }

+

+    /* Allocate and initialize the transport. */

+    tr = pj_pool_calloc(tr_pool, 1, sizeof(*tr));

+    tr->pool = tr_pool;

+    tr->type = type;

+    tr->mgr = mgr;

+    tr->sock = sock_hnd;

+    pj_memcpy(&tr->local_addr, local_addr, sizeof(pj_sockaddr_in));

+    pj_list_init(&tr->cb_list);

+    pj_sprintf(tr->obj_name, transport_get_name_format(type), tr);

+

+    if (type != PJSIP_TRANSPORT_UDP) {

+	tr->flag |= PJSIP_TRANSPORT_RELIABLE;

+    }

+

+    /* Address name. */

+    if (addr_name == NULL) {

+	addr_name = &tr->local_addr;

+    } 

+    pj_memcpy(&tr->addr_name, addr_name, sizeof(*addr_name));

+

+    /* Create atomic */

+    status = pj_atomic_create(tr_pool, 0, &tr->ref_cnt);

+    if (status != PJ_SUCCESS)

+	goto on_error;

+    

+    /* Init rdata in the transport. */

+    tr->rdata = pj_pool_alloc(rdata_pool, sizeof(*tr->rdata));

+    tr->rdata->pool = rdata_pool;

+    tr->rdata->len = 0;

+    tr->rdata->transport = tr;

+    

+    /* Init transport mutex. */

+    status = pj_mutex_create_recursive(tr_pool, "mtr%p", &tr->tr_mutex);

+    if (status != PJ_SUCCESS)

+	goto on_error;

+

+    /* Register to I/O Queue */

+    status = pj_ioqueue_register_sock( tr_pool, mgr->ioqueue, 

+				       tr->sock, tr,

+				       &ioqueue_transport_callback,

+				       &tr->key);

+    if (status != PJ_SUCCESS)

+	goto on_error;

+

+    *p_transport = tr;

+    return PJ_SUCCESS;

+

+on_error:

+    if (tr && tr->tr_mutex) {

+	pj_mutex_destroy(tr->tr_mutex);

+    }

+    if (tr_pool) {

+	pjsip_endpt_destroy_pool(mgr->endpt, tr_pool);

+    }

+    if (rdata_pool) {

+	pjsip_endpt_destroy_pool(mgr->endpt, rdata_pool);

+    }

+    return status;

+}

+

+/*

+ * Destroy transport.

+ */

+static void destroy_transport( pjsip_transport_mgr *mgr, pjsip_transport_t *tr)

+{

+    transport_key hash_key;

+

+    /* Remove from I/O queue. */

+    pj_ioqueue_unregister( tr->key );

+

+    /* Remove from hash table */

+    init_key_from_transport(&hash_key, tr);

+    pj_hash_set(NULL, mgr->transport_table, &hash_key, sizeof(hash_key), NULL);

+

+    /* Close transport. */

+    destroy_socket(tr);

+

+    /* Destroy the transport mutex. */

+    pj_mutex_destroy(tr->tr_mutex);

+

+    /* Destroy atomic */

+    pj_atomic_destroy( tr->ref_cnt );

+

+    /* Release the pool associated with the rdata. */

+    pjsip_endpt_destroy_pool(mgr->endpt, tr->rdata->pool );

+

+    /* Release the pool associated with the transport. */

+    pjsip_endpt_destroy_pool(mgr->endpt, tr->pool );

+}

+

+

 static pj_status_t transport_send_msg( pjsip_transport_t *tr, 

-				       pjsip_tx_data *tdata,
+				       pjsip_tx_data *tdata,

 				       const pj_sockaddr_in *addr, 

-				       pj_ssize_t *p_sent)
-{
-    const char *buf = tdata->buf.start;
-    pj_ssize_t size;
-    pj_status_t status;
+				       pj_ssize_t *p_sent)

+{

+    const char *buf = tdata->buf.start;

+    pj_ssize_t size;

+    pj_status_t status;

 

     /* Can only send if tdata is not being sent! */

     if (pj_ioqueue_is_pending(tr->key, &tdata->op_key))

 	return PJSIP_EPENDINGTX;

-
-    /* Allocate buffer if necessary. */
-    if (tdata->buf.start == NULL) {
-	tdata->buf.start = pj_pool_alloc( tdata->pool, PJSIP_MAX_PKT_LEN);
-	tdata->buf.cur = tdata->buf.start;
-	tdata->buf.end = tdata->buf.start + PJSIP_MAX_PKT_LEN;
-    }
-
-    /* Print the message if it's not printed */
-    if (tdata->buf.cur <= tdata->buf.start) {
-	size = pjsip_msg_print( tdata->msg, tdata->buf.start, 
-			        tdata->buf.end - tdata->buf.start);
+

+    /* Allocate buffer if necessary. */

+    if (tdata->buf.start == NULL) {

+	tdata->buf.start = pj_pool_alloc( tdata->pool, PJSIP_MAX_PKT_LEN);

+	tdata->buf.cur = tdata->buf.start;

+	tdata->buf.end = tdata->buf.start + PJSIP_MAX_PKT_LEN;

+    }

+

+    /* Print the message if it's not printed */

+    if (tdata->buf.cur <= tdata->buf.start) {

+	size = pjsip_msg_print( tdata->msg, tdata->buf.start, 

+			        tdata->buf.end - tdata->buf.start);

 	if (size < 0) {

-	    return PJSIP_EMSGTOOLONG;
+	    return PJSIP_EMSGTOOLONG;

 	}

-	pj_assert(size != 0);
-	tdata->buf.cur += size;
-	tdata->buf.cur[size] = '\0';
-    }
-
-    /* Send the message. */
-    buf = tdata->buf.start;
-    size = tdata->buf.cur - tdata->buf.start;
-
-    if (tr->type == PJSIP_TRANSPORT_UDP) {
-	PJ_LOG(4,(tr->obj_name, "sendto %s:%d, %d bytes, data:\n"
-		  "----------- begin msg ------------\n"
-		  "%s"
-		  "------------ end msg -------------",
-		  pj_inet_ntoa(addr->sin_addr), 
-		  pj_sockaddr_in_get_port(addr),
-		  size, buf));
+	pj_assert(size != 0);

+	tdata->buf.cur += size;

+	tdata->buf.cur[size] = '\0';

+    }

 

-	status = pj_ioqueue_sendto( tr->key, &tdata->op_key,
-				    buf, &size, 0, addr, sizeof(*addr));
-    } 
-#if PJ_HAS_TCP
-    else {
-	PJ_LOG(4,(tr->obj_name, "sending %d bytes, data:\n"
-		  "----------- begin msg ------------\n"
-		  "%s"
-		  "------------ end msg -------------",
-		  size, buf));
-
-	status = pj_ioqueue_send(tr->key, &tdata->op_key, buf, &size, 0);
-    }
-#else
-    else {
+    /* Send the message. */

+    buf = tdata->buf.start;

+    size = tdata->buf.cur - tdata->buf.start;

+

+    if (tr->type == PJSIP_TRANSPORT_UDP) {

+	PJ_LOG(4,(tr->obj_name, "sendto %s:%d, %d bytes, data:\n"

+		  "----------- begin msg ------------\n"

+		  "%s"

+		  "------------ end msg -------------",

+		  pj_inet_ntoa(addr->sin_addr), 

+		  pj_sockaddr_in_get_port(addr),

+		  size, buf));

+

+	status = pj_ioqueue_sendto( tr->key, &tdata->op_key,

+				    buf, &size, 0, addr, sizeof(*addr));

+    } 

+#if PJ_HAS_TCP

+    else {

+	PJ_LOG(4,(tr->obj_name, "sending %d bytes, data:\n"

+		  "----------- begin msg ------------\n"

+		  "%s"

+		  "------------ end msg -------------",

+		  size, buf));

+

+	status = pj_ioqueue_send(tr->key, &tdata->op_key, buf, &size, 0);

+    }

+#else

+    else {

 	pj_assert(!"Unsupported transport");

-	status = PJSIP_EUNSUPTRANSPORT;
-    }
-#endif
+	status = PJSIP_EUNSUPTRANSPORT;

+    }

+#endif

 

-    *p_sent = size;
-    return status;
-}
-
-/*
- * Send a SIP message using the specified transport, to the address specified
- * in the outgoing data.
- */
-PJ_DEF(pj_status_t) pjsip_transport_send_msg( pjsip_transport_t *tr,
-					      pjsip_tx_data *tdata,
+    *p_sent = size;

+    return status;

+}

+

+/*

+ * Send a SIP message using the specified transport, to the address specified

+ * in the outgoing data.

+ */

+PJ_DEF(pj_status_t) pjsip_transport_send_msg( pjsip_transport_t *tr,

+					      pjsip_tx_data *tdata,

 					      const pj_sockaddr_in *addr,

-					      pj_ssize_t *sent)
-{
-    PJ_LOG(5, (tr->obj_name, "pjsip_transport_send_msg(tdata=%s)", tdata->obj_name));
-
-    return transport_send_msg(tr, tdata, addr, sent );
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-/*
- * Create a new transport manager.
- */
-PJ_DEF(pj_status_t) pjsip_transport_mgr_create( pj_pool_t *pool,
-						pjsip_endpoint * endpt,
+					      pj_ssize_t *sent)

+{

+    PJ_LOG(5, (tr->obj_name, "pjsip_transport_send_msg(tdata=%s)", tdata->obj_name));

+

+    return transport_send_msg(tr, tdata, addr, sent );

+}

+

+///////////////////////////////////////////////////////////////////////////////

+

+/*

+ * Create a new transport manager.

+ */

+PJ_DEF(pj_status_t) pjsip_transport_mgr_create( pj_pool_t *pool,

+						pjsip_endpoint * endpt,

 						void (*cb)(pjsip_endpoint*,

 							   pjsip_rx_data *),

-						pjsip_transport_mgr **p_mgr)
-{
-    pjsip_transport_mgr *mgr;
+						pjsip_transport_mgr **p_mgr)

+{

+    pjsip_transport_mgr *mgr;

     pj_status_t status;

-
-    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_create()"));
-
-    mgr = pj_pool_alloc(pool, sizeof(*mgr));
-    mgr->endpt = endpt;
-    mgr->message_callback = cb;
+

+    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_create()"));

+

+    mgr = pj_pool_alloc(pool, sizeof(*mgr));

+    mgr->endpt = endpt;

+    mgr->message_callback = cb;

     mgr->send_buf_size = DEFAULT_SO_SNDBUF;

     mgr->recv_buf_size = DEFAULT_SO_RCVBUF;

-
-    mgr->transport_table = pj_hash_create(pool, MGR_HASH_TABLE_SIZE);
-    if (!mgr->transport_table) {
-	return PJ_ENOMEM;
-    }
-    status = pj_ioqueue_create(pool, PJSIP_MAX_TRANSPORTS, &mgr->ioqueue);
-    if (status != PJ_SUCCESS) {
-	return status;
-    }
-    status = pj_mutex_create_recursive(pool, "tmgr%p", &mgr->mutex);
-    if (status != PJ_SUCCESS) {
-	pj_ioqueue_destroy(mgr->ioqueue);
-	return status;
-    }
-    pj_gettimeofday(&mgr->next_idle_check);
+

+    mgr->transport_table = pj_hash_create(pool, MGR_HASH_TABLE_SIZE);

+    if (!mgr->transport_table) {

+	return PJ_ENOMEM;

+    }

+    status = pj_ioqueue_create(pool, PJSIP_MAX_TRANSPORTS, &mgr->ioqueue);

+    if (status != PJ_SUCCESS) {

+	return status;

+    }

+    status = pj_mutex_create_recursive(pool, "tmgr%p", &mgr->mutex);

+    if (status != PJ_SUCCESS) {

+	pj_ioqueue_destroy(mgr->ioqueue);

+	return status;

+    }

+    pj_gettimeofday(&mgr->next_idle_check);

     mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL;

 

-    *p_mgr = mgr;
-    return status;
-}
-
-/*
- * Destroy transport manager.
- */
-PJ_DEF(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr )
-{
-    pj_hash_iterator_t itr_val;
-    pj_hash_iterator_t *itr;
-    
-    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_destroy()"));
-
-    pj_mutex_lock(mgr->mutex);
-
-    itr = pjsip_transport_first(mgr, &itr_val);
-    while (itr != NULL) {
-	pj_hash_iterator_t *next;
-	pjsip_transport_t *transport;
-	
-	transport = pjsip_transport_this(mgr, itr);
-
-	next = pjsip_transport_next(mgr, itr);
-
-	pj_atomic_set(transport->ref_cnt, 0);
-	destroy_transport( mgr, transport);
-
-	itr = next;
-    }
-    pj_ioqueue_destroy(mgr->ioqueue);
-
+    *p_mgr = mgr;

+    return status;

+}

+

+/*

+ * Destroy transport manager.

+ */

+PJ_DEF(pj_status_t) pjsip_transport_mgr_destroy( pjsip_transport_mgr *mgr )

+{

+    pj_hash_iterator_t itr_val;

+    pj_hash_iterator_t *itr;

+    

+    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_destroy()"));

+

+    pj_mutex_lock(mgr->mutex);

+

+    itr = pjsip_transport_first(mgr, &itr_val);

+    while (itr != NULL) {

+	pj_hash_iterator_t *next;

+	pjsip_transport_t *transport;

+	

+	transport = pjsip_transport_this(mgr, itr);

+

+	next = pjsip_transport_next(mgr, itr);

+

+	pj_atomic_set(transport->ref_cnt, 0);

+	destroy_transport( mgr, transport);

+

+	itr = next;

+    }

+    pj_ioqueue_destroy(mgr->ioqueue);

+

     pj_mutex_unlock(mgr->mutex);

 

-    return PJ_SUCCESS;
-}
-
-/*
- * Create listener
- */
-static pj_status_t create_listener( pjsip_transport_mgr *mgr,
-				    pjsip_transport_type_e type,
-				    pj_sock_t sock_hnd,
-				    pj_sockaddr_in *local_addr,
-				    const pj_sockaddr_in *addr_name)
-{
-    pjsip_transport_t *tr;
-    struct transport_key *hash_key;

-    const pj_str_t loopback_addr = { "127.0.0.1", 9 };
-    pj_status_t status;
+    return PJ_SUCCESS;

+}

 

-    if (mgr->send_buf_size != 0) {
+/*

+ * Create listener

+ */

+static pj_status_t create_listener( pjsip_transport_mgr *mgr,

+				    pjsip_transport_type_e type,

+				    pj_sock_t sock_hnd,

+				    pj_sockaddr_in *local_addr,

+				    const pj_sockaddr_in *addr_name)

+{

+    pjsip_transport_t *tr;

+    struct transport_key *hash_key;

+    const pj_str_t loopback_addr = { "127.0.0.1", 9 };

+    pj_status_t status;

+

+    if (mgr->send_buf_size != 0) {

         int opt_val = mgr->send_buf_size;

         status = pj_sock_setsockopt( sock_hnd, PJ_SOL_SOCKET, 

                                      PJ_SO_SNDBUF, 

                                      &opt_val, sizeof(opt_val));

-
-        if (status != PJ_SUCCESS) {
-	    return status;
-        }

-    }
 

-    if (mgr->recv_buf_size != 0) {
+        if (status != PJ_SUCCESS) {

+	    return status;

+        }

+    }

+

+    if (mgr->recv_buf_size != 0) {

         int opt_val = mgr->recv_buf_size;

         status = pj_sock_setsockopt( sock_hnd, PJ_SOL_SOCKET, 

                                      PJ_SO_RCVBUF, 

-                                     &opt_val, sizeof(opt_val));
-        if (status != PJ_SUCCESS) {
-	    return status;
+                                     &opt_val, sizeof(opt_val));

+        if (status != PJ_SUCCESS) {

+	    return status;

         }

-    }
-
-    status = create_transport(mgr, type, sock_hnd, local_addr, addr_name, &tr);
-    if (status != PJ_SUCCESS) {
-	pj_sock_close(sock_hnd);
-	return status;
-    }
-#if PJ_HAS_TCP
-    if (type == PJSIP_TRANSPORT_TCP) {
+    }

 

-	status = pj_sock_listen(tr->sock, BACKLOG);
-	if (status != 0) {
-	    destroy_transport(mgr, tr);
-	    return status;
-	}
+    status = create_transport(mgr, type, sock_hnd, local_addr, addr_name, &tr);

+    if (status != PJ_SUCCESS) {

+	pj_sock_close(sock_hnd);

+	return status;

+    }

+#if PJ_HAS_TCP

+    if (type == PJSIP_TRANSPORT_TCP) {

+

+	status = pj_sock_listen(tr->sock, BACKLOG);

+	if (status != 0) {

+	    destroy_transport(mgr, tr);

+	    return status;

+	}

 	

 	/* Discard immediate connections. */

 	do {

-	    tr->accept_data.addrlen = sizeof(tr->accept_data.local);
-	    status = pj_ioqueue_accept(tr->key, &tr->accept_op,
-				       &tr->accept_data.sock, 
-				       &tr->accept_data.local, 
-				       &tr->accept_data.remote,
+	    tr->accept_data.addrlen = sizeof(tr->accept_data.local);

+	    status = pj_ioqueue_accept(tr->key, &tr->accept_op,

+				       &tr->accept_data.sock, 

+				       &tr->accept_data.local, 

+				       &tr->accept_data.remote,

 				       &tr->accept_data.addrlen);

 	    if (status==PJ_SUCCESS) {

 		pj_sock_close(tr->accept_data.sock);

-	    } else if (status != PJ_EPENDING) {
-		destroy_transport(mgr, tr);
-		return status;
+	    } else if (status != PJ_EPENDING) {

+		destroy_transport(mgr, tr);

+		return status;

 	    }

-	} while (status==PJ_SUCCESS);
-
-    } else 
-#endif
+	} while (status==PJ_SUCCESS);

+

+    } else 

+#endif

     if (type == PJSIP_TRANSPORT_UDP) {

 	pj_ssize_t bytes;

 

 	/* Discard immediate data. */

-	do {
+	do {

 	    tr->rdata->addr_len = sizeof(tr->rdata->addr);

-	    bytes = PJSIP_MAX_PKT_LEN;
-	    status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key,
-					  tr->rdata->packet, &bytes, 0,
-					  &tr->rdata->addr, 
+	    bytes = PJSIP_MAX_PKT_LEN;

+	    status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key,

+					  tr->rdata->packet, &bytes, 0,

+					  &tr->rdata->addr, 

 					  &tr->rdata->addr_len);

 	    if (status == PJ_SUCCESS) {

-		;
-	    } else if (status != PJ_EPENDING) {
-		destroy_transport(mgr, tr);
-		return status;
+		;

+	    } else if (status != PJ_EPENDING) {

+		destroy_transport(mgr, tr);

+		return status;

 	    }

-	} while (status == PJ_SUCCESS);
-    }
-
-    pj_atomic_set(tr->ref_cnt, 1);
-
-    /* Listeners normally have no remote address */
-    pj_memset(&tr->remote_addr, 0, sizeof(tr->remote_addr));
-
-    /* Set remote address to 127.0.0.1 for UDP socket bound to 127.0.0.1. 
-     * See further comments on struct pjsip_transport_t definition.
+	} while (status == PJ_SUCCESS);

+    }

+

+    pj_atomic_set(tr->ref_cnt, 1);

+

+    /* Listeners normally have no remote address */

+    pj_memset(&tr->remote_addr, 0, sizeof(tr->remote_addr));

+

+    /* Set remote address to 127.0.0.1 for UDP socket bound to 127.0.0.1. 

+     * See further comments on struct pjsip_transport_t definition.

      */

     if (type == PJSIP_TRANSPORT_UDP && 

 	local_addr->sin_addr.s_addr == pj_inet_addr(&loopback_addr).s_addr)

-    {
-	pj_str_t localaddr = pj_str("127.0.0.1");
-	pj_sockaddr_in_set_str_addr( &tr->remote_addr, &localaddr);
-    }
-    hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key));
-    init_key_from_transport(hash_key, tr);
-
-    pj_mutex_lock(mgr->mutex);
-    pj_hash_set(tr->pool, mgr->transport_table, 

-		hash_key, sizeof(transport_key), tr);
-    pj_mutex_unlock(mgr->mutex);
-
-    PJ_LOG(4,(tr->obj_name, "Listening at %s %s:%d", 
-			 get_type_name(tr->type), 
-			 pj_inet_ntoa(tr->local_addr.sin_addr),
-			 pj_sockaddr_in_get_port(&tr->local_addr)));
-    PJ_LOG(4,(tr->obj_name, "Listener public address is at %s %s:%d", 
-			 get_type_name(tr->type), 
-			 pj_inet_ntoa(tr->addr_name.sin_addr),
-			 pj_sockaddr_in_get_port(&tr->addr_name)));
-    return PJ_SUCCESS;
-}
-
-/*
- * Create listener.
- */
-PJ_DEF(pj_status_t) pjsip_create_listener( pjsip_transport_mgr *mgr,
-					   pjsip_transport_type_e type,
-					   pj_sockaddr_in *local_addr,
-					   const pj_sockaddr_in *addr_name)
-{
-    pj_sock_t sock_hnd;
-    pj_status_t status;

-
-    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_create_listener(type=%d)", type));
-
-    status = create_socket(type, local_addr, &sock_hnd);
-    if (status != PJ_SUCCESS) {
-	return status;
-    }
-
-    return create_listener(mgr, type, sock_hnd, local_addr, addr_name);
-}
-
-/*
- * Create UDP listener.
- */
-PJ_DEF(pj_status_t) pjsip_create_udp_listener( pjsip_transport_mgr *mgr,
-					       pj_sock_t sock,
-					       const pj_sockaddr_in *addr_name)
-{
-    pj_sockaddr_in local_addr;

-    pj_status_t status;
-    int addrlen = sizeof(local_addr);
+    {

+	pj_str_t localaddr = pj_str("127.0.0.1");

+	pj_sockaddr_in_set_str_addr( &tr->remote_addr, &localaddr);

+    }

+    hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key));

+    init_key_from_transport(hash_key, tr);

 

-    status = pj_sock_getsockname(sock, (pj_sockaddr_t*)&local_addr, &addrlen);
-    if (status != PJ_SUCCESS)
-	return status;
-
+    pj_mutex_lock(mgr->mutex);

+    pj_hash_set(tr->pool, mgr->transport_table, 

+		hash_key, sizeof(transport_key), tr);

+    pj_mutex_unlock(mgr->mutex);

+

+    PJ_LOG(4,(tr->obj_name, "Listening at %s %s:%d", 

+			 get_type_name(tr->type), 

+			 pj_inet_ntoa(tr->local_addr.sin_addr),

+			 pj_sockaddr_in_get_port(&tr->local_addr)));

+    PJ_LOG(4,(tr->obj_name, "Listener public address is at %s %s:%d", 

+			 get_type_name(tr->type), 

+			 pj_inet_ntoa(tr->addr_name.sin_addr),

+			 pj_sockaddr_in_get_port(&tr->addr_name)));

+    return PJ_SUCCESS;

+}

+

+/*

+ * Create listener.

+ */

+PJ_DEF(pj_status_t) pjsip_create_listener( pjsip_transport_mgr *mgr,

+					   pjsip_transport_type_e type,

+					   pj_sockaddr_in *local_addr,

+					   const pj_sockaddr_in *addr_name)

+{

+    pj_sock_t sock_hnd;

+    pj_status_t status;

+

+    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_create_listener(type=%d)", type));

+

+    status = create_socket(type, local_addr, &sock_hnd);

+    if (status != PJ_SUCCESS) {

+	return status;

+    }

+

+    return create_listener(mgr, type, sock_hnd, local_addr, addr_name);

+}

+

+/*

+ * Create UDP listener.

+ */

+PJ_DEF(pj_status_t) pjsip_create_udp_listener( pjsip_transport_mgr *mgr,

+					       pj_sock_t sock,

+					       const pj_sockaddr_in *addr_name)

+{

+    pj_sockaddr_in local_addr;

+    pj_status_t status;

+    int addrlen = sizeof(local_addr);

+

+    status = pj_sock_getsockname(sock, (pj_sockaddr_t*)&local_addr, &addrlen);

+    if (status != PJ_SUCCESS)

+	return status;

+

     return create_listener(mgr, PJSIP_TRANSPORT_UDP, sock, 

-			   &local_addr, addr_name);
-}
-
-/*
- * Find transport to be used to send message to remote destination. If no
- * suitable transport is found, a new one will be created.
- */
-PJ_DEF(void) pjsip_transport_get( pjsip_transport_mgr *mgr,
-			          pj_pool_t *pool,
-				  pjsip_transport_type_e type,
-				  const pj_sockaddr_in *remote,
-				  void *token,
-				  pjsip_transport_completion_callback *cb)
-{
-    transport_key search_key, *hash_key;
-    pjsip_transport_t *tr;
-    pj_sockaddr_in local;
-    pj_sock_t sock_hnd;
-    pj_status_t status;
-    struct transport_callback *cb_rec;
-
-    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_get()"));
-
-    /* Create the callback record.
-     */
-    cb_rec = pj_pool_calloc(pool, 1, sizeof(*cb_rec));
-    cb_rec->token = token;
-    cb_rec->cb = cb;
-
-    /* Create key for hash table look-up.
-     * The key creation is different for TCP and UDP.
-     */
-#if PJ_HAS_TCP
-    if (type==PJSIP_TRANSPORT_TCP) {
-	init_tcp_key(&search_key, type, remote);
-    } else 
-#endif
-    if (type==PJSIP_TRANSPORT_UDP) {
-	init_udp_key(&search_key, type, remote);
-    }
-
-    /* Start lock the manager. */
-    pj_mutex_lock(mgr->mutex);
-
-    /* Lookup the transport in the hash table. */
-    tr = pj_hash_get(mgr->transport_table, &search_key, sizeof(transport_key));
-
-    if (tr) {
-	/* Transport found. If the transport is still busy (i.e. connecting
-	 * is in progress), then just register the callback. Otherwise
-	 * report via the callback if callback is specified. 
-	 */
-	pj_mutex_unlock(mgr->mutex);
-	pj_mutex_lock(tr->tr_mutex);
-
-	if (tr->flag & PJSIP_TRANSPORT_IOQUEUE_BUSY) {
-	    /* Transport is busy. Just register the callback. */
-	    pj_list_insert_before(&tr->cb_list, cb_rec);
-
-	} else {
-	    /* Transport is ready. Call callback now.
-	     */
-	    (*cb_rec->cb)(tr, cb_rec->token, PJ_SUCCESS);
-	}
-	pj_mutex_unlock(tr->tr_mutex);
-
-	return;
-    }
-
-
-    /* Transport not found. Create new one. */
-    pj_memset(&local, 0, sizeof(local));
-    local.sin_family = PJ_AF_INET;
-    status = create_socket(type, &local, &sock_hnd);
-    if (status != PJ_SUCCESS) {
-	pj_mutex_unlock(mgr->mutex);
-	(*cb_rec->cb)(NULL, cb_rec->token, status);
-	return;
-    }
-    status = create_transport(mgr, type, sock_hnd, &local, NULL, &tr);
-    if (status != PJ_SUCCESS) {
-	pj_mutex_unlock(mgr->mutex);
-	(*cb_rec->cb)(NULL, cb_rec->token, status);
-	return;
-    }
-
-#if PJ_HAS_TCP
-    if (type == PJSIP_TRANSPORT_TCP) {
-	pj_memcpy(&tr->remote_addr, remote, sizeof(pj_sockaddr_in));
+			   &local_addr, addr_name);

+}

+

+/*

+ * Find transport to be used to send message to remote destination. If no

+ * suitable transport is found, a new one will be created.

+ */

+PJ_DEF(void) pjsip_transport_get( pjsip_transport_mgr *mgr,

+			          pj_pool_t *pool,

+				  pjsip_transport_type_e type,

+				  const pj_sockaddr_in *remote,

+				  void *token,

+				  pjsip_transport_completion_callback *cb)

+{

+    transport_key search_key, *hash_key;

+    pjsip_transport_t *tr;

+    pj_sockaddr_in local;

+    pj_sock_t sock_hnd;

+    pj_status_t status;

+    struct transport_callback *cb_rec;

+

+    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_get()"));

+

+    /* Create the callback record.

+     */

+    cb_rec = pj_pool_calloc(pool, 1, sizeof(*cb_rec));

+    cb_rec->token = token;

+    cb_rec->cb = cb;

+

+    /* Create key for hash table look-up.

+     * The key creation is different for TCP and UDP.

+     */

+#if PJ_HAS_TCP

+    if (type==PJSIP_TRANSPORT_TCP) {

+	init_tcp_key(&search_key, type, remote);

+    } else 

+#endif

+    if (type==PJSIP_TRANSPORT_UDP) {

+	init_udp_key(&search_key, type, remote);

+    }

+

+    /* Start lock the manager. */

+    pj_mutex_lock(mgr->mutex);

+

+    /* Lookup the transport in the hash table. */

+    tr = pj_hash_get(mgr->transport_table, &search_key, sizeof(transport_key));

+

+    if (tr) {

+	/* Transport found. If the transport is still busy (i.e. connecting

+	 * is in progress), then just register the callback. Otherwise

+	 * report via the callback if callback is specified. 

+	 */

+	pj_mutex_unlock(mgr->mutex);

+	pj_mutex_lock(tr->tr_mutex);

+

+	if (tr->flag & PJSIP_TRANSPORT_IOQUEUE_BUSY) {

+	    /* Transport is busy. Just register the callback. */

+	    pj_list_insert_before(&tr->cb_list, cb_rec);

+

+	} else {

+	    /* Transport is ready. Call callback now.

+	     */

+	    (*cb_rec->cb)(tr, cb_rec->token, PJ_SUCCESS);

+	}

+	pj_mutex_unlock(tr->tr_mutex);

+

+	return;

+    }

+

+

+    /* Transport not found. Create new one. */

+    pj_memset(&local, 0, sizeof(local));

+    local.sin_family = PJ_AF_INET;

+    status = create_socket(type, &local, &sock_hnd);

+    if (status != PJ_SUCCESS) {

+	pj_mutex_unlock(mgr->mutex);

+	(*cb_rec->cb)(NULL, cb_rec->token, status);

+	return;

+    }

+    status = create_transport(mgr, type, sock_hnd, &local, NULL, &tr);

+    if (status != PJ_SUCCESS) {

+	pj_mutex_unlock(mgr->mutex);

+	(*cb_rec->cb)(NULL, cb_rec->token, status);

+	return;

+    }

+

+#if PJ_HAS_TCP

+    if (type == PJSIP_TRANSPORT_TCP) {

+	pj_memcpy(&tr->remote_addr, remote, sizeof(pj_sockaddr_in));

 	status = pj_ioqueue_connect(tr->key, &tr->remote_addr, 

-				    sizeof(pj_sockaddr_in));
-	pj_assert(status != 0);
+				    sizeof(pj_sockaddr_in));

+	pj_assert(status != 0);

 	if (status != PJ_EPENDING) {

-	    PJ_TODO(HANDLE_IMMEDIATE_CONNECT);
-	    destroy_transport(mgr, tr);
-	    pj_mutex_unlock(mgr->mutex);
-	    (*cb_rec->cb)(NULL, cb_rec->token, status);
-	    return;
-	}
-    } else 
-#endif
-    if (type == PJSIP_TRANSPORT_UDP) {
-	pj_ssize_t size;
-
-	do {
+	    PJ_TODO(HANDLE_IMMEDIATE_CONNECT);

+	    destroy_transport(mgr, tr);

+	    pj_mutex_unlock(mgr->mutex);

+	    (*cb_rec->cb)(NULL, cb_rec->token, status);

+	    return;

+	}

+    } else 

+#endif

+    if (type == PJSIP_TRANSPORT_UDP) {

+	pj_ssize_t size;

+

+	do {

 	    tr->rdata->addr_len = sizeof(tr->rdata->addr);

-	    size = PJSIP_MAX_PKT_LEN;
-	    status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key,
-					  tr->rdata->packet, &size, 0,
-					  &tr->rdata->addr, 
+	    size = PJSIP_MAX_PKT_LEN;

+	    status = pj_ioqueue_recvfrom( tr->key, &tr->rdata->op_key,

+					  tr->rdata->packet, &size, 0,

+					  &tr->rdata->addr, 

 					  &tr->rdata->addr_len);

 	    if (status == PJ_SUCCESS)

-		;
-	    else if (status != PJ_EPENDING) {
-		destroy_transport(mgr, tr);
-		pj_mutex_unlock(mgr->mutex);
-		(*cb_rec->cb)(NULL, cb_rec->token, status);
-		return;
-	    }
-
-	    /* Bug here.
-	     * If data is immediately available, although not likely, it will
-	     * be dropped because we don't expect to have data right after
-	     * the socket is created, do we ?!
-	     */
-	    PJ_TODO(FIXED_BUG_ON_IMMEDIATE_TRANSPORT_DATA);
-
-	} while (status == PJ_SUCCESS);
-
-	//Bug: cb will never be called!
-	//     Must force status to PJ_SUCCESS;
-	//status = PJ_IOQUEUE_PENDING;
-
-	status = PJ_SUCCESS;
-
-    } else {
-	pj_mutex_unlock(mgr->mutex);
-	(*cb_rec->cb)(NULL, cb_rec->token, PJSIP_EUNSUPTRANSPORT);
-	return;
-    }
-
-    pj_assert(status==PJ_EPENDING || status==PJ_SUCCESS);
-    pj_mutex_lock(tr->tr_mutex);
-    hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key));
-    pj_memcpy(hash_key, &search_key, sizeof(transport_key));
+		;

+	    else if (status != PJ_EPENDING) {

+		destroy_transport(mgr, tr);

+		pj_mutex_unlock(mgr->mutex);

+		(*cb_rec->cb)(NULL, cb_rec->token, status);

+		return;

+	    }

+

+	    /* Bug here.

+	     * If data is immediately available, although not likely, it will

+	     * be dropped because we don't expect to have data right after

+	     * the socket is created, do we ?!

+	     */

+	    PJ_TODO(FIXED_BUG_ON_IMMEDIATE_TRANSPORT_DATA);

+

+	} while (status == PJ_SUCCESS);

+

+	//Bug: cb will never be called!

+	//     Must force status to PJ_SUCCESS;

+	//status = PJ_IOQUEUE_PENDING;

+

+	status = PJ_SUCCESS;

+

+    } else {

+	pj_mutex_unlock(mgr->mutex);

+	(*cb_rec->cb)(NULL, cb_rec->token, PJSIP_EUNSUPTRANSPORT);

+	return;

+    }

+

+    pj_assert(status==PJ_EPENDING || status==PJ_SUCCESS);

+    pj_mutex_lock(tr->tr_mutex);

+    hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key));

+    pj_memcpy(hash_key, &search_key, sizeof(transport_key));

     pj_hash_set(tr->pool, mgr->transport_table, 

-		hash_key, sizeof(transport_key), tr);
-    if (status == PJ_SUCCESS) {
-	pj_mutex_unlock(tr->tr_mutex);
-	pj_mutex_unlock(mgr->mutex);
-	(*cb_rec->cb)(tr, cb_rec->token, PJ_SUCCESS);
-    } else {
-	pj_list_insert_before(&tr->cb_list, cb_rec);
-	pj_mutex_unlock(tr->tr_mutex);
-	pj_mutex_unlock(mgr->mutex);
-    }
-
-}
-
-#if PJ_HAS_TCP
-/*
- * Handle completion of asynchronous accept() operation.
- * This function is called by handle_events() function.
- */
-static void handle_new_connection( pjsip_transport_mgr *mgr,
-				   pjsip_transport_t *listener,
-				   pj_status_t status )
-{
-    pjsip_transport_t *tr;
+		hash_key, sizeof(transport_key), tr);

+    if (status == PJ_SUCCESS) {

+	pj_mutex_unlock(tr->tr_mutex);

+	pj_mutex_unlock(mgr->mutex);

+	(*cb_rec->cb)(tr, cb_rec->token, PJ_SUCCESS);

+    } else {

+	pj_list_insert_before(&tr->cb_list, cb_rec);

+	pj_mutex_unlock(tr->tr_mutex);

+	pj_mutex_unlock(mgr->mutex);

+    }

+

+}

+

+#if PJ_HAS_TCP

+/*

+ * Handle completion of asynchronous accept() operation.

+ * This function is called by handle_events() function.

+ */

+static void handle_new_connection( pjsip_transport_mgr *mgr,

+				   pjsip_transport_t *listener,

+				   pj_status_t status )

+{

+    pjsip_transport_t *tr;

     transport_key *hash_key;

     pj_ssize_t size;

-
-    pj_assert (listener->type == PJSIP_TRANSPORT_TCP);
-
-    if (status != PJ_SUCCESS) {
+

+    pj_assert (listener->type == PJSIP_TRANSPORT_TCP);

+

+    if (status != PJ_SUCCESS) {

 	PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,

 			       "Error in accept() completion"));

-	goto on_return;
-    }
-
-    PJ_LOG(4,(listener->obj_name, "incoming tcp connection from %s:%d",
-	      pj_inet_ntoa(listener->accept_data.remote.sin_addr),
-	      pj_sockaddr_in_get_port(&listener->accept_data.remote)));
-
-    status = create_transport(mgr, listener->type, 
-			      listener->accept_data.sock,
-			      &listener->accept_data.local,
-			      NULL, &tr);
-    if (status != PJ_SUCCESS) {
+	goto on_return;

+    }

+

+    PJ_LOG(4,(listener->obj_name, "incoming tcp connection from %s:%d",

+	      pj_inet_ntoa(listener->accept_data.remote.sin_addr),

+	      pj_sockaddr_in_get_port(&listener->accept_data.remote)));

+

+    status = create_transport(mgr, listener->type, 

+			      listener->accept_data.sock,

+			      &listener->accept_data.local,

+			      NULL, &tr);

+    if (status != PJ_SUCCESS) {

 	PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,

 			       "Error in creating new incoming TCP"));

-	goto on_return;
-    }
-
-    /*
-    tr->rdata->addr_len = sizeof(tr->rdata->addr);
-    status = pj_ioqueue_recvfrom( mgr->ioqueue, tr->key, 
-				  tr->rdata->packet, PJSIP_MAX_PKT_LEN,
-				  &tr->rdata->addr, 
-				  &tr->rdata->addr_len);
-    */
-    tr->rdata->addr = listener->accept_data.remote;
-    tr->rdata->addr_len = listener->accept_data.addrlen;
+	goto on_return;

+    }

 

-    size = PJSIP_MAX_PKT_LEN;
+    /*

+    tr->rdata->addr_len = sizeof(tr->rdata->addr);

+    status = pj_ioqueue_recvfrom( mgr->ioqueue, tr->key, 

+				  tr->rdata->packet, PJSIP_MAX_PKT_LEN,

+				  &tr->rdata->addr, 

+				  &tr->rdata->addr_len);

+    */

+    tr->rdata->addr = listener->accept_data.remote;

+    tr->rdata->addr_len = listener->accept_data.addrlen;

+

+    size = PJSIP_MAX_PKT_LEN;

     status = pj_ioqueue_recv(tr->key, &tr->rdata->op_key, 

-			     tr->rdata->packet, &size, 0);
-    if (status != PJ_EPENDING) {
+			     tr->rdata->packet, &size, 0);

+    if (status != PJ_EPENDING) {

 	PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,

 			       "Error in receiving data"));

-	PJ_TODO(IMMEDIATE_DATA);
-	destroy_transport(mgr, tr);
-	goto on_return;
-    }
-
+	PJ_TODO(IMMEDIATE_DATA);

+	destroy_transport(mgr, tr);

+	goto on_return;

+    }

+

     pj_memcpy(&tr->remote_addr, &listener->accept_data.remote, 

-	      listener->accept_data.addrlen);
-    hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key));
-    init_key_from_transport(hash_key, tr);
-
-    pj_mutex_lock(mgr->mutex);
+	      listener->accept_data.addrlen);

+    hash_key = pj_pool_alloc(tr->pool, sizeof(transport_key));

+    init_key_from_transport(hash_key, tr);

+

+    pj_mutex_lock(mgr->mutex);

     pj_hash_set(tr->pool, mgr->transport_table, hash_key, 

-		sizeof(transport_key), tr);
-    pj_mutex_unlock(mgr->mutex);
-
-on_return:
-    /* Re-initiate asynchronous accept() */
-    listener->accept_data.addrlen = sizeof(listener->accept_data.local);
-    status = pj_ioqueue_accept(listener->key, &listener->accept_op,
-			       &listener->accept_data.sock, 
-			       &listener->accept_data.local, 
-			       &listener->accept_data.remote,
-			       &listener->accept_data.addrlen);
-    if (status != PJ_EPENDING) {
+		sizeof(transport_key), tr);

+    pj_mutex_unlock(mgr->mutex);

+

+on_return:

+    /* Re-initiate asynchronous accept() */

+    listener->accept_data.addrlen = sizeof(listener->accept_data.local);

+    status = pj_ioqueue_accept(listener->key, &listener->accept_op,

+			       &listener->accept_data.sock, 

+			       &listener->accept_data.local, 

+			       &listener->accept_data.remote,

+			       &listener->accept_data.addrlen);

+    if (status != PJ_EPENDING) {

 	PJSIP_ENDPT_LOG_ERROR((mgr->endpt, listener->obj_name, status,

 			       "Error in receiving data"));

-	PJ_TODO(IMMEDIATE_ACCEPT);
-	return;
-    }
-}
-
-/*
- * Handle completion of asynchronous connect() function.
- * This function is called by the handle_events() function.
- */
-static void handle_connect_completion( pjsip_transport_mgr *mgr,
-				       pjsip_transport_t *tr,
-				       pj_status_t status )
-{
-    struct transport_callback new_list;
-    struct transport_callback *cb_rec;
+	PJ_TODO(IMMEDIATE_ACCEPT);

+	return;

+    }

+}

+

+/*

+ * Handle completion of asynchronous connect() function.

+ * This function is called by the handle_events() function.

+ */

+static void handle_connect_completion( pjsip_transport_mgr *mgr,

+				       pjsip_transport_t *tr,

+				       pj_status_t status )

+{

+    struct transport_callback new_list;

+    struct transport_callback *cb_rec;

     pj_ssize_t recv_size;

-
-    PJ_UNUSED_ARG(mgr);
-
-    /* On connect completion, we must call all registered callbacks in
-     * the transport.
-     */
-
-    /* Initialize new list. */
-    pj_list_init(&new_list);
-
-    /* Hold transport's mutex. We don't want other thread to register a 
-     * callback while we're dealing with it. 
-    */
-    pj_mutex_lock(tr->tr_mutex);
-
-    /* Copy callback list to new list so that we can call the callbacks
-     * without holding the mutex.
-     */
-    pj_list_merge_last(&new_list, &tr->cb_list);
-
-    /* Clear transport's busy flag. */
-    tr->flag &= ~PJSIP_TRANSPORT_IOQUEUE_BUSY;
-
-    /* If success, update local address. 
-     * Local address is only available after connect() has returned.
-     */
-    if (status == PJ_SUCCESS) {
-	int addrlen = sizeof(tr->local_addr);
+

+    PJ_UNUSED_ARG(mgr);

+

+    /* On connect completion, we must call all registered callbacks in

+     * the transport.

+     */

+

+    /* Initialize new list. */

+    pj_list_init(&new_list);

+

+    /* Hold transport's mutex. We don't want other thread to register a 

+     * callback while we're dealing with it. 

+    */

+    pj_mutex_lock(tr->tr_mutex);

+

+    /* Copy callback list to new list so that we can call the callbacks

+     * without holding the mutex.

+     */

+    pj_list_merge_last(&new_list, &tr->cb_list);

+

+    /* Clear transport's busy flag. */

+    tr->flag &= ~PJSIP_TRANSPORT_IOQUEUE_BUSY;

+

+    /* If success, update local address. 

+     * Local address is only available after connect() has returned.

+     */

+    if (status == PJ_SUCCESS) {

+	int addrlen = sizeof(tr->local_addr);

 	

 	status = pj_sock_getsockname(tr->sock, 

 				     (pj_sockaddr_t*)&tr->local_addr, 

-				     &addrlen);
-	if (status == PJ_SUCCESS) {
-	    pj_memcpy(&tr->addr_name, &tr->local_addr, sizeof(tr->addr_name));
-	}
-    }
-
-    /* Unlock mutex. */
-    pj_mutex_unlock(tr->tr_mutex);
-
-    /* Call all registered callbacks. */
-    cb_rec = new_list.next;
-    while (cb_rec != &new_list) {
-	struct transport_callback *next;
-	next = cb_rec->next;
-	(*cb_rec->cb)(tr, cb_rec->token, status);
-	cb_rec = next;
-    }
-
-    /* Success? */
-    if (status != PJ_SUCCESS) {
+				     &addrlen);

+	if (status == PJ_SUCCESS) {

+	    pj_memcpy(&tr->addr_name, &tr->local_addr, sizeof(tr->addr_name));

+	}

+    }

+

+    /* Unlock mutex. */

+    pj_mutex_unlock(tr->tr_mutex);

+

+    /* Call all registered callbacks. */

+    cb_rec = new_list.next;

+    while (cb_rec != &new_list) {

+	struct transport_callback *next;

+	next = cb_rec->next;

+	(*cb_rec->cb)(tr, cb_rec->token, status);

+	cb_rec = next;

+    }

+

+    /* Success? */

+    if (status != PJ_SUCCESS) {

 	destroy_transport(mgr, tr);

-	PJ_TODO(WTF);
-	return;
-    }
-
+	PJ_TODO(WTF);

+	return;

+    }

+

     /* Initiate read operation to socket. */

-    recv_size = PJSIP_MAX_PKT_LEN;
+    recv_size = PJSIP_MAX_PKT_LEN;

     status = pj_ioqueue_recv( tr->key, &tr->rdata->op_key, tr->rdata->packet, 

-			      &recv_size, 0);
-    if (status != PJ_EPENDING) {
+			      &recv_size, 0);

+    if (status != PJ_EPENDING) {

 	destroy_transport(mgr, tr);

-	PJ_TODO(IMMEDIATE_DATA);
-	return;
-    }
-}
-#endif /* PJ_HAS_TCP */
-
-/*
- * Handle incoming data.
- * This function is called when the transport manager receives 'notification'
- * from the I/O Queue that the receive operation has completed.
- * This function will then attempt to parse the message, and hands over the
- * message to the endpoint.
- */
-static void handle_received_data( pjsip_transport_mgr *mgr,
-				  pjsip_transport_t *tr,
-				  pj_ssize_t size )
-{
-    pjsip_msg *msg;
-    pjsip_rx_data *rdata = tr->rdata;
-    pj_pool_t *rdata_pool;
-    pjsip_hdr *hdr;
-    pj_str_t s;
-    char *src_addr;
-    int src_port;
-    pj_size_t msg_fragment_size = 0;
-
-    /* Check size. */
-    if (size < 1) {
-	if (tr->type != PJSIP_TRANSPORT_UDP) {
-	    /* zero bytes indicates transport has been closed for TCP.
-	     * But alas, we can't destroy it now since transactions may still
-	     * have reference to it. In that case, just do nothing, the 
-	     * transaction will receive error when it tries to send anything.
-	     * But alas!! UAC transactions wont send anything!!.
-	     * So this is a bug!
-	     */
-	    if (pj_atomic_get(tr->ref_cnt)==0) {
-		PJ_LOG(4,(tr->obj_name, "connection closed"));
-		destroy_transport(mgr, tr);
-	    } else {
-		PJ_TODO(HANDLE_TCP_TRANSPORT_CLOSED);
-		//PJ_TODO(SIGNAL_TRANSACTIONS_ON_TRANSPORT_CLOSED);
-	    }
-	    return;
-	} else {
-	    /* On Windows machines, UDP recv() will return zero upon receiving
-	     * ICMP port unreachable message.
-	     */
-	    PJ_LOG(4,(tr->obj_name, "Ignored zero length UDP packet (port unreachable?)"));
-	    goto on_return;
-	}
-    }
-    
-    /* Save received time. */
-    pj_gettimeofday(&rdata->timestamp);
-    
-    /* Update length. */
-    rdata->len += size;
-
-    /* Null terminate packet, this is the requirement of the parser. */
-    rdata->packet[rdata->len] = '\0';
-
-    /* Get source address and port for logging purpose. */
-    src_addr = pj_inet_ntoa(rdata->addr.sin_addr);
-    src_port = pj_sockaddr_in_get_port(&rdata->addr);
-
-    /* Print the whole data to the log. */
-    PJ_LOG(4,(tr->obj_name, "%d bytes recvfrom %s:%d:\n"
-		    "----------- begin msg ------------\n"
-		    "%s"
-		    "------------ end msg -------------", 
-	       rdata->len, src_addr, src_port, rdata->packet));
-
-
-    /* Process all message fragments. */
-    while (rdata->len > 0) {
-
-	msg_fragment_size = rdata->len;
-#if PJ_HAS_TCP
-	/* For TCP transport, check if the whole message has been received. */
-	if (tr->type != PJSIP_TRANSPORT_UDP) {
-	    pj_status_t msg_status;
+	PJ_TODO(IMMEDIATE_DATA);

+	return;

+    }

+}

+#endif /* PJ_HAS_TCP */

+

+/*

+ * Handle incoming data.

+ * This function is called when the transport manager receives 'notification'

+ * from the I/O Queue that the receive operation has completed.

+ * This function will then attempt to parse the message, and hands over the

+ * message to the endpoint.

+ */

+static void handle_received_data( pjsip_transport_mgr *mgr,

+				  pjsip_transport_t *tr,

+				  pj_ssize_t size )

+{

+    pjsip_msg *msg;

+    pjsip_rx_data *rdata = tr->rdata;

+    pj_pool_t *rdata_pool;

+    pjsip_hdr *hdr;

+    pj_str_t s;

+    char *src_addr;

+    int src_port;

+    pj_size_t msg_fragment_size = 0;

+

+    /* Check size. */

+    if (size < 1) {

+	if (tr->type != PJSIP_TRANSPORT_UDP) {

+	    /* zero bytes indicates transport has been closed for TCP.

+	     * But alas, we can't destroy it now since transactions may still

+	     * have reference to it. In that case, just do nothing, the 

+	     * transaction will receive error when it tries to send anything.

+	     * But alas!! UAC transactions wont send anything!!.

+	     * So this is a bug!

+	     */

+	    if (pj_atomic_get(tr->ref_cnt)==0) {

+		PJ_LOG(4,(tr->obj_name, "connection closed"));

+		destroy_transport(mgr, tr);

+	    } else {

+		PJ_TODO(HANDLE_TCP_TRANSPORT_CLOSED);

+		//PJ_TODO(SIGNAL_TRANSACTIONS_ON_TRANSPORT_CLOSED);

+	    }

+	    return;

+	} else {

+	    /* On Windows machines, UDP recv() will return zero upon receiving

+	     * ICMP port unreachable message.

+	     */

+	    PJ_LOG(4,(tr->obj_name, "Ignored zero length UDP packet (port unreachable?)"));

+	    goto on_return;

+	}

+    }

+    

+    /* Save received time. */

+    pj_gettimeofday(&rdata->timestamp);

+    

+    /* Update length. */

+    rdata->len += size;

+

+    /* Null terminate packet, this is the requirement of the parser. */

+    rdata->packet[rdata->len] = '\0';

+

+    /* Get source address and port for logging purpose. */

+    src_addr = pj_inet_ntoa(rdata->addr.sin_addr);

+    src_port = pj_sockaddr_in_get_port(&rdata->addr);

+

+    /* Print the whole data to the log. */

+    PJ_LOG(4,(tr->obj_name, "%d bytes recvfrom %s:%d:\n"

+		    "----------- begin msg ------------\n"

+		    "%s"

+		    "------------ end msg -------------", 

+	       rdata->len, src_addr, src_port, rdata->packet));

+

+

+    /* Process all message fragments. */

+    while (rdata->len > 0) {

+

+	msg_fragment_size = rdata->len;

+#if PJ_HAS_TCP

+	/* For TCP transport, check if the whole message has been received. */

+	if (tr->type != PJSIP_TRANSPORT_UDP) {

+	    pj_status_t msg_status;

 	    msg_status = pjsip_find_msg(rdata->packet, rdata->len, PJ_FALSE, 

-                                        &msg_fragment_size);
-	    if (msg_status != PJ_SUCCESS) {
+                                        &msg_fragment_size);

+	    if (msg_status != PJ_SUCCESS) {

 		if (rdata->len == PJSIP_MAX_PKT_LEN) {

                     PJSIP_ENDPT_LOG_ERROR((mgr->endpt, tr->obj_name, 

                                            PJSIP_EOVERFLOW,

-                                           "Buffer discarded for %s:%d",
-			                   src_addr, src_port));
-		    goto on_return;
-		} else {
-		    goto tcp_read_packet;
-		}
-	    }
-	}
-#endif
-
-	/* Clear parser error report */
-	pj_list_init(&rdata->parse_err);
-
-	/* Parse the message. */
-	PJ_LOG(5,(tr->obj_name, "Parsing %d bytes from %s:%d", msg_fragment_size,
-		src_addr, src_port));
-
-	msg = pjsip_parse_rdata( rdata->packet, msg_fragment_size, rdata);
-	if (msg == NULL) {
-	    PJ_LOG(3,(tr->obj_name, "Bad message (%d bytes from %s:%d)", msg_fragment_size,
-		    src_addr, src_port));
-	    goto finish_process_fragment;
-	}
+                                           "Buffer discarded for %s:%d",

+			                   src_addr, src_port));

+		    goto on_return;

+		} else {

+		    goto tcp_read_packet;

+		}

+	    }

+	}

+#endif

 

-	/* Perform basic header checking. */
+	/* Clear parser error report */

+	pj_list_init(&rdata->parse_err);

+

+	/* Parse the message. */

+	PJ_LOG(5,(tr->obj_name, "Parsing %d bytes from %s:%d", msg_fragment_size,

+		src_addr, src_port));

+

+	msg = pjsip_parse_rdata( rdata->packet, msg_fragment_size, rdata);

+	if (msg == NULL) {

+	    PJ_LOG(3,(tr->obj_name, "Bad message (%d bytes from %s:%d)", msg_fragment_size,

+		    src_addr, src_port));

+	    goto finish_process_fragment;

+	}

+

+	/* Perform basic header checking. */

 	if (rdata->call_id.ptr == NULL || rdata->from == NULL || 

-	    rdata->to == NULL || rdata->via == NULL || rdata->cseq == NULL) 
-	{
-	    PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: missing some header", 
-		    src_addr, src_port));
-	    goto finish_process_fragment;
-	}
-
-	/* If message is received from address that's different from the sent-by,
-  	 * MUST add received parameter to the via.
-	 * In our case, we add Via receive param for EVERY received message, 
-	 * because it saves us from resolving the host HERE in case sent-by is in
-	 * FQDN format. And it doesn't hurt either.
-	 */
-	s = pj_str(src_addr);
-	pj_strdup(rdata->pool, &rdata->via->recvd_param, &s);
-
-	/* RFC 3581:
-	 * If message contains "rport" param, put the received port there.
-	 */
-	if (rdata->via->rport_param == 0) {
-	    rdata->via->rport_param = pj_sockaddr_in_get_port(&rdata->addr);
-	}
-
-	/* Drop response message if it has more than one Via.
-	*/
-	if (msg->type == PJSIP_RESPONSE_MSG) {
-	    hdr = (pjsip_hdr*)rdata->via->next;
-	    if (hdr != &rdata->msg->hdr) {
-		hdr = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, hdr);
-		if (hdr) {
-		    PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: "
-					    "multiple Via in response message",
-					    src_addr, src_port));
-		    goto finish_process_fragment;
-		}
-	    }
-	}
-
-	/* Call the transport manager's upstream message callback.
-	*/
-	(*mgr->message_callback)(mgr->endpt, rdata);
-
-finish_process_fragment:
-	rdata->len -= msg_fragment_size;
-	if (rdata->len > 0) {
-	    pj_memmove(rdata->packet, rdata->packet+msg_fragment_size, rdata->len);
-	    PJ_LOG(4,(tr->obj_name, "Processing next fragment, size=%d bytes", rdata->len));
-	}
-
-    }	/* while (rdata->len > 0) */
-
-on_return:
-    /* Reset the pool and rdata */
-    rdata_pool = rdata->pool;
-    pj_pool_reset(rdata_pool);
-    rdata = pj_pool_alloc( rdata_pool, sizeof(*rdata) );
-    rdata->len = 0;
-    rdata->transport = tr;
-    rdata->pool = rdata_pool;
-    tr->rdata = rdata;
-
-    /* Read the next packet. */
-    rdata->addr_len = sizeof(rdata->addr);
+	    rdata->to == NULL || rdata->via == NULL || rdata->cseq == NULL) 

+	{

+	    PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: missing some header", 

+		    src_addr, src_port));

+	    goto finish_process_fragment;

+	}

+

+	/* If message is received from address that's different from the sent-by,

+  	 * MUST add received parameter to the via.

+	 * In our case, we add Via receive param for EVERY received message, 

+	 * because it saves us from resolving the host HERE in case sent-by is in

+	 * FQDN format. And it doesn't hurt either.

+	 */

+	s = pj_str(src_addr);

+	pj_strdup(rdata->pool, &rdata->via->recvd_param, &s);

+

+	/* RFC 3581:

+	 * If message contains "rport" param, put the received port there.

+	 */

+	if (rdata->via->rport_param == 0) {

+	    rdata->via->rport_param = pj_sockaddr_in_get_port(&rdata->addr);

+	}

+

+	/* Drop response message if it has more than one Via.

+	*/

+	if (msg->type == PJSIP_RESPONSE_MSG) {

+	    hdr = (pjsip_hdr*)rdata->via->next;

+	    if (hdr != &rdata->msg->hdr) {

+		hdr = pjsip_msg_find_hdr(msg, PJSIP_H_VIA, hdr);

+		if (hdr) {

+		    PJ_LOG(3,(tr->obj_name, "Bad message from %s:%d: "

+					    "multiple Via in response message",

+					    src_addr, src_port));

+		    goto finish_process_fragment;

+		}

+	    }

+	}

+

+	/* Call the transport manager's upstream message callback.

+	*/

+	(*mgr->message_callback)(mgr->endpt, rdata);

+

+finish_process_fragment:

+	rdata->len -= msg_fragment_size;

+	if (rdata->len > 0) {

+	    pj_memmove(rdata->packet, rdata->packet+msg_fragment_size, rdata->len);

+	    PJ_LOG(4,(tr->obj_name, "Processing next fragment, size=%d bytes", rdata->len));

+	}

+

+    }	/* while (rdata->len > 0) */

+

+on_return:

+    /* Reset the pool and rdata */

+    rdata_pool = rdata->pool;

+    pj_pool_reset(rdata_pool);

+    rdata = pj_pool_alloc( rdata_pool, sizeof(*rdata) );

+    rdata->len = 0;

+    rdata->transport = tr;

+    rdata->pool = rdata_pool;

+    tr->rdata = rdata;

+

+    /* Read the next packet. */

+    rdata->addr_len = sizeof(rdata->addr);

     if (tr->type == PJSIP_TRANSPORT_UDP) {

-	pj_ssize_t size = PJSIP_MAX_PKT_LEN;
-	pj_ioqueue_recvfrom(tr->key, &tr->rdata->op_key,
-			    tr->rdata->packet, &size, 0, 
+	pj_ssize_t size = PJSIP_MAX_PKT_LEN;

+	pj_ioqueue_recvfrom(tr->key, &tr->rdata->op_key,

+			    tr->rdata->packet, &size, 0, 

 			    &rdata->addr, &rdata->addr_len);

-	PJ_TODO(HANDLE_IMMEDIATE_DATA);
-    }
-
-#if PJ_HAS_TCP
-    /* The next 'if' should have been 'else if', but we need to put the
-       label inside the '#if PJ_HAS_TCP' block to avoid 'unreferenced label' warning.
-     */
-tcp_read_packet:
+	PJ_TODO(HANDLE_IMMEDIATE_DATA);

+    }

+

+#if PJ_HAS_TCP

+    /* The next 'if' should have been 'else if', but we need to put the

+       label inside the '#if PJ_HAS_TCP' block to avoid 'unreferenced label' warning.

+     */

+tcp_read_packet:

     if (tr->type == PJSIP_TRANSPORT_TCP) {

 	pj_ssize_t size = PJSIP_MAX_PKT_LEN - tr->rdata->len;

-	pj_ioqueue_recv( tr->key, &tr->rdata->op_key,
-			 tr->rdata->packet + tr->rdata->len,
+	pj_ioqueue_recv( tr->key, &tr->rdata->op_key,

+			 tr->rdata->packet + tr->rdata->len,

 			 &size, 0);

-	PJ_TODO(HANDLE_IMMEDIATE_DATA_1);
-    }
-#endif
-}
-
-static void transport_mgr_on_idle( pjsip_transport_mgr *mgr )
-{
-    pj_time_val now;
-    pj_hash_iterator_t itr_val;
-    pj_hash_iterator_t *itr;
-
-
-    /* Get time for comparing transport's close time. */
-    pj_gettimeofday(&now);
-    if (now.sec < mgr->next_idle_check.sec) {
-	return;
-    }
-
-    /* Acquire transport manager's lock. */
-    pj_mutex_lock(mgr->mutex);
-
-    /* Update next idle check. */
-    mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL;
-
-    /* Iterate all transports, and close transports that are not used for
-       some periods.
-     */
-    itr = pjsip_transport_first(mgr, &itr_val);
-    while (itr != NULL) {
-	pj_hash_iterator_t *next;
-	pjsip_transport_t *transport;
-	
-	transport = pjsip_transport_this(mgr, itr);
-
-	next = pjsip_transport_next(mgr, itr);
-
-	if (pj_atomic_get(transport->ref_cnt)==0 && 
-	    PJ_TIME_VAL_LTE(transport->close_time, now))
-	{
-	    destroy_transport(mgr, transport);
-	}
-
-	itr = next;
-    }
-
-    /* Release transport manager's lock. */
-    pj_mutex_unlock(mgr->mutex);
-}
-
+	PJ_TODO(HANDLE_IMMEDIATE_DATA_1);

+    }

+#endif

+}

+

+static void transport_mgr_on_idle( pjsip_transport_mgr *mgr )

+{

+    pj_time_val now;

+    pj_hash_iterator_t itr_val;

+    pj_hash_iterator_t *itr;

+

+

+    /* Get time for comparing transport's close time. */

+    pj_gettimeofday(&now);

+    if (now.sec < mgr->next_idle_check.sec) {

+	return;

+    }

+

+    /* Acquire transport manager's lock. */

+    pj_mutex_lock(mgr->mutex);

+

+    /* Update next idle check. */

+    mgr->next_idle_check.sec += MGR_IDLE_CHECK_INTERVAL;

+

+    /* Iterate all transports, and close transports that are not used for

+       some periods.

+     */

+    itr = pjsip_transport_first(mgr, &itr_val);

+    while (itr != NULL) {

+	pj_hash_iterator_t *next;

+	pjsip_transport_t *transport;

+	

+	transport = pjsip_transport_this(mgr, itr);

+

+	next = pjsip_transport_next(mgr, itr);

+

+	if (pj_atomic_get(transport->ref_cnt)==0 && 

+	    PJ_TIME_VAL_LTE(transport->close_time, now))

+	{

+	    destroy_transport(mgr, transport);

+	}

+

+	itr = next;

+    }

+

+    /* Release transport manager's lock. */

+    pj_mutex_unlock(mgr->mutex);

+}

+

 static void on_ioqueue_read(pj_ioqueue_key_t *key, 

 			    pj_ioqueue_op_key_t *op_key, 

-			    pj_ssize_t bytes_read)
-{
-    pjsip_transport_t *t;
-    t = pj_ioqueue_get_user_data(key);
-
-    handle_received_data( t->mgr, t, bytes_read );
-}
-
+			    pj_ssize_t bytes_read)

+{

+    pjsip_transport_t *t;

+    t = pj_ioqueue_get_user_data(key);

+

+    handle_received_data( t->mgr, t, bytes_read );

+}

+

 static void on_ioqueue_write(pj_ioqueue_key_t *key, 

 			     pj_ioqueue_op_key_t *op_key, 

-			     pj_ssize_t bytes_sent)
-{
-    PJ_UNUSED_ARG(key);
-    PJ_UNUSED_ARG(bytes_sent);
-
-    /* Completion of write operation. 
-     * Do nothing.
-     */
-}
-
+			     pj_ssize_t bytes_sent)

+{

+    PJ_UNUSED_ARG(key);

+    PJ_UNUSED_ARG(bytes_sent);

+

+    /* Completion of write operation. 

+     * Do nothing.

+     */

+}

+

 static void on_ioqueue_accept(pj_ioqueue_key_t *key, 

 			      pj_ioqueue_op_key_t *op_key, 

 			      pj_sock_t newsock,

-			      int status)
-{
-#if PJ_HAS_TCP
-    pjsip_transport_t *t;
-    t = pj_ioqueue_get_user_data(key);
-
-    handle_new_connection( t->mgr, t, status );
-#else
-    PJ_UNUSED_ARG(key);
-    PJ_UNUSED_ARG(status);
-#endif
-}
-
-static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)
-{
-#if PJ_HAS_TCP
-    pjsip_transport_t *t;
-    t = pj_ioqueue_get_user_data(key);
-
-    handle_connect_completion( t->mgr, t, status);
-#else
-    PJ_UNUSED_ARG(key);
-    PJ_UNUSED_ARG(status);
-#endif
-}
-
-
-/*
- * Poll for events.
- */
-PJ_DEF(int) pjsip_transport_mgr_handle_events( pjsip_transport_mgr *mgr,
-					       const pj_time_val *req_timeout )
-{
-    int event_count;
-    int break_loop;
-    int result;
-    pj_time_val timeout;
-
-    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_handle_events()"));
-
-    event_count = 0;
-    break_loop = 0;
-    timeout = *req_timeout;
-    do {
-	result = pj_ioqueue_poll( mgr->ioqueue, &timeout);
-	if (result == 1) {
-	    ++event_count;
-
-	    /* Break the loop. */
-	    //if (timeout.msec==0 && timeout.sec==0) {
-	    	break_loop = 1;
-	    //}
-
-	} else {
-	    /* On idle, cleanup transport. */
-	    transport_mgr_on_idle(mgr);
-
-	    break_loop = 1;
-	}
-	timeout.sec = timeout.msec = 0;
-    } while (!break_loop);
-
-    return event_count;
-}
-
-
-PJ_DEF(pj_hash_iterator_t*) pjsip_transport_first( pjsip_transport_mgr *mgr,
-						   pj_hash_iterator_t *it )
-{
-    return pj_hash_first(mgr->transport_table, it);
-}
-
-PJ_DEF(pj_hash_iterator_t*) pjsip_transport_next( pjsip_transport_mgr *mgr,
-						  pj_hash_iterator_t *itr )
-{
-    return pj_hash_next(mgr->transport_table, itr);
-}
-
-PJ_DEF(pjsip_transport_t*) pjsip_transport_this( pjsip_transport_mgr *mgr,
-						 pj_hash_iterator_t *itr )
-{
-    return pj_hash_this(mgr->transport_table, itr);
-}
+			      int status)

+{

+#if PJ_HAS_TCP

+    pjsip_transport_t *t;

+    t = pj_ioqueue_get_user_data(key);

+

+    handle_new_connection( t->mgr, t, status );

+#else

+    PJ_UNUSED_ARG(key);

+    PJ_UNUSED_ARG(status);

+#endif

+}

+

+static void on_ioqueue_connect(pj_ioqueue_key_t *key, int status)

+{

+#if PJ_HAS_TCP

+    pjsip_transport_t *t;

+    t = pj_ioqueue_get_user_data(key);

+

+    handle_connect_completion( t->mgr, t, status);

+#else

+    PJ_UNUSED_ARG(key);

+    PJ_UNUSED_ARG(status);

+#endif

+}

+

+

+/*

+ * Poll for events.

+ */

+PJ_DEF(int) pjsip_transport_mgr_handle_events( pjsip_transport_mgr *mgr,

+					       const pj_time_val *req_timeout )

+{

+    int event_count;

+    int break_loop;

+    int result;

+    pj_time_val timeout;

+

+    PJ_LOG(5, (LOG_TRANSPORT_MGR, "pjsip_transport_mgr_handle_events()"));

+

+    event_count = 0;

+    break_loop = 0;

+    timeout = *req_timeout;

+    do {

+	result = pj_ioqueue_poll( mgr->ioqueue, &timeout);

+	if (result == 1) {

+	    ++event_count;

+

+	    /* Break the loop. */

+	    //if (timeout.msec==0 && timeout.sec==0) {

+	    	break_loop = 1;

+	    //}

+

+	} else {

+	    /* On idle, cleanup transport. */

+	    transport_mgr_on_idle(mgr);

+

+	    break_loop = 1;

+	}

+	timeout.sec = timeout.msec = 0;

+    } while (!break_loop);

+

+    return event_count;

+}

+

+

+PJ_DEF(pj_hash_iterator_t*) pjsip_transport_first( pjsip_transport_mgr *mgr,

+						   pj_hash_iterator_t *it )

+{

+    return pj_hash_first(mgr->transport_table, it);

+}

+

+PJ_DEF(pj_hash_iterator_t*) pjsip_transport_next( pjsip_transport_mgr *mgr,

+						  pj_hash_iterator_t *itr )

+{

+    return pj_hash_next(mgr->transport_table, itr);

+}

+

+PJ_DEF(pjsip_transport_t*) pjsip_transport_this( pjsip_transport_mgr *mgr,

+						 pj_hash_iterator_t *itr )

+{

+    return pj_hash_this(mgr->transport_table, itr);

+}

diff --git a/pjsip/src/pjsip/sip_uri.c b/pjsip/src/pjsip/sip_uri.c
index 8085f7f..e6db870 100644
--- a/pjsip/src/pjsip/sip_uri.c
+++ b/pjsip/src/pjsip/sip_uri.c
@@ -1,398 +1,420 @@
-/* $Id$
- */
-#include <pjsip/sip_uri.h>
-#include <pjsip/sip_msg.h>
-#include <pjsip/print_util.h>
-#include <pj/string.h>
-#include <pj/pool.h>
+/* $Id$

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_uri.h>

+#include <pjsip/sip_msg.h>

+#include <pjsip/print_util.h>

+#include <pj/string.h>

+#include <pj/pool.h>

 #include <pj/assert.h>

-
-#define IS_SIPS(url)	((url)->vptr==&sips_url_vptr)
-
-static const pj_str_t *pjsip_url_get_scheme( const pjsip_url* );
-static const pj_str_t *pjsips_url_get_scheme( const pjsip_url* );
-static const pj_str_t *pjsip_name_addr_get_scheme( const pjsip_name_addr * );
-static void *pjsip_get_uri( pjsip_uri *uri );
-static void *pjsip_name_addr_get_uri( pjsip_name_addr *name );
-
-static pj_str_t sip_str = { "sip", 3 };
-static pj_str_t sips_str = { "sips", 4 };
-
-#ifdef __GNUC__
-#  define HAPPY_FLAG	(void*)
-#else
-#  define HAPPY_FLAG
-#endif
-
-static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool, 
-					       const pjsip_name_addr *rhs);
-static int pjsip_name_addr_print( pjsip_uri_context_e context,
-				  const pjsip_name_addr *name, 
-				  char *buf, pj_size_t size);
-static int pjsip_name_addr_compare(  pjsip_uri_context_e context,
-				     const pjsip_name_addr *naddr1,
-				     const pjsip_name_addr *naddr2);
-static int pjsip_url_print(  pjsip_uri_context_e context,
-			     const pjsip_url *url, 
-			     char *buf, pj_size_t size);
-static int pjsip_url_compare( pjsip_uri_context_e context,
-			      const pjsip_url *url1, const pjsip_url *url2);
-static pjsip_url* pjsip_url_clone(pj_pool_t *pool, const pjsip_url *rhs);
-
-static pjsip_uri_vptr sip_url_vptr = 
-{
-    HAPPY_FLAG &pjsip_url_get_scheme,
-    HAPPY_FLAG &pjsip_get_uri,
-    HAPPY_FLAG &pjsip_url_print,
-    HAPPY_FLAG &pjsip_url_compare,
-    HAPPY_FLAG &pjsip_url_clone
-};
-
-static pjsip_uri_vptr sips_url_vptr = 
-{
-    HAPPY_FLAG &pjsips_url_get_scheme,
-    HAPPY_FLAG &pjsip_get_uri,
-    HAPPY_FLAG &pjsip_url_print,
-    HAPPY_FLAG &pjsip_url_compare,
-    HAPPY_FLAG &pjsip_url_clone
-};
-
-static pjsip_uri_vptr name_addr_vptr = 
-{
-    HAPPY_FLAG &pjsip_name_addr_get_scheme,
-    HAPPY_FLAG &pjsip_name_addr_get_uri,
-    HAPPY_FLAG &pjsip_name_addr_print,
-    HAPPY_FLAG &pjsip_name_addr_compare,
-    HAPPY_FLAG &pjsip_name_addr_clone
-};
-
-static const pj_str_t *pjsip_url_get_scheme(const pjsip_url *url)
-{
-    PJ_UNUSED_ARG(url);
-    return &sip_str;
-}
-
-static const pj_str_t *pjsips_url_get_scheme(const pjsip_url *url)
-{
-    PJ_UNUSED_ARG(url);
-    return &sips_str;
-}
-
-static void *pjsip_get_uri( pjsip_uri *uri )
-{
-    return uri;
-}
-
-static void *pjsip_name_addr_get_uri( pjsip_name_addr *name )
-{
-    return name->uri;
-}
-
-PJ_DEF(void) pjsip_url_init(pjsip_url *url, int secure)
-{
-    pj_memset(url, 0, sizeof(*url));
-    url->ttl_param = -1;
-    url->vptr = secure ? &sips_url_vptr : &sip_url_vptr;
-}
-
-PJ_DEF(pjsip_url*) pjsip_url_create( pj_pool_t *pool, int secure )
-{
-    pjsip_url *url = pj_pool_alloc(pool, sizeof(pjsip_url));
-    pjsip_url_init(url, secure);
-    return url;
-}
-
-static int pjsip_url_print(  pjsip_uri_context_e context,
-			     const pjsip_url *url, 
-			     char *buf, pj_size_t size)
-{
-    int printed;
-    pj_size_t size_required;
-    char *startbuf = buf;
-    const pj_str_t *scheme;
-    *buf = '\0';
-
-    /* Check the buffer length. */
-    size_required = 6 + url->host.slen + 10 +
-		    url->user.slen + url->passwd.slen + 2 +
-		    url->user_param.slen + 6 +
-		    url->method_param.slen + 8 +
-		    url->transport_param.slen + 11 +
-		    9 + 5 +
-		    url->maddr_param.slen + 7 +
-		    3 +
-		    url->other_param.slen +
-		    url->header_param.slen;
-    if (size < size_required) {
-	return -1;
-    }
-
-    /* Print scheme ("sip:" or "sips:") */
-    scheme = pjsip_uri_get_scheme(url);
-    copy_advance_no_check(buf, *scheme);
-    *buf++ = ':';
-
-    /* Print "user:password@", if any. */
-    if (url->user.slen) {
-	copy_advance_no_check(buf, url->user);
-	if (url->passwd.slen) {
-	    *buf++ = ':';
-	    copy_advance_no_check(buf, url->passwd);
-	}
-
-	*buf++ = '@';
-    }
-
-    /* Print host. */
-    pj_assert(url->host.slen != 0);
-    copy_advance_no_check(buf, url->host);
-
-    /* Only print port if it is explicitly specified. 
-     * Port is not allowed in To and From header.
-     */
-    /* Unfortunately some UA requires us to send back the port
-     * number exactly as it was sent. We don't remember whether an
-     * UA has sent us port, so we'll just send the port indiscrimately
-     */
-    PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER)
-    if (url->port /*&& context != PJSIP_URI_IN_FROMTO_HDR*/) {
-	*buf++ = ':';
-	printed = pj_utoa(url->port, buf);
-	buf += printed;
-    }
-
-    /* User param is allowed in all contexes */
-    copy_advance_pair_no_check(buf, ";user=", 6, url->user_param);
-
-    /* Method param is only allowed in external/other context. */
-    if (context == PJSIP_URI_IN_OTHER) {
-	copy_advance_pair_no_check(buf, ";method=", 8, url->method_param);
-    }
-
-    /* Transport is not allowed in From/To header. */
-    if (context != PJSIP_URI_IN_FROMTO_HDR) {
-	copy_advance_pair_no_check(buf, ";transport=", 11, url->transport_param);
-    }
-
-    /* TTL param is not allowed in From, To, Route, and Record-Route header. */
-    if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR &&
-	context != PJSIP_URI_IN_ROUTING_HDR) 
-    {
-	pj_memcpy(buf, ";ttl=", 5);
-	printed = pj_utoa(url->ttl_param, buf+5);
-	buf += printed + 5;
-    }
-
-    /* maddr param is not allowed in From and To header. */
-    if (context != PJSIP_URI_IN_FROMTO_HDR) {
-	copy_advance_pair_no_check(buf, ";maddr=", 7, url->maddr_param);
-    }
-
-    /* lr param is not allowed in From, To, and Contact header. */
-    if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR &&
-	context != PJSIP_URI_IN_CONTACT_HDR) 
-    {
-	pj_str_t lr = { ";lr", 3 };
-	copy_advance_no_check(buf, lr);
-    }
-
-    /* Other param. */
-    if (url->other_param.slen) {
-	copy_advance_no_check(buf, url->other_param);
-    }
-
-    /* Header param. */
-    if (url->header_param.slen) {
-	copy_advance_no_check(buf, url->header_param);
-    }
-
-    *buf = '\0';
-    return buf-startbuf;
-}
-
-static int pjsip_url_compare( pjsip_uri_context_e context,
-			      const pjsip_url *url1, const pjsip_url *url2)
-{
-    /* The easiest (and probably the most efficient) way to compare two URLs
-       are to print them, and compare them bytes per bytes. This technique
-       works quite well with RFC3261, as the RFC (unlike RFC2543) defines that
-       components specified in one URL does NOT match its default value if
-       it is not specified in the second URL. For example, parameter "user=ip"
-       does NOT match if it is omited in second URL.
-
-       HOWEVER, THE SAME CAN NOT BE APPLIED FOR other-param NOR header-param.
-       For these, each of the parameters must be compared one by one. Parameter
-       that exists in one URL will match the comparison. But parameter that
-       exists in both URLs and doesn't match wont match the URL comparison.
-
-       The solution for this is to compare 'standard' URL components with
-       bytes-to-bytes comparison, and compare other-param and header-param with
-       more intelligent comparison.
-     */
-    char str_url1[PJSIP_MAX_URL_SIZE];
-    char str_url2[PJSIP_MAX_URL_SIZE];
-    int len1, len2;
-
-    /* Must compare scheme first, as the second URI may not be SIP URL. */
-    if (pj_stricmp(pjsip_uri_get_scheme(url1), pjsip_uri_get_scheme(url2)))
-	return -1;
-
-    len1 = pjsip_url_print(context, url1, str_url1, sizeof(str_url1));
-    if (len1 < 1) {
-	pj_assert(0);
-	return -1;
-    }
-    len2 = pjsip_url_print(context, url2, str_url2, sizeof(str_url2));
-    if (len2 < 1) {
-	pj_assert(0);
-	return -1;
-    }
-
-    if (len1 != len2) {
-	/* Not equal. */
-	return -1;
-    }
-
-    if (pj_native_strcmp(str_url1, str_url2)) {
-	/* Not equal */
-	return -1;
-    }
-
-    /* TODO: compare other-param and header-param in more intelligent manner. */
-    PJ_TODO(HPARAM_AND_OTHER_PARAM_COMPARISON_IN_URL_COMPARISON)
-
-    if (pj_strcmp(&url1->other_param, &url2->other_param)) {
-	/* Not equal. */
-	return -1;
-    }
-    if (pj_strcmp(&url1->header_param, &url2->header_param)) {
-	/* Not equal. */
-	return -1;
-    }
-
-    /* Seems to be equal, isn't it. */
-    return 0;
-    
-}
-
-
-PJ_DEF(void) pjsip_url_assign(pj_pool_t *pool, pjsip_url *url, 
-			      const pjsip_url *rhs)
-{
-    pj_strdup( pool, &url->user, &rhs->user);
-    pj_strdup( pool, &url->passwd, &rhs->passwd);
-    pj_strdup( pool, &url->host, &rhs->host);
-    url->port = rhs->port;
-    pj_strdup( pool, &url->user_param, &rhs->user_param);
-    pj_strdup( pool, &url->method_param, &rhs->method_param);
-    pj_strdup( pool, &url->transport_param, &rhs->transport_param);
-    url->ttl_param = rhs->ttl_param;
-    pj_strdup( pool, &url->maddr_param, &rhs->maddr_param);
-    pj_strdup( pool, &url->other_param, &rhs->other_param);
-    pj_strdup( pool, &url->header_param, &rhs->header_param);
-    url->lr_param = rhs->lr_param;
-}
-
-static pjsip_url* pjsip_url_clone(pj_pool_t *pool, const pjsip_url *rhs)
-{
-    pjsip_url *url = pj_pool_alloc(pool, sizeof(pjsip_url));
-    if (!url)
-	return NULL;
-
-    pjsip_url_init(url, IS_SIPS(rhs));
-    pjsip_url_assign(pool, url, rhs);
-    return url;
-}
-
-static const pj_str_t *pjsip_name_addr_get_scheme(const pjsip_name_addr *name)
-{
-    pj_assert(name->uri != NULL);
-    return pjsip_uri_get_scheme(name->uri);
-}
-
-PJ_DEF(void) pjsip_name_addr_init(pjsip_name_addr *name)
-{
-    name->vptr = &name_addr_vptr;
-    name->uri = NULL;
-    name->display.slen = 0;
-}
-
-PJ_DEF(pjsip_name_addr*) pjsip_name_addr_create(pj_pool_t *pool)
-{
-    pjsip_name_addr *name_addr = pj_pool_alloc(pool, sizeof(pjsip_name_addr));
-    pjsip_name_addr_init(name_addr);
-    return name_addr;
-}
-
-static int pjsip_name_addr_print( pjsip_uri_context_e context,
-				  const pjsip_name_addr *name, 
-				  char *buf, pj_size_t size)
-{
-    int printed;
-    char *startbuf = buf;
-    char *endbuf = buf + size;
-
-    pj_assert(name->uri != NULL);
-
-    if (context != PJSIP_URI_IN_REQ_URI) {
-	copy_advance(buf, name->display);
-	if (name->display.slen) {
-	    *buf++ = ' ';
-	}
-	*buf++ = '<';
-    }
-
-    printed = pjsip_uri_print(context,name->uri, buf, size-(buf-startbuf));
-    if (printed < 1)
-	return -1;
-    buf += printed;
-
-    if (context != PJSIP_URI_IN_REQ_URI) {
-	*buf++ = '>';
-    }
-
-    *buf = '\0';
-    return buf-startbuf;
-}
-
-PJ_DEF(void) pjsip_name_addr_assign(pj_pool_t *pool, pjsip_name_addr *dst,
-				    const pjsip_name_addr *src)
-{
-    pj_strdup( pool, &dst->display, &src->display);
-    dst->uri = pjsip_uri_clone(pool, src->uri);
-}
-
-static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool, 
-					       const pjsip_name_addr *rhs)
-{
-    pjsip_name_addr *addr = pj_pool_alloc(pool, sizeof(pjsip_name_addr));
-    if (!addr)
-	return NULL;
-
-    pjsip_name_addr_init(addr);
-    pjsip_name_addr_assign(pool, addr, rhs);
-    return addr;
-}
-
-static int pjsip_name_addr_compare(  pjsip_uri_context_e context,
-				     const pjsip_name_addr *naddr1,
-				     const pjsip_name_addr *naddr2)
-{
-    int d;
-
-    /* I'm not sure whether display name is included in the comparison. */
-    if (pj_strcmp(&naddr1->display, &naddr2->display) != 0) {
-	return -1;
-    }
-
-    pj_assert( naddr1->uri != NULL );
-    pj_assert( naddr2->uri != NULL );
-
-    /* Compare name-addr as URL */
-    d = pjsip_uri_cmp( context, naddr1->uri, naddr2->uri);
-    if (d)
-	return d;
-
-    return 0;
-}
-
+

+#define IS_SIPS(url)	((url)->vptr==&sips_url_vptr)

+

+static const pj_str_t *pjsip_url_get_scheme( const pjsip_url* );

+static const pj_str_t *pjsips_url_get_scheme( const pjsip_url* );

+static const pj_str_t *pjsip_name_addr_get_scheme( const pjsip_name_addr * );

+static void *pjsip_get_uri( pjsip_uri *uri );

+static void *pjsip_name_addr_get_uri( pjsip_name_addr *name );

+

+static pj_str_t sip_str = { "sip", 3 };

+static pj_str_t sips_str = { "sips", 4 };

+

+#ifdef __GNUC__

+#  define HAPPY_FLAG	(void*)

+#else

+#  define HAPPY_FLAG

+#endif

+

+static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool, 

+					       const pjsip_name_addr *rhs);

+static int pjsip_name_addr_print( pjsip_uri_context_e context,

+				  const pjsip_name_addr *name, 

+				  char *buf, pj_size_t size);

+static int pjsip_name_addr_compare(  pjsip_uri_context_e context,

+				     const pjsip_name_addr *naddr1,

+				     const pjsip_name_addr *naddr2);

+static int pjsip_url_print(  pjsip_uri_context_e context,

+			     const pjsip_url *url, 

+			     char *buf, pj_size_t size);

+static int pjsip_url_compare( pjsip_uri_context_e context,

+			      const pjsip_url *url1, const pjsip_url *url2);

+static pjsip_url* pjsip_url_clone(pj_pool_t *pool, const pjsip_url *rhs);

+

+static pjsip_uri_vptr sip_url_vptr = 

+{

+    HAPPY_FLAG &pjsip_url_get_scheme,

+    HAPPY_FLAG &pjsip_get_uri,

+    HAPPY_FLAG &pjsip_url_print,

+    HAPPY_FLAG &pjsip_url_compare,

+    HAPPY_FLAG &pjsip_url_clone

+};

+

+static pjsip_uri_vptr sips_url_vptr = 

+{

+    HAPPY_FLAG &pjsips_url_get_scheme,

+    HAPPY_FLAG &pjsip_get_uri,

+    HAPPY_FLAG &pjsip_url_print,

+    HAPPY_FLAG &pjsip_url_compare,

+    HAPPY_FLAG &pjsip_url_clone

+};

+

+static pjsip_uri_vptr name_addr_vptr = 

+{

+    HAPPY_FLAG &pjsip_name_addr_get_scheme,

+    HAPPY_FLAG &pjsip_name_addr_get_uri,

+    HAPPY_FLAG &pjsip_name_addr_print,

+    HAPPY_FLAG &pjsip_name_addr_compare,

+    HAPPY_FLAG &pjsip_name_addr_clone

+};

+

+static const pj_str_t *pjsip_url_get_scheme(const pjsip_url *url)

+{

+    PJ_UNUSED_ARG(url);

+    return &sip_str;

+}

+

+static const pj_str_t *pjsips_url_get_scheme(const pjsip_url *url)

+{

+    PJ_UNUSED_ARG(url);

+    return &sips_str;

+}

+

+static void *pjsip_get_uri( pjsip_uri *uri )

+{

+    return uri;

+}

+

+static void *pjsip_name_addr_get_uri( pjsip_name_addr *name )

+{

+    return name->uri;

+}

+

+PJ_DEF(void) pjsip_url_init(pjsip_url *url, int secure)

+{

+    pj_memset(url, 0, sizeof(*url));

+    url->ttl_param = -1;

+    url->vptr = secure ? &sips_url_vptr : &sip_url_vptr;

+}

+

+PJ_DEF(pjsip_url*) pjsip_url_create( pj_pool_t *pool, int secure )

+{

+    pjsip_url *url = pj_pool_alloc(pool, sizeof(pjsip_url));

+    pjsip_url_init(url, secure);

+    return url;

+}

+

+static int pjsip_url_print(  pjsip_uri_context_e context,

+			     const pjsip_url *url, 

+			     char *buf, pj_size_t size)

+{

+    int printed;

+    pj_size_t size_required;

+    char *startbuf = buf;

+    const pj_str_t *scheme;

+    *buf = '\0';

+

+    /* Check the buffer length. */

+    size_required = 6 + url->host.slen + 10 +

+		    url->user.slen + url->passwd.slen + 2 +

+		    url->user_param.slen + 6 +

+		    url->method_param.slen + 8 +

+		    url->transport_param.slen + 11 +

+		    9 + 5 +

+		    url->maddr_param.slen + 7 +

+		    3 +

+		    url->other_param.slen +

+		    url->header_param.slen;

+    if (size < size_required) {

+	return -1;

+    }

+

+    /* Print scheme ("sip:" or "sips:") */

+    scheme = pjsip_uri_get_scheme(url);

+    copy_advance_no_check(buf, *scheme);

+    *buf++ = ':';

+

+    /* Print "user:password@", if any. */

+    if (url->user.slen) {

+	copy_advance_no_check(buf, url->user);

+	if (url->passwd.slen) {

+	    *buf++ = ':';

+	    copy_advance_no_check(buf, url->passwd);

+	}

+

+	*buf++ = '@';

+    }

+

+    /* Print host. */

+    pj_assert(url->host.slen != 0);

+    copy_advance_no_check(buf, url->host);

+

+    /* Only print port if it is explicitly specified. 

+     * Port is not allowed in To and From header.

+     */

+    /* Unfortunately some UA requires us to send back the port

+     * number exactly as it was sent. We don't remember whether an

+     * UA has sent us port, so we'll just send the port indiscrimately

+     */

+    PJ_TODO(SHOULD_DISALLOW_URI_PORT_IN_FROM_TO_HEADER)

+    if (url->port /*&& context != PJSIP_URI_IN_FROMTO_HDR*/) {

+	*buf++ = ':';

+	printed = pj_utoa(url->port, buf);

+	buf += printed;

+    }

+

+    /* User param is allowed in all contexes */

+    copy_advance_pair_no_check(buf, ";user=", 6, url->user_param);

+

+    /* Method param is only allowed in external/other context. */

+    if (context == PJSIP_URI_IN_OTHER) {

+	copy_advance_pair_no_check(buf, ";method=", 8, url->method_param);

+    }

+

+    /* Transport is not allowed in From/To header. */

+    if (context != PJSIP_URI_IN_FROMTO_HDR) {

+	copy_advance_pair_no_check(buf, ";transport=", 11, url->transport_param);

+    }

+

+    /* TTL param is not allowed in From, To, Route, and Record-Route header. */

+    if (url->ttl_param >= 0 && context != PJSIP_URI_IN_FROMTO_HDR &&

+	context != PJSIP_URI_IN_ROUTING_HDR) 

+    {

+	pj_memcpy(buf, ";ttl=", 5);

+	printed = pj_utoa(url->ttl_param, buf+5);

+	buf += printed + 5;

+    }

+

+    /* maddr param is not allowed in From and To header. */

+    if (context != PJSIP_URI_IN_FROMTO_HDR) {

+	copy_advance_pair_no_check(buf, ";maddr=", 7, url->maddr_param);

+    }

+

+    /* lr param is not allowed in From, To, and Contact header. */

+    if (url->lr_param && context != PJSIP_URI_IN_FROMTO_HDR &&

+	context != PJSIP_URI_IN_CONTACT_HDR) 

+    {

+	pj_str_t lr = { ";lr", 3 };

+	copy_advance_no_check(buf, lr);

+    }

+

+    /* Other param. */

+    if (url->other_param.slen) {

+	copy_advance_no_check(buf, url->other_param);

+    }

+

+    /* Header param. */

+    if (url->header_param.slen) {

+	copy_advance_no_check(buf, url->header_param);

+    }

+

+    *buf = '\0';

+    return buf-startbuf;

+}

+

+static int pjsip_url_compare( pjsip_uri_context_e context,

+			      const pjsip_url *url1, const pjsip_url *url2)

+{

+    /* The easiest (and probably the most efficient) way to compare two URLs

+       are to print them, and compare them bytes per bytes. This technique

+       works quite well with RFC3261, as the RFC (unlike RFC2543) defines that

+       components specified in one URL does NOT match its default value if

+       it is not specified in the second URL. For example, parameter "user=ip"

+       does NOT match if it is omited in second URL.

+

+       HOWEVER, THE SAME CAN NOT BE APPLIED FOR other-param NOR header-param.

+       For these, each of the parameters must be compared one by one. Parameter

+       that exists in one URL will match the comparison. But parameter that

+       exists in both URLs and doesn't match wont match the URL comparison.

+

+       The solution for this is to compare 'standard' URL components with

+       bytes-to-bytes comparison, and compare other-param and header-param with

+       more intelligent comparison.

+     */

+    char str_url1[PJSIP_MAX_URL_SIZE];

+    char str_url2[PJSIP_MAX_URL_SIZE];

+    int len1, len2;

+

+    /* Must compare scheme first, as the second URI may not be SIP URL. */

+    if (pj_stricmp(pjsip_uri_get_scheme(url1), pjsip_uri_get_scheme(url2)))

+	return -1;

+

+    len1 = pjsip_url_print(context, url1, str_url1, sizeof(str_url1));

+    if (len1 < 1) {

+	pj_assert(0);

+	return -1;

+    }

+    len2 = pjsip_url_print(context, url2, str_url2, sizeof(str_url2));

+    if (len2 < 1) {

+	pj_assert(0);

+	return -1;

+    }

+

+    if (len1 != len2) {

+	/* Not equal. */

+	return -1;

+    }

+

+    if (pj_native_strcmp(str_url1, str_url2)) {

+	/* Not equal */

+	return -1;

+    }

+

+    /* TODO: compare other-param and header-param in more intelligent manner. */

+    PJ_TODO(HPARAM_AND_OTHER_PARAM_COMPARISON_IN_URL_COMPARISON)

+

+    if (pj_strcmp(&url1->other_param, &url2->other_param)) {

+	/* Not equal. */

+	return -1;

+    }

+    if (pj_strcmp(&url1->header_param, &url2->header_param)) {

+	/* Not equal. */

+	return -1;

+    }

+

+    /* Seems to be equal, isn't it. */

+    return 0;

+    

+}

+

+

+PJ_DEF(void) pjsip_url_assign(pj_pool_t *pool, pjsip_url *url, 

+			      const pjsip_url *rhs)

+{

+    pj_strdup( pool, &url->user, &rhs->user);

+    pj_strdup( pool, &url->passwd, &rhs->passwd);

+    pj_strdup( pool, &url->host, &rhs->host);

+    url->port = rhs->port;

+    pj_strdup( pool, &url->user_param, &rhs->user_param);

+    pj_strdup( pool, &url->method_param, &rhs->method_param);

+    pj_strdup( pool, &url->transport_param, &rhs->transport_param);

+    url->ttl_param = rhs->ttl_param;

+    pj_strdup( pool, &url->maddr_param, &rhs->maddr_param);

+    pj_strdup( pool, &url->other_param, &rhs->other_param);

+    pj_strdup( pool, &url->header_param, &rhs->header_param);

+    url->lr_param = rhs->lr_param;

+}

+

+static pjsip_url* pjsip_url_clone(pj_pool_t *pool, const pjsip_url *rhs)

+{

+    pjsip_url *url = pj_pool_alloc(pool, sizeof(pjsip_url));

+    if (!url)

+	return NULL;

+

+    pjsip_url_init(url, IS_SIPS(rhs));

+    pjsip_url_assign(pool, url, rhs);

+    return url;

+}

+

+static const pj_str_t *pjsip_name_addr_get_scheme(const pjsip_name_addr *name)

+{

+    pj_assert(name->uri != NULL);

+    return pjsip_uri_get_scheme(name->uri);

+}

+

+PJ_DEF(void) pjsip_name_addr_init(pjsip_name_addr *name)

+{

+    name->vptr = &name_addr_vptr;

+    name->uri = NULL;

+    name->display.slen = 0;

+}

+

+PJ_DEF(pjsip_name_addr*) pjsip_name_addr_create(pj_pool_t *pool)

+{

+    pjsip_name_addr *name_addr = pj_pool_alloc(pool, sizeof(pjsip_name_addr));

+    pjsip_name_addr_init(name_addr);

+    return name_addr;

+}

+

+static int pjsip_name_addr_print( pjsip_uri_context_e context,

+				  const pjsip_name_addr *name, 

+				  char *buf, pj_size_t size)

+{

+    int printed;

+    char *startbuf = buf;

+    char *endbuf = buf + size;

+

+    pj_assert(name->uri != NULL);

+

+    if (context != PJSIP_URI_IN_REQ_URI) {

+	copy_advance(buf, name->display);

+	if (name->display.slen) {

+	    *buf++ = ' ';

+	}

+	*buf++ = '<';

+    }

+

+    printed = pjsip_uri_print(context,name->uri, buf, size-(buf-startbuf));

+    if (printed < 1)

+	return -1;

+    buf += printed;

+

+    if (context != PJSIP_URI_IN_REQ_URI) {

+	*buf++ = '>';

+    }

+

+    *buf = '\0';

+    return buf-startbuf;

+}

+

+PJ_DEF(void) pjsip_name_addr_assign(pj_pool_t *pool, pjsip_name_addr *dst,

+				    const pjsip_name_addr *src)

+{

+    pj_strdup( pool, &dst->display, &src->display);

+    dst->uri = pjsip_uri_clone(pool, src->uri);

+}

+

+static pjsip_name_addr* pjsip_name_addr_clone( pj_pool_t *pool, 

+					       const pjsip_name_addr *rhs)

+{

+    pjsip_name_addr *addr = pj_pool_alloc(pool, sizeof(pjsip_name_addr));

+    if (!addr)

+	return NULL;

+

+    pjsip_name_addr_init(addr);

+    pjsip_name_addr_assign(pool, addr, rhs);

+    return addr;

+}

+

+static int pjsip_name_addr_compare(  pjsip_uri_context_e context,

+				     const pjsip_name_addr *naddr1,

+				     const pjsip_name_addr *naddr2)

+{

+    int d;

+

+    /* I'm not sure whether display name is included in the comparison. */

+    if (pj_strcmp(&naddr1->display, &naddr2->display) != 0) {

+	return -1;

+    }

+

+    pj_assert( naddr1->uri != NULL );

+    pj_assert( naddr2->uri != NULL );

+

+    /* Compare name-addr as URL */

+    d = pjsip_uri_cmp( context, naddr1->uri, naddr2->uri);

+    if (d)

+	return d;

+

+    return 0;

+}

+

diff --git a/pjsip/src/pjsua/getopt.c b/pjsip/src/pjsua/getopt.c
index 5d4689c..ce7891d 100644
--- a/pjsip/src/pjsua/getopt.c
+++ b/pjsip/src/pjsua/getopt.c
@@ -1,1046 +1,1068 @@
-/* $Id$
- *
- */
-
-#ifdef _MSC_VER
-/* in VC this file will generate a lot of warning about old style function
- * declarations.
- */
-# pragma warning(push, 3)
-#endif
-
-/* 
- * getopt entry points
- *
- * modified by Mike Borella <mike_borella@mw.3com.com>
- *
- * $Id: getopt.c,v 1.4 2000/10/30 22:06:03 mborella Exp $
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifndef HAVE_GETOPT_LONG
-
-/* getopt_long and getopt_long_only entry points for GNU getopt.
-   Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#include "getopt.h"
-
-
-#include <stdio.h>
-
-/* Comment out all this code if we are using the GNU C Library, and are not
-   actually compiling the library itself.  This code is part of the GNU C
-   Library, but also included in many other GNU distributions.  Compiling
-   and linking in this code is a waste when using the GNU C library
-   (especially if it is a shared library).  Rather than having every GNU
-   program understand `configure --with-gnu-libc' and omit the object files,
-   it is simpler to just do this in the source for each such file.  */
-
-#define GETOPT_INTERFACE_VERSION 2
-#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
-#include <gnu-versions.h>
-#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
-#define ELIDE_CODE
-#endif
-#endif
-
-#ifndef ELIDE_CODE
-
-
-/* This needs to come after some library #include
-   to get __GNU_LIBRARY__ defined.  */
-#ifdef __GNU_LIBRARY__
-#include <stdlib.h>
-#endif
-
-#ifndef	NULL
-#define NULL 0
-#endif
-
-int
-getopt_long (int argc, char *const *argv, const char *options, 
-	     const struct option *long_options, int *opt_index)
-{
-  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
-}
-
-/* Like getopt_long, but '-' as well as '--' can indicate a long option.
-   If an option that starts with '-' (not '--') doesn't match a long option,
-   but does match a short option, it is parsed as a short option
-   instead.  */
- 
-int
-getopt_long_only (argc, argv, options, long_options, opt_index)
-     int argc;
-     char *const *argv;
-     const char *options;
-     const struct option *long_options;
-     int *opt_index;
-{
-  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
-}
-
-int
-getopt (int argc, char * const * argv, const char * optstring)
-{
-  return _getopt_internal (argc, argv, optstring,
-			   (const struct option *) 0,
-			   (int *) 0,
-			   0);
-}
-
-#endif	/* Not ELIDE_CODE.  */
-
-
-#ifndef _NO_PROTO
-#define _NO_PROTO
-#endif
-
-
-//#include <strings.h>
-
-/* Comment out all this code if we are using the GNU C Library, and are not
-   actually compiling the library itself.  This code is part of the GNU C
-   Library, but also included in many other GNU distributions.  Compiling
-   and linking in this code is a waste when using the GNU C library
-   (especially if it is a shared library).  Rather than having every GNU
-   program understand `configure --with-gnu-libc' and omit the object files,
-   it is simpler to just do this in the source for each such file.  */
-
-#define GETOPT_INTERFACE_VERSION 2
-#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2
-#include <gnu-versions.h>
-#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
-#define ELIDE_CODE
-#endif
-#endif
-
-#ifndef ELIDE_CODE
-
-
-/* This needs to come after some library #include
-   to get __GNU_LIBRARY__ defined.  */
-#ifdef	__GNU_LIBRARY__
-/* Don't include stdlib.h for non-GNU C libraries because some of them
-   contain conflicting prototypes for getopt.  */
-#include <stdlib.h>
-#include <unistd.h>
-#endif	/* GNU C library.  */
-
-#ifdef VMS
-#include <unixlib.h>
-#if HAVE_STRING_H - 0
-#include <string.h>
-#endif
-#endif
-
-#if defined (WIN32) && !defined (__CYGWIN32__)
-/* It's not Unix, really.  See?  Capital letters.  */
-#include <windows.h>
-#define getpid() GetCurrentProcessId()
-#endif
-
-#ifndef _
-/* This is for other GNU distributions with internationalized messages.
-   When compiling libc, the _ macro is predefined.  */
-#ifdef HAVE_LIBINTL_H
-# include <libintl.h>
-# define _(msgid)	gettext (msgid)
-#else
-# define _(msgid)	(msgid)
-#endif
-#endif
-
-/* This version of `getopt' appears to the caller like standard Unix `getopt'
-   but it behaves differently for the user, since it allows the user
-   to intersperse the options with the other arguments.
-
-   As `getopt' works, it permutes the elements of ARGV so that,
-   when it is done, all the options precede everything else.  Thus
-   all application programs are extended to handle flexible argument order.
-
-   Setting the environment variable POSIXLY_CORRECT disables permutation.
-   Then the behavior is completely standard.
-
-   GNU application programs can use a third alternative mode in which
-   they can distinguish the relative order of options and other arguments.  */
-
-#include "getopt.h"
-
-/* For communication from `getopt' to the caller.
-   When `getopt' finds an option that takes an argument,
-   the argument value is returned here.
-   Also, when `ordering' is RETURN_IN_ORDER,
-   each non-option ARGV-element is returned here.  */
-
-char *optarg = NULL;
-
-/* Index in ARGV of the next element to be scanned.
-   This is used for communication to and from the caller
-   and for communication between successive calls to `getopt'.
-
-   On entry to `getopt', zero means this is the first call; initialize.
-
-   When `getopt' returns -1, this is the index of the first of the
-   non-option elements that the caller should itself scan.
-
-   Otherwise, `optind' communicates from one call to the next
-   how much of ARGV has been scanned so far.  */
-
-/* 1003.2 says this must be 1 before any call.  */
-int optind = 1;
-
-/* Formerly, initialization of getopt depended on optind==0, which
-   causes problems with re-calling getopt as programs generally don't
-   know that. */
-
-int __getopt_initialized = 0;
-
-/* The next char to be scanned in the option-element
-   in which the last option character we returned was found.
-   This allows us to pick up the scan where we left off.
-
-   If this is zero, or a null string, it means resume the scan
-   by advancing to the next ARGV-element.  */
-
-static char *nextchar;
-
-/* Callers store zero here to inhibit the error message
-   for unrecognized options.  */
-
-int opterr = 1;
-
-/* Set to an option character which was unrecognized.
-   This must be initialized on some systems to avoid linking in the
-   system's own getopt implementation.  */
-
-int optopt = '?';
-
-/* Describe how to deal with options that follow non-option ARGV-elements.
-
-   If the caller did not specify anything,
-   the default is REQUIRE_ORDER if the environment variable
-   POSIXLY_CORRECT is defined, PERMUTE otherwise.
-
-   REQUIRE_ORDER means don't recognize them as options;
-   stop option processing when the first non-option is seen.
-   This is what Unix does.
-   This mode of operation is selected by either setting the environment
-   variable POSIXLY_CORRECT, or using `+' as the first character
-   of the list of option characters.
-
-   PERMUTE is the default.  We permute the contents of ARGV as we scan,
-   so that eventually all the non-options are at the end.  This allows options
-   to be given in any order, even with programs that were not written to
-   expect this.
-
-   RETURN_IN_ORDER is an option available to programs that were written
-   to expect options and other ARGV-elements in any order and that care about
-   the ordering of the two.  We describe each non-option ARGV-element
-   as if it were the argument of an option with character code 1.
-   Using `-' as the first character of the list of option characters
-   selects this mode of operation.
-
-   The special argument `--' forces an end of option-scanning regardless
-   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
-   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
-
-static enum
-{
-  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
-} ordering;
-
-/* Value of POSIXLY_CORRECT environment variable.  */
-static char *posixly_correct;
-
-#ifdef	__GNU_LIBRARY__
-/* We want to avoid inclusion of string.h with non-GNU libraries
-   because there are many ways it can cause trouble.
-   On some systems, it contains special magic macros that don't work
-   in GCC.  */
-#include <string.h>
-#define	my_index	pj_native_strchr
-#else
-
-static char *
-my_index (const char *str, int chr)
-{
-  while (*str)
-    {
-      if (*str == chr)
-	return (char *) str;
-      str++;
-    }
-  return 0;
-}
-
-/* If using GCC, we can safely declare strlen this way.
-   If not using GCC, it is ok not to declare it.  */
-#ifdef __GNUC__
-/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
-   That was relevant to code that was here before.  */
-#if !defined (__STDC__) || !__STDC__
-/* gcc with -traditional declares the built-in strlen to return int,
-   and has done so at least since version 2.4.5. -- rms.  */
-extern int strlen (const char *);
-#endif /* not __STDC__ */
-#endif /* __GNUC__ */
-
-#endif /* not __GNU_LIBRARY__ */
-
-/* Handle permutation of arguments.  */
-
-/* Describe the part of ARGV that contains non-options that have
-   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
-   `last_nonopt' is the index after the last of them.  */
-
-static int first_nonopt;
-static int last_nonopt;
-
-#ifdef _LIBC
-/* Bash 2.0 gives us an environment variable containing flags
-   indicating ARGV elements that should not be considered arguments.  */
-
-/* Defined in getopt_init.c  */
-extern char *__getopt_nonoption_flags;
-
-static int nonoption_flags_max_len;
-static int nonoption_flags_len;
-
-static int original_argc;
-static char *const *original_argv;
-
-extern pid_t __libc_pid;
-
-/* Make sure the environment variable bash 2.0 puts in the environment
-   is valid for the getopt call we must make sure that the ARGV passed
-   to getopt is that one passed to the process.  */
-static void
-__attribute__ ((unused))
-store_args_and_env (int argc, char *const *argv)
-{
-  /* XXX This is no good solution.  We should rather copy the args so
-     that we can compare them later.  But we must not use malloc(3).  */
-  original_argc = argc;
-  original_argv = argv;
-}
-text_set_element (__libc_subinit, store_args_and_env);
-
-# define SWAP_FLAGS(ch1, ch2) \
-  if (nonoption_flags_len > 0)						      \
-    {									      \
-      char __tmp = __getopt_nonoption_flags[ch1];			      \
-      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];	      \
-      __getopt_nonoption_flags[ch2] = __tmp;				      \
-    }
-#else	/* !_LIBC */
-# define SWAP_FLAGS(ch1, ch2)
-#endif	/* _LIBC */
-
-/* Exchange two adjacent subsequences of ARGV.
-   One subsequence is elements [first_nonopt,last_nonopt)
-   which contains all the non-options that have been skipped so far.
-   The other is elements [last_nonopt,optind), which contains all
-   the options processed since those non-options were skipped.
-
-   `first_nonopt' and `last_nonopt' are relocated so that they describe
-   the new indices of the non-options in ARGV after they are moved.  */
-
-#if defined (__STDC__) && __STDC__
-static void exchange (char **);
-#endif
-
-static void
-exchange (argv)
-     char **argv;
-{
-  int bottom = first_nonopt;
-  int middle = last_nonopt;
-  int top = optind;
-  char *tem;
-
-  /* Exchange the shorter segment with the far end of the longer segment.
-     That puts the shorter segment into the right place.
-     It leaves the longer segment in the right place overall,
-     but it consists of two parts that need to be swapped next.  */
-
-#ifdef _LIBC
-  /* First make sure the handling of the `__getopt_nonoption_flags'
-     string can work normally.  Our top argument must be in the range
-     of the string.  */
-  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
-    {
-      /* We must extend the array.  The user plays games with us and
-	 presents new arguments.  */
-      char *new_str = malloc (top + 1);
-      if (new_str == NULL)
-	nonoption_flags_len = nonoption_flags_max_len = 0;
-      else
-	{
-	  memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len);
-	  memset (&new_str[nonoption_flags_max_len], '\0',
-		  top + 1 - nonoption_flags_max_len);
-	  nonoption_flags_max_len = top + 1;
-	  __getopt_nonoption_flags = new_str;
-	}
-    }
-#endif
-
-  while (top > middle && middle > bottom)
-    {
-      if (top - middle > middle - bottom)
-	{
-	  /* Bottom segment is the short one.  */
-	  int len = middle - bottom;
-	  register int i;
-
-	  /* Swap it with the top part of the top segment.  */
-	  for (i = 0; i < len; i++)
-	    {
-	      tem = argv[bottom + i];
-	      argv[bottom + i] = argv[top - (middle - bottom) + i];
-	      argv[top - (middle - bottom) + i] = tem;
-	      SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
-	    }
-	  /* Exclude the moved bottom segment from further swapping.  */
-	  top -= len;
-	}
-      else
-	{
-	  /* Top segment is the short one.  */
-	  int len = top - middle;
-	  register int i;
-
-	  /* Swap it with the bottom part of the bottom segment.  */
-	  for (i = 0; i < len; i++)
-	    {
-	      tem = argv[bottom + i];
-	      argv[bottom + i] = argv[middle + i];
-	      argv[middle + i] = tem;
-	      SWAP_FLAGS (bottom + i, middle + i);
-	    }
-	  /* Exclude the moved top segment from further swapping.  */
-	  bottom += len;
-	}
-    }
-
-  /* Update records for the slots the non-options now occupy.  */
-
-  first_nonopt += (optind - last_nonopt);
-  last_nonopt = optind;
-}
-
-/* Initialize the internal data when the first call is made.  */
-
-#if defined (__STDC__) && __STDC__
-static const char *_getopt_initialize (int, char *const *, const char *);
-#endif
-static const char *
-_getopt_initialize (argc, argv, optstring)
-     int argc;
-     char *const *argv;
-     const char *optstring;
-{
-  /* Start processing options with ARGV-element 1 (since ARGV-element 0
-     is the program name); the sequence of previously skipped
-     non-option ARGV-elements is empty.  */
-
-  first_nonopt = last_nonopt = optind;
-
-  nextchar = NULL;
-
-  posixly_correct = getenv ("POSIXLY_CORRECT");
-
-  /* Determine how to handle the ordering of options and nonoptions.  */
-
-  if (optstring[0] == '-')
-    {
-      ordering = RETURN_IN_ORDER;
-      ++optstring;
-    }
-  else if (optstring[0] == '+')
-    {
-      ordering = REQUIRE_ORDER;
-      ++optstring;
-    }
-  else if (posixly_correct != NULL)
-    ordering = REQUIRE_ORDER;
-  else
-    ordering = PERMUTE;
-
-#ifdef _LIBC
-  if (posixly_correct == NULL
-      && argc == original_argc && argv == original_argv)
-    {
-      if (nonoption_flags_max_len == 0)
-	{
-	  if (__getopt_nonoption_flags == NULL
-	      || __getopt_nonoption_flags[0] == '\0')
-	    nonoption_flags_max_len = -1;
-	  else
-	    {
-	      const char *orig_str = __getopt_nonoption_flags;
-	      int len = nonoption_flags_max_len = strlen (orig_str);
-	      if (nonoption_flags_max_len < argc)
-		nonoption_flags_max_len = argc;
-	      __getopt_nonoption_flags =
-		(char *) malloc (nonoption_flags_max_len);
-	      if (__getopt_nonoption_flags == NULL)
-		nonoption_flags_max_len = -1;
-	      else
-		{
-		  memcpy (__getopt_nonoption_flags, orig_str, len);
-		  memset (&__getopt_nonoption_flags[len], '\0',
-			  nonoption_flags_max_len - len);
-		}
-	    }
-	}
-      nonoption_flags_len = nonoption_flags_max_len;
-    }
-  else
-    nonoption_flags_len = 0;
-#endif
-
-  return optstring;
-}
-
-/* Scan elements of ARGV (whose length is ARGC) for option characters
-   given in OPTSTRING.
-
-   If an element of ARGV starts with '-', and is not exactly "-" or "--",
-   then it is an option element.  The characters of this element
-   (aside from the initial '-') are option characters.  If `getopt'
-   is called repeatedly, it returns successively each of the option characters
-   from each of the option elements.
-
-   If `getopt' finds another option character, it returns that character,
-   updating `optind' and `nextchar' so that the next call to `getopt' can
-   resume the scan with the following option character or ARGV-element.
-
-   If there are no more option characters, `getopt' returns -1.
-   Then `optind' is the index in ARGV of the first ARGV-element
-   that is not an option.  (The ARGV-elements have been permuted
-   so that those that are not options now come last.)
-
-   OPTSTRING is a string containing the legitimate option characters.
-   If an option character is seen that is not listed in OPTSTRING,
-   return '?' after printing an error message.  If you set `opterr' to
-   zero, the error message is suppressed but we still return '?'.
-
-   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
-   so the following text in the same ARGV-element, or the text of the following
-   ARGV-element, is returned in `optarg'.  Two colons mean an option that
-   wants an optional arg; if there is text in the current ARGV-element,
-   it is returned in `optarg', otherwise `optarg' is set to zero.
-
-   If OPTSTRING starts with `-' or `+', it requests different methods of
-   handling the non-option ARGV-elements.
-   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
-
-   Long-named options begin with `--' instead of `-'.
-   Their names may be abbreviated as long as the abbreviation is unique
-   or is an exact match for some defined option.  If they have an
-   argument, it follows the option name in the same ARGV-element, separated
-   from the option name by a `=', or else the in next ARGV-element.
-   When `getopt' finds a long-named option, it returns 0 if that option's
-   `flag' field is nonzero, the value of the option's `val' field
-   if the `flag' field is zero.
-
-   The elements of ARGV aren't really const, because we permute them.
-   But we pretend they're const in the prototype to be compatible
-   with other systems.
-
-   LONGOPTS is a vector of `struct option' terminated by an
-   element containing a name which is zero.
-
-   LONGIND returns the index in LONGOPT of the long-named option found.
-   It is only valid when a long-named option has been found by the most
-   recent call.
-
-   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
-   long-named options.  */
-
-int
-_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
-     int argc;
-     char *const *argv;
-     const char *optstring;
-     const struct option *longopts;
-     int *longind;
-     int long_only;
-{
-  optarg = NULL;
-
-  if (optind == 0 || !__getopt_initialized)
-    {
-      if (optind == 0)
-	optind = 1;	/* Don't scan ARGV[0], the program name.  */
-      optstring = _getopt_initialize (argc, argv, optstring);
-      __getopt_initialized = 1;
-    }
-
-  /* Test whether ARGV[optind] points to a non-option argument.
-     Either it does not have option syntax, or there is an environment flag
-     from the shell indicating it is not an option.  The later information
-     is only used when the used in the GNU libc.  */
-#ifdef _LIBC
-#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \
-		     || (optind < nonoption_flags_len			      \
-			 && __getopt_nonoption_flags[optind] == '1'))
-#else
-#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
-#endif
-
-  if (nextchar == NULL || *nextchar == '\0')
-    {
-      /* Advance to the next ARGV-element.  */
-
-      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
-	 moved back by the user (who may also have changed the arguments).  */
-      if (last_nonopt > optind)
-	last_nonopt = optind;
-      if (first_nonopt > optind)
-	first_nonopt = optind;
-
-      if (ordering == PERMUTE)
-	{
-	  /* If we have just processed some options following some non-options,
-	     exchange them so that the options come first.  */
-
-	  if (first_nonopt != last_nonopt && last_nonopt != optind)
-	    exchange ((char **) argv);
-	  else if (last_nonopt != optind)
-	    first_nonopt = optind;
-
-	  /* Skip any additional non-options
-	     and extend the range of non-options previously skipped.  */
-
-	  while (optind < argc && NONOPTION_P)
-	    optind++;
-	  last_nonopt = optind;
-	}
-
-      /* The special ARGV-element `--' means premature end of options.
-	 Skip it like a null option,
-	 then exchange with previous non-options as if it were an option,
-	 then skip everything else like a non-option.  */
-
-      if (optind != argc && !pj_native_strcmp(argv[optind], "--"))
-	{
-	  optind++;
-
-	  if (first_nonopt != last_nonopt && last_nonopt != optind)
-	    exchange ((char **) argv);
-	  else if (first_nonopt == last_nonopt)
-	    first_nonopt = optind;
-	  last_nonopt = argc;
-
-	  optind = argc;
-	}
-
-      /* If we have done all the ARGV-elements, stop the scan
-	 and back over any non-options that we skipped and permuted.  */
-
-      if (optind == argc)
-	{
-	  /* Set the next-arg-index to point at the non-options
-	     that we previously skipped, so the caller will digest them.  */
-	  if (first_nonopt != last_nonopt)
-	    optind = first_nonopt;
-	  return -1;
-	}
-
-      /* If we have come to a non-option and did not permute it,
-	 either stop the scan or describe it to the caller and pass it by.  */
-
-      if (NONOPTION_P)
-	{
-	  if (ordering == REQUIRE_ORDER)
-	    return -1;
-	  optarg = argv[optind++];
-	  return 1;
-	}
-
-      /* We have found another option-ARGV-element.
-	 Skip the initial punctuation.  */
-
-      nextchar = (argv[optind] + 1
-		  + (longopts != NULL && argv[optind][1] == '-'));
-    }
-
-  /* Decode the current option-ARGV-element.  */
-
-  /* Check whether the ARGV-element is a long option.
-
-     If long_only and the ARGV-element has the form "-f", where f is
-     a valid short option, don't consider it an abbreviated form of
-     a long option that starts with f.  Otherwise there would be no
-     way to give the -f short option.
-
-     On the other hand, if there's a long option "fubar" and
-     the ARGV-element is "-fu", do consider that an abbreviation of
-     the long option, just like "--fu", and not "-f" with arg "u".
-
-     This distinction seems to be the most useful approach.  */
-
-  if (longopts != NULL
-      && (argv[optind][1] == '-'
-	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
-    {
-      char *nameend;
-      const struct option *p;
-      const struct option *pfound = NULL;
-      int exact = 0;
-      int ambig = 0;
-      int indfound = -1;
-      int option_index;
-
-      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
-	/* Do nothing.  */ ;
-
-      /* Test all long options for either exact match
-	 or abbreviated matches.  */
-      for (p = longopts, option_index = 0; p->name; p++, option_index++)
-	if (!strncmp (p->name, nextchar, nameend - nextchar))
-	  {
-	    if ((unsigned int) (nameend - nextchar)
-		== (unsigned int) strlen (p->name))
-	      {
-		/* Exact match found.  */
-		pfound = p;
-		indfound = option_index;
-		exact = 1;
-		break;
-	      }
-	    else if (pfound == NULL)
-	      {
-		/* First nonexact match found.  */
-		pfound = p;
-		indfound = option_index;
-	      }
-	    else
-	      /* Second or later nonexact match found.  */
-	      ambig = 1;
-	  }
-
-      if (ambig && !exact)
-	{
-	  if (opterr)
-	    fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
-		     argv[0], argv[optind]);
-	  nextchar += strlen (nextchar);
-	  optind++;
-	  optopt = 0;
-	  return '?';
-	}
-
-      if (pfound != NULL)
-	{
-	  option_index = indfound;
-	  optind++;
-	  if (*nameend)
-	    {
-	      /* Don't test has_arg with >, because some C compilers don't
-		 allow it to be used on enums.  */
-	      if (pfound->has_arg)
-		optarg = nameend + 1;
-	      else
-		{
-		  if (opterr)
-		   {
-		   if (argv[optind - 1][1] == '-')
-		    /* --option */
-		    fprintf (stderr,
-		     _("%s: option `--%s' doesn't allow an argument\n"),
-		     argv[0], pfound->name);
-		   else
-		      {	
-		    /* +option or -option */
-		    fprintf (stderr,
-		     _("%s: option `%c%s' doesn't allow an argument\n"),
-		     argv[0], argv[optind - 1][0], pfound->name);
-                      }
-		    }
-		  nextchar += strlen (nextchar);
-
-		  optopt = pfound->val;
-		  return '?';
-		}
-	    }
-	  else if (pfound->has_arg == 1)
-	    {
-	      if (optind < argc)
-		optarg = argv[optind++];
-	      else
-		{
-		  if (opterr)
-		    fprintf (stderr,
-			   _("%s: option `%s' requires an argument\n"),
-			   argv[0], argv[optind - 1]);
-		  nextchar += strlen (nextchar);
-		  optopt = pfound->val;
-		  return optstring[0] == ':' ? ':' : '?';
-		}
-	    }
-	  nextchar += strlen (nextchar);
-	  if (longind != NULL)
-	    *longind = option_index;
-	  if (pfound->flag)
-	    {
-	      *(pfound->flag) = pfound->val;
-	      return 0;
-	    }
-	  return pfound->val;
-	}
-
-      /* Can't find it as a long option.  If this is not getopt_long_only,
-	 or the option starts with '--' or is not a valid short
-	 option, then it's an error.
-	 Otherwise interpret it as a short option.  */
-      if (!long_only || argv[optind][1] == '-'
-	  || my_index (optstring, *nextchar) == NULL)
-	{
-	  if (opterr)
-	    {
-	      if (argv[optind][1] == '-')
-		/* --option */
-		fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
-			 argv[0], nextchar);
-	      else
-		/* +option or -option */
-		fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
-			 argv[0], argv[optind][0], nextchar);
-	    }
-	  nextchar = (char *) "";
-	  optind++;
-	  optopt = 0;
-	  return '?';
-	}
-    }
-
-  /* Look at and handle the next short option-character.  */
-
-  {
-    char c = *nextchar++;
-    char *temp = my_index (optstring, c);
-
-    /* Increment `optind' when we start to process its last character.  */
-    if (*nextchar == '\0')
-      ++optind;
-
-    if (temp == NULL || c == ':')
-      {
-	if (opterr)
-	  {
-	    if (posixly_correct)
-	      /* 1003.2 specifies the format of this message.  */
-	      fprintf (stderr, _("%s: illegal option -- %c\n"),
-		       argv[0], c);
-	    else
-	      fprintf (stderr, _("%s: invalid option -- %c\n"),
-		       argv[0], c);
-	  }
-	optopt = c;
-	return '?';
-      }
-    /* Convenience. Treat POSIX -W foo same as long option --foo */
-    if (temp[0] == 'W' && temp[1] == ';')
-      {
-	char *nameend;
-	const struct option *p;
-	const struct option *pfound = NULL;
-	int exact = 0;
-	int ambig = 0;
-	int indfound = 0;
-	int option_index;
-
-	/* This is an option that requires an argument.  */
-	if (*nextchar != '\0')
-	  {
-	    optarg = nextchar;
-	    /* If we end this ARGV-element by taking the rest as an arg,
-	       we must advance to the next element now.  */
-	    optind++;
-	  }
-	else if (optind == argc)
-	  {
-	    if (opterr)
-	      {
-		/* 1003.2 specifies the format of this message.  */
-		fprintf (stderr, _("%s: option requires an argument -- %c\n"),
-			 argv[0], c);
-	      }
-	    optopt = c;
-	    if (optstring[0] == ':')
-	      c = ':';
-	    else
-	      c = '?';
-	    return c;
-	  }
-	else
-	  /* We already incremented `optind' once;
-	     increment it again when taking next ARGV-elt as argument.  */
-	  optarg = argv[optind++];
-
-	/* optarg is now the argument, see if it's in the
-	   table of longopts.  */
-
-	for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
-	  /* Do nothing.  */ ;
-
-	/* Test all long options for either exact match
-	   or abbreviated matches.  */
-	for (p = longopts, option_index = 0; p->name; p++, option_index++)
-	  if (!strncmp (p->name, nextchar, nameend - nextchar))
-	    {
-	      if ((unsigned int) (nameend - nextchar) == strlen (p->name))
-		{
-		  /* Exact match found.  */
-		  pfound = p;
-		  indfound = option_index;
-		  exact = 1;
-		  break;
-		}
-	      else if (pfound == NULL)
-		{
-		  /* First nonexact match found.  */
-		  pfound = p;
-		  indfound = option_index;
-		}
-	      else
-		/* Second or later nonexact match found.  */
-		ambig = 1;
-	    }
-	if (ambig && !exact)
-	  {
-	    if (opterr)
-	      fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
-		       argv[0], argv[optind]);
-	    nextchar += strlen (nextchar);
-	    optind++;
-	    return '?';
-	  }
-	if (pfound != NULL)
-	  {
-	    option_index = indfound;
-	    if (*nameend)
-	      {
-		/* Don't test has_arg with >, because some C compilers don't
-		   allow it to be used on enums.  */
-		if (pfound->has_arg)
-		  optarg = nameend + 1;
-		else
-		  {
-		    if (opterr)
-		      fprintf (stderr, _("\
-%s: option `-W %s' doesn't allow an argument\n"),
-			       argv[0], pfound->name);
-
-		    nextchar += strlen (nextchar);
-		    return '?';
-		  }
-	      }
-	    else if (pfound->has_arg == 1)
-	      {
-		if (optind < argc)
-		  optarg = argv[optind++];
-		else
-		  {
-		    if (opterr)
-		      fprintf (stderr,
-			       _("%s: option `%s' requires an argument\n"),
-			       argv[0], argv[optind - 1]);
-		    nextchar += strlen (nextchar);
-		    return optstring[0] == ':' ? ':' : '?';
-		  }
-	      }
-	    nextchar += strlen (nextchar);
-	    if (longind != NULL)
-	      *longind = option_index;
-	    if (pfound->flag)
-	      {
-		*(pfound->flag) = pfound->val;
-		return 0;
-	      }
-	    return pfound->val;
-	  }
-	  nextchar = NULL;
-	  return 'W';	/* Let the application handle it.   */
-      }
-    if (temp[1] == ':')
-      {
-	if (temp[2] == ':')
-	  {
-	    /* This is an option that accepts an argument optionally.  */
-	    if (*nextchar != '\0')
-	      {
-		optarg = nextchar;
-		optind++;
-	      }
-	    else
-	      optarg = NULL;
-	    nextchar = NULL;
-	  }
-	else
-	  {
-	    /* This is an option that requires an argument.  */
-	    if (*nextchar != '\0')
-	      {
-		optarg = nextchar;
-		/* If we end this ARGV-element by taking the rest as an arg,
-		   we must advance to the next element now.  */
-		optind++;
-	      }
-	    else if (optind == argc)
-	      {
-		if (opterr)
-		  {
-		    /* 1003.2 specifies the format of this message.  */
-		    fprintf (stderr,
-			   _("%s: option requires an argument -- %c\n"),
-			   argv[0], c);
-		  }
-		optopt = c;
-		if (optstring[0] == ':')
-		  c = ':';
-		else
-		  c = '?';
-	      }
-	    else
-	      /* We already incremented `optind' once;
-		 increment it again when taking next ARGV-elt as argument.  */
-	      optarg = argv[optind++];
-	    nextchar = NULL;
-	  }
-      }
-    return c;
-  }
-}
-
-#endif	/* Not ELIDE_CODE.  */
-
-#endif
-
-#ifdef _MSC_VER
-# pragma warning(pop)
-#endif
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+

+#ifdef _MSC_VER

+/* in VC this file will generate a lot of warning about old style function

+ * declarations.

+ */

+# pragma warning(push, 3)

+#endif

+

+/* 

+ * getopt entry points

+ *

+ * modified by Mike Borella <mike_borella@mw.3com.com>

+ *

+ * $Id: getopt.c,v 1.4 2000/10/30 22:06:03 mborella Exp $

+ */

+

+#ifdef HAVE_CONFIG_H

+#include "config.h"

+#endif

+

+#ifndef HAVE_GETOPT_LONG

+

+/* getopt_long and getopt_long_only entry points for GNU getopt.

+   Copyright (C) 1987,88,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.

+   This file is part of the GNU C Library.

+

+   The GNU C Library is free software; you can redistribute it and/or

+   modify it under the terms of the GNU Library General Public License as

+   published by the Free Software Foundation; either version 2 of the

+   License, or (at your option) any later version.

+

+   The GNU C Library 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

+   Library General Public License for more details.

+

+   You should have received a copy of the GNU Library General Public

+   License along with the GNU C Library; see the file COPYING.LIB.  If not,

+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,

+   Boston, MA 02111-1307, USA.  */

+

+#include "getopt.h"

+

+

+#include <stdio.h>

+

+/* Comment out all this code if we are using the GNU C Library, and are not

+   actually compiling the library itself.  This code is part of the GNU C

+   Library, but also included in many other GNU distributions.  Compiling

+   and linking in this code is a waste when using the GNU C library

+   (especially if it is a shared library).  Rather than having every GNU

+   program understand `configure --with-gnu-libc' and omit the object files,

+   it is simpler to just do this in the source for each such file.  */

+

+#define GETOPT_INTERFACE_VERSION 2

+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2

+#include <gnu-versions.h>

+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION

+#define ELIDE_CODE

+#endif

+#endif

+

+#ifndef ELIDE_CODE

+

+

+/* This needs to come after some library #include

+   to get __GNU_LIBRARY__ defined.  */

+#ifdef __GNU_LIBRARY__

+#include <stdlib.h>

+#endif

+

+#ifndef	NULL

+#define NULL 0

+#endif

+

+int

+getopt_long (int argc, char *const *argv, const char *options, 

+	     const struct option *long_options, int *opt_index)

+{

+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);

+}

+

+/* Like getopt_long, but '-' as well as '--' can indicate a long option.

+   If an option that starts with '-' (not '--') doesn't match a long option,

+   but does match a short option, it is parsed as a short option

+   instead.  */

+ 

+int

+getopt_long_only (argc, argv, options, long_options, opt_index)

+     int argc;

+     char *const *argv;

+     const char *options;

+     const struct option *long_options;

+     int *opt_index;

+{

+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);

+}

+

+int

+getopt (int argc, char * const * argv, const char * optstring)

+{

+  return _getopt_internal (argc, argv, optstring,

+			   (const struct option *) 0,

+			   (int *) 0,

+			   0);

+}

+

+#endif	/* Not ELIDE_CODE.  */

+

+

+#ifndef _NO_PROTO

+#define _NO_PROTO

+#endif

+

+

+//#include <strings.h>

+

+/* Comment out all this code if we are using the GNU C Library, and are not

+   actually compiling the library itself.  This code is part of the GNU C

+   Library, but also included in many other GNU distributions.  Compiling

+   and linking in this code is a waste when using the GNU C library

+   (especially if it is a shared library).  Rather than having every GNU

+   program understand `configure --with-gnu-libc' and omit the object files,

+   it is simpler to just do this in the source for each such file.  */

+

+#define GETOPT_INTERFACE_VERSION 2

+#if !defined (_LIBC) && defined (__GLIBC__) && __GLIBC__ >= 2

+#include <gnu-versions.h>

+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION

+#define ELIDE_CODE

+#endif

+#endif

+

+#ifndef ELIDE_CODE

+

+

+/* This needs to come after some library #include

+   to get __GNU_LIBRARY__ defined.  */

+#ifdef	__GNU_LIBRARY__

+/* Don't include stdlib.h for non-GNU C libraries because some of them

+   contain conflicting prototypes for getopt.  */

+#include <stdlib.h>

+#include <unistd.h>

+#endif	/* GNU C library.  */

+

+#ifdef VMS

+#include <unixlib.h>

+#if HAVE_STRING_H - 0

+#include <string.h>

+#endif

+#endif

+

+#if defined (WIN32) && !defined (__CYGWIN32__)

+/* It's not Unix, really.  See?  Capital letters.  */

+#include <windows.h>

+#define getpid() GetCurrentProcessId()

+#endif

+

+#ifndef _

+/* This is for other GNU distributions with internationalized messages.

+   When compiling libc, the _ macro is predefined.  */

+#ifdef HAVE_LIBINTL_H

+# include <libintl.h>

+# define _(msgid)	gettext (msgid)

+#else

+# define _(msgid)	(msgid)

+#endif

+#endif

+

+/* This version of `getopt' appears to the caller like standard Unix `getopt'

+   but it behaves differently for the user, since it allows the user

+   to intersperse the options with the other arguments.

+

+   As `getopt' works, it permutes the elements of ARGV so that,

+   when it is done, all the options precede everything else.  Thus

+   all application programs are extended to handle flexible argument order.

+

+   Setting the environment variable POSIXLY_CORRECT disables permutation.

+   Then the behavior is completely standard.

+

+   GNU application programs can use a third alternative mode in which

+   they can distinguish the relative order of options and other arguments.  */

+

+#include "getopt.h"

+

+/* For communication from `getopt' to the caller.

+   When `getopt' finds an option that takes an argument,

+   the argument value is returned here.

+   Also, when `ordering' is RETURN_IN_ORDER,

+   each non-option ARGV-element is returned here.  */

+

+char *optarg = NULL;

+

+/* Index in ARGV of the next element to be scanned.

+   This is used for communication to and from the caller

+   and for communication between successive calls to `getopt'.

+

+   On entry to `getopt', zero means this is the first call; initialize.

+

+   When `getopt' returns -1, this is the index of the first of the

+   non-option elements that the caller should itself scan.

+

+   Otherwise, `optind' communicates from one call to the next

+   how much of ARGV has been scanned so far.  */

+

+/* 1003.2 says this must be 1 before any call.  */

+int optind = 1;

+

+/* Formerly, initialization of getopt depended on optind==0, which

+   causes problems with re-calling getopt as programs generally don't

+   know that. */

+

+int __getopt_initialized = 0;

+

+/* The next char to be scanned in the option-element

+   in which the last option character we returned was found.

+   This allows us to pick up the scan where we left off.

+

+   If this is zero, or a null string, it means resume the scan

+   by advancing to the next ARGV-element.  */

+

+static char *nextchar;

+

+/* Callers store zero here to inhibit the error message

+   for unrecognized options.  */

+

+int opterr = 1;

+

+/* Set to an option character which was unrecognized.

+   This must be initialized on some systems to avoid linking in the

+   system's own getopt implementation.  */

+

+int optopt = '?';

+

+/* Describe how to deal with options that follow non-option ARGV-elements.

+

+   If the caller did not specify anything,

+   the default is REQUIRE_ORDER if the environment variable

+   POSIXLY_CORRECT is defined, PERMUTE otherwise.

+

+   REQUIRE_ORDER means don't recognize them as options;

+   stop option processing when the first non-option is seen.

+   This is what Unix does.

+   This mode of operation is selected by either setting the environment

+   variable POSIXLY_CORRECT, or using `+' as the first character

+   of the list of option characters.

+

+   PERMUTE is the default.  We permute the contents of ARGV as we scan,

+   so that eventually all the non-options are at the end.  This allows options

+   to be given in any order, even with programs that were not written to

+   expect this.

+

+   RETURN_IN_ORDER is an option available to programs that were written

+   to expect options and other ARGV-elements in any order and that care about

+   the ordering of the two.  We describe each non-option ARGV-element

+   as if it were the argument of an option with character code 1.

+   Using `-' as the first character of the list of option characters

+   selects this mode of operation.

+

+   The special argument `--' forces an end of option-scanning regardless

+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only

+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */

+

+static enum

+{

+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER

+} ordering;

+

+/* Value of POSIXLY_CORRECT environment variable.  */

+static char *posixly_correct;

+

+#ifdef	__GNU_LIBRARY__

+/* We want to avoid inclusion of string.h with non-GNU libraries

+   because there are many ways it can cause trouble.

+   On some systems, it contains special magic macros that don't work

+   in GCC.  */

+#include <string.h>

+#define	my_index	pj_native_strchr

+#else

+

+static char *

+my_index (const char *str, int chr)

+{

+  while (*str)

+    {

+      if (*str == chr)

+	return (char *) str;

+      str++;

+    }

+  return 0;

+}

+

+/* If using GCC, we can safely declare strlen this way.

+   If not using GCC, it is ok not to declare it.  */

+#ifdef __GNUC__

+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.

+   That was relevant to code that was here before.  */

+#if !defined (__STDC__) || !__STDC__

+/* gcc with -traditional declares the built-in strlen to return int,

+   and has done so at least since version 2.4.5. -- rms.  */

+extern int strlen (const char *);

+#endif /* not __STDC__ */

+#endif /* __GNUC__ */

+

+#endif /* not __GNU_LIBRARY__ */

+

+/* Handle permutation of arguments.  */

+

+/* Describe the part of ARGV that contains non-options that have

+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;

+   `last_nonopt' is the index after the last of them.  */

+

+static int first_nonopt;

+static int last_nonopt;

+

+#ifdef _LIBC

+/* Bash 2.0 gives us an environment variable containing flags

+   indicating ARGV elements that should not be considered arguments.  */

+

+/* Defined in getopt_init.c  */

+extern char *__getopt_nonoption_flags;

+

+static int nonoption_flags_max_len;

+static int nonoption_flags_len;

+

+static int original_argc;

+static char *const *original_argv;

+

+extern pid_t __libc_pid;

+

+/* Make sure the environment variable bash 2.0 puts in the environment

+   is valid for the getopt call we must make sure that the ARGV passed

+   to getopt is that one passed to the process.  */

+static void

+__attribute__ ((unused))

+store_args_and_env (int argc, char *const *argv)

+{

+  /* XXX This is no good solution.  We should rather copy the args so

+     that we can compare them later.  But we must not use malloc(3).  */

+  original_argc = argc;

+  original_argv = argv;

+}

+text_set_element (__libc_subinit, store_args_and_env);

+

+# define SWAP_FLAGS(ch1, ch2) \

+  if (nonoption_flags_len > 0)						      \

+    {									      \

+      char __tmp = __getopt_nonoption_flags[ch1];			      \

+      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];	      \

+      __getopt_nonoption_flags[ch2] = __tmp;				      \

+    }

+#else	/* !_LIBC */

+# define SWAP_FLAGS(ch1, ch2)

+#endif	/* _LIBC */

+

+/* Exchange two adjacent subsequences of ARGV.

+   One subsequence is elements [first_nonopt,last_nonopt)

+   which contains all the non-options that have been skipped so far.

+   The other is elements [last_nonopt,optind), which contains all

+   the options processed since those non-options were skipped.

+

+   `first_nonopt' and `last_nonopt' are relocated so that they describe

+   the new indices of the non-options in ARGV after they are moved.  */

+

+#if defined (__STDC__) && __STDC__

+static void exchange (char **);

+#endif

+

+static void

+exchange (argv)

+     char **argv;

+{

+  int bottom = first_nonopt;

+  int middle = last_nonopt;

+  int top = optind;

+  char *tem;

+

+  /* Exchange the shorter segment with the far end of the longer segment.

+     That puts the shorter segment into the right place.

+     It leaves the longer segment in the right place overall,

+     but it consists of two parts that need to be swapped next.  */

+

+#ifdef _LIBC

+  /* First make sure the handling of the `__getopt_nonoption_flags'

+     string can work normally.  Our top argument must be in the range

+     of the string.  */

+  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)

+    {

+      /* We must extend the array.  The user plays games with us and

+	 presents new arguments.  */

+      char *new_str = malloc (top + 1);

+      if (new_str == NULL)

+	nonoption_flags_len = nonoption_flags_max_len = 0;

+      else

+	{

+	  memcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len);

+	  memset (&new_str[nonoption_flags_max_len], '\0',

+		  top + 1 - nonoption_flags_max_len);

+	  nonoption_flags_max_len = top + 1;

+	  __getopt_nonoption_flags = new_str;

+	}

+    }

+#endif

+

+  while (top > middle && middle > bottom)

+    {

+      if (top - middle > middle - bottom)

+	{

+	  /* Bottom segment is the short one.  */

+	  int len = middle - bottom;

+	  register int i;

+

+	  /* Swap it with the top part of the top segment.  */

+	  for (i = 0; i < len; i++)

+	    {

+	      tem = argv[bottom + i];

+	      argv[bottom + i] = argv[top - (middle - bottom) + i];

+	      argv[top - (middle - bottom) + i] = tem;

+	      SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);

+	    }

+	  /* Exclude the moved bottom segment from further swapping.  */

+	  top -= len;

+	}

+      else

+	{

+	  /* Top segment is the short one.  */

+	  int len = top - middle;

+	  register int i;

+

+	  /* Swap it with the bottom part of the bottom segment.  */

+	  for (i = 0; i < len; i++)

+	    {

+	      tem = argv[bottom + i];

+	      argv[bottom + i] = argv[middle + i];

+	      argv[middle + i] = tem;

+	      SWAP_FLAGS (bottom + i, middle + i);

+	    }

+	  /* Exclude the moved top segment from further swapping.  */

+	  bottom += len;

+	}

+    }

+

+  /* Update records for the slots the non-options now occupy.  */

+

+  first_nonopt += (optind - last_nonopt);

+  last_nonopt = optind;

+}

+

+/* Initialize the internal data when the first call is made.  */

+

+#if defined (__STDC__) && __STDC__

+static const char *_getopt_initialize (int, char *const *, const char *);

+#endif

+static const char *

+_getopt_initialize (argc, argv, optstring)

+     int argc;

+     char *const *argv;

+     const char *optstring;

+{

+  /* Start processing options with ARGV-element 1 (since ARGV-element 0

+     is the program name); the sequence of previously skipped

+     non-option ARGV-elements is empty.  */

+

+  first_nonopt = last_nonopt = optind;

+

+  nextchar = NULL;

+

+  posixly_correct = getenv ("POSIXLY_CORRECT");

+

+  /* Determine how to handle the ordering of options and nonoptions.  */

+

+  if (optstring[0] == '-')

+    {

+      ordering = RETURN_IN_ORDER;

+      ++optstring;

+    }

+  else if (optstring[0] == '+')

+    {

+      ordering = REQUIRE_ORDER;

+      ++optstring;

+    }

+  else if (posixly_correct != NULL)

+    ordering = REQUIRE_ORDER;

+  else

+    ordering = PERMUTE;

+

+#ifdef _LIBC

+  if (posixly_correct == NULL

+      && argc == original_argc && argv == original_argv)

+    {

+      if (nonoption_flags_max_len == 0)

+	{

+	  if (__getopt_nonoption_flags == NULL

+	      || __getopt_nonoption_flags[0] == '\0')

+	    nonoption_flags_max_len = -1;

+	  else

+	    {

+	      const char *orig_str = __getopt_nonoption_flags;

+	      int len = nonoption_flags_max_len = strlen (orig_str);

+	      if (nonoption_flags_max_len < argc)

+		nonoption_flags_max_len = argc;

+	      __getopt_nonoption_flags =

+		(char *) malloc (nonoption_flags_max_len);

+	      if (__getopt_nonoption_flags == NULL)

+		nonoption_flags_max_len = -1;

+	      else

+		{

+		  memcpy (__getopt_nonoption_flags, orig_str, len);

+		  memset (&__getopt_nonoption_flags[len], '\0',

+			  nonoption_flags_max_len - len);

+		}

+	    }

+	}

+      nonoption_flags_len = nonoption_flags_max_len;

+    }

+  else

+    nonoption_flags_len = 0;

+#endif

+

+  return optstring;

+}

+

+/* Scan elements of ARGV (whose length is ARGC) for option characters

+   given in OPTSTRING.

+

+   If an element of ARGV starts with '-', and is not exactly "-" or "--",

+   then it is an option element.  The characters of this element

+   (aside from the initial '-') are option characters.  If `getopt'

+   is called repeatedly, it returns successively each of the option characters

+   from each of the option elements.

+

+   If `getopt' finds another option character, it returns that character,

+   updating `optind' and `nextchar' so that the next call to `getopt' can

+   resume the scan with the following option character or ARGV-element.

+

+   If there are no more option characters, `getopt' returns -1.

+   Then `optind' is the index in ARGV of the first ARGV-element

+   that is not an option.  (The ARGV-elements have been permuted

+   so that those that are not options now come last.)

+

+   OPTSTRING is a string containing the legitimate option characters.

+   If an option character is seen that is not listed in OPTSTRING,

+   return '?' after printing an error message.  If you set `opterr' to

+   zero, the error message is suppressed but we still return '?'.

+

+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,

+   so the following text in the same ARGV-element, or the text of the following

+   ARGV-element, is returned in `optarg'.  Two colons mean an option that

+   wants an optional arg; if there is text in the current ARGV-element,

+   it is returned in `optarg', otherwise `optarg' is set to zero.

+

+   If OPTSTRING starts with `-' or `+', it requests different methods of

+   handling the non-option ARGV-elements.

+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.

+

+   Long-named options begin with `--' instead of `-'.

+   Their names may be abbreviated as long as the abbreviation is unique

+   or is an exact match for some defined option.  If they have an

+   argument, it follows the option name in the same ARGV-element, separated

+   from the option name by a `=', or else the in next ARGV-element.

+   When `getopt' finds a long-named option, it returns 0 if that option's

+   `flag' field is nonzero, the value of the option's `val' field

+   if the `flag' field is zero.

+

+   The elements of ARGV aren't really const, because we permute them.

+   But we pretend they're const in the prototype to be compatible

+   with other systems.

+

+   LONGOPTS is a vector of `struct option' terminated by an

+   element containing a name which is zero.

+

+   LONGIND returns the index in LONGOPT of the long-named option found.

+   It is only valid when a long-named option has been found by the most

+   recent call.

+

+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce

+   long-named options.  */

+

+int

+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)

+     int argc;

+     char *const *argv;

+     const char *optstring;

+     const struct option *longopts;

+     int *longind;

+     int long_only;

+{

+  optarg = NULL;

+

+  if (optind == 0 || !__getopt_initialized)

+    {

+      if (optind == 0)

+	optind = 1;	/* Don't scan ARGV[0], the program name.  */

+      optstring = _getopt_initialize (argc, argv, optstring);

+      __getopt_initialized = 1;

+    }

+

+  /* Test whether ARGV[optind] points to a non-option argument.

+     Either it does not have option syntax, or there is an environment flag

+     from the shell indicating it is not an option.  The later information

+     is only used when the used in the GNU libc.  */

+#ifdef _LIBC

+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'	      \

+		     || (optind < nonoption_flags_len			      \

+			 && __getopt_nonoption_flags[optind] == '1'))

+#else

+#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')

+#endif

+

+  if (nextchar == NULL || *nextchar == '\0')

+    {

+      /* Advance to the next ARGV-element.  */

+

+      /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been

+	 moved back by the user (who may also have changed the arguments).  */

+      if (last_nonopt > optind)

+	last_nonopt = optind;

+      if (first_nonopt > optind)

+	first_nonopt = optind;

+

+      if (ordering == PERMUTE)

+	{

+	  /* If we have just processed some options following some non-options,

+	     exchange them so that the options come first.  */

+

+	  if (first_nonopt != last_nonopt && last_nonopt != optind)

+	    exchange ((char **) argv);

+	  else if (last_nonopt != optind)

+	    first_nonopt = optind;

+

+	  /* Skip any additional non-options

+	     and extend the range of non-options previously skipped.  */

+

+	  while (optind < argc && NONOPTION_P)

+	    optind++;

+	  last_nonopt = optind;

+	}

+

+      /* The special ARGV-element `--' means premature end of options.

+	 Skip it like a null option,

+	 then exchange with previous non-options as if it were an option,

+	 then skip everything else like a non-option.  */

+

+      if (optind != argc && !pj_native_strcmp(argv[optind], "--"))

+	{

+	  optind++;

+

+	  if (first_nonopt != last_nonopt && last_nonopt != optind)

+	    exchange ((char **) argv);

+	  else if (first_nonopt == last_nonopt)

+	    first_nonopt = optind;

+	  last_nonopt = argc;

+

+	  optind = argc;

+	}

+

+      /* If we have done all the ARGV-elements, stop the scan

+	 and back over any non-options that we skipped and permuted.  */

+

+      if (optind == argc)

+	{

+	  /* Set the next-arg-index to point at the non-options

+	     that we previously skipped, so the caller will digest them.  */

+	  if (first_nonopt != last_nonopt)

+	    optind = first_nonopt;

+	  return -1;

+	}

+

+      /* If we have come to a non-option and did not permute it,

+	 either stop the scan or describe it to the caller and pass it by.  */

+

+      if (NONOPTION_P)

+	{

+	  if (ordering == REQUIRE_ORDER)

+	    return -1;

+	  optarg = argv[optind++];

+	  return 1;

+	}

+

+      /* We have found another option-ARGV-element.

+	 Skip the initial punctuation.  */

+

+      nextchar = (argv[optind] + 1

+		  + (longopts != NULL && argv[optind][1] == '-'));

+    }

+

+  /* Decode the current option-ARGV-element.  */

+

+  /* Check whether the ARGV-element is a long option.

+

+     If long_only and the ARGV-element has the form "-f", where f is

+     a valid short option, don't consider it an abbreviated form of

+     a long option that starts with f.  Otherwise there would be no

+     way to give the -f short option.

+

+     On the other hand, if there's a long option "fubar" and

+     the ARGV-element is "-fu", do consider that an abbreviation of

+     the long option, just like "--fu", and not "-f" with arg "u".

+

+     This distinction seems to be the most useful approach.  */

+

+  if (longopts != NULL

+      && (argv[optind][1] == '-'

+	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))

+    {

+      char *nameend;

+      const struct option *p;

+      const struct option *pfound = NULL;

+      int exact = 0;

+      int ambig = 0;

+      int indfound = -1;

+      int option_index;

+

+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)

+	/* Do nothing.  */ ;

+

+      /* Test all long options for either exact match

+	 or abbreviated matches.  */

+      for (p = longopts, option_index = 0; p->name; p++, option_index++)

+	if (!strncmp (p->name, nextchar, nameend - nextchar))

+	  {

+	    if ((unsigned int) (nameend - nextchar)

+		== (unsigned int) strlen (p->name))

+	      {

+		/* Exact match found.  */

+		pfound = p;

+		indfound = option_index;

+		exact = 1;

+		break;

+	      }

+	    else if (pfound == NULL)

+	      {

+		/* First nonexact match found.  */

+		pfound = p;

+		indfound = option_index;

+	      }

+	    else

+	      /* Second or later nonexact match found.  */

+	      ambig = 1;

+	  }

+

+      if (ambig && !exact)

+	{

+	  if (opterr)

+	    fprintf (stderr, _("%s: option `%s' is ambiguous\n"),

+		     argv[0], argv[optind]);

+	  nextchar += strlen (nextchar);

+	  optind++;

+	  optopt = 0;

+	  return '?';

+	}

+

+      if (pfound != NULL)

+	{

+	  option_index = indfound;

+	  optind++;

+	  if (*nameend)

+	    {

+	      /* Don't test has_arg with >, because some C compilers don't

+		 allow it to be used on enums.  */

+	      if (pfound->has_arg)

+		optarg = nameend + 1;

+	      else

+		{

+		  if (opterr)

+		   {

+		   if (argv[optind - 1][1] == '-')

+		    /* --option */

+		    fprintf (stderr,

+		     _("%s: option `--%s' doesn't allow an argument\n"),

+		     argv[0], pfound->name);

+		   else

+		      {	

+		    /* +option or -option */

+		    fprintf (stderr,

+		     _("%s: option `%c%s' doesn't allow an argument\n"),

+		     argv[0], argv[optind - 1][0], pfound->name);

+                      }

+		    }

+		  nextchar += strlen (nextchar);

+

+		  optopt = pfound->val;

+		  return '?';

+		}

+	    }

+	  else if (pfound->has_arg == 1)

+	    {

+	      if (optind < argc)

+		optarg = argv[optind++];

+	      else

+		{

+		  if (opterr)

+		    fprintf (stderr,

+			   _("%s: option `%s' requires an argument\n"),

+			   argv[0], argv[optind - 1]);

+		  nextchar += strlen (nextchar);

+		  optopt = pfound->val;

+		  return optstring[0] == ':' ? ':' : '?';

+		}

+	    }

+	  nextchar += strlen (nextchar);

+	  if (longind != NULL)

+	    *longind = option_index;

+	  if (pfound->flag)

+	    {

+	      *(pfound->flag) = pfound->val;

+	      return 0;

+	    }

+	  return pfound->val;

+	}

+

+      /* Can't find it as a long option.  If this is not getopt_long_only,

+	 or the option starts with '--' or is not a valid short

+	 option, then it's an error.

+	 Otherwise interpret it as a short option.  */

+      if (!long_only || argv[optind][1] == '-'

+	  || my_index (optstring, *nextchar) == NULL)

+	{

+	  if (opterr)

+	    {

+	      if (argv[optind][1] == '-')

+		/* --option */

+		fprintf (stderr, _("%s: unrecognized option `--%s'\n"),

+			 argv[0], nextchar);

+	      else

+		/* +option or -option */

+		fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),

+			 argv[0], argv[optind][0], nextchar);

+	    }

+	  nextchar = (char *) "";

+	  optind++;

+	  optopt = 0;

+	  return '?';

+	}

+    }

+

+  /* Look at and handle the next short option-character.  */

+

+  {

+    char c = *nextchar++;

+    char *temp = my_index (optstring, c);

+

+    /* Increment `optind' when we start to process its last character.  */

+    if (*nextchar == '\0')

+      ++optind;

+

+    if (temp == NULL || c == ':')

+      {

+	if (opterr)

+	  {

+	    if (posixly_correct)

+	      /* 1003.2 specifies the format of this message.  */

+	      fprintf (stderr, _("%s: illegal option -- %c\n"),

+		       argv[0], c);

+	    else

+	      fprintf (stderr, _("%s: invalid option -- %c\n"),

+		       argv[0], c);

+	  }

+	optopt = c;

+	return '?';

+      }

+    /* Convenience. Treat POSIX -W foo same as long option --foo */

+    if (temp[0] == 'W' && temp[1] == ';')

+      {

+	char *nameend;

+	const struct option *p;

+	const struct option *pfound = NULL;

+	int exact = 0;

+	int ambig = 0;

+	int indfound = 0;

+	int option_index;

+

+	/* This is an option that requires an argument.  */

+	if (*nextchar != '\0')

+	  {

+	    optarg = nextchar;

+	    /* If we end this ARGV-element by taking the rest as an arg,

+	       we must advance to the next element now.  */

+	    optind++;

+	  }

+	else if (optind == argc)

+	  {

+	    if (opterr)

+	      {

+		/* 1003.2 specifies the format of this message.  */

+		fprintf (stderr, _("%s: option requires an argument -- %c\n"),

+			 argv[0], c);

+	      }

+	    optopt = c;

+	    if (optstring[0] == ':')

+	      c = ':';

+	    else

+	      c = '?';

+	    return c;

+	  }

+	else

+	  /* We already incremented `optind' once;

+	     increment it again when taking next ARGV-elt as argument.  */

+	  optarg = argv[optind++];

+

+	/* optarg is now the argument, see if it's in the

+	   table of longopts.  */

+

+	for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)

+	  /* Do nothing.  */ ;

+

+	/* Test all long options for either exact match

+	   or abbreviated matches.  */

+	for (p = longopts, option_index = 0; p->name; p++, option_index++)

+	  if (!strncmp (p->name, nextchar, nameend - nextchar))

+	    {

+	      if ((unsigned int) (nameend - nextchar) == strlen (p->name))

+		{

+		  /* Exact match found.  */

+		  pfound = p;

+		  indfound = option_index;

+		  exact = 1;

+		  break;

+		}

+	      else if (pfound == NULL)

+		{

+		  /* First nonexact match found.  */

+		  pfound = p;

+		  indfound = option_index;

+		}

+	      else

+		/* Second or later nonexact match found.  */

+		ambig = 1;

+	    }

+	if (ambig && !exact)

+	  {

+	    if (opterr)

+	      fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),

+		       argv[0], argv[optind]);

+	    nextchar += strlen (nextchar);

+	    optind++;

+	    return '?';

+	  }

+	if (pfound != NULL)

+	  {

+	    option_index = indfound;

+	    if (*nameend)

+	      {

+		/* Don't test has_arg with >, because some C compilers don't

+		   allow it to be used on enums.  */

+		if (pfound->has_arg)

+		  optarg = nameend + 1;

+		else

+		  {

+		    if (opterr)

+		      fprintf (stderr, _("\

+%s: option `-W %s' doesn't allow an argument\n"),

+			       argv[0], pfound->name);

+

+		    nextchar += strlen (nextchar);

+		    return '?';

+		  }

+	      }

+	    else if (pfound->has_arg == 1)

+	      {

+		if (optind < argc)

+		  optarg = argv[optind++];

+		else

+		  {

+		    if (opterr)

+		      fprintf (stderr,

+			       _("%s: option `%s' requires an argument\n"),

+			       argv[0], argv[optind - 1]);

+		    nextchar += strlen (nextchar);

+		    return optstring[0] == ':' ? ':' : '?';

+		  }

+	      }

+	    nextchar += strlen (nextchar);

+	    if (longind != NULL)

+	      *longind = option_index;

+	    if (pfound->flag)

+	      {

+		*(pfound->flag) = pfound->val;

+		return 0;

+	      }

+	    return pfound->val;

+	  }

+	  nextchar = NULL;

+	  return 'W';	/* Let the application handle it.   */

+      }

+    if (temp[1] == ':')

+      {

+	if (temp[2] == ':')

+	  {

+	    /* This is an option that accepts an argument optionally.  */

+	    if (*nextchar != '\0')

+	      {

+		optarg = nextchar;

+		optind++;

+	      }

+	    else

+	      optarg = NULL;

+	    nextchar = NULL;

+	  }

+	else

+	  {

+	    /* This is an option that requires an argument.  */

+	    if (*nextchar != '\0')

+	      {

+		optarg = nextchar;

+		/* If we end this ARGV-element by taking the rest as an arg,

+		   we must advance to the next element now.  */

+		optind++;

+	      }

+	    else if (optind == argc)

+	      {

+		if (opterr)

+		  {

+		    /* 1003.2 specifies the format of this message.  */

+		    fprintf (stderr,

+			   _("%s: option requires an argument -- %c\n"),

+			   argv[0], c);

+		  }

+		optopt = c;

+		if (optstring[0] == ':')

+		  c = ':';

+		else

+		  c = '?';

+	      }

+	    else

+	      /* We already incremented `optind' once;

+		 increment it again when taking next ARGV-elt as argument.  */

+	      optarg = argv[optind++];

+	    nextchar = NULL;

+	  }

+      }

+    return c;

+  }

+}

+

+#endif	/* Not ELIDE_CODE.  */

+

+#endif

+

+#ifdef _MSC_VER

+# pragma warning(pop)

+#endif

+

diff --git a/pjsip/src/pjsua/getopt.h b/pjsip/src/pjsua/getopt.h
index b5c91d0..d9778f1 100644
--- a/pjsip/src/pjsua/getopt.h
+++ b/pjsip/src/pjsua/getopt.h
@@ -1,142 +1,164 @@
-/* $Id$
- *
- */
-/* Declarations for getopt.
-   Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#ifndef _GETOPT_H
-#define _GETOPT_H 1
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/* For communication from `getopt' to the caller.
-   When `getopt' finds an option that takes an argument,
-   the argument value is returned here.
-   Also, when `ordering' is RETURN_IN_ORDER,
-   each non-option ARGV-element is returned here.  */
-
-extern char *optarg;
-
-/* Index in ARGV of the next element to be scanned.
-   This is used for communication to and from the caller
-   and for communication between successive calls to `getopt'.
-
-   On entry to `getopt', zero means this is the first call; initialize.
-
-   When `getopt' returns -1, this is the index of the first of the
-   non-option elements that the caller should itself scan.
-
-   Otherwise, `optind' communicates from one call to the next
-   how much of ARGV has been scanned so far.  */
-
-extern int optind;
-
-/* Callers store zero here to inhibit the error message `getopt' prints
-   for unrecognized options.  */
-
-extern int opterr;
-
-/* Set to an option character which was unrecognized.  */
-
-extern int optopt;
-
-/* Describe the long-named options requested by the application.
-   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
-   of `struct option' terminated by an element containing a name which is
-   zero.
-
-   The field `has_arg' is:
-   no_argument		(or 0) if the option does not take an argument,
-   required_argument	(or 1) if the option requires an argument,
-   optional_argument 	(or 2) if the option takes an optional argument.
-
-   If the field `flag' is not NULL, it points to a variable that is set
-   to the value given in the field `val' when the option is found, but
-   left unchanged if the option is not found.
-
-   To have a long-named option do something other than set an `int' to
-   a compiled-in constant, such as set a value from `optarg', set the
-   option's `flag' field to zero and its `val' field to a nonzero
-   value (the equivalent single-letter option character, if there is
-   one).  For long options that have a zero `flag' field, `getopt'
-   returns the contents of the `val' field.  */
-
-struct option
-{
-  const char *name;
-  /* has_arg can't be an enum because some compilers complain about
-     type mismatches in all the code that assumes it is an int.  */
-  int has_arg;
-  int *flag;
-  int val;
-};
-
-/* Names for the values of the `has_arg' field of `struct option'.  */
-
-# define no_argument		0
-# define required_argument	1
-# define optional_argument	2
-
-
-/* Get definitions and prototypes for functions to process the
-   arguments in ARGV (ARGC of them, minus the program name) for
-   options given in OPTS.
-
-   Return the option character from OPTS just read.  Return -1 when
-   there are no more options.  For unrecognized options, or options
-   missing arguments, `optopt' is set to the option letter, and '?' is
-   returned.
-
-   The OPTS string is a list of characters which are recognized option
-   letters, optionally followed by colons, specifying that that letter
-   takes an argument, to be placed in `optarg'.
-
-   If a letter in OPTS is followed by two colons, its argument is
-   optional.  This behavior is specific to the GNU `getopt'.
-
-   The argument `--' causes premature termination of argument
-   scanning, explicitly telling `getopt' that there are no more
-   options.
-
-   If OPTS begins with `--', then non-option arguments are treated as
-   arguments to the option '\0'.  This behavior is specific to the GNU
-   `getopt'.  */
-
-int getopt (int argc, char *const *argv, const char *shortopts);
-
-int getopt_long (int argc, char *const *argv, const char *options,
-		        const struct option *longopts, int *longind);
-int getopt_long_only (int argc, char *const *argv,
-			     const char *shortopts,
-		             const struct option *longopts, int *longind);
-
-/* Internal only.  Users should not call this directly.  */
-int _getopt_internal (int argc, char *const *argv,
-			     const char *shortopts,
-		             const struct option *longopts, int *longind,
-			     int long_only);
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif /* getopt.h */
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+/* Declarations for getopt.

+   Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.

+   This file is part of the GNU C Library.

+

+   The GNU C Library is free software; you can redistribute it and/or

+   modify it under the terms of the GNU Library General Public License as

+   published by the Free Software Foundation; either version 2 of the

+   License, or (at your option) any later version.

+

+   The GNU C Library 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

+   Library General Public License for more details.

+

+   You should have received a copy of the GNU Library General Public

+   License along with the GNU C Library; see the file COPYING.LIB.  If not,

+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,

+   Boston, MA 02111-1307, USA.  */

+

+#ifndef _GETOPT_H

+#define _GETOPT_H 1

+

+#ifdef	__cplusplus

+extern "C" {

+#endif

+

+/* For communication from `getopt' to the caller.

+   When `getopt' finds an option that takes an argument,

+   the argument value is returned here.

+   Also, when `ordering' is RETURN_IN_ORDER,

+   each non-option ARGV-element is returned here.  */

+

+extern char *optarg;

+

+/* Index in ARGV of the next element to be scanned.

+   This is used for communication to and from the caller

+   and for communication between successive calls to `getopt'.

+

+   On entry to `getopt', zero means this is the first call; initialize.

+

+   When `getopt' returns -1, this is the index of the first of the

+   non-option elements that the caller should itself scan.

+

+   Otherwise, `optind' communicates from one call to the next

+   how much of ARGV has been scanned so far.  */

+

+extern int optind;

+

+/* Callers store zero here to inhibit the error message `getopt' prints

+   for unrecognized options.  */

+

+extern int opterr;

+

+/* Set to an option character which was unrecognized.  */

+

+extern int optopt;

+

+/* Describe the long-named options requested by the application.

+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector

+   of `struct option' terminated by an element containing a name which is

+   zero.

+

+   The field `has_arg' is:

+   no_argument		(or 0) if the option does not take an argument,

+   required_argument	(or 1) if the option requires an argument,

+   optional_argument 	(or 2) if the option takes an optional argument.

+

+   If the field `flag' is not NULL, it points to a variable that is set

+   to the value given in the field `val' when the option is found, but

+   left unchanged if the option is not found.

+

+   To have a long-named option do something other than set an `int' to

+   a compiled-in constant, such as set a value from `optarg', set the

+   option's `flag' field to zero and its `val' field to a nonzero

+   value (the equivalent single-letter option character, if there is

+   one).  For long options that have a zero `flag' field, `getopt'

+   returns the contents of the `val' field.  */

+

+struct option

+{

+  const char *name;

+  /* has_arg can't be an enum because some compilers complain about

+     type mismatches in all the code that assumes it is an int.  */

+  int has_arg;

+  int *flag;

+  int val;

+};

+

+/* Names for the values of the `has_arg' field of `struct option'.  */

+

+# define no_argument		0

+# define required_argument	1

+# define optional_argument	2

+

+

+/* Get definitions and prototypes for functions to process the

+   arguments in ARGV (ARGC of them, minus the program name) for

+   options given in OPTS.

+

+   Return the option character from OPTS just read.  Return -1 when

+   there are no more options.  For unrecognized options, or options

+   missing arguments, `optopt' is set to the option letter, and '?' is

+   returned.

+

+   The OPTS string is a list of characters which are recognized option

+   letters, optionally followed by colons, specifying that that letter

+   takes an argument, to be placed in `optarg'.

+

+   If a letter in OPTS is followed by two colons, its argument is

+   optional.  This behavior is specific to the GNU `getopt'.

+

+   The argument `--' causes premature termination of argument

+   scanning, explicitly telling `getopt' that there are no more

+   options.

+

+   If OPTS begins with `--', then non-option arguments are treated as

+   arguments to the option '\0'.  This behavior is specific to the GNU

+   `getopt'.  */

+

+int getopt (int argc, char *const *argv, const char *shortopts);

+

+int getopt_long (int argc, char *const *argv, const char *options,

+		        const struct option *longopts, int *longind);

+int getopt_long_only (int argc, char *const *argv,

+			     const char *shortopts,

+		             const struct option *longopts, int *longind);

+

+/* Internal only.  Users should not call this directly.  */

+int _getopt_internal (int argc, char *const *argv,

+			     const char *shortopts,

+		             const struct option *longopts, int *longind,

+			     int long_only);

+

+#ifdef	__cplusplus

+}

+#endif

+

+#endif /* getopt.h */

+

diff --git a/pjsip/src/pjsua/main.c b/pjsip/src/pjsua/main.c
index a8a0f49..35a89c8 100644
--- a/pjsip/src/pjsua/main.c
+++ b/pjsip/src/pjsua/main.c
@@ -1,1813 +1,1835 @@
-/* $Id$
- *
- */
-
-#include <pjlib.h>
-#include <pjsip_core.h>
-#include <pjsip_ua.h>
-#include <pjsip_simple.h>
-#include <pjmedia.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <pj/stun.h>
-
-#define START_PORT	    5060
-#define MAX_BUDDIES	    32
-#define THIS_FILE	    "main.c"
-#define MAX_PRESENTITY	    32
-#define PRESENCE_TIMEOUT    60
-
-/* By default we'll have one worker thread, except when threading 
- * is disabled. 
- */
-#if PJ_HAS_THREADS
-#  define WORKER_COUNT	1
-#else
-#  define WORKER_COUNT	0
-#endif
-
-/* Global variable. */
-static struct
-{
-    /* Control. */
-    pj_pool_factory *pf;
-    pjsip_endpoint  *endpt;
-    pj_pool_t	    *pool;
-    pjsip_user_agent *user_agent;
-    int		     worker_cnt;
-    int		     worker_quit_flag;
-
-    /* User info. */
-    char	     user_id[64];
-    pj_str_t	     local_uri;
-    pj_str_t	     contact;
-    pj_str_t	     real_contact;
-
-    /* Dialog. */
-    pjsip_dlg	    *cur_dlg;
-
-    /* Authentication. */
-    int		     cred_count;
-    pjsip_cred_info  cred_info[4];
-
-    /* Media stack. */
-    pj_bool_t	     null_audio;
-    pj_med_mgr_t    *mmgr;
-
-    /* Misc. */
-    int		     app_log_level;
-    char	    *log_filename;
-    FILE	    *log_file;
-
-    /* Proxy URLs */
-    pj_str_t	     proxy;
-    pj_str_t	     outbound_proxy;
-
-    /* UA auto options. */
-    int		     auto_answer;	/* -1 to disable. */
-    int		     auto_hangup;	/* -1 to disable */
-
-    /* Registration. */
-    pj_str_t	     registrar_uri;
-    pjsip_regc	    *regc;
-    pj_int32_t	     reg_timeout;
-    pj_timer_entry   regc_timer;
-
-    /* STUN */
-    pj_str_t	     stun_srv1;
-    int		     stun_port1;
-    pj_str_t	     stun_srv2;
-    int		     stun_port2;
-
-    /* UDP sockets and their public address. */
-    int		     sip_port;
-    pj_sock_t	     sip_sock;
-    pj_sockaddr_in   sip_sock_name;
-    pj_sock_t	     rtp_sock;
-    pj_sockaddr_in   rtp_sock_name;
-    pj_sock_t	     rtcp_sock;
-    pj_sockaddr_in   rtcp_sock_name;
-
-    /* SIMPLE */
-    pj_bool_t	     hide_status;
-    pj_bool_t	     offer_x_ms_msg;
-    int		     im_counter;
-    int		     buddy_cnt;
-    pj_str_t	     buddy[MAX_BUDDIES];
-    pj_bool_t	     buddy_status[MAX_BUDDIES];
-    pj_bool_t	     no_presence;
-    pjsip_presentity *buddy_pres[MAX_BUDDIES];
-
-    int		    pres_cnt;
-    pjsip_presentity *pres[MAX_PRESENTITY];
-
-} global;
-
-enum { AUTO_ANSWER, AUTO_HANGUP };
-
-/* This is the data that will be 'attached' on per dialog basis. */
-struct dialog_data
-{
-    /* Media session. */
-    pj_media_session_t *msession;
-
-    /* x-ms-chat session. */
-    pj_bool_t		x_ms_msg_session;
-
-    /* Cached SDP body, updated when media session changed. */
-    pjsip_msg_body *body;
-
-    /* Timer. */
-    pj_bool_t	     has_auto_timer;
-    pj_timer_entry   auto_timer;
-};
-
-/*
- * These are the callbacks to be registered to dialog to receive notifications
- * about various events in the dialog.
- */
-static void dlg_on_all_events	(pjsip_dlg *dlg, pjsip_dlg_event_e dlg_evt,
-				 pjsip_event *event );
-static void dlg_on_before_tx	(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-				 pjsip_tx_data *tdata, int retransmission);
-static void dlg_on_tx_msg	(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-				 pjsip_tx_data *tdata);
-static void dlg_on_rx_msg	(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-				 pjsip_rx_data *rdata);
-static void dlg_on_incoming	(pjsip_dlg *dlg, pjsip_transaction *tsx,
-				 pjsip_rx_data *rdata);
-static void dlg_on_calling	(pjsip_dlg *dlg, pjsip_transaction *tsx,
-				 pjsip_tx_data *tdata);
-static void dlg_on_provisional	(pjsip_dlg *dlg, pjsip_transaction *tsx,
-				 pjsip_event *event);
-static void dlg_on_connecting	(pjsip_dlg *dlg, pjsip_event *event);
-static void dlg_on_established	(pjsip_dlg *dlg, pjsip_event *event);
-static void dlg_on_disconnected	(pjsip_dlg *dlg, pjsip_event *event);
-static void dlg_on_terminated	(pjsip_dlg *dlg);
-static void dlg_on_mid_call_evt	(pjsip_dlg *dlg, pjsip_event *event);
-
-/* The callback structure that will be registered to UA layer. */
-struct pjsip_dlg_callback dlg_callback = {
-    &dlg_on_all_events,
-    &dlg_on_before_tx,
-    &dlg_on_tx_msg,
-    &dlg_on_rx_msg,
-    &dlg_on_incoming,
-    &dlg_on_calling,
-    &dlg_on_provisional,
-    &dlg_on_connecting,
-    &dlg_on_established,
-    &dlg_on_disconnected,
-    &dlg_on_terminated,
-    &dlg_on_mid_call_evt
-};
-
-
-/* 
- * Auxiliary things are put in misc.c, so that this main.c file is more 
- * readable. 
- */
-#include "misc.c"
-
-static void dlg_auto_timer_callback( pj_timer_heap_t *timer_heap,
-				     struct pj_timer_entry *entry)
-{
-    pjsip_dlg *dlg = entry->user_data;
-    struct dialog_data *dlg_data = dlg->user_data;
-    
-    PJ_UNUSED_ARG(timer_heap)
-
-    dlg_data->has_auto_timer = 0;
-
-    if (entry->id == AUTO_ANSWER) {
-	pjsip_tx_data *tdata = pjsip_dlg_answer(dlg, 200);
-	if (tdata) {
-	    struct dialog_data *dlg_data = global.cur_dlg->user_data;
-	    tdata->msg->body = dlg_data->body;
-	    pjsip_dlg_send_msg(dlg, tdata);
-	}
-    } else {
-	pjsip_tx_data *tdata = pjsip_dlg_disconnect(dlg, 500);
-	if (tdata) 
-	    pjsip_dlg_send_msg(dlg, tdata);
-    }
-}
-
-static void update_registration(pjsip_regc *regc, int renew)
-{
-    pjsip_tx_data *tdata;
-
-    PJ_LOG(3,(THIS_FILE, "Performing SIP registration..."));
-
-    if (renew) {
-	tdata = pjsip_regc_register(regc, 1);
-    } else {
-	tdata = pjsip_regc_unregister(regc);
-    }
-
-    pjsip_regc_send( regc, tdata );
-}
-
-static void regc_cb(struct pjsip_regc_cbparam *param)
-{
-    /*
-     * Print registration status.
-     */
-    if (param->code < 0 || param->code >= 300) {
-	PJ_LOG(2, (THIS_FILE, "SIP registration failed, status=%d (%s)", 
-		   param->code, pjsip_get_status_text(param->code)->ptr));
-	global.regc = NULL;
-
-    } else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
-	PJ_LOG(3, (THIS_FILE, "SIP registration success, status=%d (%s), "
-			      "will re-register in %d seconds", 
-			      param->code,
-			      pjsip_get_status_text(param->code)->ptr,
-			      param->expiration));
-
-    } else {
-	PJ_LOG(4, (THIS_FILE, "SIP registration updated status=%d", param->code));
-    }
-}
-
-static void pres_on_received_request(pjsip_presentity *pres, pjsip_rx_data *rdata,
-				     int *timeout)
-{
-    int state;
-    int i;
-    char url[PJSIP_MAX_URL_SIZE];
-    int urllen;
-
-    PJ_UNUSED_ARG(rdata)
-
-    if (*timeout > 0) {
-	state = PJSIP_EVENT_SUB_STATE_ACTIVE;
-	if (*timeout > 300)
-	    *timeout = 300;
-    } else {
-	state = PJSIP_EVENT_SUB_STATE_TERMINATED;
-    }
-
-    urllen = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->from->uri, url, sizeof(url)-1);
-    if (urllen < 1) {
-	pj_native_strcpy(url, "<unknown>");
-    } else {
-	url[urllen] = '\0';
-    }
-    PJ_LOG(3,(THIS_FILE, "Received presence request from %s, sub_state=%s", 
-			 url, 
-			 (state==PJSIP_EVENT_SUB_STATE_ACTIVE?"active":"terminated")));
-
-    for (i=0; i<global.pres_cnt; ++i)
-	if (global.pres[i] == pres)
-	    break;
-    if (i == global.pres_cnt)
-	global.pres[global.pres_cnt++] = pres;
-
-    pjsip_presence_set_credentials( pres, global.cred_count, global.cred_info );
-    pjsip_presence_notify(pres, state, !global.hide_status);
-
-}
-
-static void pres_on_received_refresh(pjsip_presentity *pres, pjsip_rx_data *rdata)
-{
-    pres_on_received_request(pres, rdata, &pres->sub->default_interval);
-}
-
-/* This is called by presence framework when we receives presence update
- * of a resource (buddy).
- */
-static void pres_on_received_update(pjsip_presentity *pres, pj_bool_t is_open)
-{
-    int buddy_index = (int)pres->user_data;
-
-    global.buddy_status[buddy_index] = is_open;
-    PJ_LOG(3,(THIS_FILE, "Presence update: %s is %s", 
-			 global.buddy[buddy_index].ptr,
-			 (is_open ? "Online" : "Offline")));
-}
-
-/* This is called when the subscription is terminated. */
-static void pres_on_terminated(pjsip_presentity *pres, const pj_str_t *reason)
-{
-    if (pres->sub->role == PJSIP_ROLE_UAC) {
-	int buddy_index = (int)pres->user_data;
-	PJ_LOG(3,(THIS_FILE, "Presence subscription for %s is terminated (reason=%.*s)", 
-			    global.buddy[buddy_index].ptr,
-			    reason->slen, reason->ptr));
-	global.buddy_pres[buddy_index] = NULL;
-	global.buddy_status[buddy_index] = 0;
-    } else {
-	int i;
-	PJ_LOG(3,(THIS_FILE, "Notifier terminated (reason=%.*s)", 
-			    reason->slen, reason->ptr));
-	pjsip_presence_notify(pres, PJSIP_EVENT_SUB_STATE_TERMINATED, 1);
-	for (i=0; i<global.pres_cnt; ++i) {
-	    if (global.pres[i] == pres) {
-		int j;
-		global.pres[i] = NULL;
-		for (j=i+1; j<global.pres_cnt; ++j)
-		    global.pres[j-1] = global.pres[j];
-		global.pres_cnt--;
-		break;
-	    }
-	}
-    }
-    pjsip_presence_destroy(pres);
-}
-
-
-/* Callback attached to SIP body to print the body to message buffer. */
-static int print_msg_body(pjsip_msg_body *msg_body, char *buf, pj_size_t size)
-{
-    pjsip_msg_body *body = msg_body;
-    return pjsdp_print ((pjsdp_session_desc*)body->data, buf, size);
-}
-
-/* When media session has changed, call this function to update the cached body
- * information in the dialog. 
- */
-static pjsip_msg_body *create_msg_body (pjsip_dlg *dlg, pj_bool_t is_ack_msg)
-{
-    struct dialog_data *dlg_data = dlg->user_data;
-    pjsdp_session_desc *sdp;
-
-    sdp = pj_media_session_create_sdp (dlg_data->msession, dlg->pool, is_ack_msg);
-    if (!sdp) {
-	dlg_data->body = NULL;
-	return NULL;
-    }
-
-    /* For outgoing INVITE, if we offer "x-ms-message" line, then add a new
-     * "m=" line in the SDP.
-     */
-    if (dlg_data->x_ms_msg_session >= 0 && 
-	dlg_data->x_ms_msg_session >= (int)sdp->media_count) 
-    {
-	pjsdp_media_desc *m = pj_pool_calloc(dlg->pool, 1, sizeof(*m));
-	sdp->media[sdp->media_count] = m;
-	dlg_data->x_ms_msg_session = sdp->media_count++;
-    }
-
-    /*
-     * For "x-ms-message" line, remove all attributes and connection line etc.
-     */
-    if (dlg_data->x_ms_msg_session >= 0) {
-	pjsdp_media_desc *m = sdp->media[dlg_data->x_ms_msg_session];
-	if (m) {
-	    m->desc.media = pj_str("x-ms-message");
-	    m->desc.port = 5060;
-	    m->desc.transport = pj_str("sip");
-	    m->desc.fmt_count = 1;
-	    m->desc.fmt[0] = pj_str("null");
-	    m->attr_count = 0;
-	    m->conn = NULL;
-	}
-    }
-
-    dlg_data->body = pj_pool_calloc(dlg->pool, 1, sizeof(*dlg_data->body));
-    dlg_data->body->content_type.type = pj_str("application");
-    dlg_data->body->content_type.subtype = pj_str("sdp");
-    dlg_data->body->len = 0;	/* ignored */
-    dlg_data->body->print_body = &print_msg_body;
-
-    dlg_data->body->data = sdp;
-    return dlg_data->body;
-}
-
-/* This callback will be called on every occurence of events in dialogs */
-static void dlg_on_all_events(pjsip_dlg *dlg, pjsip_dlg_event_e dlg_evt,
-			      pjsip_event *event )
-{
-    PJ_UNUSED_ARG(dlg_evt)
-    PJ_UNUSED_ARG(event)
-
-    PJ_LOG(4, (THIS_FILE, "dlg_on_all_events %p", dlg));
-}
-
-/* This callback is called before each outgoing msg is sent (including 
- * retransmission). Application can override this notification if it wants
- * to modify the message before transmission or if it wants to do something
- * else for each transmission.
- */
-static void dlg_on_before_tx(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-			     pjsip_tx_data *tdata, int ret_cnt)
-{
-    PJ_UNUSED_ARG(tsx)
-    PJ_UNUSED_ARG(tdata)
-
-    if (ret_cnt > 0) {
-	PJ_LOG(3, (THIS_FILE, "Dialog %s: retransmitting message (cnt=%d)", 
-			      dlg->obj_name, ret_cnt));
-    }
-}
-
-/* This callback is called after a message is sent. */
-static void dlg_on_tx_msg(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-			  pjsip_tx_data *tdata)
-{
-    PJ_UNUSED_ARG(tsx)
-    PJ_UNUSED_ARG(tdata)
-
-    PJ_LOG(4, (THIS_FILE, "dlg_on_tx_msg %p", dlg));
-}
-
-/* This callback is called on receipt of incoming message. */
-static void dlg_on_rx_msg(pjsip_dlg *dlg, pjsip_transaction *tsx, 
-			  pjsip_rx_data *rdata)
-{
-    PJ_UNUSED_ARG(tsx)
-    PJ_UNUSED_ARG(rdata)
-    PJ_LOG(4, (THIS_FILE, "dlg_on_tx_msg %p", dlg));
-}
-
-/* This callback is called after dialog has sent INVITE */
-static void dlg_on_calling(pjsip_dlg *dlg, pjsip_transaction *tsx,
-			   pjsip_tx_data *tdata)
-{
-    PJ_UNUSED_ARG(tsx)
-    PJ_UNUSED_ARG(tdata)
-
-    pj_assert(tdata->msg->type == PJSIP_REQUEST_MSG &&
-	      tdata->msg->line.req.method.id == PJSIP_INVITE_METHOD &&
-	      tsx->method.id == PJSIP_INVITE_METHOD);
-
-    PJ_LOG(3, (THIS_FILE, "Dialog %s: start calling...", dlg->obj_name));
-}
-
-static void create_session_from_sdp( pjsip_dlg *dlg, pjsdp_session_desc *sdp)
-{
-    struct dialog_data *dlg_data = dlg->user_data;
-    pj_bool_t sdp_x_ms_msg_index = -1;
-    int i;
-    int mcnt;
-    const pj_media_stream_info *mi[PJSDP_MAX_MEDIA];
-    int has_active;
-    pj_media_sock_info sock_info;
-
-    /* Find "m=x-ms-message" line in the SDP. */
-    for (i=0; i<(int)sdp->media_count; ++i) {
-	if (pj_stricmp2(&sdp->media[i]->desc.media, "x-ms-message")==0)
-	    sdp_x_ms_msg_index = i;
-    }
-
-    /*
-     * Create media session.
-     */
-    pj_memset(&sock_info, 0, sizeof(sock_info));
-    sock_info.rtp_sock = global.rtp_sock;
-    sock_info.rtcp_sock = global.rtcp_sock;
-    pj_memcpy(&sock_info.rtp_addr_name, &global.rtp_sock_name, sizeof(pj_sockaddr_in));
-
-    dlg_data->msession = pj_media_session_create_from_sdp (global.mmgr, sdp, &sock_info);
-
-    /* A session will always be created, unless there is memory
-     * alloc problem.
-     */
-    pj_assert(dlg_data->msession);
-
-    /* See if we can take the offer by checking that we have at least
-     * one media stream active.
-     */
-    mcnt = pj_media_session_enum_streams(dlg_data->msession, PJSDP_MAX_MEDIA, mi);
-    for (i=0, has_active=0; i<mcnt; ++i) {
-	if (mi[i]->fmt_cnt>0 && mi[i]->dir!=PJ_MEDIA_DIR_NONE) {
-	    has_active = 1;
-	    break;
-	}
-    }
-
-    if (!has_active && sdp_x_ms_msg_index==-1) {
-	pjsip_tx_data *tdata;
-
-	/* Unable to accept remote's SDP. 
-	 * Answer with 488 (Not Acceptable Here)
-	 */
-	/* Create 488 response. */
-	tdata = pjsip_dlg_answer(dlg, PJSIP_SC_NOT_ACCEPTABLE_HERE);
-
-	/* Send response. */
-	if (tdata)
-	    pjsip_dlg_send_msg(dlg, tdata);
-	return;
-    }
-
-    dlg_data->x_ms_msg_session = sdp_x_ms_msg_index;
-
-    /* Create msg body to be used later in 2xx/response */
-    create_msg_body(dlg, 0);
-
-}
-
-/* This callback is called after an INVITE is received. */
-static void dlg_on_incoming(pjsip_dlg *dlg, pjsip_transaction *tsx,
-			    pjsip_rx_data *rdata)
-{
-    struct dialog_data *dlg_data;
-    pjsip_msg *msg;
-    pjsip_tx_data *tdata;
-    char buf[128];
-    int len;
-
-    PJ_UNUSED_ARG(tsx)
-
-    pj_assert(rdata->msg->type == PJSIP_REQUEST_MSG &&
-	      rdata->msg->line.req.method.id == PJSIP_INVITE_METHOD &&
-	      tsx->method.id == PJSIP_INVITE_METHOD);
-
-    /*
-     * Notify user!
-     */
-    PJ_LOG(3, (THIS_FILE, ""));
-    PJ_LOG(3, (THIS_FILE, "INCOMING CALL ON DIALOG %s!!", dlg->obj_name));
-    PJ_LOG(3, (THIS_FILE, ""));
-    len = pjsip_uri_print( PJSIP_URI_IN_FROMTO_HDR, 
-			   (pjsip_name_addr*)dlg->remote.info->uri, 
-			   buf, sizeof(buf)-1);
-    if (len > 0) {
-	buf[len] = '\0';
-	PJ_LOG(3,(THIS_FILE, "From:\t%s", buf));
-    }
-    len = pjsip_uri_print( PJSIP_URI_IN_FROMTO_HDR, 
-			   (pjsip_name_addr*)dlg->local.info->uri, 
-			   buf, sizeof(buf)-1);
-    if (len > 0) {
-	buf[len] = '\0';
-	PJ_LOG(3,(THIS_FILE, "To:\t%s", buf));
-    }
-    PJ_LOG(3, (THIS_FILE, "Press 'a' to answer, or 'h' to hangup!!", dlg->obj_name));
-    PJ_LOG(3, (THIS_FILE, ""));
-
-    /*
-     * Process incoming dialog.
-     */
-
-    dlg_data = pj_pool_calloc(dlg->pool, 1, sizeof(struct dialog_data));
-    dlg->user_data = dlg_data;
-
-    /* Update contact. */
-    pjsip_dlg_set_contact(dlg, &global.contact);
-
-    /* Initialize credentials. */
-    pjsip_dlg_set_credentials(dlg, global.cred_count, global.cred_info);
-
-    /* Create media session if the request has "application/sdp" body. */
-    msg = rdata->msg;
-    if (msg->body && 
-	pj_stricmp2(&msg->body->content_type.type, "application")==0 &&
-	pj_stricmp2(&msg->body->content_type.subtype, "sdp")==0)
-    {
-	pjsdp_session_desc *sdp;
-
-	/* Parse SDP body, and instantiate media session based on remote's SDP.
-	 * Then create our SDP body from the session.
-	 */
-	sdp = pjsdp_parse (msg->body->data, msg->body->len, rdata->pool);
-	if (!sdp)
-	    goto send_answer;
-
-	create_session_from_sdp(dlg, sdp);
-
-    } else if (msg->body) {
-	/* The request has a message body other than "application/sdp" */
-	pjsip_accept_hdr *accept;
-
-	/* Create response. */
-	tdata = pjsip_dlg_answer(dlg, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);
-
-	/* Add "Accept" header. */
-	accept = pjsip_accept_hdr_create(tdata->pool);
-	accept->values[0] = pj_str("application/sdp");
-	accept->count = 1;
-	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)accept);
-
-	/* Send response. */
-	pjsip_dlg_send_msg(dlg, tdata);
-	return;
-
-    } else {
-	/* The request has no message body. We can take this request, but
-	 * no media session will be activated.
-	 */
-	/* Nothing to do here. */
-    }
-
-send_answer:
-    /* Immediately answer with 100 (or 180? */
-    tdata = pjsip_dlg_answer( dlg, PJSIP_SC_RINGING );
-    pjsip_dlg_send_msg(dlg, tdata);
-
-    /* Set current dialog to this dialog if we don't currently have
-     * current dialog.
-     */
-    if (global.cur_dlg == NULL) {
-	global.cur_dlg = dlg;
-    }
-
-    /* Auto-answer if option is specified. */
-    if (global.auto_answer >= 0) {
-	pj_time_val delay = { 0, 0};
-	struct dialog_data *dlg_data = dlg->user_data;
-
-	PJ_LOG(4, (THIS_FILE, "Scheduling auto-answer in %d seconds", 
-			      global.auto_answer));
-
-	delay.sec = global.auto_answer;
-	dlg_data->auto_timer.user_data = dlg;
-	dlg_data->auto_timer.id = AUTO_ANSWER;
-	dlg_data->auto_timer.cb = &dlg_auto_timer_callback;
-	dlg_data->has_auto_timer = 1;
-	pjsip_endpt_schedule_timer(dlg->ua->endpt, &dlg_data->auto_timer, &delay);
-    }
-}
-
-/* This callback is called when dialog has sent/received a provisional response
- * to INVITE.
- */
-static void dlg_on_provisional(pjsip_dlg *dlg, pjsip_transaction *tsx,
-			       pjsip_event *event)
-{
-    const char *action;
-
-    pj_assert((event->src_type == PJSIP_EVENT_TX_MSG &&
-	       event->src.tdata->msg->type == PJSIP_RESPONSE_MSG &&
-	       event->src.tdata->msg->line.status.code/100 == 1 &&
-	       tsx->method.id == PJSIP_INVITE_METHOD) 
-	       ||
-	       (event->src_type == PJSIP_EVENT_RX_MSG &&
-	       event->src.rdata->msg->type == PJSIP_RESPONSE_MSG &&
-	       event->src.rdata->msg->line.status.code/100 == 1 &&
-	       tsx->method.id == PJSIP_INVITE_METHOD));
-
-    if (event->src_type == PJSIP_EVENT_TX_MSG)
-	action = "Sending";
-    else
-	action = "Received";
-
-    PJ_LOG(3, (THIS_FILE, "Dialog %s: %s %d (%s)", 
-			  dlg->obj_name, action, tsx->status_code,
-			  pjsip_get_status_text(tsx->status_code)->ptr));
-}
-
-/* This callback is called when 200 response to INVITE is sent/received. */
-static void dlg_on_connecting(pjsip_dlg *dlg, pjsip_event *event)
-{
-    struct dialog_data *dlg_data = dlg->user_data;
-    const char *action;
-
-    pj_assert((event->src_type == PJSIP_EVENT_TX_MSG &&
-	       event->src.tdata->msg->type == PJSIP_RESPONSE_MSG &&
-	       event->src.tdata->msg->line.status.code/100 == 2)
-	       ||
-	       (event->src_type == PJSIP_EVENT_RX_MSG &&
-	       event->src.rdata->msg->type == PJSIP_RESPONSE_MSG &&
-	       event->src.rdata->msg->line.status.code/100 == 2));
-
-    if (event->src_type == PJSIP_EVENT_RX_MSG)
-	action = "Received";
-    else
-	action = "Sending";
-
-    PJ_LOG(3, (THIS_FILE, "Dialog %s: %s 200 (OK)", dlg->obj_name, action));
-
-    if (event->src_type == PJSIP_EVENT_RX_MSG) {
-	/* On receipt of 2xx response, negotiate our media capability
-	 * and start media.
-	 */
-	pjsip_msg *msg = event->src.rdata->msg;
-	pjsip_msg_body *body;
-	pjsdp_session_desc *sdp;
-
-	/* Get SDP from message. */
-
-	/* Ignore if no SDP body is present. */
-	body = msg->body;
-	if (!body) {
-	    PJ_LOG(3, (THIS_FILE, "Dialog %s: the 200/OK response has no body!",
-				  dlg->obj_name));
-	    return;
-	}
-
-	if (pj_stricmp2(&body->content_type.type, "application") != 0 &&
-	    pj_stricmp2(&body->content_type.subtype, "sdp") != 0) 
-	{
-	    PJ_LOG(3, (THIS_FILE, "Dialog %s: the 200/OK response has no SDP body!",
-				   dlg->obj_name));
-	    return;
-	}
-
-	/* Got what seems to be a SDP content. Parse it. */
-	sdp = pjsdp_parse (body->data, body->len, event->src.rdata->pool);
-	if (!sdp) {
-	    PJ_LOG(3, (THIS_FILE, "Dialog %s: SDP syntax error!",
-				  dlg->obj_name));
-	    return;
-	}
-
-	/* Negotiate media session with remote's media capability. */
-	if (pj_media_session_update (dlg_data->msession, sdp) != 0) {
-	    PJ_LOG(3, (THIS_FILE, "Dialog %s: media session update error!",
-				  dlg->obj_name));
-	    return;
-	}
-
-	/* Update the saved SDP body because media session has changed. 
-	 * Also set ack flag to '1', because we only want to send one format/
-	 * codec for each media streams.
-	 */
-	create_msg_body(dlg, 1);
-
-	/* Activate media. */
-	pj_media_session_activate (dlg_data->msession);
-
-    } else {
-	pjsip_msg *msg = event->src.tdata->msg;
-
-	if (msg->body) {
-	    /* On transmission of 2xx response, start media session. */
-	    pj_media_session_activate (dlg_data->msession);
-	}
-    }
-
-}
-
-/* This callback is called when ACK to initial INVITE is sent/received. */
-static void dlg_on_established(pjsip_dlg *dlg, pjsip_event *event)
-{
-    const char *action;
-
-    pj_assert((event->src_type == PJSIP_EVENT_TX_MSG &&
-	       event->src.tdata->msg->type == PJSIP_REQUEST_MSG &&
-	       event->src.tdata->msg->line.req.method.id == PJSIP_ACK_METHOD)
-	       ||
-	       (event->src_type == PJSIP_EVENT_RX_MSG &&
-	       event->src.rdata->msg->type == PJSIP_REQUEST_MSG &&
-	       event->src.rdata->msg->line.req.method.id == PJSIP_ACK_METHOD));
-
-    if (event->src_type == PJSIP_EVENT_RX_MSG)
-	action = "Received";
-    else
-	action = "Sending";
-
-    PJ_LOG(3, (THIS_FILE, "Dialog %s: %s ACK, dialog is ESTABLISHED", 
-			  dlg->obj_name, action));
-
-    /* Attach SDP body for outgoing ACK. */
-    if (event->src_type == PJSIP_EVENT_TX_MSG &&
-	event->src.tdata->msg->line.req.method.id == PJSIP_ACK_METHOD)
-    {
-	struct dialog_data *dlg_data = dlg->user_data;
-	event->src.tdata->msg->body = dlg_data->body;
-    }
-
-    /* Auto-hangup if option is specified. */
-    if (global.auto_hangup >= 0) {
-	pj_time_val delay = { 0, 0};
-	struct dialog_data *dlg_data = dlg->user_data;
-
-	PJ_LOG(4, (THIS_FILE, "Scheduling auto-hangup in %d seconds", 
-			      global.auto_hangup));
-
-	delay.sec = global.auto_hangup;
-	dlg_data->auto_timer.user_data = dlg;
-	dlg_data->auto_timer.id = AUTO_HANGUP;
-	dlg_data->auto_timer.cb = &dlg_auto_timer_callback;
-	dlg_data->has_auto_timer = 1;
-	pjsip_endpt_schedule_timer(dlg->ua->endpt, &dlg_data->auto_timer, &delay);
-    }
-}
-
-
-/* This callback is called when dialog is disconnected (because of final
- * response, BYE, or timer).
- */
-static void dlg_on_disconnected(pjsip_dlg *dlg, pjsip_event *event)
-{
-    struct dialog_data *dlg_data = dlg->user_data;
-    int status_code;
-    const pj_str_t *reason;
-    
-    PJ_UNUSED_ARG(event)
-
-    /* Cancel auto-answer/auto-hangup timer. */
-    if (dlg_data->has_auto_timer) {
-	pjsip_endpt_cancel_timer(dlg->ua->endpt, &dlg_data->auto_timer);
-	dlg_data->has_auto_timer = 0;
-    }
-
-    if (dlg->invite_tsx)
-	status_code = dlg->invite_tsx->status_code;
-    else
-	status_code = 200;
-
-    if (event->obj.tsx->method.id == PJSIP_INVITE_METHOD) {
-	if (event->src_type == PJSIP_EVENT_RX_MSG)
-	    reason = &event->src.rdata->msg->line.status.reason;
-	else if (event->src_type == PJSIP_EVENT_TX_MSG)
-	    reason = &event->src.tdata->msg->line.status.reason;
-	else
-	    reason = pjsip_get_status_text(event->obj.tsx->status_code);
-    } else {
-	reason = &event->obj.tsx->method.name;
-    }
-
-    PJ_LOG(3, (THIS_FILE, "Dialog %s: DISCONNECTED! Reason=%d (%.*s)", 
-			  dlg->obj_name, status_code, 
-			  reason->slen, reason->ptr));
-
-    if (dlg_data->msession) {
-	pj_media_session_destroy (dlg_data->msession);
-	dlg_data->msession = NULL;
-    }
-}
-
-/* This callback is called when dialog is about to be destroyed. */
-static void dlg_on_terminated(pjsip_dlg *dlg)
-{
-    PJ_LOG(3, (THIS_FILE, "Dialog %s: terminated!", dlg->obj_name));
-
-    /* If current dialog is equal to this dialog, update it. */
-    if (global.cur_dlg == dlg) {
-	global.cur_dlg = global.cur_dlg->next;
-	if (global.cur_dlg == (void*)&global.user_agent->dlg_list) {
-	    global.cur_dlg = NULL;
-	}
-    }
-}
-
-/* This callback is called for any requests when dialog is established. */
-static void dlg_on_mid_call_evt	(pjsip_dlg *dlg, pjsip_event *event)
-{
-    pjsip_transaction *tsx = event->obj.tsx;
-
-    if (event->src_type == PJSIP_EVENT_RX_MSG &&
-	event->src.rdata->msg->type == PJSIP_REQUEST_MSG) 
-    {
-	if (event->src.rdata->cseq->method.id == PJSIP_INVITE_METHOD) {
-	    /* Re-invitation. */
-	    pjsip_tx_data *tdata;
-
-	    PJ_LOG(3,(THIS_FILE, "Dialog %s: accepting re-invitation (dummy)",
-				 dlg->obj_name));
-	    tdata = pjsip_dlg_answer(dlg, 200);
-	    if (tdata) {
-		struct dialog_data *dlg_data = dlg->user_data;
-		tdata->msg->body = dlg_data->body;
-		pjsip_dlg_send_msg(dlg, tdata);
-	    }
-	} else {
-	    /* Don't worry, endpoint will answer with 500 or whetever. */
-	}
-
-    } else if (tsx->status_code/100 == 2) {
-	PJ_LOG(3,(THIS_FILE, "Dialog %s: outgoing %.*s success: %d (%s)",
-		  dlg->obj_name, 
-		  tsx->method.name.slen, tsx->method.name.ptr,
-		  tsx->status_code, 
-		  pjsip_get_status_text(tsx->status_code)->ptr));
-
-
-    } else if (tsx->status_code >= 300) {
-	pj_bool_t report_failure = PJ_TRUE;
-
-	/* Check for authentication failures. */
-	if (tsx->status_code==401 || tsx->status_code==407) {
-	    pjsip_tx_data *tdata;
-	    tdata = pjsip_auth_reinit_req( global.endpt,
-					   dlg->pool, &dlg->auth_sess,
-					   dlg->cred_count, dlg->cred_info,
-					   tsx->last_tx, event->src.rdata );
-	    if (tdata) {
-		int rc;
-		rc = pjsip_dlg_send_msg( dlg, tdata);
-		report_failure = (rc != 0);
-	    }
-	}
-	if (report_failure) {
-	    const pj_str_t *reason;
-	    if (event->src_type == PJSIP_EVENT_RX_MSG) {
-		reason = &event->src.rdata->msg->line.status.reason;
-	    } else {
-		reason = pjsip_get_status_text(tsx->status_code);
-	    }
-	    PJ_LOG(2,(THIS_FILE, "Dialog %s: outgoing request failed: %d (%.*s)",
-		      dlg->obj_name, tsx->status_code, 
-		      reason->slen, reason->ptr));
-	}
-    }
-}
-
-/* Initialize sockets and optionally get the public address via STUN. */
-static pj_status_t init_sockets()
-{
-    enum { 
-	RTP_START_PORT = 4000,
-	RTP_RANDOM_START = 2,
-	RTP_RETRY = 10 
-    };
-    enum {
-	SIP_SOCK,
-	RTP_SOCK,
-	RTCP_SOCK,
-    };
-    int i;
-    int rtp_port;
-    pj_sock_t sock[3];
-    pj_sockaddr_in mapped_addr[3];
-
-    for (i=0; i<3; ++i)
-	sock[i] = PJ_INVALID_SOCKET;
-
-    /* Create and bind SIP UDP socket. */
-    sock[SIP_SOCK] = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, 0);
-    if (sock[SIP_SOCK] == PJ_INVALID_SOCKET) {
-	PJ_LOG(2,(THIS_FILE, "Unable to create socket"));
-	goto on_error;
-    }
-    if (pj_sock_bind_in(sock[SIP_SOCK], 0, (pj_uint16_t)global.sip_port) != 0) {
-	PJ_LOG(2,(THIS_FILE, "Unable to bind to SIP port"));
-	goto on_error;
-    }
-
-    /* Initialize start of RTP port to try. */
-    rtp_port = RTP_START_PORT + (pj_rand() % RTP_RANDOM_START) / 2;
-
-    /* Loop retry to bind RTP and RTCP sockets. */
-    for (i=0; i<RTP_RETRY; ++i, rtp_port += 2) {
-
-	/* Create and bind RTP socket. */
-	sock[RTP_SOCK] = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, 0);
-	if (sock[RTP_SOCK] == PJ_INVALID_SOCKET)
-	    goto on_error;
-	if (pj_sock_bind_in(sock[RTP_SOCK], 0, (pj_uint16_t)rtp_port) != 0) {
-	    pj_sock_close(sock[RTP_SOCK]); sock[RTP_SOCK] = PJ_INVALID_SOCKET;
-	    continue;
-	}
-
-	/* Create and bind RTCP socket. */
-	sock[RTCP_SOCK] = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, 0);
-	if (sock[RTCP_SOCK] == PJ_INVALID_SOCKET)
-	    goto on_error;
-	if (pj_sock_bind_in(sock[RTCP_SOCK], 0, (pj_uint16_t)(rtp_port+1)) != 0) {
-	    pj_sock_close(sock[RTP_SOCK]); sock[RTP_SOCK] = PJ_INVALID_SOCKET;
-	    pj_sock_close(sock[RTCP_SOCK]); sock[RTCP_SOCK] = PJ_INVALID_SOCKET;
-	    continue;
-	}
-
-	/*
-	 * If we're configured to use STUN, then find out the mapped address,
-	 * and make sure that the mapped RTCP port is adjacent with the RTP.
-	 */
-	if (global.stun_port1 == 0) {
-	    pj_str_t hostname;
-	    pj_sockaddr_in addr;
-
-	    /* Get local IP address. */
-	    char hostname_buf[PJ_MAX_HOSTNAME];
-	    if (gethostname(hostname_buf, sizeof(hostname_buf)))
-		goto on_error;
-	    hostname = pj_str(hostname_buf);
-
-	    pj_memset( &addr, 0, sizeof(addr));
-	    addr.sin_family = PJ_AF_INET;
-	    if (pj_sockaddr_set_str_addr( &addr, &hostname) != PJ_SUCCESS)
-		goto on_error;
-
-	    for (i=0; i<3; ++i)
-		pj_memcpy(&mapped_addr[i], &addr, sizeof(addr));
-
-	    mapped_addr[SIP_SOCK].sin_port = pj_htons((pj_uint16_t)global.sip_port);
-	    mapped_addr[RTP_SOCK].sin_port = pj_htons((pj_uint16_t)rtp_port);
-	    mapped_addr[RTCP_SOCK].sin_port = pj_htons((pj_uint16_t)(rtp_port+1));
-	    break;
-	} else {
-	    pj_status_t rc;
-	    rc = pj_stun_get_mapped_addr( global.pf, 3, sock,
-					  &global.stun_srv1, global.stun_port1,
-					  &global.stun_srv2, global.stun_port2,
-					  mapped_addr);
-	    if (rc != 0) {
-		PJ_LOG(3,(THIS_FILE, "Error: %s", pj_stun_get_err_msg(rc)));
-		goto on_error;
-	    }
-
-	    if (pj_ntohs(mapped_addr[2].sin_port) == pj_ntohs(mapped_addr[1].sin_port)+1)
-		break;
-
-	    pj_sock_close(sock[RTP_SOCK]); sock[RTP_SOCK] = PJ_INVALID_SOCKET;
-	    pj_sock_close(sock[RTCP_SOCK]); sock[RTCP_SOCK] = PJ_INVALID_SOCKET;
-	}
-    }
-
-    if (sock[RTP_SOCK] == PJ_INVALID_SOCKET) {
-	PJ_LOG(2,(THIS_FILE, "Unable to find appropriate RTP/RTCP ports combination"));
-	goto on_error;
-    }
-
-    global.sip_sock = sock[SIP_SOCK];
-    pj_memcpy(&global.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in));
-    global.rtp_sock = sock[RTP_SOCK];
-    pj_memcpy(&global.rtp_sock_name, &mapped_addr[RTP_SOCK], sizeof(pj_sockaddr_in));
-    global.rtcp_sock = sock[RTCP_SOCK];
-    pj_memcpy(&global.rtcp_sock_name, &mapped_addr[RTCP_SOCK], sizeof(pj_sockaddr_in));
-
-    PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
-	      pj_inet_ntoa(global.sip_sock_name.sin_addr), 
-	      pj_ntohs(global.sip_sock_name.sin_port)));
-    PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d",
-	      pj_inet_ntoa(global.rtp_sock_name.sin_addr), 
-	      pj_ntohs(global.rtp_sock_name.sin_port)));
-    PJ_LOG(4,(THIS_FILE, "RTCP UDP socket reachable at %s:%d",
-	      pj_inet_ntoa(global.rtcp_sock_name.sin_addr), 
-	      pj_ntohs(global.rtcp_sock_name.sin_port)));
-    return 0;
-
-on_error:
-    for (i=0; i<3; ++i) {
-	if (sock[i] != PJ_INVALID_SOCKET)
-	    pj_sock_close(sock[i]);
-    }
-    return -1;
-}
-
-static void log_function(int level, const char *buffer, int len)
-{
-    /* Write to both stdout and file. */
-    if (level <= global.app_log_level)
-	pj_log_to_stdout(level, buffer, len);
-    if (global.log_file) {
-	fwrite(buffer, len, 1, global.log_file);
-	fflush(global.log_file);
-    }
-}
-
-/* Initialize stack. */
-static pj_status_t init_stack()
-{
-    pj_status_t status;
-    pj_sockaddr_in bind_addr;
-    pj_sockaddr_in bind_name;
-    const char *local_addr;
-    static char local_uri[128];
-
-    /* Optionally set logging file. */
-    if (global.log_filename) {
-	global.log_file = fopen(global.log_filename, "wt");
-    }
-
-    /* Initialize endpoint. This will also call initialization to all the
-     * modules.
-     */
-    global.endpt = pjsip_endpt_create(global.pf);
-    if (global.endpt == NULL) {
-	return -1;
-    }
-
-    /* Set dialog callback. */
-    pjsip_ua_set_dialog_callback(global.user_agent, &dlg_callback);
-
-    /* Init listener's bound address and port. */
-    pj_sockaddr_init2(&bind_addr, "0.0.0.0", global.sip_port);
-    pj_sockaddr_init(&bind_name, pj_gethostname(), global.sip_port);
-
-    /* Add UDP transport listener. */
-    status = pjsip_endpt_create_udp_listener( global.endpt, global.sip_sock,
-					      &global.sip_sock_name);
-    if (status != 0)
-	return -1;
-
-    local_addr = pj_inet_ntoa(global.sip_sock_name.sin_addr);
-
-#if PJ_HAS_TCP
-    /* Add TCP transport listener. */
-    status = pjsip_endpt_create_listener( global.endpt, PJSIP_TRANSPORT_TCP, 
-					  &bind_addr, &bind_name);
-    if (status != 0)
-	return -1;
-#endif
-
-    /* Determine user_id to be put in Contact */
-    if (global.local_uri.slen) {
-	pj_pool_t *pool = pj_pool_create(global.pf, "parser", 1024, 0, NULL);
-	pjsip_uri *uri;
-
-	uri = pjsip_parse_uri(pool, global.local_uri.ptr, global.local_uri.slen, 0);
-	if (uri) {
-	    if (pj_stricmp2(pjsip_uri_get_scheme(uri), "sip")==0) {
-		pjsip_url *url = (pjsip_url*)pjsip_uri_get_uri(uri);
-		if (url->user.slen)
-		    strncpy(global.user_id, url->user.ptr, url->user.slen);
-	    }
-	} 
-	pj_pool_release(pool);
-    } 
-    
-    if (global.user_id[0]=='\0') {
-	pj_native_strcpy(global.user_id, "user");
-    }
-
-    /* build contact */
-    global.real_contact.ptr = local_uri;
-    global.real_contact.slen = 
-	sprintf(local_uri, "<sip:%s@%s:%d>", global.user_id, local_addr, global.sip_port);
-
-    if (global.contact.slen == 0)
-	global.contact = global.real_contact;
-
-    /* initialize local_uri with contact if it's not specified in cmdline */
-    if (global.local_uri.slen == 0)
-	global.local_uri = global.contact;
-
-    /* Init proxy. */
-    if (global.proxy.slen || global.outbound_proxy.slen) {
-	int count = 0;
-	pj_str_t proxy_url[2];
-
-	if (global.outbound_proxy.slen) {
-	    proxy_url[count++] = global.outbound_proxy;
-	}
-	if (global.proxy.slen) {
-	    proxy_url[count++] = global.proxy;
-	}
-
-	if (pjsip_endpt_set_proxies(global.endpt, count, proxy_url) != 0) {
-	    PJ_LOG(2,(THIS_FILE, "Error setting proxy address!"));
-	    return -1;
-	}
-    }
-
-    /* initialize SIP registration if registrar is configured */
-    if (global.registrar_uri.slen) {
-	global.regc = pjsip_regc_create( global.endpt, NULL, &regc_cb);
-	pjsip_regc_init( global.regc, &global.registrar_uri, 
-			 &global.local_uri, 
-			 &global.local_uri,
-			 1, &global.contact, 
-			 global.reg_timeout);
-	pjsip_regc_set_credentials( global.regc, global.cred_count, global.cred_info );
-    }
-
-    return PJ_SUCCESS;
-}
-
-/* Worker thread function, only used when threading is enabled. */
-static void *PJ_THREAD_FUNC worker_thread(void *unused)
-{
-    PJ_UNUSED_ARG(unused)
-
-    while (!global.worker_quit_flag) {
-	pj_time_val timeout = { 0, 10 };
-	pjsip_endpt_handle_events (global.endpt, &timeout);
-    }
-    return NULL;
-}
-
-
-/* Make call to the specified URI. */
-static pjsip_dlg *make_call(pj_str_t *remote_uri)
-{
-    pjsip_dlg *dlg;
-    pj_str_t local = global.contact;
-    pj_str_t remote = *remote_uri;
-    struct dialog_data *dlg_data;
-    pjsip_tx_data *tdata;
-    pj_media_sock_info sock_info;
-
-    /* Create new dialog instance. */
-    dlg = pjsip_ua_create_dialog(global.user_agent, PJSIP_ROLE_UAC);
-
-    /* Attach our own user data. */
-    dlg_data = pj_pool_calloc(dlg->pool, 1, sizeof(struct dialog_data));
-    dlg->user_data = dlg_data;
-
-    /* Create media session. */
-    pj_memset(&sock_info, 0, sizeof(sock_info));
-    sock_info.rtp_sock = global.rtp_sock;
-    sock_info.rtcp_sock = global.rtcp_sock;
-    pj_memcpy(&sock_info.rtp_addr_name, &global.rtp_sock_name, sizeof(pj_sockaddr_in));
-
-    dlg_data->msession = pj_media_session_create (global.mmgr, &sock_info);
-    dlg_data->x_ms_msg_session = -1;
-
-    if (global.offer_x_ms_msg) {
-	const pj_media_stream_info *minfo[32];
-	unsigned cnt;
-
-	cnt = pj_media_session_enum_streams(dlg_data->msession, 32, minfo);
-	if (cnt > 0)
-	    dlg_data->x_ms_msg_session = cnt;
-    } 
-
-    /* Initialize dialog with local and remote URI. */
-    if (pjsip_dlg_init(dlg, &local, &remote, NULL) != PJ_SUCCESS) {
-	pjsip_ua_destroy_dialog(dlg);
-	return NULL;
-    }
-
-    /* Initialize credentials. */
-    pjsip_dlg_set_credentials(dlg, global.cred_count, global.cred_info);
-
-    /* Send INVITE! */
-    tdata = pjsip_dlg_invite(dlg);
-    tdata->msg->body = create_msg_body (dlg, 0);
-
-    if (pjsip_dlg_send_msg(dlg, tdata) != PJ_SUCCESS) {
-	pjsip_ua_destroy_dialog(dlg);
-	return NULL;
-    }
-
-    return dlg;
-}
-
-/*
- * Callback to receive incoming IM message.
- */
-static int on_incoming_im_msg(pjsip_rx_data *rdata)
-{
-    pjsip_msg *msg = rdata->msg;
-    pjsip_msg_body *body = msg->body;
-    int len;
-    char to[128], from[128];
-
-
-    len = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR, 
-			   rdata->from->uri, from, sizeof(from));
-    if (len > 0) from[len] = '\0';
-    else pj_native_strcpy(from, "<URL too long..>");
-
-    len = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR, 
-			   rdata->to->uri, to, sizeof(to));
-    if (len > 0) to[len] = '\0';
-    else pj_native_strcpy(to, "<URL too long..>");
-
-    PJ_LOG(3,(THIS_FILE, "Incoming instant message:"));
-    
-    printf("----- BEGIN INSTANT MESSAGE ----->\n");
-    printf("From:\t%s\n", from);
-    printf("To:\t%s\n", to);
-    printf("Body:\n%.*s\n", (body ? body->len : 0), (body ? (char*)body->data : ""));
-    printf("<------ END INSTANT MESSAGE ------\n");
-
-    fflush(stdout);
-
-    /* Must answer with final response. */
-    return 200;
-}
-
-/*
- * Input URL.
- */
-static pj_str_t *ui_input_url(pj_str_t *out, char *buf, int len, int *selection)
-{
-    int i;
-
-    *selection = -1;
-
-    printf("\nBuddy list:\n");
-    printf("---------------------------------------\n");
-    for (i=0; i<global.buddy_cnt; ++i) {
-	printf(" %d\t%s  <%s>\n", i+1, global.buddy[i].ptr,
-		(global.buddy_status[i]?"Online":"Offline"));
-    }
-    printf("-------------------------------------\n");
-
-    printf("Choices\n"
-	   "\t0        For current dialog.\n"
-	   "\t[1-%02d]   Select from buddy list\n"
-	   "\tURL      An URL\n"
-	   , global.buddy_cnt);
-    printf("Input: ");
-
-    fflush(stdout);
-    fgets(buf, len, stdin);
-    buf[strlen(buf)-1] = '\0'; /* remove trailing newline. */
-
-    while (isspace(*buf)) ++buf;
-
-    if (!*buf || *buf=='\n' || *buf=='\r')
-	return NULL;
-
-    i = atoi(buf);
-
-    if (i == 0) {
-	if (isdigit(*buf)) {
-	    *selection = 0;
-	    *out = pj_str("0");
-	    return out;
-	} else {
-	    if (verify_sip_url(buf) != 0) {
-		puts("Invalid URL specified!");
-		return NULL;
-	    }
-	    *out = pj_str(buf);
-	    return out;
-	}
-    } else if (i > global.buddy_cnt || i < 0) {
-	printf("Error: invalid selection!\n");
-	return NULL;
-    } else {
-	*out = global.buddy[i-1];
-	*selection = i;
-	return out;
-    }
-}
-
-
-static void generic_request_callback( void *token, pjsip_event *event )
-{
-    pjsip_transaction *tsx = event->obj.tsx;
-    
-    PJ_UNUSED_ARG(token)
-
-    if (tsx->status_code/100 == 2) {
-	PJ_LOG(3,(THIS_FILE, "Outgoing %.*s %d (%s)",
-		  event->obj.tsx->method.name.slen,
-		  event->obj.tsx->method.name.ptr,
-		  tsx->status_code,
-		  pjsip_get_status_text(tsx->status_code)->ptr));
-    } else if (tsx->status_code==401 || tsx->status_code==407)  {
-	pjsip_tx_data *tdata;
-	tdata = pjsip_auth_reinit_req( global.endpt,
-				       global.pool, NULL, global.cred_count, global.cred_info,
-				       tsx->last_tx, event->src.rdata);
-	if (tdata) {
-	    int rc;
-	    pjsip_cseq_hdr *cseq;
-	    cseq = (pjsip_cseq_hdr*)pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
-	    cseq->cseq++;
-	    rc = pjsip_endpt_send_request( global.endpt, tdata, -1, NULL, 
-					    &generic_request_callback);
-	    if (rc == 0)
-		return;
-	}
-	PJ_LOG(2,(THIS_FILE, "Outgoing %.*s failed, status=%d (%s)",
-		  event->obj.tsx->method.name.slen,
-		  event->obj.tsx->method.name.ptr,
-		  event->obj.tsx->status_code,
-		  pjsip_get_status_text(event->obj.tsx->status_code)->ptr));
-    } else {
-	const pj_str_t *reason;
-	if (event->src_type == PJSIP_EVENT_RX_MSG)
-	    reason = &event->src.rdata->msg->line.status.reason;
-	else
-	    reason = pjsip_get_status_text(tsx->status_code);
-	PJ_LOG(2,(THIS_FILE, "Outgoing %.*s failed, status=%d (%.*s)",
-		  event->obj.tsx->method.name.slen,
-		  event->obj.tsx->method.name.ptr,
-		  event->obj.tsx->status_code,
-		  reason->slen, reason->ptr));
-    }
-}
-
-
-static void ui_send_im_message()
-{
-    char line[100];
-    char text_buf[100];
-    pj_str_t str;
-    pj_str_t text_msg;
-    int selection, rc;
-    pjsip_tx_data *tdata;
-  
-    if (ui_input_url(&str, line, sizeof(line), &selection) == NULL)
-	return;
-
-	
-    printf("Enter text to send (empty to cancel): "); fflush(stdout);
-    fgets(text_buf, sizeof(text_buf), stdin);
-    text_buf[strlen(text_buf)-1] = '\0';
-    if (!*text_buf)
-	return;
-
-    text_msg = pj_str(text_buf);
-    
-    if (selection==0) {
-	pjsip_method message_method;
-	pj_str_t str_MESSAGE = { "MESSAGE", 7 };
-
-	/* Send IM to current dialog. */
-	if (global.cur_dlg == NULL || global.cur_dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {
-	    printf("No current dialog or dialog state is not ESTABLISHED!\n");
-	    return;
-	}
-
-	pjsip_method_init( &message_method, global.cur_dlg->pool, &str_MESSAGE);
-	tdata = pjsip_dlg_create_request( global.cur_dlg, &message_method, -1 );
-
-	if (tdata) {
-	    /* Create message body for the text. */
-	    pjsip_msg_body *body = pj_pool_calloc(tdata->pool, 1, sizeof(*body));
-	    body->content_type.type = pj_str("text");
-	    body->content_type.subtype = pj_str("plain");
-	    body->data = pj_pool_alloc(tdata->pool, text_msg.slen);
-	    pj_memcpy(body->data, text_msg.ptr, text_msg.slen);
-	    body->len = text_msg.slen;
-	    body->print_body = &pjsip_print_text_body;
-
-	    /* Assign body to message, and send the message! */
-	    tdata->msg->body = body;
-	    pjsip_dlg_send_msg( global.cur_dlg, tdata );
-	}
-
-    } else {
-	/* Send IM to buddy list. */
-	pjsip_method message;
-	static pj_str_t MESSAGE = { "MESSAGE", 7 };
-	pjsip_method_init_np(&message, &MESSAGE);
-	tdata = pjsip_endpt_create_request(global.endpt, &message, 
-					   &str,
-					   &global.real_contact,
-				           &str, &global.real_contact, NULL, -1, 
-					   &text_msg);
-	if (!tdata) {
-	    puts("Error creating request");
-	    return;
-	}
-	rc = pjsip_endpt_send_request(global.endpt, tdata, -1, NULL, &generic_request_callback);
-	if (rc == 0) {
-	    printf("Sending IM message %d\n", global.im_counter);
-	    ++global.im_counter;
-	} else {
-	    printf("Error: unable to send IM message!\n");
-	}
-    }
-}
-
-static void ui_send_options()
-{
-    char line[100];
-    pj_str_t str;
-    int selection, rc;
-    pjsip_tx_data *tdata;
-    pjsip_method options;
-
-    if (ui_input_url(&str, line, sizeof(line), &selection) == NULL)
-	return;
-
-    pjsip_method_set( &options, PJSIP_OPTIONS_METHOD );
-
-    if (selection == 0) {
-	/* Send OPTIONS to current dialog. */
-	tdata = pjsip_dlg_create_request(global.cur_dlg, &options, -1);
-	if (tdata)
-	    pjsip_dlg_send_msg( global.cur_dlg, tdata );
-    } else {
-	/* Send OPTIONS to arbitrary party. */
-	tdata = pjsip_endpt_create_request( global.endpt, &options,
-					    &str,
-					    &global.local_uri, &str, 
-					    &global.real_contact,
-					    NULL, -1, NULL);
-	if (tdata) {
-	    rc = pjsip_endpt_send_request( global.endpt, tdata, -1, NULL, 
-					   &generic_request_callback);
-	    if (rc != 0)
-		PJ_LOG(2,(THIS_FILE, "Error sending OPTIONS!"));
-	}
-    }
-}
-
-static void init_presence()
-{
-    const pjsip_presence_cb pres_cb = {
-	NULL,
-	&pres_on_received_request,
-	&pres_on_received_refresh,
-	&pres_on_received_update,
-	&pres_on_terminated
-    };
-
-    pjsip_presence_init(&pres_cb);
-}
-
-/* Subscribe presence information for all buddies. */
-static void subscribe_buddies_presence()
-{
-    int i;
-    for (i=0; i<global.buddy_cnt; ++i) {
-	pjsip_presentity *pres;
-	if (global.buddy_pres[i])
-	    continue;
-	pres = pjsip_presence_create( global.endpt, &global.local_uri,
-				      &global.buddy[i], PRESENCE_TIMEOUT, (void*)i);
-	if (pres) {
-	    pjsip_presence_set_credentials( pres, global.cred_count, global.cred_info );
-	    pjsip_presence_subscribe( pres );
-	}
-	global.buddy_pres[i] = pres;
-    }
-}
-
-/* Unsubscribe presence information for all buddies. */
-static void unsubscribe_buddies_presence()
-{
-    int i;
-    for (i=0; i<global.buddy_cnt; ++i) {
-	pjsip_presentity *pres = global.buddy_pres[i];
-	if (pres) {
-	    pjsip_presence_unsubscribe(pres);
-	    pjsip_presence_destroy(pres);
-	    global.buddy_pres[i] = NULL;
-	}
-    }
-}
-
-/* Unsubscribe presence. */
-static void unsubscribe_presence()
-{
-    int i;
-
-    unsubscribe_buddies_presence();
-    for (i=0; i<global.pres_cnt; ++i) {
-	pjsip_presentity *pres = global.pres[i];
-	pjsip_presence_notify( pres, PJSIP_EVENT_SUB_STATE_TERMINATED, 0);
-	pjsip_presence_destroy( pres );
-    }
-}
-
-/* Advertise online status to subscribers. */
-static void update_im_status()
-{
-    int i;
-    for (i=0; i<global.pres_cnt; ++i) {
-	pjsip_presentity *pres = global.pres[i];
-	pjsip_presence_notify( pres, PJSIP_EVENT_SUB_STATE_ACTIVE, 
-			       !global.hide_status);
-    }
-}
-
-/*
- * Main program.
- */
-int main(int argc, char *argv[])
-{
-    /* set to WORKER_COUNT+1 to avoid zero size warning 
-     * when threading is disabled. */
-    pj_thread_t *thread[WORKER_COUNT+1];
-    pj_caching_pool cp;
-    int i;
-
-    global.sip_port = 5060;
-    global.auto_answer = -1;
-    global.auto_hangup = -1;
-    global.app_log_level = 3;
-
-    pj_log_set_level(4);
-    pj_log_set_log_func(&log_function);
-
-    /* Init PJLIB */
-    if (pj_init() != PJ_SUCCESS)
-	return 1;
-
-    /* Init caching pool. */
-    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
-    global.pf = &cp.factory;
-
-    /* Create memory pool for application. */
-    global.pool = pj_pool_create(global.pf, "main", 1024, 0, NULL);
-
-    /* Parse command line arguments. */
-    if (parse_args(global.pool, argc, argv) != PJ_SUCCESS) {
-	pj_caching_pool_destroy(&cp);
-	return 1;
-    }
-
-    /* Init sockets */
-    if (init_sockets() != 0) {
-	pj_caching_pool_destroy(&cp);
-	return 1;
-    }
-
-    /* Initialize stack. */
-    if (init_stack() != PJ_SUCCESS) {
-	pj_caching_pool_destroy(&cp);
-	return 1;
-    }
-
-    /* Set callback to receive incoming IM */
-    pjsip_messaging_set_incoming_callback( &on_incoming_im_msg );
-
-    /* Set default worker count (can be zero) */
-    global.worker_cnt = WORKER_COUNT;
-
-    /* Create user worker thread(s), only when threading is enabled. */
-    for (i=0; i<global.worker_cnt; ++i) {
-	thread[i] = pj_thread_create( global.pool, "sip%p", 
-				      &worker_thread, 
-				      NULL, 0, NULL, 0);
-	if (thread == NULL) {
-	    global.worker_quit_flag = 1;
-	    for (--i; i>=0; --i) {
-		pj_thread_join(thread[i]);
-		pj_thread_destroy(thread[i]);
-	    }
-	    pj_caching_pool_destroy(&cp);
-	    return 1;
-	}
-    }
-
-    printf("Worker thread count: %d\n", global.worker_cnt);
-
-    /* Perform registration, if required. */
-    if (global.regc) {
-	update_registration(global.regc, 1);
-    }
-
-    /* Initialize media manager. */
-    global.mmgr = pj_med_mgr_create(global.pf);
-
-    /* Init presence. */
-    init_presence();
-
-    /* Subscribe presence information of all buddies. */
-    if (!global.no_presence)
-	subscribe_buddies_presence();
-
-    /* Initializatio completes, loop waiting for commands. */
-    for (;!global.worker_quit_flag;) {
-	pj_str_t str;
-	char line[128];
-
-#if WORKER_COUNT==0
-	/* If worker thread does not exist, main thread must poll for evetns. 
-	 * But this won't work very well since main thread is blocked by 
-	 * fgets(). So keep pressing the ENTER key to get the events!
-	 */
-	pj_time_val timeout = { 0, 100 };
-	pjsip_endpt_handle_events(global.endpt, &timeout);
-	puts("Keep pressing ENTER key to get the events!");
-#endif
-
-	printf("\nCurrent dialog: ");
-	print_dialog(global.cur_dlg);
-	puts("");
-
-	keystroke_help();
-
-	fgets(line, sizeof(line), stdin);
-
-	switch (*line) {
-	case 'm':
-	    puts("Make outgoing call");
-	    if (ui_input_url(&str, line, sizeof(line), &i) != NULL) {
-		pjsip_dlg *dlg = make_call(&str);
-		if (global.cur_dlg == NULL) {
-		    global.cur_dlg = dlg;
-		}
-	    }
-	    break;
-	case 'i':
-	    puts("Send Instant Messaging");
-	    ui_send_im_message();
-	    break;
-	case 'o':
-	    puts("Send OPTIONS");
-	    ui_send_options();
-	    break;
-	case 'a':
-	    if (global.cur_dlg) {
-		unsigned code;
-		pjsip_tx_data *tdata;
-		struct dialog_data *dlg_data = global.cur_dlg->user_data;
-
-		printf("Answer with status code (1xx-6xx): ");
-		fflush(stdout);
-		fgets(line, sizeof(line), stdin);
-		str = pj_str(line);
-		str.slen -= 1;
-
-		code = pj_strtoul(&str);
-		tdata = pjsip_dlg_answer(global.cur_dlg, code);
-		if (tdata) {
-		    if (code/100 == 2) {
-			tdata->msg->body = dlg_data->body;
-		    }
-		    pjsip_dlg_send_msg(global.cur_dlg, tdata);
-
-		}
-	    } else {
-		puts("No current dialog");
-	    }
-	    break;
-	case 'h':
-	    if (global.cur_dlg) {
-		pjsip_tx_data *tdata;
-		tdata = pjsip_dlg_disconnect(global.cur_dlg, PJSIP_SC_DECLINE);
-		if (tdata) {
-		    pjsip_dlg_send_msg(global.cur_dlg, tdata);
-		}
-	    } else {
-		puts("No current dialog");
-	    }
-	    break;
-	case ']':
-	    if (global.cur_dlg) {
-		global.cur_dlg = global.cur_dlg->next;
-		if (global.cur_dlg == (void*)&global.user_agent->dlg_list) {
-		    global.cur_dlg = global.cur_dlg->next;
-		}
-	    } else {
-		puts("No current dialog");
-	    }
-	    break;
-	case '[':
-	    if (global.cur_dlg) {
-		global.cur_dlg = global.cur_dlg->prev;
-		if (global.cur_dlg == (void*)&global.user_agent->dlg_list) {
-		    global.cur_dlg = global.cur_dlg->prev;
-		}
-	    } else {
-		puts("No current dialog");
-	    }
-	    break;
-	case 'd':
-	    pjsip_endpt_dump(global.endpt, *(line+1)=='1');
-	    pjsip_ua_dump(global.user_agent);
-	    break;
-	case 's':
-	    if (*(line+1) == 'u')
-		subscribe_buddies_presence();
-	    break;
-	case 'u':
-	    if (*(line+1) == 's')
-		unsubscribe_presence();
-	    break;
-	case 't':
-	    global.hide_status = !global.hide_status;
-	    update_im_status();
-	    break;
-	case 'q':
-	    goto on_exit;
-	case 'l':
-	    print_all_dialogs();
-	    break;
-	}
-    }
-
-on_exit:
-    /* Unregister, if required. */
-    if (global.regc) {
-	update_registration(global.regc, 0);
-    }
-
-    /* Unsubscribe presence. */
-    unsubscribe_presence();
-
-    /* Allow one second to get all events. */
-    if (1) {
-	pj_time_val end_time;
-
-	pj_gettimeofday(&end_time);
-	end_time.sec++;
-
-	PJ_LOG(3,(THIS_FILE, "Shutting down.."));
-	for (;;) {
-	    pj_time_val timeout = { 0, 20 }, now;
-	    pjsip_endpt_handle_events (global.endpt, &timeout);
-	    pj_gettimeofday(&now);
-	    PJ_TIME_VAL_SUB(now, end_time);
-	    if (now.sec >= 1)
-		break;
-	}
-    }
-
-    global.worker_quit_flag = 1;
-
-    pj_med_mgr_destroy(global.mmgr);
-
-    /* Wait all threads to quit. */
-    for (i=0; i<global.worker_cnt; ++i) {
-	pj_thread_join(thread[i]);
-	pj_thread_destroy(thread[i]);
-    }
-
-    /* Destroy endpoint. */
-    pjsip_endpt_destroy(global.endpt);
-
-    /* Destroy caching pool. */
-    pj_caching_pool_destroy(&cp);
-
-    /* Close log file, if any. */
-    if (global.log_file)
-	fclose(global.log_file);
-
-    return 0;
-}
-
-/*
- * Register static modules to the endpoint.
- */
-pj_status_t register_static_modules( pj_size_t *count,
-				     pjsip_module **modules )
-{
-    /* Reset count. */
-    *count = 0;
-
-    /* Register user agent module. */
-    modules[(*count)++] = pjsip_ua_get_module();
-    global.user_agent = modules[0]->mod_data;
-    modules[(*count)++] = pjsip_messaging_get_module();
-    modules[(*count)++] = pjsip_event_sub_get_module();
-
-    return PJ_SUCCESS;
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+

+#include <pjlib.h>

+#include <pjsip_core.h>

+#include <pjsip_ua.h>

+#include <pjsip_simple.h>

+#include <pjmedia.h>

+#include <ctype.h>

+#include <stdlib.h>

+#include <pj/stun.h>

+

+#define START_PORT	    5060

+#define MAX_BUDDIES	    32

+#define THIS_FILE	    "main.c"

+#define MAX_PRESENTITY	    32

+#define PRESENCE_TIMEOUT    60

+

+/* By default we'll have one worker thread, except when threading 

+ * is disabled. 

+ */

+#if PJ_HAS_THREADS

+#  define WORKER_COUNT	1

+#else

+#  define WORKER_COUNT	0

+#endif

+

+/* Global variable. */

+static struct

+{

+    /* Control. */

+    pj_pool_factory *pf;

+    pjsip_endpoint  *endpt;

+    pj_pool_t	    *pool;

+    pjsip_user_agent *user_agent;

+    int		     worker_cnt;

+    int		     worker_quit_flag;

+

+    /* User info. */

+    char	     user_id[64];

+    pj_str_t	     local_uri;

+    pj_str_t	     contact;

+    pj_str_t	     real_contact;

+

+    /* Dialog. */

+    pjsip_dlg	    *cur_dlg;

+

+    /* Authentication. */

+    int		     cred_count;

+    pjsip_cred_info  cred_info[4];

+

+    /* Media stack. */

+    pj_bool_t	     null_audio;

+    pj_med_mgr_t    *mmgr;

+

+    /* Misc. */

+    int		     app_log_level;

+    char	    *log_filename;

+    FILE	    *log_file;

+

+    /* Proxy URLs */

+    pj_str_t	     proxy;

+    pj_str_t	     outbound_proxy;

+

+    /* UA auto options. */

+    int		     auto_answer;	/* -1 to disable. */

+    int		     auto_hangup;	/* -1 to disable */

+

+    /* Registration. */

+    pj_str_t	     registrar_uri;

+    pjsip_regc	    *regc;

+    pj_int32_t	     reg_timeout;

+    pj_timer_entry   regc_timer;

+

+    /* STUN */

+    pj_str_t	     stun_srv1;

+    int		     stun_port1;

+    pj_str_t	     stun_srv2;

+    int		     stun_port2;

+

+    /* UDP sockets and their public address. */

+    int		     sip_port;

+    pj_sock_t	     sip_sock;

+    pj_sockaddr_in   sip_sock_name;

+    pj_sock_t	     rtp_sock;

+    pj_sockaddr_in   rtp_sock_name;

+    pj_sock_t	     rtcp_sock;

+    pj_sockaddr_in   rtcp_sock_name;

+

+    /* SIMPLE */

+    pj_bool_t	     hide_status;

+    pj_bool_t	     offer_x_ms_msg;

+    int		     im_counter;

+    int		     buddy_cnt;

+    pj_str_t	     buddy[MAX_BUDDIES];

+    pj_bool_t	     buddy_status[MAX_BUDDIES];

+    pj_bool_t	     no_presence;

+    pjsip_presentity *buddy_pres[MAX_BUDDIES];

+

+    int		    pres_cnt;

+    pjsip_presentity *pres[MAX_PRESENTITY];

+

+} global;

+

+enum { AUTO_ANSWER, AUTO_HANGUP };

+

+/* This is the data that will be 'attached' on per dialog basis. */

+struct dialog_data

+{

+    /* Media session. */

+    pj_media_session_t *msession;

+

+    /* x-ms-chat session. */

+    pj_bool_t		x_ms_msg_session;

+

+    /* Cached SDP body, updated when media session changed. */

+    pjsip_msg_body *body;

+

+    /* Timer. */

+    pj_bool_t	     has_auto_timer;

+    pj_timer_entry   auto_timer;

+};

+

+/*

+ * These are the callbacks to be registered to dialog to receive notifications

+ * about various events in the dialog.

+ */

+static void dlg_on_all_events	(pjsip_dlg *dlg, pjsip_dlg_event_e dlg_evt,

+				 pjsip_event *event );

+static void dlg_on_before_tx	(pjsip_dlg *dlg, pjsip_transaction *tsx, 

+				 pjsip_tx_data *tdata, int retransmission);

+static void dlg_on_tx_msg	(pjsip_dlg *dlg, pjsip_transaction *tsx, 

+				 pjsip_tx_data *tdata);

+static void dlg_on_rx_msg	(pjsip_dlg *dlg, pjsip_transaction *tsx, 

+				 pjsip_rx_data *rdata);

+static void dlg_on_incoming	(pjsip_dlg *dlg, pjsip_transaction *tsx,

+				 pjsip_rx_data *rdata);

+static void dlg_on_calling	(pjsip_dlg *dlg, pjsip_transaction *tsx,

+				 pjsip_tx_data *tdata);

+static void dlg_on_provisional	(pjsip_dlg *dlg, pjsip_transaction *tsx,

+				 pjsip_event *event);

+static void dlg_on_connecting	(pjsip_dlg *dlg, pjsip_event *event);

+static void dlg_on_established	(pjsip_dlg *dlg, pjsip_event *event);

+static void dlg_on_disconnected	(pjsip_dlg *dlg, pjsip_event *event);

+static void dlg_on_terminated	(pjsip_dlg *dlg);

+static void dlg_on_mid_call_evt	(pjsip_dlg *dlg, pjsip_event *event);

+

+/* The callback structure that will be registered to UA layer. */

+struct pjsip_dlg_callback dlg_callback = {

+    &dlg_on_all_events,

+    &dlg_on_before_tx,

+    &dlg_on_tx_msg,

+    &dlg_on_rx_msg,

+    &dlg_on_incoming,

+    &dlg_on_calling,

+    &dlg_on_provisional,

+    &dlg_on_connecting,

+    &dlg_on_established,

+    &dlg_on_disconnected,

+    &dlg_on_terminated,

+    &dlg_on_mid_call_evt

+};

+

+

+/* 

+ * Auxiliary things are put in misc.c, so that this main.c file is more 

+ * readable. 

+ */

+#include "misc.c"

+

+static void dlg_auto_timer_callback( pj_timer_heap_t *timer_heap,

+				     struct pj_timer_entry *entry)

+{

+    pjsip_dlg *dlg = entry->user_data;

+    struct dialog_data *dlg_data = dlg->user_data;

+    

+    PJ_UNUSED_ARG(timer_heap)

+

+    dlg_data->has_auto_timer = 0;

+

+    if (entry->id == AUTO_ANSWER) {

+	pjsip_tx_data *tdata = pjsip_dlg_answer(dlg, 200);

+	if (tdata) {

+	    struct dialog_data *dlg_data = global.cur_dlg->user_data;

+	    tdata->msg->body = dlg_data->body;

+	    pjsip_dlg_send_msg(dlg, tdata);

+	}

+    } else {

+	pjsip_tx_data *tdata = pjsip_dlg_disconnect(dlg, 500);

+	if (tdata) 

+	    pjsip_dlg_send_msg(dlg, tdata);

+    }

+}

+

+static void update_registration(pjsip_regc *regc, int renew)

+{

+    pjsip_tx_data *tdata;

+

+    PJ_LOG(3,(THIS_FILE, "Performing SIP registration..."));

+

+    if (renew) {

+	tdata = pjsip_regc_register(regc, 1);

+    } else {

+	tdata = pjsip_regc_unregister(regc);

+    }

+

+    pjsip_regc_send( regc, tdata );

+}

+

+static void regc_cb(struct pjsip_regc_cbparam *param)

+{

+    /*

+     * Print registration status.

+     */

+    if (param->code < 0 || param->code >= 300) {

+	PJ_LOG(2, (THIS_FILE, "SIP registration failed, status=%d (%s)", 

+		   param->code, pjsip_get_status_text(param->code)->ptr));

+	global.regc = NULL;

+

+    } else if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {

+	PJ_LOG(3, (THIS_FILE, "SIP registration success, status=%d (%s), "

+			      "will re-register in %d seconds", 

+			      param->code,

+			      pjsip_get_status_text(param->code)->ptr,

+			      param->expiration));

+

+    } else {

+	PJ_LOG(4, (THIS_FILE, "SIP registration updated status=%d", param->code));

+    }

+}

+

+static void pres_on_received_request(pjsip_presentity *pres, pjsip_rx_data *rdata,

+				     int *timeout)

+{

+    int state;

+    int i;

+    char url[PJSIP_MAX_URL_SIZE];

+    int urllen;

+

+    PJ_UNUSED_ARG(rdata)

+

+    if (*timeout > 0) {

+	state = PJSIP_EVENT_SUB_STATE_ACTIVE;

+	if (*timeout > 300)

+	    *timeout = 300;

+    } else {

+	state = PJSIP_EVENT_SUB_STATE_TERMINATED;

+    }

+

+    urllen = pjsip_uri_print(PJSIP_URI_IN_FROMTO_HDR, rdata->from->uri, url, sizeof(url)-1);

+    if (urllen < 1) {

+	pj_native_strcpy(url, "<unknown>");

+    } else {

+	url[urllen] = '\0';

+    }

+    PJ_LOG(3,(THIS_FILE, "Received presence request from %s, sub_state=%s", 

+			 url, 

+			 (state==PJSIP_EVENT_SUB_STATE_ACTIVE?"active":"terminated")));

+

+    for (i=0; i<global.pres_cnt; ++i)

+	if (global.pres[i] == pres)

+	    break;

+    if (i == global.pres_cnt)

+	global.pres[global.pres_cnt++] = pres;

+

+    pjsip_presence_set_credentials( pres, global.cred_count, global.cred_info );

+    pjsip_presence_notify(pres, state, !global.hide_status);

+

+}

+

+static void pres_on_received_refresh(pjsip_presentity *pres, pjsip_rx_data *rdata)

+{

+    pres_on_received_request(pres, rdata, &pres->sub->default_interval);

+}

+

+/* This is called by presence framework when we receives presence update

+ * of a resource (buddy).

+ */

+static void pres_on_received_update(pjsip_presentity *pres, pj_bool_t is_open)

+{

+    int buddy_index = (int)pres->user_data;

+

+    global.buddy_status[buddy_index] = is_open;

+    PJ_LOG(3,(THIS_FILE, "Presence update: %s is %s", 

+			 global.buddy[buddy_index].ptr,

+			 (is_open ? "Online" : "Offline")));

+}

+

+/* This is called when the subscription is terminated. */

+static void pres_on_terminated(pjsip_presentity *pres, const pj_str_t *reason)

+{

+    if (pres->sub->role == PJSIP_ROLE_UAC) {

+	int buddy_index = (int)pres->user_data;

+	PJ_LOG(3,(THIS_FILE, "Presence subscription for %s is terminated (reason=%.*s)", 

+			    global.buddy[buddy_index].ptr,

+			    reason->slen, reason->ptr));

+	global.buddy_pres[buddy_index] = NULL;

+	global.buddy_status[buddy_index] = 0;

+    } else {

+	int i;

+	PJ_LOG(3,(THIS_FILE, "Notifier terminated (reason=%.*s)", 

+			    reason->slen, reason->ptr));

+	pjsip_presence_notify(pres, PJSIP_EVENT_SUB_STATE_TERMINATED, 1);

+	for (i=0; i<global.pres_cnt; ++i) {

+	    if (global.pres[i] == pres) {

+		int j;

+		global.pres[i] = NULL;

+		for (j=i+1; j<global.pres_cnt; ++j)

+		    global.pres[j-1] = global.pres[j];

+		global.pres_cnt--;

+		break;

+	    }

+	}

+    }

+    pjsip_presence_destroy(pres);

+}

+

+

+/* Callback attached to SIP body to print the body to message buffer. */

+static int print_msg_body(pjsip_msg_body *msg_body, char *buf, pj_size_t size)

+{

+    pjsip_msg_body *body = msg_body;

+    return pjsdp_print ((pjsdp_session_desc*)body->data, buf, size);

+}

+

+/* When media session has changed, call this function to update the cached body

+ * information in the dialog. 

+ */

+static pjsip_msg_body *create_msg_body (pjsip_dlg *dlg, pj_bool_t is_ack_msg)

+{

+    struct dialog_data *dlg_data = dlg->user_data;

+    pjsdp_session_desc *sdp;

+

+    sdp = pj_media_session_create_sdp (dlg_data->msession, dlg->pool, is_ack_msg);

+    if (!sdp) {

+	dlg_data->body = NULL;

+	return NULL;

+    }

+

+    /* For outgoing INVITE, if we offer "x-ms-message" line, then add a new

+     * "m=" line in the SDP.

+     */

+    if (dlg_data->x_ms_msg_session >= 0 && 

+	dlg_data->x_ms_msg_session >= (int)sdp->media_count) 

+    {

+	pjsdp_media_desc *m = pj_pool_calloc(dlg->pool, 1, sizeof(*m));

+	sdp->media[sdp->media_count] = m;

+	dlg_data->x_ms_msg_session = sdp->media_count++;

+    }

+

+    /*

+     * For "x-ms-message" line, remove all attributes and connection line etc.

+     */

+    if (dlg_data->x_ms_msg_session >= 0) {

+	pjsdp_media_desc *m = sdp->media[dlg_data->x_ms_msg_session];

+	if (m) {

+	    m->desc.media = pj_str("x-ms-message");

+	    m->desc.port = 5060;

+	    m->desc.transport = pj_str("sip");

+	    m->desc.fmt_count = 1;

+	    m->desc.fmt[0] = pj_str("null");

+	    m->attr_count = 0;

+	    m->conn = NULL;

+	}

+    }

+

+    dlg_data->body = pj_pool_calloc(dlg->pool, 1, sizeof(*dlg_data->body));

+    dlg_data->body->content_type.type = pj_str("application");

+    dlg_data->body->content_type.subtype = pj_str("sdp");

+    dlg_data->body->len = 0;	/* ignored */

+    dlg_data->body->print_body = &print_msg_body;

+

+    dlg_data->body->data = sdp;

+    return dlg_data->body;

+}

+

+/* This callback will be called on every occurence of events in dialogs */

+static void dlg_on_all_events(pjsip_dlg *dlg, pjsip_dlg_event_e dlg_evt,

+			      pjsip_event *event )

+{

+    PJ_UNUSED_ARG(dlg_evt)

+    PJ_UNUSED_ARG(event)

+

+    PJ_LOG(4, (THIS_FILE, "dlg_on_all_events %p", dlg));

+}

+

+/* This callback is called before each outgoing msg is sent (including 

+ * retransmission). Application can override this notification if it wants

+ * to modify the message before transmission or if it wants to do something

+ * else for each transmission.

+ */

+static void dlg_on_before_tx(pjsip_dlg *dlg, pjsip_transaction *tsx, 

+			     pjsip_tx_data *tdata, int ret_cnt)

+{

+    PJ_UNUSED_ARG(tsx)

+    PJ_UNUSED_ARG(tdata)

+

+    if (ret_cnt > 0) {

+	PJ_LOG(3, (THIS_FILE, "Dialog %s: retransmitting message (cnt=%d)", 

+			      dlg->obj_name, ret_cnt));

+    }

+}

+

+/* This callback is called after a message is sent. */

+static void dlg_on_tx_msg(pjsip_dlg *dlg, pjsip_transaction *tsx, 

+			  pjsip_tx_data *tdata)

+{

+    PJ_UNUSED_ARG(tsx)

+    PJ_UNUSED_ARG(tdata)

+

+    PJ_LOG(4, (THIS_FILE, "dlg_on_tx_msg %p", dlg));

+}

+

+/* This callback is called on receipt of incoming message. */

+static void dlg_on_rx_msg(pjsip_dlg *dlg, pjsip_transaction *tsx, 

+			  pjsip_rx_data *rdata)

+{

+    PJ_UNUSED_ARG(tsx)

+    PJ_UNUSED_ARG(rdata)

+    PJ_LOG(4, (THIS_FILE, "dlg_on_tx_msg %p", dlg));

+}

+

+/* This callback is called after dialog has sent INVITE */

+static void dlg_on_calling(pjsip_dlg *dlg, pjsip_transaction *tsx,

+			   pjsip_tx_data *tdata)

+{

+    PJ_UNUSED_ARG(tsx)

+    PJ_UNUSED_ARG(tdata)

+

+    pj_assert(tdata->msg->type == PJSIP_REQUEST_MSG &&

+	      tdata->msg->line.req.method.id == PJSIP_INVITE_METHOD &&

+	      tsx->method.id == PJSIP_INVITE_METHOD);

+

+    PJ_LOG(3, (THIS_FILE, "Dialog %s: start calling...", dlg->obj_name));

+}

+

+static void create_session_from_sdp( pjsip_dlg *dlg, pjsdp_session_desc *sdp)

+{

+    struct dialog_data *dlg_data = dlg->user_data;

+    pj_bool_t sdp_x_ms_msg_index = -1;

+    int i;

+    int mcnt;

+    const pj_media_stream_info *mi[PJSDP_MAX_MEDIA];

+    int has_active;

+    pj_media_sock_info sock_info;

+

+    /* Find "m=x-ms-message" line in the SDP. */

+    for (i=0; i<(int)sdp->media_count; ++i) {

+	if (pj_stricmp2(&sdp->media[i]->desc.media, "x-ms-message")==0)

+	    sdp_x_ms_msg_index = i;

+    }

+

+    /*

+     * Create media session.

+     */

+    pj_memset(&sock_info, 0, sizeof(sock_info));

+    sock_info.rtp_sock = global.rtp_sock;

+    sock_info.rtcp_sock = global.rtcp_sock;

+    pj_memcpy(&sock_info.rtp_addr_name, &global.rtp_sock_name, sizeof(pj_sockaddr_in));

+

+    dlg_data->msession = pj_media_session_create_from_sdp (global.mmgr, sdp, &sock_info);

+

+    /* A session will always be created, unless there is memory

+     * alloc problem.

+     */

+    pj_assert(dlg_data->msession);

+

+    /* See if we can take the offer by checking that we have at least

+     * one media stream active.

+     */

+    mcnt = pj_media_session_enum_streams(dlg_data->msession, PJSDP_MAX_MEDIA, mi);

+    for (i=0, has_active=0; i<mcnt; ++i) {

+	if (mi[i]->fmt_cnt>0 && mi[i]->dir!=PJ_MEDIA_DIR_NONE) {

+	    has_active = 1;

+	    break;

+	}

+    }

+

+    if (!has_active && sdp_x_ms_msg_index==-1) {

+	pjsip_tx_data *tdata;

+

+	/* Unable to accept remote's SDP. 

+	 * Answer with 488 (Not Acceptable Here)

+	 */

+	/* Create 488 response. */

+	tdata = pjsip_dlg_answer(dlg, PJSIP_SC_NOT_ACCEPTABLE_HERE);

+

+	/* Send response. */

+	if (tdata)

+	    pjsip_dlg_send_msg(dlg, tdata);

+	return;

+    }

+

+    dlg_data->x_ms_msg_session = sdp_x_ms_msg_index;

+

+    /* Create msg body to be used later in 2xx/response */

+    create_msg_body(dlg, 0);

+

+}

+

+/* This callback is called after an INVITE is received. */

+static void dlg_on_incoming(pjsip_dlg *dlg, pjsip_transaction *tsx,

+			    pjsip_rx_data *rdata)

+{

+    struct dialog_data *dlg_data;

+    pjsip_msg *msg;

+    pjsip_tx_data *tdata;

+    char buf[128];

+    int len;

+

+    PJ_UNUSED_ARG(tsx)

+

+    pj_assert(rdata->msg->type == PJSIP_REQUEST_MSG &&

+	      rdata->msg->line.req.method.id == PJSIP_INVITE_METHOD &&

+	      tsx->method.id == PJSIP_INVITE_METHOD);

+

+    /*

+     * Notify user!

+     */

+    PJ_LOG(3, (THIS_FILE, ""));

+    PJ_LOG(3, (THIS_FILE, "INCOMING CALL ON DIALOG %s!!", dlg->obj_name));

+    PJ_LOG(3, (THIS_FILE, ""));

+    len = pjsip_uri_print( PJSIP_URI_IN_FROMTO_HDR, 

+			   (pjsip_name_addr*)dlg->remote.info->uri, 

+			   buf, sizeof(buf)-1);

+    if (len > 0) {

+	buf[len] = '\0';

+	PJ_LOG(3,(THIS_FILE, "From:\t%s", buf));

+    }

+    len = pjsip_uri_print( PJSIP_URI_IN_FROMTO_HDR, 

+			   (pjsip_name_addr*)dlg->local.info->uri, 

+			   buf, sizeof(buf)-1);

+    if (len > 0) {

+	buf[len] = '\0';

+	PJ_LOG(3,(THIS_FILE, "To:\t%s", buf));

+    }

+    PJ_LOG(3, (THIS_FILE, "Press 'a' to answer, or 'h' to hangup!!", dlg->obj_name));

+    PJ_LOG(3, (THIS_FILE, ""));

+

+    /*

+     * Process incoming dialog.

+     */

+

+    dlg_data = pj_pool_calloc(dlg->pool, 1, sizeof(struct dialog_data));

+    dlg->user_data = dlg_data;

+

+    /* Update contact. */

+    pjsip_dlg_set_contact(dlg, &global.contact);

+

+    /* Initialize credentials. */

+    pjsip_dlg_set_credentials(dlg, global.cred_count, global.cred_info);

+

+    /* Create media session if the request has "application/sdp" body. */

+    msg = rdata->msg;

+    if (msg->body && 

+	pj_stricmp2(&msg->body->content_type.type, "application")==0 &&

+	pj_stricmp2(&msg->body->content_type.subtype, "sdp")==0)

+    {

+	pjsdp_session_desc *sdp;

+

+	/* Parse SDP body, and instantiate media session based on remote's SDP.

+	 * Then create our SDP body from the session.

+	 */

+	sdp = pjsdp_parse (msg->body->data, msg->body->len, rdata->pool);

+	if (!sdp)

+	    goto send_answer;

+

+	create_session_from_sdp(dlg, sdp);

+

+    } else if (msg->body) {

+	/* The request has a message body other than "application/sdp" */

+	pjsip_accept_hdr *accept;

+

+	/* Create response. */

+	tdata = pjsip_dlg_answer(dlg, PJSIP_SC_UNSUPPORTED_MEDIA_TYPE);

+

+	/* Add "Accept" header. */

+	accept = pjsip_accept_hdr_create(tdata->pool);

+	accept->values[0] = pj_str("application/sdp");

+	accept->count = 1;

+	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)accept);

+

+	/* Send response. */

+	pjsip_dlg_send_msg(dlg, tdata);

+	return;

+

+    } else {

+	/* The request has no message body. We can take this request, but

+	 * no media session will be activated.

+	 */

+	/* Nothing to do here. */

+    }

+

+send_answer:

+    /* Immediately answer with 100 (or 180? */

+    tdata = pjsip_dlg_answer( dlg, PJSIP_SC_RINGING );

+    pjsip_dlg_send_msg(dlg, tdata);

+

+    /* Set current dialog to this dialog if we don't currently have

+     * current dialog.

+     */

+    if (global.cur_dlg == NULL) {

+	global.cur_dlg = dlg;

+    }

+

+    /* Auto-answer if option is specified. */

+    if (global.auto_answer >= 0) {

+	pj_time_val delay = { 0, 0};

+	struct dialog_data *dlg_data = dlg->user_data;

+

+	PJ_LOG(4, (THIS_FILE, "Scheduling auto-answer in %d seconds", 

+			      global.auto_answer));

+

+	delay.sec = global.auto_answer;

+	dlg_data->auto_timer.user_data = dlg;

+	dlg_data->auto_timer.id = AUTO_ANSWER;

+	dlg_data->auto_timer.cb = &dlg_auto_timer_callback;

+	dlg_data->has_auto_timer = 1;

+	pjsip_endpt_schedule_timer(dlg->ua->endpt, &dlg_data->auto_timer, &delay);

+    }

+}

+

+/* This callback is called when dialog has sent/received a provisional response

+ * to INVITE.

+ */

+static void dlg_on_provisional(pjsip_dlg *dlg, pjsip_transaction *tsx,

+			       pjsip_event *event)

+{

+    const char *action;

+

+    pj_assert((event->src_type == PJSIP_EVENT_TX_MSG &&

+	       event->src.tdata->msg->type == PJSIP_RESPONSE_MSG &&

+	       event->src.tdata->msg->line.status.code/100 == 1 &&

+	       tsx->method.id == PJSIP_INVITE_METHOD) 

+	       ||

+	       (event->src_type == PJSIP_EVENT_RX_MSG &&

+	       event->src.rdata->msg->type == PJSIP_RESPONSE_MSG &&

+	       event->src.rdata->msg->line.status.code/100 == 1 &&

+	       tsx->method.id == PJSIP_INVITE_METHOD));

+

+    if (event->src_type == PJSIP_EVENT_TX_MSG)

+	action = "Sending";

+    else

+	action = "Received";

+

+    PJ_LOG(3, (THIS_FILE, "Dialog %s: %s %d (%s)", 

+			  dlg->obj_name, action, tsx->status_code,

+			  pjsip_get_status_text(tsx->status_code)->ptr));

+}

+

+/* This callback is called when 200 response to INVITE is sent/received. */

+static void dlg_on_connecting(pjsip_dlg *dlg, pjsip_event *event)

+{

+    struct dialog_data *dlg_data = dlg->user_data;

+    const char *action;

+

+    pj_assert((event->src_type == PJSIP_EVENT_TX_MSG &&

+	       event->src.tdata->msg->type == PJSIP_RESPONSE_MSG &&

+	       event->src.tdata->msg->line.status.code/100 == 2)

+	       ||

+	       (event->src_type == PJSIP_EVENT_RX_MSG &&

+	       event->src.rdata->msg->type == PJSIP_RESPONSE_MSG &&

+	       event->src.rdata->msg->line.status.code/100 == 2));

+

+    if (event->src_type == PJSIP_EVENT_RX_MSG)

+	action = "Received";

+    else

+	action = "Sending";

+

+    PJ_LOG(3, (THIS_FILE, "Dialog %s: %s 200 (OK)", dlg->obj_name, action));

+

+    if (event->src_type == PJSIP_EVENT_RX_MSG) {

+	/* On receipt of 2xx response, negotiate our media capability

+	 * and start media.

+	 */

+	pjsip_msg *msg = event->src.rdata->msg;

+	pjsip_msg_body *body;

+	pjsdp_session_desc *sdp;

+

+	/* Get SDP from message. */

+

+	/* Ignore if no SDP body is present. */

+	body = msg->body;

+	if (!body) {

+	    PJ_LOG(3, (THIS_FILE, "Dialog %s: the 200/OK response has no body!",

+				  dlg->obj_name));

+	    return;

+	}

+

+	if (pj_stricmp2(&body->content_type.type, "application") != 0 &&

+	    pj_stricmp2(&body->content_type.subtype, "sdp") != 0) 

+	{

+	    PJ_LOG(3, (THIS_FILE, "Dialog %s: the 200/OK response has no SDP body!",

+				   dlg->obj_name));

+	    return;

+	}

+

+	/* Got what seems to be a SDP content. Parse it. */

+	sdp = pjsdp_parse (body->data, body->len, event->src.rdata->pool);

+	if (!sdp) {

+	    PJ_LOG(3, (THIS_FILE, "Dialog %s: SDP syntax error!",

+				  dlg->obj_name));

+	    return;

+	}

+

+	/* Negotiate media session with remote's media capability. */

+	if (pj_media_session_update (dlg_data->msession, sdp) != 0) {

+	    PJ_LOG(3, (THIS_FILE, "Dialog %s: media session update error!",

+				  dlg->obj_name));

+	    return;

+	}

+

+	/* Update the saved SDP body because media session has changed. 

+	 * Also set ack flag to '1', because we only want to send one format/

+	 * codec for each media streams.

+	 */

+	create_msg_body(dlg, 1);

+

+	/* Activate media. */

+	pj_media_session_activate (dlg_data->msession);

+

+    } else {

+	pjsip_msg *msg = event->src.tdata->msg;

+

+	if (msg->body) {

+	    /* On transmission of 2xx response, start media session. */

+	    pj_media_session_activate (dlg_data->msession);

+	}

+    }

+

+}

+

+/* This callback is called when ACK to initial INVITE is sent/received. */

+static void dlg_on_established(pjsip_dlg *dlg, pjsip_event *event)

+{

+    const char *action;

+

+    pj_assert((event->src_type == PJSIP_EVENT_TX_MSG &&

+	       event->src.tdata->msg->type == PJSIP_REQUEST_MSG &&

+	       event->src.tdata->msg->line.req.method.id == PJSIP_ACK_METHOD)

+	       ||

+	       (event->src_type == PJSIP_EVENT_RX_MSG &&

+	       event->src.rdata->msg->type == PJSIP_REQUEST_MSG &&

+	       event->src.rdata->msg->line.req.method.id == PJSIP_ACK_METHOD));

+

+    if (event->src_type == PJSIP_EVENT_RX_MSG)

+	action = "Received";

+    else

+	action = "Sending";

+

+    PJ_LOG(3, (THIS_FILE, "Dialog %s: %s ACK, dialog is ESTABLISHED", 

+			  dlg->obj_name, action));

+

+    /* Attach SDP body for outgoing ACK. */

+    if (event->src_type == PJSIP_EVENT_TX_MSG &&

+	event->src.tdata->msg->line.req.method.id == PJSIP_ACK_METHOD)

+    {

+	struct dialog_data *dlg_data = dlg->user_data;

+	event->src.tdata->msg->body = dlg_data->body;

+    }

+

+    /* Auto-hangup if option is specified. */

+    if (global.auto_hangup >= 0) {

+	pj_time_val delay = { 0, 0};

+	struct dialog_data *dlg_data = dlg->user_data;

+

+	PJ_LOG(4, (THIS_FILE, "Scheduling auto-hangup in %d seconds", 

+			      global.auto_hangup));

+

+	delay.sec = global.auto_hangup;

+	dlg_data->auto_timer.user_data = dlg;

+	dlg_data->auto_timer.id = AUTO_HANGUP;

+	dlg_data->auto_timer.cb = &dlg_auto_timer_callback;

+	dlg_data->has_auto_timer = 1;

+	pjsip_endpt_schedule_timer(dlg->ua->endpt, &dlg_data->auto_timer, &delay);

+    }

+}

+

+

+/* This callback is called when dialog is disconnected (because of final

+ * response, BYE, or timer).

+ */

+static void dlg_on_disconnected(pjsip_dlg *dlg, pjsip_event *event)

+{

+    struct dialog_data *dlg_data = dlg->user_data;

+    int status_code;

+    const pj_str_t *reason;

+    

+    PJ_UNUSED_ARG(event)

+

+    /* Cancel auto-answer/auto-hangup timer. */

+    if (dlg_data->has_auto_timer) {

+	pjsip_endpt_cancel_timer(dlg->ua->endpt, &dlg_data->auto_timer);

+	dlg_data->has_auto_timer = 0;

+    }

+

+    if (dlg->invite_tsx)

+	status_code = dlg->invite_tsx->status_code;

+    else

+	status_code = 200;

+

+    if (event->obj.tsx->method.id == PJSIP_INVITE_METHOD) {

+	if (event->src_type == PJSIP_EVENT_RX_MSG)

+	    reason = &event->src.rdata->msg->line.status.reason;

+	else if (event->src_type == PJSIP_EVENT_TX_MSG)

+	    reason = &event->src.tdata->msg->line.status.reason;

+	else

+	    reason = pjsip_get_status_text(event->obj.tsx->status_code);

+    } else {

+	reason = &event->obj.tsx->method.name;

+    }

+

+    PJ_LOG(3, (THIS_FILE, "Dialog %s: DISCONNECTED! Reason=%d (%.*s)", 

+			  dlg->obj_name, status_code, 

+			  reason->slen, reason->ptr));

+

+    if (dlg_data->msession) {

+	pj_media_session_destroy (dlg_data->msession);

+	dlg_data->msession = NULL;

+    }

+}

+

+/* This callback is called when dialog is about to be destroyed. */

+static void dlg_on_terminated(pjsip_dlg *dlg)

+{

+    PJ_LOG(3, (THIS_FILE, "Dialog %s: terminated!", dlg->obj_name));

+

+    /* If current dialog is equal to this dialog, update it. */

+    if (global.cur_dlg == dlg) {

+	global.cur_dlg = global.cur_dlg->next;

+	if (global.cur_dlg == (void*)&global.user_agent->dlg_list) {

+	    global.cur_dlg = NULL;

+	}

+    }

+}

+

+/* This callback is called for any requests when dialog is established. */

+static void dlg_on_mid_call_evt	(pjsip_dlg *dlg, pjsip_event *event)

+{

+    pjsip_transaction *tsx = event->obj.tsx;

+

+    if (event->src_type == PJSIP_EVENT_RX_MSG &&

+	event->src.rdata->msg->type == PJSIP_REQUEST_MSG) 

+    {

+	if (event->src.rdata->cseq->method.id == PJSIP_INVITE_METHOD) {

+	    /* Re-invitation. */

+	    pjsip_tx_data *tdata;

+

+	    PJ_LOG(3,(THIS_FILE, "Dialog %s: accepting re-invitation (dummy)",

+				 dlg->obj_name));

+	    tdata = pjsip_dlg_answer(dlg, 200);

+	    if (tdata) {

+		struct dialog_data *dlg_data = dlg->user_data;

+		tdata->msg->body = dlg_data->body;

+		pjsip_dlg_send_msg(dlg, tdata);

+	    }

+	} else {

+	    /* Don't worry, endpoint will answer with 500 or whetever. */

+	}

+

+    } else if (tsx->status_code/100 == 2) {

+	PJ_LOG(3,(THIS_FILE, "Dialog %s: outgoing %.*s success: %d (%s)",

+		  dlg->obj_name, 

+		  tsx->method.name.slen, tsx->method.name.ptr,

+		  tsx->status_code, 

+		  pjsip_get_status_text(tsx->status_code)->ptr));

+

+

+    } else if (tsx->status_code >= 300) {

+	pj_bool_t report_failure = PJ_TRUE;

+

+	/* Check for authentication failures. */

+	if (tsx->status_code==401 || tsx->status_code==407) {

+	    pjsip_tx_data *tdata;

+	    tdata = pjsip_auth_reinit_req( global.endpt,

+					   dlg->pool, &dlg->auth_sess,

+					   dlg->cred_count, dlg->cred_info,

+					   tsx->last_tx, event->src.rdata );

+	    if (tdata) {

+		int rc;

+		rc = pjsip_dlg_send_msg( dlg, tdata);

+		report_failure = (rc != 0);

+	    }

+	}

+	if (report_failure) {

+	    const pj_str_t *reason;

+	    if (event->src_type == PJSIP_EVENT_RX_MSG) {

+		reason = &event->src.rdata->msg->line.status.reason;

+	    } else {

+		reason = pjsip_get_status_text(tsx->status_code);

+	    }

+	    PJ_LOG(2,(THIS_FILE, "Dialog %s: outgoing request failed: %d (%.*s)",

+		      dlg->obj_name, tsx->status_code, 

+		      reason->slen, reason->ptr));

+	}

+    }

+}

+

+/* Initialize sockets and optionally get the public address via STUN. */

+static pj_status_t init_sockets()

+{

+    enum { 

+	RTP_START_PORT = 4000,

+	RTP_RANDOM_START = 2,

+	RTP_RETRY = 10 

+    };

+    enum {

+	SIP_SOCK,

+	RTP_SOCK,

+	RTCP_SOCK,

+    };

+    int i;

+    int rtp_port;

+    pj_sock_t sock[3];

+    pj_sockaddr_in mapped_addr[3];

+

+    for (i=0; i<3; ++i)

+	sock[i] = PJ_INVALID_SOCKET;

+

+    /* Create and bind SIP UDP socket. */

+    sock[SIP_SOCK] = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, 0);

+    if (sock[SIP_SOCK] == PJ_INVALID_SOCKET) {

+	PJ_LOG(2,(THIS_FILE, "Unable to create socket"));

+	goto on_error;

+    }

+    if (pj_sock_bind_in(sock[SIP_SOCK], 0, (pj_uint16_t)global.sip_port) != 0) {

+	PJ_LOG(2,(THIS_FILE, "Unable to bind to SIP port"));

+	goto on_error;

+    }

+

+    /* Initialize start of RTP port to try. */

+    rtp_port = RTP_START_PORT + (pj_rand() % RTP_RANDOM_START) / 2;

+

+    /* Loop retry to bind RTP and RTCP sockets. */

+    for (i=0; i<RTP_RETRY; ++i, rtp_port += 2) {

+

+	/* Create and bind RTP socket. */

+	sock[RTP_SOCK] = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, 0);

+	if (sock[RTP_SOCK] == PJ_INVALID_SOCKET)

+	    goto on_error;

+	if (pj_sock_bind_in(sock[RTP_SOCK], 0, (pj_uint16_t)rtp_port) != 0) {

+	    pj_sock_close(sock[RTP_SOCK]); sock[RTP_SOCK] = PJ_INVALID_SOCKET;

+	    continue;

+	}

+

+	/* Create and bind RTCP socket. */

+	sock[RTCP_SOCK] = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, 0);

+	if (sock[RTCP_SOCK] == PJ_INVALID_SOCKET)

+	    goto on_error;

+	if (pj_sock_bind_in(sock[RTCP_SOCK], 0, (pj_uint16_t)(rtp_port+1)) != 0) {

+	    pj_sock_close(sock[RTP_SOCK]); sock[RTP_SOCK] = PJ_INVALID_SOCKET;

+	    pj_sock_close(sock[RTCP_SOCK]); sock[RTCP_SOCK] = PJ_INVALID_SOCKET;

+	    continue;

+	}

+

+	/*

+	 * If we're configured to use STUN, then find out the mapped address,

+	 * and make sure that the mapped RTCP port is adjacent with the RTP.

+	 */

+	if (global.stun_port1 == 0) {

+	    pj_str_t hostname;

+	    pj_sockaddr_in addr;

+

+	    /* Get local IP address. */

+	    char hostname_buf[PJ_MAX_HOSTNAME];

+	    if (gethostname(hostname_buf, sizeof(hostname_buf)))

+		goto on_error;

+	    hostname = pj_str(hostname_buf);

+

+	    pj_memset( &addr, 0, sizeof(addr));

+	    addr.sin_family = PJ_AF_INET;

+	    if (pj_sockaddr_set_str_addr( &addr, &hostname) != PJ_SUCCESS)

+		goto on_error;

+

+	    for (i=0; i<3; ++i)

+		pj_memcpy(&mapped_addr[i], &addr, sizeof(addr));

+

+	    mapped_addr[SIP_SOCK].sin_port = pj_htons((pj_uint16_t)global.sip_port);

+	    mapped_addr[RTP_SOCK].sin_port = pj_htons((pj_uint16_t)rtp_port);

+	    mapped_addr[RTCP_SOCK].sin_port = pj_htons((pj_uint16_t)(rtp_port+1));

+	    break;

+	} else {

+	    pj_status_t rc;

+	    rc = pj_stun_get_mapped_addr( global.pf, 3, sock,

+					  &global.stun_srv1, global.stun_port1,

+					  &global.stun_srv2, global.stun_port2,

+					  mapped_addr);

+	    if (rc != 0) {

+		PJ_LOG(3,(THIS_FILE, "Error: %s", pj_stun_get_err_msg(rc)));

+		goto on_error;

+	    }

+

+	    if (pj_ntohs(mapped_addr[2].sin_port) == pj_ntohs(mapped_addr[1].sin_port)+1)

+		break;

+

+	    pj_sock_close(sock[RTP_SOCK]); sock[RTP_SOCK] = PJ_INVALID_SOCKET;

+	    pj_sock_close(sock[RTCP_SOCK]); sock[RTCP_SOCK] = PJ_INVALID_SOCKET;

+	}

+    }

+

+    if (sock[RTP_SOCK] == PJ_INVALID_SOCKET) {

+	PJ_LOG(2,(THIS_FILE, "Unable to find appropriate RTP/RTCP ports combination"));

+	goto on_error;

+    }

+

+    global.sip_sock = sock[SIP_SOCK];

+    pj_memcpy(&global.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in));

+    global.rtp_sock = sock[RTP_SOCK];

+    pj_memcpy(&global.rtp_sock_name, &mapped_addr[RTP_SOCK], sizeof(pj_sockaddr_in));

+    global.rtcp_sock = sock[RTCP_SOCK];

+    pj_memcpy(&global.rtcp_sock_name, &mapped_addr[RTCP_SOCK], sizeof(pj_sockaddr_in));

+

+    PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",

+	      pj_inet_ntoa(global.sip_sock_name.sin_addr), 

+	      pj_ntohs(global.sip_sock_name.sin_port)));

+    PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d",

+	      pj_inet_ntoa(global.rtp_sock_name.sin_addr), 

+	      pj_ntohs(global.rtp_sock_name.sin_port)));

+    PJ_LOG(4,(THIS_FILE, "RTCP UDP socket reachable at %s:%d",

+	      pj_inet_ntoa(global.rtcp_sock_name.sin_addr), 

+	      pj_ntohs(global.rtcp_sock_name.sin_port)));

+    return 0;

+

+on_error:

+    for (i=0; i<3; ++i) {

+	if (sock[i] != PJ_INVALID_SOCKET)

+	    pj_sock_close(sock[i]);

+    }

+    return -1;

+}

+

+static void log_function(int level, const char *buffer, int len)

+{

+    /* Write to both stdout and file. */

+    if (level <= global.app_log_level)

+	pj_log_to_stdout(level, buffer, len);

+    if (global.log_file) {

+	fwrite(buffer, len, 1, global.log_file);

+	fflush(global.log_file);

+    }

+}

+

+/* Initialize stack. */

+static pj_status_t init_stack()

+{

+    pj_status_t status;

+    pj_sockaddr_in bind_addr;

+    pj_sockaddr_in bind_name;

+    const char *local_addr;

+    static char local_uri[128];

+

+    /* Optionally set logging file. */

+    if (global.log_filename) {

+	global.log_file = fopen(global.log_filename, "wt");

+    }

+

+    /* Initialize endpoint. This will also call initialization to all the

+     * modules.

+     */

+    global.endpt = pjsip_endpt_create(global.pf);

+    if (global.endpt == NULL) {

+	return -1;

+    }

+

+    /* Set dialog callback. */

+    pjsip_ua_set_dialog_callback(global.user_agent, &dlg_callback);

+

+    /* Init listener's bound address and port. */

+    pj_sockaddr_init2(&bind_addr, "0.0.0.0", global.sip_port);

+    pj_sockaddr_init(&bind_name, pj_gethostname(), global.sip_port);

+

+    /* Add UDP transport listener. */

+    status = pjsip_endpt_create_udp_listener( global.endpt, global.sip_sock,

+					      &global.sip_sock_name);

+    if (status != 0)

+	return -1;

+

+    local_addr = pj_inet_ntoa(global.sip_sock_name.sin_addr);

+

+#if PJ_HAS_TCP

+    /* Add TCP transport listener. */

+    status = pjsip_endpt_create_listener( global.endpt, PJSIP_TRANSPORT_TCP, 

+					  &bind_addr, &bind_name);

+    if (status != 0)

+	return -1;

+#endif

+

+    /* Determine user_id to be put in Contact */

+    if (global.local_uri.slen) {

+	pj_pool_t *pool = pj_pool_create(global.pf, "parser", 1024, 0, NULL);

+	pjsip_uri *uri;

+

+	uri = pjsip_parse_uri(pool, global.local_uri.ptr, global.local_uri.slen, 0);

+	if (uri) {

+	    if (pj_stricmp2(pjsip_uri_get_scheme(uri), "sip")==0) {

+		pjsip_url *url = (pjsip_url*)pjsip_uri_get_uri(uri);

+		if (url->user.slen)

+		    strncpy(global.user_id, url->user.ptr, url->user.slen);

+	    }

+	} 

+	pj_pool_release(pool);

+    } 

+    

+    if (global.user_id[0]=='\0') {

+	pj_native_strcpy(global.user_id, "user");

+    }

+

+    /* build contact */

+    global.real_contact.ptr = local_uri;

+    global.real_contact.slen = 

+	sprintf(local_uri, "<sip:%s@%s:%d>", global.user_id, local_addr, global.sip_port);

+

+    if (global.contact.slen == 0)

+	global.contact = global.real_contact;

+

+    /* initialize local_uri with contact if it's not specified in cmdline */

+    if (global.local_uri.slen == 0)

+	global.local_uri = global.contact;

+

+    /* Init proxy. */

+    if (global.proxy.slen || global.outbound_proxy.slen) {

+	int count = 0;

+	pj_str_t proxy_url[2];

+

+	if (global.outbound_proxy.slen) {

+	    proxy_url[count++] = global.outbound_proxy;

+	}

+	if (global.proxy.slen) {

+	    proxy_url[count++] = global.proxy;

+	}

+

+	if (pjsip_endpt_set_proxies(global.endpt, count, proxy_url) != 0) {

+	    PJ_LOG(2,(THIS_FILE, "Error setting proxy address!"));

+	    return -1;

+	}

+    }

+

+    /* initialize SIP registration if registrar is configured */

+    if (global.registrar_uri.slen) {

+	global.regc = pjsip_regc_create( global.endpt, NULL, &regc_cb);

+	pjsip_regc_init( global.regc, &global.registrar_uri, 

+			 &global.local_uri, 

+			 &global.local_uri,

+			 1, &global.contact, 

+			 global.reg_timeout);

+	pjsip_regc_set_credentials( global.regc, global.cred_count, global.cred_info );

+    }

+

+    return PJ_SUCCESS;

+}

+

+/* Worker thread function, only used when threading is enabled. */

+static void *PJ_THREAD_FUNC worker_thread(void *unused)

+{

+    PJ_UNUSED_ARG(unused)

+

+    while (!global.worker_quit_flag) {

+	pj_time_val timeout = { 0, 10 };

+	pjsip_endpt_handle_events (global.endpt, &timeout);

+    }

+    return NULL;

+}

+

+

+/* Make call to the specified URI. */

+static pjsip_dlg *make_call(pj_str_t *remote_uri)

+{

+    pjsip_dlg *dlg;

+    pj_str_t local = global.contact;

+    pj_str_t remote = *remote_uri;

+    struct dialog_data *dlg_data;

+    pjsip_tx_data *tdata;

+    pj_media_sock_info sock_info;

+

+    /* Create new dialog instance. */

+    dlg = pjsip_ua_create_dialog(global.user_agent, PJSIP_ROLE_UAC);

+

+    /* Attach our own user data. */

+    dlg_data = pj_pool_calloc(dlg->pool, 1, sizeof(struct dialog_data));

+    dlg->user_data = dlg_data;

+

+    /* Create media session. */

+    pj_memset(&sock_info, 0, sizeof(sock_info));

+    sock_info.rtp_sock = global.rtp_sock;

+    sock_info.rtcp_sock = global.rtcp_sock;

+    pj_memcpy(&sock_info.rtp_addr_name, &global.rtp_sock_name, sizeof(pj_sockaddr_in));

+

+    dlg_data->msession = pj_media_session_create (global.mmgr, &sock_info);

+    dlg_data->x_ms_msg_session = -1;

+

+    if (global.offer_x_ms_msg) {

+	const pj_media_stream_info *minfo[32];

+	unsigned cnt;

+

+	cnt = pj_media_session_enum_streams(dlg_data->msession, 32, minfo);

+	if (cnt > 0)

+	    dlg_data->x_ms_msg_session = cnt;

+    } 

+

+    /* Initialize dialog with local and remote URI. */

+    if (pjsip_dlg_init(dlg, &local, &remote, NULL) != PJ_SUCCESS) {

+	pjsip_ua_destroy_dialog(dlg);

+	return NULL;

+    }

+

+    /* Initialize credentials. */

+    pjsip_dlg_set_credentials(dlg, global.cred_count, global.cred_info);

+

+    /* Send INVITE! */

+    tdata = pjsip_dlg_invite(dlg);

+    tdata->msg->body = create_msg_body (dlg, 0);

+

+    if (pjsip_dlg_send_msg(dlg, tdata) != PJ_SUCCESS) {

+	pjsip_ua_destroy_dialog(dlg);

+	return NULL;

+    }

+

+    return dlg;

+}

+

+/*

+ * Callback to receive incoming IM message.

+ */

+static int on_incoming_im_msg(pjsip_rx_data *rdata)

+{

+    pjsip_msg *msg = rdata->msg;

+    pjsip_msg_body *body = msg->body;

+    int len;

+    char to[128], from[128];

+

+

+    len = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR, 

+			   rdata->from->uri, from, sizeof(from));

+    if (len > 0) from[len] = '\0';

+    else pj_native_strcpy(from, "<URL too long..>");

+

+    len = pjsip_uri_print( PJSIP_URI_IN_CONTACT_HDR, 

+			   rdata->to->uri, to, sizeof(to));

+    if (len > 0) to[len] = '\0';

+    else pj_native_strcpy(to, "<URL too long..>");

+

+    PJ_LOG(3,(THIS_FILE, "Incoming instant message:"));

+    

+    printf("----- BEGIN INSTANT MESSAGE ----->\n");

+    printf("From:\t%s\n", from);

+    printf("To:\t%s\n", to);

+    printf("Body:\n%.*s\n", (body ? body->len : 0), (body ? (char*)body->data : ""));

+    printf("<------ END INSTANT MESSAGE ------\n");

+

+    fflush(stdout);

+

+    /* Must answer with final response. */

+    return 200;

+}

+

+/*

+ * Input URL.

+ */

+static pj_str_t *ui_input_url(pj_str_t *out, char *buf, int len, int *selection)

+{

+    int i;

+

+    *selection = -1;

+

+    printf("\nBuddy list:\n");

+    printf("---------------------------------------\n");

+    for (i=0; i<global.buddy_cnt; ++i) {

+	printf(" %d\t%s  <%s>\n", i+1, global.buddy[i].ptr,

+		(global.buddy_status[i]?"Online":"Offline"));

+    }

+    printf("-------------------------------------\n");

+

+    printf("Choices\n"

+	   "\t0        For current dialog.\n"

+	   "\t[1-%02d]   Select from buddy list\n"

+	   "\tURL      An URL\n"

+	   , global.buddy_cnt);

+    printf("Input: ");

+

+    fflush(stdout);

+    fgets(buf, len, stdin);

+    buf[strlen(buf)-1] = '\0'; /* remove trailing newline. */

+

+    while (isspace(*buf)) ++buf;

+

+    if (!*buf || *buf=='\n' || *buf=='\r')

+	return NULL;

+

+    i = atoi(buf);

+

+    if (i == 0) {

+	if (isdigit(*buf)) {

+	    *selection = 0;

+	    *out = pj_str("0");

+	    return out;

+	} else {

+	    if (verify_sip_url(buf) != 0) {

+		puts("Invalid URL specified!");

+		return NULL;

+	    }

+	    *out = pj_str(buf);

+	    return out;

+	}

+    } else if (i > global.buddy_cnt || i < 0) {

+	printf("Error: invalid selection!\n");

+	return NULL;

+    } else {

+	*out = global.buddy[i-1];

+	*selection = i;

+	return out;

+    }

+}

+

+

+static void generic_request_callback( void *token, pjsip_event *event )

+{

+    pjsip_transaction *tsx = event->obj.tsx;

+    

+    PJ_UNUSED_ARG(token)

+

+    if (tsx->status_code/100 == 2) {

+	PJ_LOG(3,(THIS_FILE, "Outgoing %.*s %d (%s)",

+		  event->obj.tsx->method.name.slen,

+		  event->obj.tsx->method.name.ptr,

+		  tsx->status_code,

+		  pjsip_get_status_text(tsx->status_code)->ptr));

+    } else if (tsx->status_code==401 || tsx->status_code==407)  {

+	pjsip_tx_data *tdata;

+	tdata = pjsip_auth_reinit_req( global.endpt,

+				       global.pool, NULL, global.cred_count, global.cred_info,

+				       tsx->last_tx, event->src.rdata);

+	if (tdata) {

+	    int rc;

+	    pjsip_cseq_hdr *cseq;

+	    cseq = (pjsip_cseq_hdr*)pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);

+	    cseq->cseq++;

+	    rc = pjsip_endpt_send_request( global.endpt, tdata, -1, NULL, 

+					    &generic_request_callback);

+	    if (rc == 0)

+		return;

+	}

+	PJ_LOG(2,(THIS_FILE, "Outgoing %.*s failed, status=%d (%s)",

+		  event->obj.tsx->method.name.slen,

+		  event->obj.tsx->method.name.ptr,

+		  event->obj.tsx->status_code,

+		  pjsip_get_status_text(event->obj.tsx->status_code)->ptr));

+    } else {

+	const pj_str_t *reason;

+	if (event->src_type == PJSIP_EVENT_RX_MSG)

+	    reason = &event->src.rdata->msg->line.status.reason;

+	else

+	    reason = pjsip_get_status_text(tsx->status_code);

+	PJ_LOG(2,(THIS_FILE, "Outgoing %.*s failed, status=%d (%.*s)",

+		  event->obj.tsx->method.name.slen,

+		  event->obj.tsx->method.name.ptr,

+		  event->obj.tsx->status_code,

+		  reason->slen, reason->ptr));

+    }

+}

+

+

+static void ui_send_im_message()

+{

+    char line[100];

+    char text_buf[100];

+    pj_str_t str;

+    pj_str_t text_msg;

+    int selection, rc;

+    pjsip_tx_data *tdata;

+  

+    if (ui_input_url(&str, line, sizeof(line), &selection) == NULL)

+	return;

+

+	

+    printf("Enter text to send (empty to cancel): "); fflush(stdout);

+    fgets(text_buf, sizeof(text_buf), stdin);

+    text_buf[strlen(text_buf)-1] = '\0';

+    if (!*text_buf)

+	return;

+

+    text_msg = pj_str(text_buf);

+    

+    if (selection==0) {

+	pjsip_method message_method;

+	pj_str_t str_MESSAGE = { "MESSAGE", 7 };

+

+	/* Send IM to current dialog. */

+	if (global.cur_dlg == NULL || global.cur_dlg->state != PJSIP_DIALOG_STATE_ESTABLISHED) {

+	    printf("No current dialog or dialog state is not ESTABLISHED!\n");

+	    return;

+	}

+

+	pjsip_method_init( &message_method, global.cur_dlg->pool, &str_MESSAGE);

+	tdata = pjsip_dlg_create_request( global.cur_dlg, &message_method, -1 );

+

+	if (tdata) {

+	    /* Create message body for the text. */

+	    pjsip_msg_body *body = pj_pool_calloc(tdata->pool, 1, sizeof(*body));

+	    body->content_type.type = pj_str("text");

+	    body->content_type.subtype = pj_str("plain");

+	    body->data = pj_pool_alloc(tdata->pool, text_msg.slen);

+	    pj_memcpy(body->data, text_msg.ptr, text_msg.slen);

+	    body->len = text_msg.slen;

+	    body->print_body = &pjsip_print_text_body;

+

+	    /* Assign body to message, and send the message! */

+	    tdata->msg->body = body;

+	    pjsip_dlg_send_msg( global.cur_dlg, tdata );

+	}

+

+    } else {

+	/* Send IM to buddy list. */

+	pjsip_method message;

+	static pj_str_t MESSAGE = { "MESSAGE", 7 };

+	pjsip_method_init_np(&message, &MESSAGE);

+	tdata = pjsip_endpt_create_request(global.endpt, &message, 

+					   &str,

+					   &global.real_contact,

+				           &str, &global.real_contact, NULL, -1, 

+					   &text_msg);

+	if (!tdata) {

+	    puts("Error creating request");

+	    return;

+	}

+	rc = pjsip_endpt_send_request(global.endpt, tdata, -1, NULL, &generic_request_callback);

+	if (rc == 0) {

+	    printf("Sending IM message %d\n", global.im_counter);

+	    ++global.im_counter;

+	} else {

+	    printf("Error: unable to send IM message!\n");

+	}

+    }

+}

+

+static void ui_send_options()

+{

+    char line[100];

+    pj_str_t str;

+    int selection, rc;

+    pjsip_tx_data *tdata;

+    pjsip_method options;

+

+    if (ui_input_url(&str, line, sizeof(line), &selection) == NULL)

+	return;

+

+    pjsip_method_set( &options, PJSIP_OPTIONS_METHOD );

+

+    if (selection == 0) {

+	/* Send OPTIONS to current dialog. */

+	tdata = pjsip_dlg_create_request(global.cur_dlg, &options, -1);

+	if (tdata)

+	    pjsip_dlg_send_msg( global.cur_dlg, tdata );

+    } else {

+	/* Send OPTIONS to arbitrary party. */

+	tdata = pjsip_endpt_create_request( global.endpt, &options,

+					    &str,

+					    &global.local_uri, &str, 

+					    &global.real_contact,

+					    NULL, -1, NULL);

+	if (tdata) {

+	    rc = pjsip_endpt_send_request( global.endpt, tdata, -1, NULL, 

+					   &generic_request_callback);

+	    if (rc != 0)

+		PJ_LOG(2,(THIS_FILE, "Error sending OPTIONS!"));

+	}

+    }

+}

+

+static void init_presence()

+{

+    const pjsip_presence_cb pres_cb = {

+	NULL,

+	&pres_on_received_request,

+	&pres_on_received_refresh,

+	&pres_on_received_update,

+	&pres_on_terminated

+    };

+

+    pjsip_presence_init(&pres_cb);

+}

+

+/* Subscribe presence information for all buddies. */

+static void subscribe_buddies_presence()

+{

+    int i;

+    for (i=0; i<global.buddy_cnt; ++i) {

+	pjsip_presentity *pres;

+	if (global.buddy_pres[i])

+	    continue;

+	pres = pjsip_presence_create( global.endpt, &global.local_uri,

+				      &global.buddy[i], PRESENCE_TIMEOUT, (void*)i);

+	if (pres) {

+	    pjsip_presence_set_credentials( pres, global.cred_count, global.cred_info );

+	    pjsip_presence_subscribe( pres );

+	}

+	global.buddy_pres[i] = pres;

+    }

+}

+

+/* Unsubscribe presence information for all buddies. */

+static void unsubscribe_buddies_presence()

+{

+    int i;

+    for (i=0; i<global.buddy_cnt; ++i) {

+	pjsip_presentity *pres = global.buddy_pres[i];

+	if (pres) {

+	    pjsip_presence_unsubscribe(pres);

+	    pjsip_presence_destroy(pres);

+	    global.buddy_pres[i] = NULL;

+	}

+    }

+}

+

+/* Unsubscribe presence. */

+static void unsubscribe_presence()

+{

+    int i;

+

+    unsubscribe_buddies_presence();

+    for (i=0; i<global.pres_cnt; ++i) {

+	pjsip_presentity *pres = global.pres[i];

+	pjsip_presence_notify( pres, PJSIP_EVENT_SUB_STATE_TERMINATED, 0);

+	pjsip_presence_destroy( pres );

+    }

+}

+

+/* Advertise online status to subscribers. */

+static void update_im_status()

+{

+    int i;

+    for (i=0; i<global.pres_cnt; ++i) {

+	pjsip_presentity *pres = global.pres[i];

+	pjsip_presence_notify( pres, PJSIP_EVENT_SUB_STATE_ACTIVE, 

+			       !global.hide_status);

+    }

+}

+

+/*

+ * Main program.

+ */

+int main(int argc, char *argv[])

+{

+    /* set to WORKER_COUNT+1 to avoid zero size warning 

+     * when threading is disabled. */

+    pj_thread_t *thread[WORKER_COUNT+1];

+    pj_caching_pool cp;

+    int i;

+

+    global.sip_port = 5060;

+    global.auto_answer = -1;

+    global.auto_hangup = -1;

+    global.app_log_level = 3;

+

+    pj_log_set_level(4);

+    pj_log_set_log_func(&log_function);

+

+    /* Init PJLIB */

+    if (pj_init() != PJ_SUCCESS)

+	return 1;

+

+    /* Init caching pool. */

+    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);

+    global.pf = &cp.factory;

+

+    /* Create memory pool for application. */

+    global.pool = pj_pool_create(global.pf, "main", 1024, 0, NULL);

+

+    /* Parse command line arguments. */

+    if (parse_args(global.pool, argc, argv) != PJ_SUCCESS) {

+	pj_caching_pool_destroy(&cp);

+	return 1;

+    }

+

+    /* Init sockets */

+    if (init_sockets() != 0) {

+	pj_caching_pool_destroy(&cp);

+	return 1;

+    }

+

+    /* Initialize stack. */

+    if (init_stack() != PJ_SUCCESS) {

+	pj_caching_pool_destroy(&cp);

+	return 1;

+    }

+

+    /* Set callback to receive incoming IM */

+    pjsip_messaging_set_incoming_callback( &on_incoming_im_msg );

+

+    /* Set default worker count (can be zero) */

+    global.worker_cnt = WORKER_COUNT;

+

+    /* Create user worker thread(s), only when threading is enabled. */

+    for (i=0; i<global.worker_cnt; ++i) {

+	thread[i] = pj_thread_create( global.pool, "sip%p", 

+				      &worker_thread, 

+				      NULL, 0, NULL, 0);

+	if (thread == NULL) {

+	    global.worker_quit_flag = 1;

+	    for (--i; i>=0; --i) {

+		pj_thread_join(thread[i]);

+		pj_thread_destroy(thread[i]);

+	    }

+	    pj_caching_pool_destroy(&cp);

+	    return 1;

+	}

+    }

+

+    printf("Worker thread count: %d\n", global.worker_cnt);

+

+    /* Perform registration, if required. */

+    if (global.regc) {

+	update_registration(global.regc, 1);

+    }

+

+    /* Initialize media manager. */

+    global.mmgr = pj_med_mgr_create(global.pf);

+

+    /* Init presence. */

+    init_presence();

+

+    /* Subscribe presence information of all buddies. */

+    if (!global.no_presence)

+	subscribe_buddies_presence();

+

+    /* Initializatio completes, loop waiting for commands. */

+    for (;!global.worker_quit_flag;) {

+	pj_str_t str;

+	char line[128];

+

+#if WORKER_COUNT==0

+	/* If worker thread does not exist, main thread must poll for evetns. 

+	 * But this won't work very well since main thread is blocked by 

+	 * fgets(). So keep pressing the ENTER key to get the events!

+	 */

+	pj_time_val timeout = { 0, 100 };

+	pjsip_endpt_handle_events(global.endpt, &timeout);

+	puts("Keep pressing ENTER key to get the events!");

+#endif

+

+	printf("\nCurrent dialog: ");

+	print_dialog(global.cur_dlg);

+	puts("");

+

+	keystroke_help();

+

+	fgets(line, sizeof(line), stdin);

+

+	switch (*line) {

+	case 'm':

+	    puts("Make outgoing call");

+	    if (ui_input_url(&str, line, sizeof(line), &i) != NULL) {

+		pjsip_dlg *dlg = make_call(&str);

+		if (global.cur_dlg == NULL) {

+		    global.cur_dlg = dlg;

+		}

+	    }

+	    break;

+	case 'i':

+	    puts("Send Instant Messaging");

+	    ui_send_im_message();

+	    break;

+	case 'o':

+	    puts("Send OPTIONS");

+	    ui_send_options();

+	    break;

+	case 'a':

+	    if (global.cur_dlg) {

+		unsigned code;

+		pjsip_tx_data *tdata;

+		struct dialog_data *dlg_data = global.cur_dlg->user_data;

+

+		printf("Answer with status code (1xx-6xx): ");

+		fflush(stdout);

+		fgets(line, sizeof(line), stdin);

+		str = pj_str(line);

+		str.slen -= 1;

+

+		code = pj_strtoul(&str);

+		tdata = pjsip_dlg_answer(global.cur_dlg, code);

+		if (tdata) {

+		    if (code/100 == 2) {

+			tdata->msg->body = dlg_data->body;

+		    }

+		    pjsip_dlg_send_msg(global.cur_dlg, tdata);

+

+		}

+	    } else {

+		puts("No current dialog");

+	    }

+	    break;

+	case 'h':

+	    if (global.cur_dlg) {

+		pjsip_tx_data *tdata;

+		tdata = pjsip_dlg_disconnect(global.cur_dlg, PJSIP_SC_DECLINE);

+		if (tdata) {

+		    pjsip_dlg_send_msg(global.cur_dlg, tdata);

+		}

+	    } else {

+		puts("No current dialog");

+	    }

+	    break;

+	case ']':

+	    if (global.cur_dlg) {

+		global.cur_dlg = global.cur_dlg->next;

+		if (global.cur_dlg == (void*)&global.user_agent->dlg_list) {

+		    global.cur_dlg = global.cur_dlg->next;

+		}

+	    } else {

+		puts("No current dialog");

+	    }

+	    break;

+	case '[':

+	    if (global.cur_dlg) {

+		global.cur_dlg = global.cur_dlg->prev;

+		if (global.cur_dlg == (void*)&global.user_agent->dlg_list) {

+		    global.cur_dlg = global.cur_dlg->prev;

+		}

+	    } else {

+		puts("No current dialog");

+	    }

+	    break;

+	case 'd':

+	    pjsip_endpt_dump(global.endpt, *(line+1)=='1');

+	    pjsip_ua_dump(global.user_agent);

+	    break;

+	case 's':

+	    if (*(line+1) == 'u')

+		subscribe_buddies_presence();

+	    break;

+	case 'u':

+	    if (*(line+1) == 's')

+		unsubscribe_presence();

+	    break;

+	case 't':

+	    global.hide_status = !global.hide_status;

+	    update_im_status();

+	    break;

+	case 'q':

+	    goto on_exit;

+	case 'l':

+	    print_all_dialogs();

+	    break;

+	}

+    }

+

+on_exit:

+    /* Unregister, if required. */

+    if (global.regc) {

+	update_registration(global.regc, 0);

+    }

+

+    /* Unsubscribe presence. */

+    unsubscribe_presence();

+

+    /* Allow one second to get all events. */

+    if (1) {

+	pj_time_val end_time;

+

+	pj_gettimeofday(&end_time);

+	end_time.sec++;

+

+	PJ_LOG(3,(THIS_FILE, "Shutting down.."));

+	for (;;) {

+	    pj_time_val timeout = { 0, 20 }, now;

+	    pjsip_endpt_handle_events (global.endpt, &timeout);

+	    pj_gettimeofday(&now);

+	    PJ_TIME_VAL_SUB(now, end_time);

+	    if (now.sec >= 1)

+		break;

+	}

+    }

+

+    global.worker_quit_flag = 1;

+

+    pj_med_mgr_destroy(global.mmgr);

+

+    /* Wait all threads to quit. */

+    for (i=0; i<global.worker_cnt; ++i) {

+	pj_thread_join(thread[i]);

+	pj_thread_destroy(thread[i]);

+    }

+

+    /* Destroy endpoint. */

+    pjsip_endpt_destroy(global.endpt);

+

+    /* Destroy caching pool. */

+    pj_caching_pool_destroy(&cp);

+

+    /* Close log file, if any. */

+    if (global.log_file)

+	fclose(global.log_file);

+

+    return 0;

+}

+

+/*

+ * Register static modules to the endpoint.

+ */

+pj_status_t register_static_modules( pj_size_t *count,

+				     pjsip_module **modules )

+{

+    /* Reset count. */

+    *count = 0;

+

+    /* Register user agent module. */

+    modules[(*count)++] = pjsip_ua_get_module();

+    global.user_agent = modules[0]->mod_data;

+    modules[(*count)++] = pjsip_messaging_get_module();

+    modules[(*count)++] = pjsip_event_sub_get_module();

+

+    return PJ_SUCCESS;

+}

diff --git a/pjsip/src/pjsua/misc.c b/pjsip/src/pjsua/misc.c
index 58cc795..d5a1c99 100644
--- a/pjsip/src/pjsua/misc.c
+++ b/pjsip/src/pjsua/misc.c
@@ -1,470 +1,492 @@
-/* $Id$
- *
- */
-
-/*
- * THIS FILE IS INCLUDED BY main.c.
- * IT WON'T COMPILE BY ITSELF.
- */
-
-#include "getopt.h"
-#include <stdio.h>
- 
-
-/*
- * Display program usage
- */
-static void usage()
-{
-    puts("Usage:");
-    puts("  pjsua [options] [sip-url]");
-    puts("");
-    puts("  [sip-url]   Default URL to invite.");
-    puts("");
-    puts("General options:");
-    puts("  --config-file=file  Read the config/arguments from file.");
-    puts("  --log-file=fname    Log to filename (default stderr)");
-    puts("  --log-level=N       Set log max level to N (0(none) to 6(trace))");
-    puts("  --app-log-level=N   Set log max level for stdout display to N");
-    puts("  --help              Display this help screen");
-    puts("  --version           Display version info");
-    puts("");
-    puts("Media options:");
-    puts("  --null-audio        Use NULL audio device");
-    puts("");
-    puts("User Agent options:");
-    puts("  --auto-answer=sec   Auto-answer all incoming calls after sec seconds.");
-    puts("  --auto-hangup=sec   Auto-hangup all calls after sec seconds.");
-    puts("");
-    puts("SIP options:");
-    puts("  --local-port=port   Set TCP/UDP port");
-    puts("  --id=url            Set the URL of local ID (used in From header)");
-    puts("  --contact=url       Override the Contact information");
-    puts("  --proxy=url         Set the URL of proxy server");
-    puts("  --outbound=url      Set the URL of outbound proxy server");
-    puts("  --registrar=url     Set the URL of registrar server");
-    puts("  --reg-timeout=secs  Set registration interval to secs (default 3600)");
-    puts("");
-    puts("Authentication options:");
-    puts("  --realm=string      Set realm");
-    puts("  --username=string   Set authentication username");
-    puts("  --password=string   Set authentication password");
-    puts("");
-    puts("STUN options (all must be specified):");
-    puts("  --use-stun1=host[:port]");
-    puts("  --use-stun2=host[:port]  Use STUN and set host name and port of STUN servers");
-    puts("");
-    puts("SIMPLE options (may be specified more than once):");
-    puts("  --add-buddy url     Add the specified URL to the buddy list.");
-    puts("  --offer-x-ms-msg    Offer \"x-ms-message\" in outgoing INVITE");
-    puts("  --no-presence	Do not subscribe presence of buddies");
-    puts("");
-    fflush(stdout);
-}
-
-/* Display keystroke help. */
-static void keystroke_help()
-{
-    int i;
-
-    printf("Advertise status as: %s\n", (global.hide_status ? "Offline" : "Online"));
-    puts("");
-    puts("Buddy list:");
-    puts("-------------------------------------------------------------------------------");
-    for (i=0; i<global.buddy_cnt; ++i) {
-	printf(" %d\t%s  <%s>\n", i+1, global.buddy[i].ptr,
-		(global.buddy_status[i]?"Online":"Offline"));
-    }
-    //printf("-------------------------------------\n");
-    puts("");
-    //puts("Commands:");
-    puts("+=============================================================================+");
-    puts("|       Call Commands:         |      IM & Presence:      |   Misc:           |");
-    puts("|                              |                          |                   |");
-    puts("|  m  Make new call            |  i  Send IM              |  o  Send OPTIONS  |");
-    puts("|  a  Answer call              | su  Subscribe presence   |  d  Dump status   |");
-    puts("|  h  Hangup call              | us  Unsubscribe presence |  d1 Dump detailed |");
-    puts("|  ]  Select next dialog       |  t  Toggle Online status |                   |");
-    puts("|  [  Select previous dialog   |                          |                   |");
-    puts("+-----------------------------------------------------------------------------+");
-    puts("|  q  QUIT                                                                    |");
-    puts("+=============================================================================+");
-    puts("");
-
-
-    fflush(stdout);
-}
-
-/*
- * Verify that valid SIP url is given.
- */
-static pj_status_t verify_sip_url(char *url)
-{
-    pjsip_uri *p;
-    pj_pool_t *pool;
-    int len = (url ? strlen(url) : 0);
-
-    if (!len) return -1;
-
-    pool = pj_pool_create(global.pf, "check%p", 1024, 0, NULL);
-    if (!pool) return -1;
-
-    p = pjsip_parse_uri(pool, url, len, 0);
-    if (!p || pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0)
-	p = NULL;
-
-    pj_pool_release(pool);
-    return p ? 0 : -1;
-}
-
-/*
- * Read command arguments from config file.
- */
-static int read_config_file(pj_pool_t *pool, const char *filename, 
-			    int *app_argc, char ***app_argv)
-{
-    int i;
-    FILE *fhnd;
-    char line[200];
-    int argc = 0;
-    char **argv;
-    enum { MAX_ARGS = 64 };
-
-    /* Allocate MAX_ARGS+1 (argv needs to be terminated with NULL argument) */
-    argv = pj_pool_calloc(pool, MAX_ARGS+1, sizeof(char*));
-    argv[argc++] = *app_argv[0];
-
-    /* Open config file. */
-    fhnd = fopen(filename, "rt");
-    if (!fhnd) {
-	printf("Unable to open config file %s\n", filename);
-	return -1;
-    }
-
-    /* Scan tokens in the file. */
-    while (argc < MAX_ARGS && !feof(fhnd)) {
-	char *token, *p = line;
-
-	if (fgets(line, sizeof(line), fhnd) == NULL) break;
-
-	for (token = strtok(p, " \t\r\n"); argc < MAX_ARGS; 
-	     token = strtok(NULL, " \t\r\n"))
-	{
-	    int token_len;
-	    
-	    if (!token) break;
-	    if (*token == '#') break;
-
-	    token_len = strlen(token);
-	    if (!token_len)
-		continue;
-	    argv[argc] = pj_pool_alloc(pool, token_len+1);
-	    pj_memcpy(argv[argc], token, token_len+1);
-	    ++argc;
-	}
-    }
-
-    /* Copy arguments from command line */
-    for (i=1; i<*app_argc && argc < MAX_ARGS; ++i)
-	argv[argc++] = (*app_argv)[i];
-
-    if (argc == MAX_ARGS && (i!=*app_argc || !feof(fhnd))) {
-	printf("Too many arguments specified in cmd line/config file\n");
-	fclose(fhnd);
-	return -1;
-    }
-
-    fclose(fhnd);
-
-    /* Assign the new command line back to the original command line. */
-    *app_argc = argc;
-    *app_argv = argv;
-    return 0;
-
-}
-
-/*
- * Parse program arguments
- */
-static int parse_args(pj_pool_t *pool, int argc, char *argv[])
-{
-    int c;
-    int option_index;
-    enum { OPT_CONFIG_FILE, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL, 
-	   OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO,
-	   OPT_LOCAL_PORT, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR,
-	   OPT_REG_TIMEOUT, OPT_ID, OPT_CONTACT, 
-	   OPT_REALM, OPT_USERNAME, OPT_PASSWORD,
-	   OPT_USE_STUN1, OPT_USE_STUN2, 
-	   OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
-	   OPT_AUTO_ANSWER, OPT_AUTO_HANGUP};
-    struct option long_options[] = {
-	{ "config-file",1, 0, OPT_CONFIG_FILE},
-	{ "log-file",	1, 0, OPT_LOG_FILE},
-	{ "log-level",	1, 0, OPT_LOG_LEVEL},
-	{ "app-log-level",1,0,OPT_APP_LOG_LEVEL},
-	{ "help",	0, 0, OPT_HELP},
-	{ "version",	0, 0, OPT_VERSION},
-	{ "null-audio", 0, 0, OPT_NULL_AUDIO},
-	{ "local-port", 1, 0, OPT_LOCAL_PORT},
-	{ "proxy",	1, 0, OPT_PROXY},
-	{ "outbound",	1, 0, OPT_OUTBOUND_PROXY},
-	{ "registrar",	1, 0, OPT_REGISTRAR},
-	{ "reg-timeout",1, 0, OPT_REG_TIMEOUT},
-	{ "id",		1, 0, OPT_ID},
-	{ "contact",	1, 0, OPT_CONTACT},
-	{ "realm",	1, 0, OPT_REALM},
-	{ "username",	1, 0, OPT_USERNAME},
-	{ "password",	1, 0, OPT_PASSWORD},
-	{ "use-stun1",  1, 0, OPT_USE_STUN1},
-	{ "use-stun2",  1, 0, OPT_USE_STUN2},
-	{ "add-buddy",  1, 0, OPT_ADD_BUDDY},
-	{ "offer-x-ms-msg",0,0,OPT_OFFER_X_MS_MSG},
-	{ "no-presence", 0, 0, OPT_NO_PRESENCE},
-	{ "auto-answer",1, 0, OPT_AUTO_ANSWER},
-	{ "auto-hangup",1, 0, OPT_AUTO_HANGUP},
-	{ NULL, 0, 0, 0}
-    };
-    char *config_file = NULL;
-
-    /* Run getopt once to see if user specifies config file to read. */
-    while ((c=getopt_long(argc, argv, "", long_options, &option_index)) != -1) {
-	switch (c) {
-	case 0:
-	    config_file = optarg;
-	    break;
-	}
-	if (config_file)
-	    break;
-    }
-
-    if (config_file) {
-	if (read_config_file(pool, config_file, &argc, &argv) != 0)
-	    return -1;
-    }
-
-    /* Reinitialize and re-run getopt again, possibly with new arguments
-     * read from config file.
-     */
-    optind = 0;
-    while ((c=getopt_long(argc, argv, "", long_options, &option_index)) != -1) {
-	char *err, *p;
-
-	switch (c) {
-	case OPT_LOG_FILE:
-	    global.log_filename = optarg;
-	    break;
-	case OPT_LOG_LEVEL:
-	    c = strtoul(optarg, &err, 10);
-	    if (*err) {
-		printf("Error: expecting integer value 0-6 for --log-level\n");
-		return -1;
-	    }
-	    pj_log_set_level( c );
-	    break;
-	case OPT_APP_LOG_LEVEL:
-	    global.app_log_level = strtoul(optarg, &err, 10);
-	    if (*err) {
-		printf("Error: expecting integer value 0-6 for --app-log-level\n");
-		return -1;
-	    }
-	    break;
-	case OPT_HELP:
-	    usage();
-	    return -1;
-	case OPT_VERSION:   /* version */
-	    pj_dump_config();
-	    return -1;
-	case OPT_NULL_AUDIO:
-	    global.null_audio = 1;
-	    break;
-	case OPT_LOCAL_PORT:   /* local-port */
-	    global.sip_port = strtoul(optarg, &err, 10);
-	    if (*err) {
-		printf("Error: expecting integer value for --local-port\n");
-		return -1;
-	    }
-	    break;
-	case OPT_PROXY:   /* proxy */
-	    if (verify_sip_url(optarg) != 0) {
-		printf("Error: invalid SIP URL '%s' in proxy argument\n", optarg);
-		return -1;
-	    }
-	    global.proxy = pj_str(optarg);
-	    break;
-	case OPT_OUTBOUND_PROXY:   /* outbound proxy */
-	    if (verify_sip_url(optarg) != 0) {
-		printf("Error: invalid SIP URL '%s' in outbound proxy argument\n", optarg);
-		return -1;
-	    }
-	    global.outbound_proxy = pj_str(optarg);
-	    break;
-	case OPT_REGISTRAR:   /* registrar */
-	    if (verify_sip_url(optarg) != 0) {
-		printf("Error: invalid SIP URL '%s' in registrar argument\n", optarg);
-		return -1;
-	    }
-	    global.registrar_uri = pj_str(optarg);
-	    break;
-	case OPT_REG_TIMEOUT:   /* reg-timeout */
-	    global.reg_timeout = strtoul(optarg, &err, 10);
-	    if (*err) {
-		printf("Error: expecting integer value for --reg-timeout\n");
-		return -1;
-	    }
-	    break;
-	case OPT_ID:   /* id */
-	    if (verify_sip_url(optarg) != 0) {
-		printf("Error: invalid SIP URL '%s' in local id argument\n", optarg);
-		return -1;
-	    }
-	    global.local_uri = pj_str(optarg);
-	    break;
-	case OPT_CONTACT:   /* contact */
-	    if (verify_sip_url(optarg) != 0) {
-		printf("Error: invalid SIP URL '%s' in contact argument\n", optarg);
-		return -1;
-	    }
-	    global.contact = pj_str(optarg);
-	    break;
-	case OPT_USERNAME:   /* Default authentication user */
-	    if (!global.cred_count) global.cred_count = 1;
-	    global.cred_info[0].username = pj_str(optarg);
-	    break;
-	case OPT_REALM:	    /* Default authentication realm. */
-	    if (!global.cred_count) global.cred_count = 1;
-	    global.cred_info[0].realm = pj_str(optarg);
-	    break;
-	case OPT_PASSWORD:   /* authentication password */
-	    if (!global.cred_count) global.cred_count = 1;
-	    global.cred_info[0].data_type = 0;
-	    global.cred_info[0].data = pj_str(optarg);
-	    break;
-	case OPT_USE_STUN1:   /* STUN server 1 */
-	    p = pj_native_strchr(optarg, ':');
-	    if (p) {
-		*p = '\0';
-		global.stun_srv1 = pj_str(optarg);
-		global.stun_port1 = strtoul(p+1, &err, 10);
-		if (*err || global.stun_port1==0) {
-		    printf("Error: expecting port number with option --use-stun1\n");
-		    return -1;
-		}
-	    } else {
-		global.stun_port1 = 3478;
-		global.stun_srv1 = pj_str(optarg);
-	    }
-	    break;
-	case OPT_USE_STUN2:   /* STUN server 2 */
-	    p = pj_native_strchr(optarg, ':');
-	    if (p) {
-		*p = '\0';
-		global.stun_srv2 = pj_str(optarg);
-		global.stun_port2 = strtoul(p+1, &err, 10);
-		if (*err || global.stun_port2==0) {
-		    printf("Error: expecting port number with option --use-stun2\n");
-		    return -1;
-		}
-	    } else {
-		global.stun_port2 = 3478;
-		global.stun_srv2 = pj_str(optarg);
-	    }
-	    break;
-	case OPT_ADD_BUDDY: /* Add to buddy list. */
-	    if (verify_sip_url(optarg) != 0) {
-		printf("Error: invalid URL '%s' in --add-buddy option\n", optarg);
-		return -1;
-	    }
-	    if (global.buddy_cnt == MAX_BUDDIES) {
-		printf("Error: too many buddies in buddy list.\n");
-		return -1;
-	    }
-	    global.buddy[global.buddy_cnt++] = pj_str(optarg);
-	    break;
-	case OPT_OFFER_X_MS_MSG:
-	    global.offer_x_ms_msg = 1;
-	    break;
-	case OPT_NO_PRESENCE:
-	    global.no_presence = 1;
-	    break;
-	case OPT_AUTO_ANSWER:
-	    global.auto_answer = strtoul(optarg, &err, 10);
-	    if (*err) {
-		printf("Error: expecting integer value for --auto-answer option\n");
-		return -1;
-	    }
-	    break;
-	case OPT_AUTO_HANGUP:
-	    global.auto_hangup = strtoul(optarg, &err, 10);
-	    if (*err) {
-		printf("Error: expecting integer value for --auto-hangup option\n");
-		return -1;
-	    }
-	    break;
-	}
-    }
-
-    if (optind != argc) {
-	printf("Error: unknown options %s\n", argv[optind]);
-	return -1;
-    }
-
-    if (global.reg_timeout == 0)
-	global.reg_timeout = 3600;
-
-    return 0;
-}
-
-/* Print dialog. */
-static void print_dialog(pjsip_dlg *dlg)
-{
-    if (!dlg) {
-	puts("none");
-	return;
-    }
-
-    printf("%s: call-id=%.*s", dlg->obj_name, 
-			       (int)dlg->call_id->id.slen, 
-			       dlg->call_id->id.ptr);
-
-    printf(" (%s, %s)\n", pjsip_role_name(dlg->role),
-			  pjsip_dlg_state_str(dlg->state));
-}
-
-/* Dump media statistic */
-void dump_media_statistic(pjsip_dlg *dlg)
-{
-    struct dialog_data *dlg_data = dlg->user_data;
-    pj_media_stream_stat stat[2];
-    const char *statname[2] = { "TX", "RX" };
-    int i;
-
-    pj_media_session_get_stat (dlg_data->msession, 0, &stat[0], &stat[1]);
-
-    printf("Media statistic:\n");
-    for (i=0; i<2; ++i) {
-	printf("  %s statistics:\n", statname[i]);
-	printf("    Pkt      TX=%d RX=%d\n", stat[i].pkt_tx, stat[i].pkt_rx);
-	printf("    Octets   TX=%d RX=%d\n", stat[i].oct_tx, stat[i].oct_rx);
-	printf("    Jitter   %d ms\n", stat[i].jitter);
-	printf("    Pkt lost %d\n", stat[i].pkt_lost);
-    }
-    printf("\n");
-}
-
-/* Print all dialogs. */
-static void print_all_dialogs()
-{
-    pjsip_dlg *dlg = (pjsip_dlg *)global.user_agent->dlg_list.next;
-
-    puts("List all dialogs:");
-
-    while (dlg != (pjsip_dlg *) &global.user_agent->dlg_list) {
-	printf("%c", (dlg==global.cur_dlg ? '*' : ' '));
-	print_dialog(dlg);
-	dlg = dlg->next;
-    }
-
-    puts("");
-}
-
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+

+/*

+ * THIS FILE IS INCLUDED BY main.c.

+ * IT WON'T COMPILE BY ITSELF.

+ */

+

+#include "getopt.h"

+#include <stdio.h>

+ 

+

+/*

+ * Display program usage

+ */

+static void usage()

+{

+    puts("Usage:");

+    puts("  pjsua [options] [sip-url]");

+    puts("");

+    puts("  [sip-url]   Default URL to invite.");

+    puts("");

+    puts("General options:");

+    puts("  --config-file=file  Read the config/arguments from file.");

+    puts("  --log-file=fname    Log to filename (default stderr)");

+    puts("  --log-level=N       Set log max level to N (0(none) to 6(trace))");

+    puts("  --app-log-level=N   Set log max level for stdout display to N");

+    puts("  --help              Display this help screen");

+    puts("  --version           Display version info");

+    puts("");

+    puts("Media options:");

+    puts("  --null-audio        Use NULL audio device");

+    puts("");

+    puts("User Agent options:");

+    puts("  --auto-answer=sec   Auto-answer all incoming calls after sec seconds.");

+    puts("  --auto-hangup=sec   Auto-hangup all calls after sec seconds.");

+    puts("");

+    puts("SIP options:");

+    puts("  --local-port=port   Set TCP/UDP port");

+    puts("  --id=url            Set the URL of local ID (used in From header)");

+    puts("  --contact=url       Override the Contact information");

+    puts("  --proxy=url         Set the URL of proxy server");

+    puts("  --outbound=url      Set the URL of outbound proxy server");

+    puts("  --registrar=url     Set the URL of registrar server");

+    puts("  --reg-timeout=secs  Set registration interval to secs (default 3600)");

+    puts("");

+    puts("Authentication options:");

+    puts("  --realm=string      Set realm");

+    puts("  --username=string   Set authentication username");

+    puts("  --password=string   Set authentication password");

+    puts("");

+    puts("STUN options (all must be specified):");

+    puts("  --use-stun1=host[:port]");

+    puts("  --use-stun2=host[:port]  Use STUN and set host name and port of STUN servers");

+    puts("");

+    puts("SIMPLE options (may be specified more than once):");

+    puts("  --add-buddy url     Add the specified URL to the buddy list.");

+    puts("  --offer-x-ms-msg    Offer \"x-ms-message\" in outgoing INVITE");

+    puts("  --no-presence	Do not subscribe presence of buddies");

+    puts("");

+    fflush(stdout);

+}

+

+/* Display keystroke help. */

+static void keystroke_help()

+{

+    int i;

+

+    printf("Advertise status as: %s\n", (global.hide_status ? "Offline" : "Online"));

+    puts("");

+    puts("Buddy list:");

+    puts("-------------------------------------------------------------------------------");

+    for (i=0; i<global.buddy_cnt; ++i) {

+	printf(" %d\t%s  <%s>\n", i+1, global.buddy[i].ptr,

+		(global.buddy_status[i]?"Online":"Offline"));

+    }

+    //printf("-------------------------------------\n");

+    puts("");

+    //puts("Commands:");

+    puts("+=============================================================================+");

+    puts("|       Call Commands:         |      IM & Presence:      |   Misc:           |");

+    puts("|                              |                          |                   |");

+    puts("|  m  Make new call            |  i  Send IM              |  o  Send OPTIONS  |");

+    puts("|  a  Answer call              | su  Subscribe presence   |  d  Dump status   |");

+    puts("|  h  Hangup call              | us  Unsubscribe presence |  d1 Dump detailed |");

+    puts("|  ]  Select next dialog       |  t  Toggle Online status |                   |");

+    puts("|  [  Select previous dialog   |                          |                   |");

+    puts("+-----------------------------------------------------------------------------+");

+    puts("|  q  QUIT                                                                    |");

+    puts("+=============================================================================+");

+    puts("");

+

+

+    fflush(stdout);

+}

+

+/*

+ * Verify that valid SIP url is given.

+ */

+static pj_status_t verify_sip_url(char *url)

+{

+    pjsip_uri *p;

+    pj_pool_t *pool;

+    int len = (url ? strlen(url) : 0);

+

+    if (!len) return -1;

+

+    pool = pj_pool_create(global.pf, "check%p", 1024, 0, NULL);

+    if (!pool) return -1;

+

+    p = pjsip_parse_uri(pool, url, len, 0);

+    if (!p || pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0)

+	p = NULL;

+

+    pj_pool_release(pool);

+    return p ? 0 : -1;

+}

+

+/*

+ * Read command arguments from config file.

+ */

+static int read_config_file(pj_pool_t *pool, const char *filename, 

+			    int *app_argc, char ***app_argv)

+{

+    int i;

+    FILE *fhnd;

+    char line[200];

+    int argc = 0;

+    char **argv;

+    enum { MAX_ARGS = 64 };

+

+    /* Allocate MAX_ARGS+1 (argv needs to be terminated with NULL argument) */

+    argv = pj_pool_calloc(pool, MAX_ARGS+1, sizeof(char*));

+    argv[argc++] = *app_argv[0];

+

+    /* Open config file. */

+    fhnd = fopen(filename, "rt");

+    if (!fhnd) {

+	printf("Unable to open config file %s\n", filename);

+	return -1;

+    }

+

+    /* Scan tokens in the file. */

+    while (argc < MAX_ARGS && !feof(fhnd)) {

+	char *token, *p = line;

+

+	if (fgets(line, sizeof(line), fhnd) == NULL) break;

+

+	for (token = strtok(p, " \t\r\n"); argc < MAX_ARGS; 

+	     token = strtok(NULL, " \t\r\n"))

+	{

+	    int token_len;

+	    

+	    if (!token) break;

+	    if (*token == '#') break;

+

+	    token_len = strlen(token);

+	    if (!token_len)

+		continue;

+	    argv[argc] = pj_pool_alloc(pool, token_len+1);

+	    pj_memcpy(argv[argc], token, token_len+1);

+	    ++argc;

+	}

+    }

+

+    /* Copy arguments from command line */

+    for (i=1; i<*app_argc && argc < MAX_ARGS; ++i)

+	argv[argc++] = (*app_argv)[i];

+

+    if (argc == MAX_ARGS && (i!=*app_argc || !feof(fhnd))) {

+	printf("Too many arguments specified in cmd line/config file\n");

+	fclose(fhnd);

+	return -1;

+    }

+

+    fclose(fhnd);

+

+    /* Assign the new command line back to the original command line. */

+    *app_argc = argc;

+    *app_argv = argv;

+    return 0;

+

+}

+

+/*

+ * Parse program arguments

+ */

+static int parse_args(pj_pool_t *pool, int argc, char *argv[])

+{

+    int c;

+    int option_index;

+    enum { OPT_CONFIG_FILE, OPT_LOG_FILE, OPT_LOG_LEVEL, OPT_APP_LOG_LEVEL, 

+	   OPT_HELP, OPT_VERSION, OPT_NULL_AUDIO,

+	   OPT_LOCAL_PORT, OPT_PROXY, OPT_OUTBOUND_PROXY, OPT_REGISTRAR,

+	   OPT_REG_TIMEOUT, OPT_ID, OPT_CONTACT, 

+	   OPT_REALM, OPT_USERNAME, OPT_PASSWORD,

+	   OPT_USE_STUN1, OPT_USE_STUN2, 

+	   OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,

+	   OPT_AUTO_ANSWER, OPT_AUTO_HANGUP};

+    struct option long_options[] = {

+	{ "config-file",1, 0, OPT_CONFIG_FILE},

+	{ "log-file",	1, 0, OPT_LOG_FILE},

+	{ "log-level",	1, 0, OPT_LOG_LEVEL},

+	{ "app-log-level",1,0,OPT_APP_LOG_LEVEL},

+	{ "help",	0, 0, OPT_HELP},

+	{ "version",	0, 0, OPT_VERSION},

+	{ "null-audio", 0, 0, OPT_NULL_AUDIO},

+	{ "local-port", 1, 0, OPT_LOCAL_PORT},

+	{ "proxy",	1, 0, OPT_PROXY},

+	{ "outbound",	1, 0, OPT_OUTBOUND_PROXY},

+	{ "registrar",	1, 0, OPT_REGISTRAR},

+	{ "reg-timeout",1, 0, OPT_REG_TIMEOUT},

+	{ "id",		1, 0, OPT_ID},

+	{ "contact",	1, 0, OPT_CONTACT},

+	{ "realm",	1, 0, OPT_REALM},

+	{ "username",	1, 0, OPT_USERNAME},

+	{ "password",	1, 0, OPT_PASSWORD},

+	{ "use-stun1",  1, 0, OPT_USE_STUN1},

+	{ "use-stun2",  1, 0, OPT_USE_STUN2},

+	{ "add-buddy",  1, 0, OPT_ADD_BUDDY},

+	{ "offer-x-ms-msg",0,0,OPT_OFFER_X_MS_MSG},

+	{ "no-presence", 0, 0, OPT_NO_PRESENCE},

+	{ "auto-answer",1, 0, OPT_AUTO_ANSWER},

+	{ "auto-hangup",1, 0, OPT_AUTO_HANGUP},

+	{ NULL, 0, 0, 0}

+    };

+    char *config_file = NULL;

+

+    /* Run getopt once to see if user specifies config file to read. */

+    while ((c=getopt_long(argc, argv, "", long_options, &option_index)) != -1) {

+	switch (c) {

+	case 0:

+	    config_file = optarg;

+	    break;

+	}

+	if (config_file)

+	    break;

+    }

+

+    if (config_file) {

+	if (read_config_file(pool, config_file, &argc, &argv) != 0)

+	    return -1;

+    }

+

+    /* Reinitialize and re-run getopt again, possibly with new arguments

+     * read from config file.

+     */

+    optind = 0;

+    while ((c=getopt_long(argc, argv, "", long_options, &option_index)) != -1) {

+	char *err, *p;

+

+	switch (c) {

+	case OPT_LOG_FILE:

+	    global.log_filename = optarg;

+	    break;

+	case OPT_LOG_LEVEL:

+	    c = strtoul(optarg, &err, 10);

+	    if (*err) {

+		printf("Error: expecting integer value 0-6 for --log-level\n");

+		return -1;

+	    }

+	    pj_log_set_level( c );

+	    break;

+	case OPT_APP_LOG_LEVEL:

+	    global.app_log_level = strtoul(optarg, &err, 10);

+	    if (*err) {

+		printf("Error: expecting integer value 0-6 for --app-log-level\n");

+		return -1;

+	    }

+	    break;

+	case OPT_HELP:

+	    usage();

+	    return -1;

+	case OPT_VERSION:   /* version */

+	    pj_dump_config();

+	    return -1;

+	case OPT_NULL_AUDIO:

+	    global.null_audio = 1;

+	    break;

+	case OPT_LOCAL_PORT:   /* local-port */

+	    global.sip_port = strtoul(optarg, &err, 10);

+	    if (*err) {

+		printf("Error: expecting integer value for --local-port\n");

+		return -1;

+	    }

+	    break;

+	case OPT_PROXY:   /* proxy */

+	    if (verify_sip_url(optarg) != 0) {

+		printf("Error: invalid SIP URL '%s' in proxy argument\n", optarg);

+		return -1;

+	    }

+	    global.proxy = pj_str(optarg);

+	    break;

+	case OPT_OUTBOUND_PROXY:   /* outbound proxy */

+	    if (verify_sip_url(optarg) != 0) {

+		printf("Error: invalid SIP URL '%s' in outbound proxy argument\n", optarg);

+		return -1;

+	    }

+	    global.outbound_proxy = pj_str(optarg);

+	    break;

+	case OPT_REGISTRAR:   /* registrar */

+	    if (verify_sip_url(optarg) != 0) {

+		printf("Error: invalid SIP URL '%s' in registrar argument\n", optarg);

+		return -1;

+	    }

+	    global.registrar_uri = pj_str(optarg);

+	    break;

+	case OPT_REG_TIMEOUT:   /* reg-timeout */

+	    global.reg_timeout = strtoul(optarg, &err, 10);

+	    if (*err) {

+		printf("Error: expecting integer value for --reg-timeout\n");

+		return -1;

+	    }

+	    break;

+	case OPT_ID:   /* id */

+	    if (verify_sip_url(optarg) != 0) {

+		printf("Error: invalid SIP URL '%s' in local id argument\n", optarg);

+		return -1;

+	    }

+	    global.local_uri = pj_str(optarg);

+	    break;

+	case OPT_CONTACT:   /* contact */

+	    if (verify_sip_url(optarg) != 0) {

+		printf("Error: invalid SIP URL '%s' in contact argument\n", optarg);

+		return -1;

+	    }

+	    global.contact = pj_str(optarg);

+	    break;

+	case OPT_USERNAME:   /* Default authentication user */

+	    if (!global.cred_count) global.cred_count = 1;

+	    global.cred_info[0].username = pj_str(optarg);

+	    break;

+	case OPT_REALM:	    /* Default authentication realm. */

+	    if (!global.cred_count) global.cred_count = 1;

+	    global.cred_info[0].realm = pj_str(optarg);

+	    break;

+	case OPT_PASSWORD:   /* authentication password */

+	    if (!global.cred_count) global.cred_count = 1;

+	    global.cred_info[0].data_type = 0;

+	    global.cred_info[0].data = pj_str(optarg);

+	    break;

+	case OPT_USE_STUN1:   /* STUN server 1 */

+	    p = pj_native_strchr(optarg, ':');

+	    if (p) {

+		*p = '\0';

+		global.stun_srv1 = pj_str(optarg);

+		global.stun_port1 = strtoul(p+1, &err, 10);

+		if (*err || global.stun_port1==0) {

+		    printf("Error: expecting port number with option --use-stun1\n");

+		    return -1;

+		}

+	    } else {

+		global.stun_port1 = 3478;

+		global.stun_srv1 = pj_str(optarg);

+	    }

+	    break;

+	case OPT_USE_STUN2:   /* STUN server 2 */

+	    p = pj_native_strchr(optarg, ':');

+	    if (p) {

+		*p = '\0';

+		global.stun_srv2 = pj_str(optarg);

+		global.stun_port2 = strtoul(p+1, &err, 10);

+		if (*err || global.stun_port2==0) {

+		    printf("Error: expecting port number with option --use-stun2\n");

+		    return -1;

+		}

+	    } else {

+		global.stun_port2 = 3478;

+		global.stun_srv2 = pj_str(optarg);

+	    }

+	    break;

+	case OPT_ADD_BUDDY: /* Add to buddy list. */

+	    if (verify_sip_url(optarg) != 0) {

+		printf("Error: invalid URL '%s' in --add-buddy option\n", optarg);

+		return -1;

+	    }

+	    if (global.buddy_cnt == MAX_BUDDIES) {

+		printf("Error: too many buddies in buddy list.\n");

+		return -1;

+	    }

+	    global.buddy[global.buddy_cnt++] = pj_str(optarg);

+	    break;

+	case OPT_OFFER_X_MS_MSG:

+	    global.offer_x_ms_msg = 1;

+	    break;

+	case OPT_NO_PRESENCE:

+	    global.no_presence = 1;

+	    break;

+	case OPT_AUTO_ANSWER:

+	    global.auto_answer = strtoul(optarg, &err, 10);

+	    if (*err) {

+		printf("Error: expecting integer value for --auto-answer option\n");

+		return -1;

+	    }

+	    break;

+	case OPT_AUTO_HANGUP:

+	    global.auto_hangup = strtoul(optarg, &err, 10);

+	    if (*err) {

+		printf("Error: expecting integer value for --auto-hangup option\n");

+		return -1;

+	    }

+	    break;

+	}

+    }

+

+    if (optind != argc) {

+	printf("Error: unknown options %s\n", argv[optind]);

+	return -1;

+    }

+

+    if (global.reg_timeout == 0)

+	global.reg_timeout = 3600;

+

+    return 0;

+}

+

+/* Print dialog. */

+static void print_dialog(pjsip_dlg *dlg)

+{

+    if (!dlg) {

+	puts("none");

+	return;

+    }

+

+    printf("%s: call-id=%.*s", dlg->obj_name, 

+			       (int)dlg->call_id->id.slen, 

+			       dlg->call_id->id.ptr);

+

+    printf(" (%s, %s)\n", pjsip_role_name(dlg->role),

+			  pjsip_dlg_state_str(dlg->state));

+}

+

+/* Dump media statistic */

+void dump_media_statistic(pjsip_dlg *dlg)

+{

+    struct dialog_data *dlg_data = dlg->user_data;

+    pj_media_stream_stat stat[2];

+    const char *statname[2] = { "TX", "RX" };

+    int i;

+

+    pj_media_session_get_stat (dlg_data->msession, 0, &stat[0], &stat[1]);

+

+    printf("Media statistic:\n");

+    for (i=0; i<2; ++i) {

+	printf("  %s statistics:\n", statname[i]);

+	printf("    Pkt      TX=%d RX=%d\n", stat[i].pkt_tx, stat[i].pkt_rx);

+	printf("    Octets   TX=%d RX=%d\n", stat[i].oct_tx, stat[i].oct_rx);

+	printf("    Jitter   %d ms\n", stat[i].jitter);

+	printf("    Pkt lost %d\n", stat[i].pkt_lost);

+    }

+    printf("\n");

+}

+

+/* Print all dialogs. */

+static void print_all_dialogs()

+{

+    pjsip_dlg *dlg = (pjsip_dlg *)global.user_agent->dlg_list.next;

+

+    puts("List all dialogs:");

+

+    while (dlg != (pjsip_dlg *) &global.user_agent->dlg_list) {

+	printf("%c", (dlg==global.cur_dlg ? '*' : ' '));

+	print_dialog(dlg);

+	dlg = dlg->next;

+    }

+

+    puts("");

+}

+

diff --git a/pjsip/src/tests/pjsip-core/main.c b/pjsip/src/tests/pjsip-core/main.c
index 6212ba4..4a450dd 100644
--- a/pjsip/src/tests/pjsip-core/main.c
+++ b/pjsip/src/tests/pjsip-core/main.c
@@ -1,17 +1,39 @@
-/* $Id$
- *
- */
-#include "test.h"
-#include <stdio.h>
-
-int main()
-{
-    test_uri();
-    test_msg();
-
-#if !IS_PROFILING
-    puts("Press <ENTER> to quit.");
-    fgets( s, sizeof(s), stdin);
-#endif
-    return 0;
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include "test.h"

+#include <stdio.h>

+

+int main()

+{

+    test_uri();

+    test_msg();

+

+#if !IS_PROFILING

+    puts("Press <ENTER> to quit.");

+    fgets( s, sizeof(s), stdin);

+#endif

+    return 0;

+}

diff --git a/pjsip/src/tests/pjsip-core/test.h b/pjsip/src/tests/pjsip-core/test.h
index 8bb57b2..7708313 100644
--- a/pjsip/src/tests/pjsip-core/test.h
+++ b/pjsip/src/tests/pjsip-core/test.h
@@ -1,11 +1,33 @@
-/* $Id$
- *
- */
-#include <pj/types.h>
-
-pj_status_t test_uri(void);
-pj_status_t test_msg(void);
-
-#define SILENT		1
-#define IS_PROFILING	1
-#define LOOP		2000
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pj/types.h>

+

+pj_status_t test_uri(void);

+pj_status_t test_msg(void);

+

+#define SILENT		1

+#define IS_PROFILING	1

+#define LOOP		2000

diff --git a/pjsip/src/tests/pjsip-core/test_msg.c b/pjsip/src/tests/pjsip-core/test_msg.c
index 7326e37..395d1ea 100644
--- a/pjsip/src/tests/pjsip-core/test_msg.c
+++ b/pjsip/src/tests/pjsip-core/test_msg.c
@@ -1,425 +1,447 @@
-/* $Id$
- *
- */
-#include <pjsip/sip_msg.h>
-#include <pjsip/sip_parser.h>
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "test.h"
-
-#define ERR_SYNTAX_ERR	(-2)
-#define ERR_NOT_EQUAL	(-3)
-#define ERR_SYSTEM	(-4)
-
-
-static pjsip_msg *create_msg0(pj_pool_t *pool);
-
-struct test_msg
-{
-    char	 msg[1024];
-    pjsip_msg *(*creator)(pj_pool_t *pool);
-    pj_size_t	 len;
-} test_array[] = 
-{
-    {
-	/* 'Normal' message with all headers. */
-	"INVITE sip:user@foo SIP/2.0\n"
-	"From: Hi I'm Joe <sip:joe.user@bar.otherdomain.com>;tag=1234578901234567890\r"
-	"To: Fellow User <sip:user@foo.bar.domain.com>\r\n"
-	"Call-ID: 12345678901234567890@bar\r\n"
-	"Content-Length: 0\r\n"
-	"CSeq: 123456 INVITE\n"
-	"Contact: <sip:joe@bar> ; q=0.5;expires=3600,sip:user@host;q=0.500\r"
-	"  ,sip:user2@host2\n"
-	"Content-Type: text/html ; charset=ISO-8859-4\r"
-	"Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n"
-	"  <sip:server10.biloxi.com;lr>\r"
-	"Record-Route: <sip:server10.biloxi.com>,\r\n"
-	"  <sip:bigbox3.site3.atlanta.com;lr>\n"
-	"Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n"
-	"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n"
-	" ;received=192.0.2.1\r\n"
-	"Via: SIP/2.0/UDP 10.2.1.1, SIP/2.0/TCP 192.168.1.1\n"
-	"Organization: \r"
-	"Max-Forwards: 70\n"
-	"X-Header: \r\n"
-	"\r",
-	&create_msg0
-    }
-};
-
-static pj_caching_pool cp;
-static pj_pool_factory *pf = &cp.factory;
-static pj_uint32_t parse_len, parse_time, print_time;
-
-static void pool_error(pj_pool_t *pool, pj_size_t sz)
-{
-    PJ_UNUSED_ARG(pool)
-    PJ_UNUSED_ARG(sz)
-
-    pj_assert(0);
-    exit(1);
-}
-
-static const char *STATUS_STR(pj_status_t status)
-{
-    switch (status) {
-    case 0: return "OK";
-    case ERR_SYNTAX_ERR: return "Syntax Error";
-    case ERR_NOT_EQUAL: return "Not Equal";
-    case ERR_SYSTEM: return "System Error";
-    }
-    return "???";
-}
-
-static pj_status_t test_entry( struct test_msg *entry )
-{
-    pjsip_msg *parsed_msg, *ref_msg;
-    pj_pool_t *pool;
-    pj_status_t status = PJ_SUCCESS;
-    int len;
-    pj_str_t str1, str2;
-    pjsip_hdr *hdr1, *hdr2;
-    pj_hr_timestamp t1, t2;
-    char *msgbuf;
-
-    enum { BUFLEN = 512 };
-    
-    pool = pj_pool_create( pf, "", 
-			   PJSIP_POOL_LEN_RDATA*2, PJSIP_POOL_INC_RDATA, 
-			   &pool_error);
-
-    if (entry->len == 0) {
-	entry->len = strlen(entry->msg);
-    }
-
-    /* Parse message. */
-    parse_len += entry->len;
-    pj_hr_gettimestamp(&t1);
-    parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, NULL);
-    if (parsed_msg == NULL) {
-	status = ERR_SYNTAX_ERR;
-	goto on_return;
-    }
-    pj_hr_gettimestamp(&t2);
-    parse_time += t2.u32.lo - t1.u32.lo;
-
-#if IS_PROFILING
-    goto print_msg;
-#endif
-
-    /* Create reference message. */
-    ref_msg = entry->creator(pool);
-
-    /* Create buffer for comparison. */
-    str1.ptr = pj_pool_alloc(pool, BUFLEN);
-    str2.ptr = pj_pool_alloc(pool, BUFLEN);
-
-    /* Compare message type. */
-    if (parsed_msg->type != ref_msg->type) {
-	status = ERR_NOT_EQUAL;
-	goto on_return;
-    }
-
-    /* Compare request or status line. */
-    if (parsed_msg->type == PJSIP_REQUEST_MSG) {
-	pjsip_method *m1 = &parsed_msg->line.req.method;
-	pjsip_method *m2 = &ref_msg->line.req.method;
-
-	if (m1->id != m2->id || pj_strcmp(&m1->name, &m2->name)) {
-	    status = ERR_NOT_EQUAL;
-	    goto on_return;
-	}
-    } else {
-
-    }
-
-    /* Compare headers. */
-    hdr1 = parsed_msg->hdr.next;
-    hdr2 = ref_msg->hdr.next;
-
-    while (hdr1 != &parsed_msg->hdr && hdr2 != &ref_msg->hdr) {
-	len = hdr1->vptr->print_on(hdr1, str1.ptr, BUFLEN);
-	if (len < 1) {
-	    status = ERR_SYSTEM;
-	    goto on_return;
-	}
-	str1.slen = len;
-
-	len = hdr2->vptr->print_on(hdr2, str2.ptr, BUFLEN);
-	if (len < 1) {
-	    status = ERR_SYSTEM;
-	    goto on_return;
-	}
-	str2.slen = len;
-
-	if (!SILENT) {
-	    printf("hdr1='%.*s'\n"
-		   "hdr2='%.*s'\n\n",
-		   str1.slen, str1.ptr,
-		   str2.slen, str2.ptr);
-	}
-	if (pj_strcmp(&str1, &str2) != 0) {
-	    status = ERR_NOT_EQUAL;
-	    goto on_return;
-	}
-
-	hdr1 = hdr1->next;
-	hdr2 = hdr2->next;
-    }
-
-    if (hdr1 != &parsed_msg->hdr || hdr2 != &ref_msg->hdr) {
-	status = ERR_NOT_EQUAL;
-	goto on_return;
-    }
-
-    /* Print message. */
-#if IS_PROFILING
-print_msg:
-#endif
-    msgbuf = pj_pool_alloc(pool, PJSIP_MAX_PKT_LEN);
-    if (msgbuf == NULL) {
-	status = ERR_SYSTEM;
-	goto on_return;
-    }
-    pj_hr_gettimestamp(&t1);
-    len = pjsip_msg_print(parsed_msg, msgbuf, PJSIP_MAX_PKT_LEN);
-    if (len < 1) {
-	status = ERR_SYSTEM;
-	goto on_return;
-    }
-    pj_hr_gettimestamp(&t2);
-    print_time += t2.u32.lo - t1.u32.lo;
-    status = PJ_SUCCESS;
-
-on_return:
-    pj_pool_release(pool);
-    return status;
-}
-
-static void warm_up()
-{
-    pj_pool_t *pool;
-    pool = pj_pool_create( pf, "", 
-			   PJSIP_POOL_LEN_RDATA*2, PJSIP_POOL_INC_RDATA, 
-			   &pool_error);
-    pj_pool_release(pool);
-}
-
-
-pj_status_t test_msg(void)
-{
-    pj_status_t status;
-    unsigned i;
-
-    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
-    warm_up();
-
-    for (i=0; i<LOOP; ++i) {
-	status = test_entry( &test_array[0] );
-    }
-    printf("%s\n", STATUS_STR(status));
-
-    printf("Total bytes: %u, parse time=%f/char, print time=%f/char\n", 
-	   parse_len, 
-	   parse_time*1.0/parse_len,
-	   print_time*1.0/parse_len);
-    return PJ_SUCCESS;
-}
-
-/*****************************************************************************/
-
-static pjsip_msg *create_msg0(pj_pool_t *pool)
-{
-
-    pjsip_msg *msg;
-    pjsip_name_addr *name_addr;
-    pjsip_url *url;
-    pjsip_fromto_hdr *fromto;
-    pjsip_cid_hdr *cid;
-    pjsip_clen_hdr *clen;
-    pjsip_cseq_hdr *cseq;
-    pjsip_contact_hdr *contact;
-    pjsip_ctype_hdr *ctype;
-    pjsip_routing_hdr *routing;
-    pjsip_via_hdr *via;
-    pjsip_generic_string_hdr *generic;
-    pj_str_t str;
-
-    msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG);
-
-    /* "INVITE sip:user@foo SIP/2.0\n" */
-    pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD);
-    url = pjsip_url_create(pool, 0);
-    msg->line.req.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "user");
-    pj_strdup2(pool, &url->host, "foo");
-
-    /* "From: Hi I'm Joe <sip:joe.user@bar.otherdomain.com>;tag=1234578901234567890\r" */
-    fromto = pjsip_from_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto);
-    pj_strdup2(pool, &fromto->tag, "1234578901234567890");
-    name_addr = pjsip_name_addr_create(pool);
-    fromto->uri = (pjsip_uri*)name_addr;
-    pj_strdup2(pool, &name_addr->display, "Hi I'm Joe");
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "joe.user");
-    pj_strdup2(pool, &url->host, "bar.otherdomain.com");
-
-    /* "To: Fellow User <sip:user@foo.bar.domain.com>\r\n" */
-    fromto = pjsip_to_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto);
-    name_addr = pjsip_name_addr_create(pool);
-    fromto->uri = (pjsip_uri*)name_addr;
-    pj_strdup2(pool, &name_addr->display, "Fellow User");
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "user");
-    pj_strdup2(pool, &url->host, "foo.bar.domain.com");
-
-    /* "Call-ID: 12345678901234567890@bar\r\n" */
-    cid = pjsip_cid_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid);
-    pj_strdup2(pool, &cid->id, "12345678901234567890@bar");
-
-    /* "Content-Length: 0\r\n" */
-    clen = pjsip_clen_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen);
-    clen->len = 0;
-
-    /* "CSeq: 123456 INVITE\n" */
-    cseq = pjsip_cseq_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq);
-    cseq->cseq = 123456;
-    pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD);
-
-    /* "Contact: <sip:joe@bar>;q=0.5;expires=3600*/
-    contact = pjsip_contact_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
-    contact->q1000 = 500;
-    contact->expires = 3600;
-    name_addr = pjsip_name_addr_create(pool);
-    contact->uri = (pjsip_uri*)name_addr;
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "joe");
-    pj_strdup2(pool, &url->host, "bar");
-
-    /*, sip:user@host;q=0.500\r" */
-    contact = pjsip_contact_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
-    contact->q1000 = 500;
-    url = pjsip_url_create(pool, 0);
-    contact->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "user");
-    pj_strdup2(pool, &url->host, "host");
-
-    /* "  ,sip:user2@host2\n" */
-    contact = pjsip_contact_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);
-    url = pjsip_url_create(pool, 0);
-    contact->uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->user, "user2");
-    pj_strdup2(pool, &url->host, "host2");
-
-    /* "Content-Type: text/html; charset=ISO-8859-4\r" */
-    ctype = pjsip_ctype_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype);
-    pj_strdup2(pool, &ctype->media.type, "text");
-    pj_strdup2(pool, &ctype->media.subtype, "html");
-    pj_strdup2(pool, &ctype->media.param, ";charset=ISO-8859-4");
-
-    /* "Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n" */
-    routing = pjsip_route_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
-    routing->name_addr.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
-    url->lr_param = 1;
-
-    /* "  <sip:server10.biloxi.com;lr>\r" */
-    routing = pjsip_route_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
-    routing->name_addr.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->host, "server10.biloxi.com");
-    url->lr_param = 1;
-
-    /* "Record-Route: <sip:server10.biloxi.com>,\r\n" */
-    routing = pjsip_rr_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
-    routing->name_addr.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->host, "server10.biloxi.com");
-    url->lr_param = 0;
-
-    /* "  <sip:bigbox3.site3.atlanta.com;lr>\n" */
-    routing = pjsip_rr_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);
-    url = pjsip_url_create(pool, 0);
-    routing->name_addr.uri = (pjsip_uri*)url;
-    pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");
-    url->lr_param = 1;
-
-    /* "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n" */
-    via = pjsip_via_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
-    pj_strdup2(pool, &via->transport, "SCTP");
-    pj_strdup2(pool, &via->sent_by.host, "bigbox3.site3.atlanta.com");
-    pj_strdup2(pool, &via->branch_param, "z9hG4bK77ef4c2312983.1");
-
-    /* "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n"
-	" ;received=192.0.2.1\r\n" */
-    via = pjsip_via_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
-    pj_strdup2(pool, &via->transport, "UDP");
-    pj_strdup2(pool, &via->sent_by.host, "pc33.atlanta.com");
-    pj_strdup2(pool, &via->branch_param, "z9hG4bKnashds8");
-    pj_strdup2(pool, &via->recvd_param, "192.0.2.1");
-
-
-    /* "Via: SIP/2.0/UDP 10.2.1.1, */ 
-    via = pjsip_via_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
-    pj_strdup2(pool, &via->transport, "UDP");
-    pj_strdup2(pool, &via->sent_by.host, "10.2.1.1");
-    
-    
-    /*SIP/2.0/TCP 192.168.1.1\n" */
-    via = pjsip_via_hdr_create(pool);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);
-    pj_strdup2(pool, &via->transport, "TCP");
-    pj_strdup2(pool, &via->sent_by.host, "192.168.1.1");
-
-    /* "Organization: \r" */
-    str.ptr = "Organization";
-    str.slen = 12;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
-    generic->hvalue.ptr = NULL;
-    generic->hvalue.slen = 0;
-
-    /* "Max-Forwards: 70\n" */
-    str.ptr = "Max-Forwards";
-    str.slen = 12;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
-    str.ptr = "70";
-    str.slen = 2;
-    generic->hvalue = str;
-
-    /* "X-Header: \r\n" */
-    str.ptr = "X-Header";
-    str.slen = 8;
-    generic = pjsip_generic_string_hdr_create(pool, &str);
-    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);
-    str.ptr = NULL;
-    str.slen = 0;
-    generic->hvalue = str;
-
-    return msg;
-}
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_msg.h>

+#include <pjsip/sip_parser.h>

+#include <pj/os.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <stdlib.h>

+#include <stdio.h>

+#include "test.h"

+

+#define ERR_SYNTAX_ERR	(-2)

+#define ERR_NOT_EQUAL	(-3)

+#define ERR_SYSTEM	(-4)

+

+

+static pjsip_msg *create_msg0(pj_pool_t *pool);

+

+struct test_msg

+{

+    char	 msg[1024];

+    pjsip_msg *(*creator)(pj_pool_t *pool);

+    pj_size_t	 len;

+} test_array[] = 

+{

+    {

+	/* 'Normal' message with all headers. */

+	"INVITE sip:user@foo SIP/2.0\n"

+	"From: Hi I'm Joe <sip:joe.user@bar.otherdomain.com>;tag=1234578901234567890\r"

+	"To: Fellow User <sip:user@foo.bar.domain.com>\r\n"

+	"Call-ID: 12345678901234567890@bar\r\n"

+	"Content-Length: 0\r\n"

+	"CSeq: 123456 INVITE\n"

+	"Contact: <sip:joe@bar> ; q=0.5;expires=3600,sip:user@host;q=0.500\r"

+	"  ,sip:user2@host2\n"

+	"Content-Type: text/html ; charset=ISO-8859-4\r"

+	"Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n"

+	"  <sip:server10.biloxi.com;lr>\r"

+	"Record-Route: <sip:server10.biloxi.com>,\r\n"

+	"  <sip:bigbox3.site3.atlanta.com;lr>\n"

+	"Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n"

+	"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n"

+	" ;received=192.0.2.1\r\n"

+	"Via: SIP/2.0/UDP 10.2.1.1, SIP/2.0/TCP 192.168.1.1\n"

+	"Organization: \r"

+	"Max-Forwards: 70\n"

+	"X-Header: \r\n"

+	"\r",

+	&create_msg0

+    }

+};

+

+static pj_caching_pool cp;

+static pj_pool_factory *pf = &cp.factory;

+static pj_uint32_t parse_len, parse_time, print_time;

+

+static void pool_error(pj_pool_t *pool, pj_size_t sz)

+{

+    PJ_UNUSED_ARG(pool)

+    PJ_UNUSED_ARG(sz)

+

+    pj_assert(0);

+    exit(1);

+}

+

+static const char *STATUS_STR(pj_status_t status)

+{

+    switch (status) {

+    case 0: return "OK";

+    case ERR_SYNTAX_ERR: return "Syntax Error";

+    case ERR_NOT_EQUAL: return "Not Equal";

+    case ERR_SYSTEM: return "System Error";

+    }

+    return "???";

+}

+

+static pj_status_t test_entry( struct test_msg *entry )

+{

+    pjsip_msg *parsed_msg, *ref_msg;

+    pj_pool_t *pool;

+    pj_status_t status = PJ_SUCCESS;

+    int len;

+    pj_str_t str1, str2;

+    pjsip_hdr *hdr1, *hdr2;

+    pj_hr_timestamp t1, t2;

+    char *msgbuf;

+

+    enum { BUFLEN = 512 };

+    

+    pool = pj_pool_create( pf, "", 

+			   PJSIP_POOL_LEN_RDATA*2, PJSIP_POOL_INC_RDATA, 

+			   &pool_error);

+

+    if (entry->len == 0) {

+	entry->len = strlen(entry->msg);

+    }

+

+    /* Parse message. */

+    parse_len += entry->len;

+    pj_hr_gettimestamp(&t1);

+    parsed_msg = pjsip_parse_msg(pool, entry->msg, entry->len, NULL);

+    if (parsed_msg == NULL) {

+	status = ERR_SYNTAX_ERR;

+	goto on_return;

+    }

+    pj_hr_gettimestamp(&t2);

+    parse_time += t2.u32.lo - t1.u32.lo;

+

+#if IS_PROFILING

+    goto print_msg;

+#endif

+

+    /* Create reference message. */

+    ref_msg = entry->creator(pool);

+

+    /* Create buffer for comparison. */

+    str1.ptr = pj_pool_alloc(pool, BUFLEN);

+    str2.ptr = pj_pool_alloc(pool, BUFLEN);

+

+    /* Compare message type. */

+    if (parsed_msg->type != ref_msg->type) {

+	status = ERR_NOT_EQUAL;

+	goto on_return;

+    }

+

+    /* Compare request or status line. */

+    if (parsed_msg->type == PJSIP_REQUEST_MSG) {

+	pjsip_method *m1 = &parsed_msg->line.req.method;

+	pjsip_method *m2 = &ref_msg->line.req.method;

+

+	if (m1->id != m2->id || pj_strcmp(&m1->name, &m2->name)) {

+	    status = ERR_NOT_EQUAL;

+	    goto on_return;

+	}

+    } else {

+

+    }

+

+    /* Compare headers. */

+    hdr1 = parsed_msg->hdr.next;

+    hdr2 = ref_msg->hdr.next;

+

+    while (hdr1 != &parsed_msg->hdr && hdr2 != &ref_msg->hdr) {

+	len = hdr1->vptr->print_on(hdr1, str1.ptr, BUFLEN);

+	if (len < 1) {

+	    status = ERR_SYSTEM;

+	    goto on_return;

+	}

+	str1.slen = len;

+

+	len = hdr2->vptr->print_on(hdr2, str2.ptr, BUFLEN);

+	if (len < 1) {

+	    status = ERR_SYSTEM;

+	    goto on_return;

+	}

+	str2.slen = len;

+

+	if (!SILENT) {

+	    printf("hdr1='%.*s'\n"

+		   "hdr2='%.*s'\n\n",

+		   str1.slen, str1.ptr,

+		   str2.slen, str2.ptr);

+	}

+	if (pj_strcmp(&str1, &str2) != 0) {

+	    status = ERR_NOT_EQUAL;

+	    goto on_return;

+	}

+

+	hdr1 = hdr1->next;

+	hdr2 = hdr2->next;

+    }

+

+    if (hdr1 != &parsed_msg->hdr || hdr2 != &ref_msg->hdr) {

+	status = ERR_NOT_EQUAL;

+	goto on_return;

+    }

+

+    /* Print message. */

+#if IS_PROFILING

+print_msg:

+#endif

+    msgbuf = pj_pool_alloc(pool, PJSIP_MAX_PKT_LEN);

+    if (msgbuf == NULL) {

+	status = ERR_SYSTEM;

+	goto on_return;

+    }

+    pj_hr_gettimestamp(&t1);

+    len = pjsip_msg_print(parsed_msg, msgbuf, PJSIP_MAX_PKT_LEN);

+    if (len < 1) {

+	status = ERR_SYSTEM;

+	goto on_return;

+    }

+    pj_hr_gettimestamp(&t2);

+    print_time += t2.u32.lo - t1.u32.lo;

+    status = PJ_SUCCESS;

+

+on_return:

+    pj_pool_release(pool);

+    return status;

+}

+

+static void warm_up()

+{

+    pj_pool_t *pool;

+    pool = pj_pool_create( pf, "", 

+			   PJSIP_POOL_LEN_RDATA*2, PJSIP_POOL_INC_RDATA, 

+			   &pool_error);

+    pj_pool_release(pool);

+}

+

+

+pj_status_t test_msg(void)

+{

+    pj_status_t status;

+    unsigned i;

+

+    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);

+    warm_up();

+

+    for (i=0; i<LOOP; ++i) {

+	status = test_entry( &test_array[0] );

+    }

+    printf("%s\n", STATUS_STR(status));

+

+    printf("Total bytes: %u, parse time=%f/char, print time=%f/char\n", 

+	   parse_len, 

+	   parse_time*1.0/parse_len,

+	   print_time*1.0/parse_len);

+    return PJ_SUCCESS;

+}

+

+/*****************************************************************************/

+

+static pjsip_msg *create_msg0(pj_pool_t *pool)

+{

+

+    pjsip_msg *msg;

+    pjsip_name_addr *name_addr;

+    pjsip_url *url;

+    pjsip_fromto_hdr *fromto;

+    pjsip_cid_hdr *cid;

+    pjsip_clen_hdr *clen;

+    pjsip_cseq_hdr *cseq;

+    pjsip_contact_hdr *contact;

+    pjsip_ctype_hdr *ctype;

+    pjsip_routing_hdr *routing;

+    pjsip_via_hdr *via;

+    pjsip_generic_string_hdr *generic;

+    pj_str_t str;

+

+    msg = pjsip_msg_create(pool, PJSIP_REQUEST_MSG);

+

+    /* "INVITE sip:user@foo SIP/2.0\n" */

+    pjsip_method_set(&msg->line.req.method, PJSIP_INVITE_METHOD);

+    url = pjsip_url_create(pool, 0);

+    msg->line.req.uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->user, "user");

+    pj_strdup2(pool, &url->host, "foo");

+

+    /* "From: Hi I'm Joe <sip:joe.user@bar.otherdomain.com>;tag=1234578901234567890\r" */

+    fromto = pjsip_from_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto);

+    pj_strdup2(pool, &fromto->tag, "1234578901234567890");

+    name_addr = pjsip_name_addr_create(pool);

+    fromto->uri = (pjsip_uri*)name_addr;

+    pj_strdup2(pool, &name_addr->display, "Hi I'm Joe");

+    url = pjsip_url_create(pool, 0);

+    name_addr->uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->user, "joe.user");

+    pj_strdup2(pool, &url->host, "bar.otherdomain.com");

+

+    /* "To: Fellow User <sip:user@foo.bar.domain.com>\r\n" */

+    fromto = pjsip_to_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)fromto);

+    name_addr = pjsip_name_addr_create(pool);

+    fromto->uri = (pjsip_uri*)name_addr;

+    pj_strdup2(pool, &name_addr->display, "Fellow User");

+    url = pjsip_url_create(pool, 0);

+    name_addr->uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->user, "user");

+    pj_strdup2(pool, &url->host, "foo.bar.domain.com");

+

+    /* "Call-ID: 12345678901234567890@bar\r\n" */

+    cid = pjsip_cid_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)cid);

+    pj_strdup2(pool, &cid->id, "12345678901234567890@bar");

+

+    /* "Content-Length: 0\r\n" */

+    clen = pjsip_clen_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)clen);

+    clen->len = 0;

+

+    /* "CSeq: 123456 INVITE\n" */

+    cseq = pjsip_cseq_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)cseq);

+    cseq->cseq = 123456;

+    pjsip_method_set(&cseq->method, PJSIP_INVITE_METHOD);

+

+    /* "Contact: <sip:joe@bar>;q=0.5;expires=3600*/

+    contact = pjsip_contact_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);

+    contact->q1000 = 500;

+    contact->expires = 3600;

+    name_addr = pjsip_name_addr_create(pool);

+    contact->uri = (pjsip_uri*)name_addr;

+    url = pjsip_url_create(pool, 0);

+    name_addr->uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->user, "joe");

+    pj_strdup2(pool, &url->host, "bar");

+

+    /*, sip:user@host;q=0.500\r" */

+    contact = pjsip_contact_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);

+    contact->q1000 = 500;

+    url = pjsip_url_create(pool, 0);

+    contact->uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->user, "user");

+    pj_strdup2(pool, &url->host, "host");

+

+    /* "  ,sip:user2@host2\n" */

+    contact = pjsip_contact_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)contact);

+    url = pjsip_url_create(pool, 0);

+    contact->uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->user, "user2");

+    pj_strdup2(pool, &url->host, "host2");

+

+    /* "Content-Type: text/html; charset=ISO-8859-4\r" */

+    ctype = pjsip_ctype_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)ctype);

+    pj_strdup2(pool, &ctype->media.type, "text");

+    pj_strdup2(pool, &ctype->media.subtype, "html");

+    pj_strdup2(pool, &ctype->media.param, ";charset=ISO-8859-4");

+

+    /* "Route: <sip:bigbox3.site3.atlanta.com;lr>,\r\n" */

+    routing = pjsip_route_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);

+    url = pjsip_url_create(pool, 0);

+    routing->name_addr.uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");

+    url->lr_param = 1;

+

+    /* "  <sip:server10.biloxi.com;lr>\r" */

+    routing = pjsip_route_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);

+    url = pjsip_url_create(pool, 0);

+    routing->name_addr.uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->host, "server10.biloxi.com");

+    url->lr_param = 1;

+

+    /* "Record-Route: <sip:server10.biloxi.com>,\r\n" */

+    routing = pjsip_rr_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);

+    url = pjsip_url_create(pool, 0);

+    routing->name_addr.uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->host, "server10.biloxi.com");

+    url->lr_param = 0;

+

+    /* "  <sip:bigbox3.site3.atlanta.com;lr>\n" */

+    routing = pjsip_rr_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)routing);

+    url = pjsip_url_create(pool, 0);

+    routing->name_addr.uri = (pjsip_uri*)url;

+    pj_strdup2(pool, &url->host, "bigbox3.site3.atlanta.com");

+    url->lr_param = 1;

+

+    /* "Via: SIP/2.0/SCTP bigbox3.site3.atlanta.com;branch=z9hG4bK77ef4c2312983.1\n" */

+    via = pjsip_via_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);

+    pj_strdup2(pool, &via->transport, "SCTP");

+    pj_strdup2(pool, &via->sent_by.host, "bigbox3.site3.atlanta.com");

+    pj_strdup2(pool, &via->branch_param, "z9hG4bK77ef4c2312983.1");

+

+    /* "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\n"

+	" ;received=192.0.2.1\r\n" */

+    via = pjsip_via_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);

+    pj_strdup2(pool, &via->transport, "UDP");

+    pj_strdup2(pool, &via->sent_by.host, "pc33.atlanta.com");

+    pj_strdup2(pool, &via->branch_param, "z9hG4bKnashds8");

+    pj_strdup2(pool, &via->recvd_param, "192.0.2.1");

+

+

+    /* "Via: SIP/2.0/UDP 10.2.1.1, */ 

+    via = pjsip_via_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);

+    pj_strdup2(pool, &via->transport, "UDP");

+    pj_strdup2(pool, &via->sent_by.host, "10.2.1.1");

+    

+    

+    /*SIP/2.0/TCP 192.168.1.1\n" */

+    via = pjsip_via_hdr_create(pool);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)via);

+    pj_strdup2(pool, &via->transport, "TCP");

+    pj_strdup2(pool, &via->sent_by.host, "192.168.1.1");

+

+    /* "Organization: \r" */

+    str.ptr = "Organization";

+    str.slen = 12;

+    generic = pjsip_generic_string_hdr_create(pool, &str);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);

+    generic->hvalue.ptr = NULL;

+    generic->hvalue.slen = 0;

+

+    /* "Max-Forwards: 70\n" */

+    str.ptr = "Max-Forwards";

+    str.slen = 12;

+    generic = pjsip_generic_string_hdr_create(pool, &str);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);

+    str.ptr = "70";

+    str.slen = 2;

+    generic->hvalue = str;

+

+    /* "X-Header: \r\n" */

+    str.ptr = "X-Header";

+    str.slen = 8;

+    generic = pjsip_generic_string_hdr_create(pool, &str);

+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)generic);

+    str.ptr = NULL;

+    str.slen = 0;

+    generic->hvalue = str;

+

+    return msg;

+}

diff --git a/pjsip/src/tests/pjsip-core/test_uri.c b/pjsip/src/tests/pjsip-core/test_uri.c
index 0c78660..bdbe8f1 100644
--- a/pjsip/src/tests/pjsip-core/test_uri.c
+++ b/pjsip/src/tests/pjsip-core/test_uri.c
@@ -1,645 +1,667 @@
-/* $Id$
- *
- */
-#include <pjsip/sip_parser.h>
-#include <pjsip/sip_uri.h>
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include "test.h"
-
-#define ERR_SYNTAX_ERR	(-2)
-#define ERR_NOT_EQUAL	(-3)
-
-#define ALPHANUM    "abcdefghijklmnopqrstuvwxyz" \
-		    "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
-		    "0123456789"
-#define MARK	    "-_.!~*'()"
-#define USER	    "&=+$,;?/%"
-#define PASS	    "&=+$,%"
-#define PARAM_CHAR  "[]/:&+$" MARK "%"
-
-#define POOL_SIZE	4096
-
-static const char *STATUS_STR(pj_status_t status)
-{
-    switch (status) {
-    case 0: return "OK";
-    case ERR_SYNTAX_ERR: return "Syntax Error";
-    case ERR_NOT_EQUAL: return "Not Equal";
-    }
-    return "???";
-}
-
-static pj_uint32_t parse_len, parse_time, print_time;
-static pj_caching_pool cp;
-
-
-/* URI creator functions. */
-static pjsip_uri *create_uri1( pj_pool_t *pool );
-static pjsip_uri *create_uri2( pj_pool_t *pool );
-static pjsip_uri *create_uri3( pj_pool_t *pool );
-static pjsip_uri *create_uri4( pj_pool_t *pool );
-static pjsip_uri *create_uri5( pj_pool_t *pool );
-static pjsip_uri *create_uri6( pj_pool_t *pool );
-static pjsip_uri *create_uri7( pj_pool_t *pool );
-static pjsip_uri *create_uri8( pj_pool_t *pool );
-static pjsip_uri *create_uri9( pj_pool_t *pool );
-static pjsip_uri *create_uri10( pj_pool_t *pool );
-static pjsip_uri *create_uri11( pj_pool_t *pool );
-static pjsip_uri *create_uri12( pj_pool_t *pool );
-static pjsip_uri *create_uri13( pj_pool_t *pool );
-static pjsip_uri *create_uri14( pj_pool_t *pool );
-static pjsip_uri *create_uri15( pj_pool_t *pool );
-static pjsip_uri *create_uri16( pj_pool_t *pool );
-static pjsip_uri *create_uri17( pj_pool_t *pool );
-static pjsip_uri *create_uri18( pj_pool_t *pool );
-static pjsip_uri *create_uri19( pj_pool_t *pool );
-static pjsip_uri *create_dummy( pj_pool_t *pool );
-
-struct uri_test
-{
-    pj_status_t	     status;
-    char	     str[PJSIP_MAX_URL_SIZE];
-    pjsip_uri *(*creator)(pj_pool_t *pool);
-    pj_size_t	     len;
-} uri_test_array[] = 
-{
-    {
-	PJ_SUCCESS,
-	"sip:localhost",
-	&create_uri1
-    },
-    {
-	PJ_SUCCESS,
-	"sip:user@localhost",
-	&create_uri2
-    },
-    {
-	PJ_SUCCESS,
-	"sip:user:password@localhost:5060",
-	&create_uri3,
-    },
-    {
-	/* Port is specified should not match unspecified port. */
-	ERR_NOT_EQUAL,
-	"sip:localhost:5060",
-	&create_uri4
-    },
-    {
-	/* All recognized parameters. */
-	PJ_SUCCESS,
-	"sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK",
-	&create_uri5
-    },
-    {
-	/* Params mixed with other params and header params. */
-	PJ_SUCCESS,
-	"sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"
-	"?Subject=Hello%20There&Server=SIP%20Server",
-	&create_uri6
-    },
-    {
-	/* SIPS. */
-	PJ_SUCCESS,
-	"sips:localhost",
-	&create_uri7,
-    },
-    {
-	/* Name address */
-	PJ_SUCCESS,
-	"<sip:localhost>",
-	&create_uri8
-    },
-    {
-	/* Name address with display name and SIPS scheme with some redundant
-	 * whitespaced.
-	 */
-	PJ_SUCCESS,
-	"  Power Administrator  <sips:localhost>",
-	&create_uri9
-    },
-    {
-	/* Name address. */
-	PJ_SUCCESS,
-	" \"User\" <sip:user@localhost:5071>",
-	&create_uri10
-    },
-    {
-	/* Escaped sequence in display name (display=Strange User\"\\\"). */
-	PJ_SUCCESS,
-	" \"Strange User\\\"\\\\\\\"\" <sip:localhost>",
-	&create_uri11,
-    },
-    {
-	/* Errorneous escaping in display name. */
-	ERR_SYNTAX_ERR,
-	" \"Rogue User\\\" <sip:localhost>",
-	&create_uri12,
-    },
-    {
-	/* Dangling quote in display name, but that should be OK. */
-	PJ_SUCCESS,
-	"Strange User\" <sip:localhost>",
-	&create_uri13,
-    },
-    {
-	/* Special characters in parameter value must be quoted. */
-	PJ_SUCCESS,
-	"sip:localhost;pvalue=\"hello world\"",
-	&create_uri14,
-    },
-    {
-	/* Excercise strange character sets allowed in display, user, password,
-	 * host, and port. 
-	 */
-	PJ_SUCCESS,
-	"This is -. !% *_+`'~ me <sip:a19A&=+$,;?/%2c:%09a&Zz=+$,@"
-	"my_proxy09.MY-domain.com:9801>",
-	&create_uri15,
-    },
-    {
-	/* Another excercise to the allowed character sets to the hostname. */
-	PJ_SUCCESS,
-	"sip:" ALPHANUM "-_.com",
-	&create_uri16,
-    },
-    {
-	/* Another excercise to the allowed character sets to the username 
-	 * and password.
-	 */
-	PJ_SUCCESS,
-	"sip:" ALPHANUM USER ":" ALPHANUM PASS "@host",
-	&create_uri17,
-    },
-    {
-	/* Excercise to the pname and pvalue, and mixup of other-param
-	 * between 'recognized' params.
-	 */
-	PJ_SUCCESS,
-	"sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR 
-	";lr;other=1;transport=sctp;other2",
-	&create_uri18,
-    },
-    {
-	/* This should trigger syntax error. */
-	ERR_SYNTAX_ERR,
-	"sip:",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: whitespace after scheme. */
-	ERR_SYNTAX_ERR,
-	"sip :host",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: whitespace before hostname. */
-	ERR_SYNTAX_ERR,
-	"sip: host",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: invalid port. */
-	ERR_SYNTAX_ERR,
-	"sip:user:password",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: no host. */
-	ERR_SYNTAX_ERR,
-	"sip:user@",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: no user/host. */
-	ERR_SYNTAX_ERR,
-	"sip:@",
-	&create_dummy,
-    },
-    {
-	/* Syntax error: empty string. */
-	ERR_SYNTAX_ERR,
-	"",
-	&create_dummy,
-    },
-    {
-	PJ_SUCCESS,
-	"",
-	NULL,
-    },
-};
-
-static pjsip_uri *create_uri1(pj_pool_t *pool)
-{
-    /* "sip:localhost" */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri2(pj_pool_t *pool)
-{
-    /* "sip:user@localhost" */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2( pool, &url->user, "user");
-    pj_strdup2( pool, &url->host, "localhost");
-
-    return (pjsip_uri*) url;
-}
-
-static pjsip_uri *create_uri3(pj_pool_t *pool)
-{
-    /* "sip:user:password@localhost:5060" */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2( pool, &url->user, "user");
-    pj_strdup2( pool, &url->passwd, "password");
-    pj_strdup2( pool, &url->host, "localhost");
-    url->port = 5060;
-
-    return (pjsip_uri*) url;
-}
-
-static pjsip_uri *create_uri4(pj_pool_t *pool)
-{
-    /* Like: "sip:localhost:5060", but without the port. */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri5(pj_pool_t *pool)
-{
-    /* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    pj_strdup2(pool, &url->transport_param, "tcp");
-    pj_strdup2(pool, &url->user_param, "ip");
-    url->ttl_param = 255;
-    url->lr_param = 1;
-    pj_strdup2(pool, &url->maddr_param, "127.0.0.1");
-    pj_strdup2(pool, &url->method_param, "ACK");
-
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri6(pj_pool_t *pool)
-{
-    /* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"
-       "?Subject=Hello%20There&Server=SIP%20Server" 
-     */
-    pjsip_url *url = pjsip_url_create(pool, 0);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    pj_strdup2(pool, &url->user_param, "phone");
-    pj_strdup2(pool, &url->other_param, ";pickup=hurry;message=I%20am%20sorry");
-    pj_strdup2(pool, &url->header_param, "?Subject=Hello%20There&Server=SIP%20Server");
-    return (pjsip_uri*)url;
-
-}
-
-static pjsip_uri *create_uri7(pj_pool_t *pool)
-{
-    /* "sips:localhost" */
-    pjsip_url *url = pjsip_url_create(pool, 1);
-
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri8(pj_pool_t *pool)
-{
-    /* "<sip:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri9(pj_pool_t *pool)
-{
-    /* "  Power Administrator <sips:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 1);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "Power Administrator");
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri10(pj_pool_t *pool)
-{
-    /* " \"User\" <sip:user@localhost:5071>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "\"User\"");
-    pj_strdup2(pool, &url->user, "user");
-    pj_strdup2(pool, &url->host, "localhost");
-    url->port = 5071;
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri11(pj_pool_t *pool)
-{
-    /* " \"Strange User\\\"\\\\\\\"\" <sip:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "\"Strange User\\\"\\\\\\\"\"");
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri12(pj_pool_t *pool)
-{
-    /* " \"Rogue User\\\" <sip:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "\"Rogue User\\\"");
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri13(pj_pool_t *pool)
-{
-    /* "Strange User\" <sip:localhost>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "Strange User\"");
-    pj_strdup2(pool, &url->host, "localhost");
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri14(pj_pool_t *pool)
-{
-    /* "sip:localhost;pvalue=\"hello world\"" */
-    pjsip_url *url;
-    url = pjsip_url_create(pool, 0);
-    pj_strdup2(pool, &url->host, "localhost");
-    pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\"");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri15(pj_pool_t *pool)
-{
-    /* "This is -. !% *_+`'~ me <sip:a19A&=+$,;?/%2c:%09a&Zz=+$,@my_proxy09.my-domain.com:9801>" */
-    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);
-    pjsip_url *url;
-
-    url = pjsip_url_create(pool, 0);
-    name_addr->uri = (pjsip_uri*) url;
-
-    pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me");
-    pj_strdup2(pool, &url->user, "a19A&=+$,;?/%2c");
-    pj_strdup2(pool, &url->passwd, "%09a&Zz=+$,");
-    pj_strdup2(pool, &url->host, "my_proxy09.MY-domain.com");
-    url->port = 9801;
-    return (pjsip_uri*)name_addr;
-}
-
-static pjsip_uri *create_uri16(pj_pool_t *pool)
-{
-    /* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */
-    pjsip_url *url;
-    url = pjsip_url_create(pool, 0);
-    pj_strdup2(pool, &url->host, ALPHANUM "-_.com");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri17(pj_pool_t *pool)
-{
-    /* "sip:" ALPHANUM USER ":" ALPHANUM PASS "@host" */
-    pjsip_url *url;
-    url = pjsip_url_create(pool, 0);
-    pj_strdup2(pool, &url->user, ALPHANUM USER);
-    pj_strdup2(pool, &url->passwd, ALPHANUM PASS);
-    pj_strdup2(pool, &url->host, "host");
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_uri18(pj_pool_t *pool)
-{
-    /* "sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";lr;other=1;transport=sctp;other2" */
-    pjsip_url *url;
-    url = pjsip_url_create(pool, 0);
-    pj_strdup2(pool, &url->host, "host");
-    pj_strdup2(pool, &url->user_param, "ip");
-    pj_strdup2(pool, &url->transport_param, "sctp");
-    pj_strdup2(pool, &url->other_param, ";" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";other=1;other2");    
-    url->lr_param = 1;
-    return (pjsip_uri*)url;
-}
-
-static pjsip_uri *create_dummy(pj_pool_t *pool)
-{
-    PJ_UNUSED_ARG(pool)
-    return NULL;
-}
-
-/*****************************************************************************/
-
-static void pool_error(pj_pool_t *pool, pj_size_t sz)
-{
-    PJ_UNUSED_ARG(pool)
-    PJ_UNUSED_ARG(sz)
-
-    pj_assert(0);
-    exit(1);
-}
-
-/*
- * Test one test entry.
- */
-static pj_status_t test_entry(struct uri_test *entry)
-{
-    pj_status_t status;
-    pj_pool_t *pool;
-    int len;
-    pjsip_uri *parsed_uri, *ref_uri;
-    pj_str_t s1 = {NULL, 0}, s2 = {NULL, 0};
-    pj_hr_timestamp t1, t2;
-
-    pool = (*cp.factory.create_pool)( &cp.factory, "", POOL_SIZE, 0, &pool_error);
-
-    /* Parse URI text. */
-    pj_hr_gettimestamp(&t1);
-    parse_len += entry->len;
-    parsed_uri = pjsip_parse_uri(pool, entry->str, entry->len, 0);
-    if (!parsed_uri) {
-	/* Parsing failed. If the entry says that this is expected, then
-	 * return OK.
-	 */
-	status = entry->status==ERR_SYNTAX_ERR ? PJ_SUCCESS : ERR_SYNTAX_ERR;
-	goto on_return;
-    }
-    pj_hr_gettimestamp(&t2);
-    parse_time += t2.u32.lo - t1.u32.lo;
-
-    /* Create the reference URI. */
-    ref_uri = entry->creator(pool);
-
-    /* Print both URI. */
-    s1.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
-    s2.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
-
-    pj_hr_gettimestamp(&t1);
-    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, parsed_uri, s1.ptr, PJSIP_MAX_URL_SIZE);
-    if (len < 1) {
-	status = -1;
-	goto on_return;
-    }
-    s1.slen = len;
-
-    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE);
-    if (len < 1) {
-	status = -1;
-	goto on_return;
-    }
-    s2.slen = len;
-    pj_hr_gettimestamp(&t2);
-    print_time += t2.u32.lo - t1.u32.lo;
-
-    /* Full comparison of parsed URI with reference URI. */
-    if (pjsip_uri_cmp(PJSIP_URI_IN_OTHER, parsed_uri, ref_uri) != 0) {
-	/* Not equal. See if this is the expected status. */
-	status = entry->status==ERR_NOT_EQUAL ? PJ_SUCCESS : ERR_NOT_EQUAL;
-	goto on_return;
-
-    } else {
-	/* Equal. See if this is the expected status. */
-	status = entry->status==PJ_SUCCESS ? PJ_SUCCESS : -1;
-	if (status != PJ_SUCCESS) {
-	    goto on_return;
-	}
-    }
-
-    /* Compare text. */
-    if (pj_strcmp(&s1, &s2) != 0) {
-	/* Not equal. */
-	status = ERR_NOT_EQUAL;
-    }
-
-on_return:
-    if (!SILENT) {
-	printf("%.2d %s (expected status=%s)\n"
-	       "   str=%s\n"
-	       "   uri=%.*s\n"
-	       "   ref=%.*s\n\n", 
-	       entry-uri_test_array, 
-	       STATUS_STR(status), 
-	       STATUS_STR(entry->status), 
-	       entry->str, 
-	       (int)s1.slen, s1.ptr, (int)s2.slen, s2.ptr);
-    }
-
-    pj_pool_release(pool);
-    return status;
-}
-
-static void warm_up(pj_pool_factory *pf)
-{
-    pj_pool_t *pool;
-    struct uri_test *entry;
-
-    pool = pj_pool_create(pf, "", POOL_SIZE, 0, &pool_error);
-    pjsip_parse_uri(pool, "sip:host", 8, 0);
-    entry = &uri_test_array[0];
-    while (entry->creator) {
-	entry->len = strlen(entry->str);
-	++entry;
-    }
-    pj_pool_release(pool);
-}
-
-//#if !IS_PROFILING
-#if 1
-pj_status_t test_uri()
-{
-    struct uri_test *entry;
-    int i=0, err=0;
-    pj_status_t status;
-    pj_hr_timestamp t1, t2;
-    pj_uint32_t total_time;
-
-    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
-    warm_up(&cp.factory);
-
-    pj_hr_gettimestamp(&t1);
-    for (i=0; i<LOOP; ++i) {
-	entry = &uri_test_array[0];
-	while (entry->creator) {
-	    status = test_entry(entry);
-	    if (status != PJ_SUCCESS) {
-		++err;
-	    }
-	    ++entry;
-	}
-    }
-    pj_hr_gettimestamp(&t2);
-    total_time = t2.u32.lo - t1.u32.lo;
-
-    printf("Error=%d\n", err);
-    printf("Total parse len:  %u bytes\n", parse_len);
-    printf("Total parse time: %u (%f/char), print time: %u (%f/char)\n", 
-	    parse_time, parse_time*1.0/parse_len,
-	    print_time, print_time*1.0/parse_len);
-    printf("Total time: %u (%f/char)\n", total_time, total_time*1.0/parse_len);
-    return err;
-}
-
-#else
-
-pj_status_t test_uri()
-{
-    struct uri_test *entry;
-    unsigned i;
-
-    warm_up();
-    pj_caching_pool_init(&cp, 1024*1024);
-
-    for (i=0; i<LOOP; ++i) {
-	entry = &uri_test_array[0];
-	while (entry->creator) {
-	    pj_pool_t *pool;
-	    pjsip_uri *uri1, *uri2;
-
-	    pool = pj_pool_create( &cp.factory, "", POOL_SIZE, 0, &pool_error);
-	    uri1 = pjsip_parse_uri(pool, entry->str, strlen(entry->str));
-	    pj_pool_release(pool);
-	    ++entry;
-	}
-    }
-
-    return 0;
-}
-
-#endif
+/* $Id$

+ *

+ */

+/* 

+ * PJSIP - SIP Stack

+ * (C)2003-2005 Benny Prijono <bennylp@bulukucing.org>

+ *

+ * Author:

+ *  Benny Prijono <bennylp@bulukucing.org>

+ *

+ * This library is free software; you can redistribute it and/or

+ * modify it under the terms of the GNU Lesser General Public

+ * License as published by the Free Software Foundation; either

+ * version 2.1 of the License, or (at your option) any later version.

+ * 

+ * This library 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

+ * Lesser General Public License for more details.

+ * 

+ * You should have received a copy of the GNU Lesser General Public

+ * License along with this library; if not, write to the Free Software

+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

+ *

+ */

+#include <pjsip/sip_parser.h>

+#include <pjsip/sip_uri.h>

+#include <pj/os.h>

+#include <pj/pool.h>

+#include <pj/string.h>

+#include <stdlib.h>

+#include <stdio.h>

+#include "test.h"

+

+#define ERR_SYNTAX_ERR	(-2)

+#define ERR_NOT_EQUAL	(-3)

+

+#define ALPHANUM    "abcdefghijklmnopqrstuvwxyz" \

+		    "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \

+		    "0123456789"

+#define MARK	    "-_.!~*'()"

+#define USER	    "&=+$,;?/%"

+#define PASS	    "&=+$,%"

+#define PARAM_CHAR  "[]/:&+$" MARK "%"

+

+#define POOL_SIZE	4096

+

+static const char *STATUS_STR(pj_status_t status)

+{

+    switch (status) {

+    case 0: return "OK";

+    case ERR_SYNTAX_ERR: return "Syntax Error";

+    case ERR_NOT_EQUAL: return "Not Equal";

+    }

+    return "???";

+}

+

+static pj_uint32_t parse_len, parse_time, print_time;

+static pj_caching_pool cp;

+

+

+/* URI creator functions. */

+static pjsip_uri *create_uri1( pj_pool_t *pool );

+static pjsip_uri *create_uri2( pj_pool_t *pool );

+static pjsip_uri *create_uri3( pj_pool_t *pool );

+static pjsip_uri *create_uri4( pj_pool_t *pool );

+static pjsip_uri *create_uri5( pj_pool_t *pool );

+static pjsip_uri *create_uri6( pj_pool_t *pool );

+static pjsip_uri *create_uri7( pj_pool_t *pool );

+static pjsip_uri *create_uri8( pj_pool_t *pool );

+static pjsip_uri *create_uri9( pj_pool_t *pool );

+static pjsip_uri *create_uri10( pj_pool_t *pool );

+static pjsip_uri *create_uri11( pj_pool_t *pool );

+static pjsip_uri *create_uri12( pj_pool_t *pool );

+static pjsip_uri *create_uri13( pj_pool_t *pool );

+static pjsip_uri *create_uri14( pj_pool_t *pool );

+static pjsip_uri *create_uri15( pj_pool_t *pool );

+static pjsip_uri *create_uri16( pj_pool_t *pool );

+static pjsip_uri *create_uri17( pj_pool_t *pool );

+static pjsip_uri *create_uri18( pj_pool_t *pool );

+static pjsip_uri *create_uri19( pj_pool_t *pool );

+static pjsip_uri *create_dummy( pj_pool_t *pool );

+

+struct uri_test

+{

+    pj_status_t	     status;

+    char	     str[PJSIP_MAX_URL_SIZE];

+    pjsip_uri *(*creator)(pj_pool_t *pool);

+    pj_size_t	     len;

+} uri_test_array[] = 

+{

+    {

+	PJ_SUCCESS,

+	"sip:localhost",

+	&create_uri1

+    },

+    {

+	PJ_SUCCESS,

+	"sip:user@localhost",

+	&create_uri2

+    },

+    {

+	PJ_SUCCESS,

+	"sip:user:password@localhost:5060",

+	&create_uri3,

+    },

+    {

+	/* Port is specified should not match unspecified port. */

+	ERR_NOT_EQUAL,

+	"sip:localhost:5060",

+	&create_uri4

+    },

+    {

+	/* All recognized parameters. */

+	PJ_SUCCESS,

+	"sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK",

+	&create_uri5

+    },

+    {

+	/* Params mixed with other params and header params. */

+	PJ_SUCCESS,

+	"sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"

+	"?Subject=Hello%20There&Server=SIP%20Server",

+	&create_uri6

+    },

+    {

+	/* SIPS. */

+	PJ_SUCCESS,

+	"sips:localhost",

+	&create_uri7,

+    },

+    {

+	/* Name address */

+	PJ_SUCCESS,

+	"<sip:localhost>",

+	&create_uri8

+    },

+    {

+	/* Name address with display name and SIPS scheme with some redundant

+	 * whitespaced.

+	 */

+	PJ_SUCCESS,

+	"  Power Administrator  <sips:localhost>",

+	&create_uri9

+    },

+    {

+	/* Name address. */

+	PJ_SUCCESS,

+	" \"User\" <sip:user@localhost:5071>",

+	&create_uri10

+    },

+    {

+	/* Escaped sequence in display name (display=Strange User\"\\\"). */

+	PJ_SUCCESS,

+	" \"Strange User\\\"\\\\\\\"\" <sip:localhost>",

+	&create_uri11,

+    },

+    {

+	/* Errorneous escaping in display name. */

+	ERR_SYNTAX_ERR,

+	" \"Rogue User\\\" <sip:localhost>",

+	&create_uri12,

+    },

+    {

+	/* Dangling quote in display name, but that should be OK. */

+	PJ_SUCCESS,

+	"Strange User\" <sip:localhost>",

+	&create_uri13,

+    },

+    {

+	/* Special characters in parameter value must be quoted. */

+	PJ_SUCCESS,

+	"sip:localhost;pvalue=\"hello world\"",

+	&create_uri14,

+    },

+    {

+	/* Excercise strange character sets allowed in display, user, password,

+	 * host, and port. 

+	 */

+	PJ_SUCCESS,

+	"This is -. !% *_+`'~ me <sip:a19A&=+$,;?/%2c:%09a&Zz=+$,@"

+	"my_proxy09.MY-domain.com:9801>",

+	&create_uri15,

+    },

+    {

+	/* Another excercise to the allowed character sets to the hostname. */

+	PJ_SUCCESS,

+	"sip:" ALPHANUM "-_.com",

+	&create_uri16,

+    },

+    {

+	/* Another excercise to the allowed character sets to the username 

+	 * and password.

+	 */

+	PJ_SUCCESS,

+	"sip:" ALPHANUM USER ":" ALPHANUM PASS "@host",

+	&create_uri17,

+    },

+    {

+	/* Excercise to the pname and pvalue, and mixup of other-param

+	 * between 'recognized' params.

+	 */

+	PJ_SUCCESS,

+	"sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR 

+	";lr;other=1;transport=sctp;other2",

+	&create_uri18,

+    },

+    {

+	/* This should trigger syntax error. */

+	ERR_SYNTAX_ERR,

+	"sip:",

+	&create_dummy,

+    },

+    {

+	/* Syntax error: whitespace after scheme. */

+	ERR_SYNTAX_ERR,

+	"sip :host",

+	&create_dummy,

+    },

+    {

+	/* Syntax error: whitespace before hostname. */

+	ERR_SYNTAX_ERR,

+	"sip: host",

+	&create_dummy,

+    },

+    {

+	/* Syntax error: invalid port. */

+	ERR_SYNTAX_ERR,

+	"sip:user:password",

+	&create_dummy,

+    },

+    {

+	/* Syntax error: no host. */

+	ERR_SYNTAX_ERR,

+	"sip:user@",

+	&create_dummy,

+    },

+    {

+	/* Syntax error: no user/host. */

+	ERR_SYNTAX_ERR,

+	"sip:@",

+	&create_dummy,

+    },

+    {

+	/* Syntax error: empty string. */

+	ERR_SYNTAX_ERR,

+	"",

+	&create_dummy,

+    },

+    {

+	PJ_SUCCESS,

+	"",

+	NULL,

+    },

+};

+

+static pjsip_uri *create_uri1(pj_pool_t *pool)

+{

+    /* "sip:localhost" */

+    pjsip_url *url = pjsip_url_create(pool, 0);

+

+    pj_strdup2(pool, &url->host, "localhost");

+    return (pjsip_uri*)url;

+}

+

+static pjsip_uri *create_uri2(pj_pool_t *pool)

+{

+    /* "sip:user@localhost" */

+    pjsip_url *url = pjsip_url_create(pool, 0);

+

+    pj_strdup2( pool, &url->user, "user");

+    pj_strdup2( pool, &url->host, "localhost");

+

+    return (pjsip_uri*) url;

+}

+

+static pjsip_uri *create_uri3(pj_pool_t *pool)

+{

+    /* "sip:user:password@localhost:5060" */

+    pjsip_url *url = pjsip_url_create(pool, 0);

+

+    pj_strdup2( pool, &url->user, "user");

+    pj_strdup2( pool, &url->passwd, "password");

+    pj_strdup2( pool, &url->host, "localhost");

+    url->port = 5060;

+

+    return (pjsip_uri*) url;

+}

+

+static pjsip_uri *create_uri4(pj_pool_t *pool)

+{

+    /* Like: "sip:localhost:5060", but without the port. */

+    pjsip_url *url = pjsip_url_create(pool, 0);

+

+    pj_strdup2(pool, &url->host, "localhost");

+    return (pjsip_uri*)url;

+}

+

+static pjsip_uri *create_uri5(pj_pool_t *pool)

+{

+    /* "sip:localhost;transport=tcp;user=ip;ttl=255;lr;maddr=127.0.0.1;method=ACK" */

+    pjsip_url *url = pjsip_url_create(pool, 0);

+

+    pj_strdup2(pool, &url->host, "localhost");

+    pj_strdup2(pool, &url->transport_param, "tcp");

+    pj_strdup2(pool, &url->user_param, "ip");

+    url->ttl_param = 255;

+    url->lr_param = 1;

+    pj_strdup2(pool, &url->maddr_param, "127.0.0.1");

+    pj_strdup2(pool, &url->method_param, "ACK");

+

+    return (pjsip_uri*)url;

+}

+

+static pjsip_uri *create_uri6(pj_pool_t *pool)

+{

+    /* "sip:localhost;pickup=hurry;user=phone;message=I%20am%20sorry"

+       "?Subject=Hello%20There&Server=SIP%20Server" 

+     */

+    pjsip_url *url = pjsip_url_create(pool, 0);

+

+    pj_strdup2(pool, &url->host, "localhost");

+    pj_strdup2(pool, &url->user_param, "phone");

+    pj_strdup2(pool, &url->other_param, ";pickup=hurry;message=I%20am%20sorry");

+    pj_strdup2(pool, &url->header_param, "?Subject=Hello%20There&Server=SIP%20Server");

+    return (pjsip_uri*)url;

+

+}

+

+static pjsip_uri *create_uri7(pj_pool_t *pool)

+{

+    /* "sips:localhost" */

+    pjsip_url *url = pjsip_url_create(pool, 1);

+

+    pj_strdup2(pool, &url->host, "localhost");

+    return (pjsip_uri*)url;

+}

+

+static pjsip_uri *create_uri8(pj_pool_t *pool)

+{

+    /* "<sip:localhost>" */

+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);

+    pjsip_url *url;

+

+    url = pjsip_url_create(pool, 0);

+    name_addr->uri = (pjsip_uri*) url;

+

+    pj_strdup2(pool, &url->host, "localhost");

+    return (pjsip_uri*)name_addr;

+}

+

+static pjsip_uri *create_uri9(pj_pool_t *pool)

+{

+    /* "  Power Administrator <sips:localhost>" */

+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);

+    pjsip_url *url;

+

+    url = pjsip_url_create(pool, 1);

+    name_addr->uri = (pjsip_uri*) url;

+

+    pj_strdup2(pool, &name_addr->display, "Power Administrator");

+    pj_strdup2(pool, &url->host, "localhost");

+    return (pjsip_uri*)name_addr;

+}

+

+static pjsip_uri *create_uri10(pj_pool_t *pool)

+{

+    /* " \"User\" <sip:user@localhost:5071>" */

+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);

+    pjsip_url *url;

+

+    url = pjsip_url_create(pool, 0);

+    name_addr->uri = (pjsip_uri*) url;

+

+    pj_strdup2(pool, &name_addr->display, "\"User\"");

+    pj_strdup2(pool, &url->user, "user");

+    pj_strdup2(pool, &url->host, "localhost");

+    url->port = 5071;

+    return (pjsip_uri*)name_addr;

+}

+

+static pjsip_uri *create_uri11(pj_pool_t *pool)

+{

+    /* " \"Strange User\\\"\\\\\\\"\" <sip:localhost>" */

+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);

+    pjsip_url *url;

+

+    url = pjsip_url_create(pool, 0);

+    name_addr->uri = (pjsip_uri*) url;

+

+    pj_strdup2(pool, &name_addr->display, "\"Strange User\\\"\\\\\\\"\"");

+    pj_strdup2(pool, &url->host, "localhost");

+    return (pjsip_uri*)name_addr;

+}

+

+static pjsip_uri *create_uri12(pj_pool_t *pool)

+{

+    /* " \"Rogue User\\\" <sip:localhost>" */

+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);

+    pjsip_url *url;

+

+    url = pjsip_url_create(pool, 0);

+    name_addr->uri = (pjsip_uri*) url;

+

+    pj_strdup2(pool, &name_addr->display, "\"Rogue User\\\"");

+    pj_strdup2(pool, &url->host, "localhost");

+    return (pjsip_uri*)name_addr;

+}

+

+static pjsip_uri *create_uri13(pj_pool_t *pool)

+{

+    /* "Strange User\" <sip:localhost>" */

+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);

+    pjsip_url *url;

+

+    url = pjsip_url_create(pool, 0);

+    name_addr->uri = (pjsip_uri*) url;

+

+    pj_strdup2(pool, &name_addr->display, "Strange User\"");

+    pj_strdup2(pool, &url->host, "localhost");

+    return (pjsip_uri*)name_addr;

+}

+

+static pjsip_uri *create_uri14(pj_pool_t *pool)

+{

+    /* "sip:localhost;pvalue=\"hello world\"" */

+    pjsip_url *url;

+    url = pjsip_url_create(pool, 0);

+    pj_strdup2(pool, &url->host, "localhost");

+    pj_strdup2(pool, &url->other_param, ";pvalue=\"hello world\"");

+    return (pjsip_uri*)url;

+}

+

+static pjsip_uri *create_uri15(pj_pool_t *pool)

+{

+    /* "This is -. !% *_+`'~ me <sip:a19A&=+$,;?/%2c:%09a&Zz=+$,@my_proxy09.my-domain.com:9801>" */

+    pjsip_name_addr *name_addr = pjsip_name_addr_create(pool);

+    pjsip_url *url;

+

+    url = pjsip_url_create(pool, 0);

+    name_addr->uri = (pjsip_uri*) url;

+

+    pj_strdup2(pool, &name_addr->display, "This is -. !% *_+`'~ me");

+    pj_strdup2(pool, &url->user, "a19A&=+$,;?/%2c");

+    pj_strdup2(pool, &url->passwd, "%09a&Zz=+$,");

+    pj_strdup2(pool, &url->host, "my_proxy09.MY-domain.com");

+    url->port = 9801;

+    return (pjsip_uri*)name_addr;

+}

+

+static pjsip_uri *create_uri16(pj_pool_t *pool)

+{

+    /* "sip:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.com" */

+    pjsip_url *url;

+    url = pjsip_url_create(pool, 0);

+    pj_strdup2(pool, &url->host, ALPHANUM "-_.com");

+    return (pjsip_uri*)url;

+}

+

+static pjsip_uri *create_uri17(pj_pool_t *pool)

+{

+    /* "sip:" ALPHANUM USER ":" ALPHANUM PASS "@host" */

+    pjsip_url *url;

+    url = pjsip_url_create(pool, 0);

+    pj_strdup2(pool, &url->user, ALPHANUM USER);

+    pj_strdup2(pool, &url->passwd, ALPHANUM PASS);

+    pj_strdup2(pool, &url->host, "host");

+    return (pjsip_uri*)url;

+}

+

+static pjsip_uri *create_uri18(pj_pool_t *pool)

+{

+    /* "sip:host;user=ip;" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";lr;other=1;transport=sctp;other2" */

+    pjsip_url *url;

+    url = pjsip_url_create(pool, 0);

+    pj_strdup2(pool, &url->host, "host");

+    pj_strdup2(pool, &url->user_param, "ip");

+    pj_strdup2(pool, &url->transport_param, "sctp");

+    pj_strdup2(pool, &url->other_param, ";" ALPHANUM PARAM_CHAR "=" ALPHANUM PARAM_CHAR ";other=1;other2");    

+    url->lr_param = 1;

+    return (pjsip_uri*)url;

+}

+

+static pjsip_uri *create_dummy(pj_pool_t *pool)

+{

+    PJ_UNUSED_ARG(pool)

+    return NULL;

+}

+

+/*****************************************************************************/

+

+static void pool_error(pj_pool_t *pool, pj_size_t sz)

+{

+    PJ_UNUSED_ARG(pool)

+    PJ_UNUSED_ARG(sz)

+

+    pj_assert(0);

+    exit(1);

+}

+

+/*

+ * Test one test entry.

+ */

+static pj_status_t test_entry(struct uri_test *entry)

+{

+    pj_status_t status;

+    pj_pool_t *pool;

+    int len;

+    pjsip_uri *parsed_uri, *ref_uri;

+    pj_str_t s1 = {NULL, 0}, s2 = {NULL, 0};

+    pj_hr_timestamp t1, t2;

+

+    pool = (*cp.factory.create_pool)( &cp.factory, "", POOL_SIZE, 0, &pool_error);

+

+    /* Parse URI text. */

+    pj_hr_gettimestamp(&t1);

+    parse_len += entry->len;

+    parsed_uri = pjsip_parse_uri(pool, entry->str, entry->len, 0);

+    if (!parsed_uri) {

+	/* Parsing failed. If the entry says that this is expected, then

+	 * return OK.

+	 */

+	status = entry->status==ERR_SYNTAX_ERR ? PJ_SUCCESS : ERR_SYNTAX_ERR;

+	goto on_return;

+    }

+    pj_hr_gettimestamp(&t2);

+    parse_time += t2.u32.lo - t1.u32.lo;

+

+    /* Create the reference URI. */

+    ref_uri = entry->creator(pool);

+

+    /* Print both URI. */

+    s1.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);

+    s2.ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);

+

+    pj_hr_gettimestamp(&t1);

+    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, parsed_uri, s1.ptr, PJSIP_MAX_URL_SIZE);

+    if (len < 1) {

+	status = -1;

+	goto on_return;

+    }

+    s1.slen = len;

+

+    len = pjsip_uri_print( PJSIP_URI_IN_OTHER, ref_uri, s2.ptr, PJSIP_MAX_URL_SIZE);

+    if (len < 1) {

+	status = -1;

+	goto on_return;

+    }

+    s2.slen = len;

+    pj_hr_gettimestamp(&t2);

+    print_time += t2.u32.lo - t1.u32.lo;

+

+    /* Full comparison of parsed URI with reference URI. */

+    if (pjsip_uri_cmp(PJSIP_URI_IN_OTHER, parsed_uri, ref_uri) != 0) {

+	/* Not equal. See if this is the expected status. */

+	status = entry->status==ERR_NOT_EQUAL ? PJ_SUCCESS : ERR_NOT_EQUAL;

+	goto on_return;

+

+    } else {

+	/* Equal. See if this is the expected status. */

+	status = entry->status==PJ_SUCCESS ? PJ_SUCCESS : -1;

+	if (status != PJ_SUCCESS) {

+	    goto on_return;

+	}

+    }

+

+    /* Compare text. */

+    if (pj_strcmp(&s1, &s2) != 0) {

+	/* Not equal. */

+	status = ERR_NOT_EQUAL;

+    }

+

+on_return:

+    if (!SILENT) {

+	printf("%.2d %s (expected status=%s)\n"

+	       "   str=%s\n"

+	       "   uri=%.*s\n"

+	       "   ref=%.*s\n\n", 

+	       entry-uri_test_array, 

+	       STATUS_STR(status), 

+	       STATUS_STR(entry->status), 

+	       entry->str, 

+	       (int)s1.slen, s1.ptr, (int)s2.slen, s2.ptr);

+    }

+

+    pj_pool_release(pool);

+    return status;

+}

+

+static void warm_up(pj_pool_factory *pf)

+{

+    pj_pool_t *pool;

+    struct uri_test *entry;

+

+    pool = pj_pool_create(pf, "", POOL_SIZE, 0, &pool_error);

+    pjsip_parse_uri(pool, "sip:host", 8, 0);

+    entry = &uri_test_array[0];

+    while (entry->creator) {

+	entry->len = strlen(entry->str);

+	++entry;

+    }

+    pj_pool_release(pool);

+}

+

+//#if !IS_PROFILING

+#if 1

+pj_status_t test_uri()

+{

+    struct uri_test *entry;

+    int i=0, err=0;

+    pj_status_t status;

+    pj_hr_timestamp t1, t2;

+    pj_uint32_t total_time;

+

+    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);

+    warm_up(&cp.factory);

+

+    pj_hr_gettimestamp(&t1);

+    for (i=0; i<LOOP; ++i) {

+	entry = &uri_test_array[0];

+	while (entry->creator) {

+	    status = test_entry(entry);

+	    if (status != PJ_SUCCESS) {

+		++err;

+	    }

+	    ++entry;

+	}

+    }

+    pj_hr_gettimestamp(&t2);

+    total_time = t2.u32.lo - t1.u32.lo;

+

+    printf("Error=%d\n", err);

+    printf("Total parse len:  %u bytes\n", parse_len);

+    printf("Total parse time: %u (%f/char), print time: %u (%f/char)\n", 

+	    parse_time, parse_time*1.0/parse_len,

+	    print_time, print_time*1.0/parse_len);

+    printf("Total time: %u (%f/char)\n", total_time, total_time*1.0/parse_len);

+    return err;

+}

+

+#else

+

+pj_status_t test_uri()

+{

+    struct uri_test *entry;

+    unsigned i;

+

+    warm_up();

+    pj_caching_pool_init(&cp, 1024*1024);

+

+    for (i=0; i<LOOP; ++i) {

+	entry = &uri_test_array[0];

+	while (entry->creator) {

+	    pj_pool_t *pool;

+	    pjsip_uri *uri1, *uri2;

+

+	    pool = pj_pool_create( &cp.factory, "", POOL_SIZE, 0, &pool_error);

+	    uri1 = pjsip_parse_uri(pool, entry->str, strlen(entry->str));

+	    pj_pool_release(pool);

+	    ++entry;

+	}

+    }

+

+    return 0;

+}

+

+#endif