Index: /pjproject/trunk/pjmedia/build/Makefile
===================================================================
--- /pjproject/trunk/pjmedia/build/Makefile	(revision 517)
+++ /pjproject/trunk/pjmedia/build/Makefile	(revision 518)
@@ -93,10 +93,11 @@
 		speex/exc_10_32_table.o speex/exc_20_32_table.o \
 		speex/exc_5_256_table.o speex/exc_5_64_table.o \
-		speex/exc_8_128_table.o speex/filters.o \
+		speex/exc_8_128_table.o speex/fftwrap.c speex/filters.o \
 		speex/gain_table.o speex/gain_table_lbr.o \
 		speex/hexc_10_32_table.o speex/hexc_table.o \
-		speex/high_lsp_tables.o speex/lpc_spx.o \
+		speex/high_lsp_tables.o speex/jitter.c \
+		speex/kiss_fft.c speex/kiss_fftr.c speex/lpc_spx.o \
 		speex/lsp.o speex/lsp_tables_nb.o speex/ltp.o \
-		speex/math_approx.o speex/misc.o speex/modes.o \
+		speex/math_approx.o speex/misc.o speex/mdf.c speex/modes.o \
 		speex/nb_celp.o speex/preprocess_spx.o \
 		speex/quant_lsp.o speex/sb_celp.o speex/smallft.o \
Index: /pjproject/trunk/pjmedia/build/pjmedia.dsp
===================================================================
--- /pjproject/trunk/pjmedia/build/pjmedia.dsp	(revision 517)
+++ /pjproject/trunk/pjmedia/build/pjmedia.dsp	(revision 518)
@@ -312,4 +312,8 @@
 # Begin Source File
 
+SOURCE=..\include\pjmedia\transport.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\include\pjmedia\transport_udp.h
 # End Source File
Index: /pjproject/trunk/pjmedia/build/pjmedia_codec.dsp
===================================================================
--- /pjproject/trunk/pjmedia/build/pjmedia_codec.dsp	(revision 517)
+++ /pjproject/trunk/pjmedia/build/pjmedia_codec.dsp	(revision 518)
@@ -227,4 +227,8 @@
 # Begin Source File
 
+SOURCE="..\src\pjmedia-codec\speex\_kiss_fft_guts.h"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjmedia-codec\speex\arch.h"
 # End Source File
@@ -251,4 +255,8 @@
 # Begin Source File
 
+SOURCE="..\src\pjmedia-codec\speex\fftwrap.h"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjmedia-codec\speex\filters.h"
 # End Source File
@@ -284,4 +292,12 @@
 
 SOURCE="..\src\pjmedia-codec\speex\fixed_generic.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\speex\kiss_fft.h"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\speex\kiss_fftr.h"
 # End Source File
 # Begin Source File
@@ -455,4 +471,8 @@
 # Begin Source File
 
+SOURCE="..\src\pjmedia-codec\speex\fftwrap.c"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjmedia-codec\speex\filters.c"
 # ADD CPP /W4
@@ -485,4 +505,16 @@
 # Begin Source File
 
+SOURCE="..\src\pjmedia-codec\speex\jitter.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\speex\kiss_fft.c"
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\speex\kiss_fftr.c"
+# End Source File
+# Begin Source File
+
 SOURCE="..\src\pjmedia-codec\speex\lpc_spx.c"
 # ADD CPP /W4
@@ -507,4 +539,8 @@
 SOURCE="..\src\pjmedia-codec\speex\math_approx.c"
 # ADD CPP /W4
+# End Source File
+# Begin Source File
+
+SOURCE="..\src\pjmedia-codec\speex\mdf.c"
 # End Source File
 # Begin Source File
Index: /pjproject/trunk/pjmedia/docs/doxygen.cfg
===================================================================
--- /pjproject/trunk/pjmedia/docs/doxygen.cfg	(revision 517)
+++ /pjproject/trunk/pjmedia/docs/doxygen.cfg	(revision 518)
@@ -18,5 +18,5 @@
 # by quotes) that should identify the project.
 
-PROJECT_NAME           =  PJMEDIA
+PROJECT_NAME           =  "PJMEDIA and PJMEDIA-CODEC"
 
 # The PROJECT_NUMBER tag can be used to enter a project or revision number. 
@@ -108,5 +108,5 @@
 # brief descriptions will be completely suppressed.
 
-REPEAT_BRIEF           = YES
+REPEAT_BRIEF           = NO
 
 # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
@@ -134,5 +134,5 @@
 # the path. It is allowed to use relative paths in the argument list.
 
-STRIP_FROM_PATH        = "c:\project\pjproject"
+STRIP_FROM_PATH        = "/c/project/pjproject/pjmedia"
 
 # The INTERNAL_DOCS tag determines if documentation 
@@ -155,5 +155,5 @@
 # doesn't support long names like on DOS, Mac, or CD-ROM.
 
-SHORT_NAMES            = YES
+SHORT_NAMES            = NO
 
 # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
@@ -167,5 +167,5 @@
 # which an include is specified. Set to NO to disable this.
 
-VERBATIM_HEADERS       = YES
+VERBATIM_HEADERS       = NO
 
 # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
@@ -346,5 +346,5 @@
 # with spaces.
 
-INPUT                  =  include/pjmedia
+INPUT                  =  include
 
 # If the value of the INPUT tag contains directories, you can use the 
@@ -404,5 +404,5 @@
 # the \image command).
 
-IMAGE_PATH             = 
+IMAGE_PATH             = docs
 
 # The INPUT_FILTER tag can be used to specify a program that doxygen should 
@@ -495,5 +495,5 @@
 # doxygen will generate files with .html extension.
 
-HTML_FILE_EXTENSION    = .html
+HTML_FILE_EXTENSION    = .htm
 
 # The HTML_HEADER tag can be used to specify a personal HTML header for 
@@ -569,5 +569,5 @@
 # that doxygen will group on one line in the generated HTML documentation.
 
-ENUM_VALUES_PER_LINE   = 4
+ENUM_VALUES_PER_LINE   = 1
 
 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
@@ -843,5 +843,6 @@
 
 PREDEFINED             = PJ_DECL(x)=x PJ_DEF(x)=x PJ_IDECL(x)=x \
-			 PJ_IDEF(x)=x PJ_INLINE(x)=x
+			 PJ_IDEF(x)=x PJ_INLINE(x)=x \
+			 PJ_BEGIN_DECL= PJ_END_DECL=
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
Index: /pjproject/trunk/pjmedia/docs/footer.html
===================================================================
--- /pjproject/trunk/pjmedia/docs/footer.html	(revision 517)
+++ /pjproject/trunk/pjmedia/docs/footer.html	(revision 518)
@@ -1,9 +1,3 @@
-</TD></TR>
-</TABLE>
-
-</td>
-</tr>
-</table>
-
+	<!--#include virtual="/footer.html" -->
 </BODY>
 </HTML>
Index: /pjproject/trunk/pjmedia/docs/header.html
===================================================================
--- /pjproject/trunk/pjmedia/docs/header.html	(revision 517)
+++ /pjproject/trunk/pjmedia/docs/header.html	(revision 518)
@@ -1,32 +1,7 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
-<title>PJMEDIA Documentation</title>
-<link href="doxygen.css" rel="stylesheet" type="text/css">
+<title>PJMEDIA - Open Source media stack with RTP, RTCP, SDP, conference bridge, PLC, VAD, etc.</title>
+<link href="/style/style.css" rel="stylesheet" type="text/css">
 </head><body>
+	<!--#include virtual="/header.html" -->
 
-<TABLE id="MainTable" cellSpacing="0" cellPadding="0" width="100%" border="0">
-<!-- First Row, PJPROJECT logo. -->
-<TR>
-    <TD>
-	<TABLE id="LogoTable" cellSpacing="0" cellPadding="0" width="100%" border="0">
-	    <TR>
-		<TD><a href="/" target="_top"><IMG src="/images/pjlogo.jpg" border="0"></a></TD>
-		<TD>&nbsp;</TD>
-		<TD>&nbsp;</TD>
-	    </TR>
-	</TABLE>
-    </TD>
-</TR>
-<!-- Second Row, a HR. -->
-<TR>
-    <td colspan="3"><hr noshade size="1">
-    </td>
-</TR>
-<!-- Third row, main contents. -->
-<TR>
-    <TD>
-
-<!-- Main doxygen content -->
-<TABLE border="0">
-  <TR><TD width="800" align="left">
-
Index: /pjproject/trunk/pjmedia/include/pjmedia-codec/gsm.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-codec/gsm.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia-codec/gsm.h	(revision 518)
@@ -20,6 +20,20 @@
 #define __PJMEDIA_CODEC_GSM_H__
 
+/**
+ * @file pjmedia-codec/gsm.h
+ * @brief GSM 06.10 codec.
+ */
+
 #include <pjmedia-codec/types.h>
 
+/**
+ * @defgroup PJMED_GSM GSM 06.10
+ * @ingroup PJMEDIA_CODEC
+ * @brief Implementation of GSM FR based on GSM 06.10 library
+ * @{
+ * This section describes functions to register and register GSM codec
+ * factory to the codec manager. After the codec factory has been registered,
+ * application can use @ref PJMEDIA_CODEC API to manipulate the codec.
+ */
 
 PJ_BEGIN_DECL
@@ -49,4 +63,8 @@
 
 
+/**
+ * @}
+ */
+
 #endif	/* __PJMEDIA_CODEC_GSM_H__ */
 
Index: /pjproject/trunk/pjmedia/include/pjmedia-codec/l16.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-codec/l16.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia-codec/l16.h	(revision 518)
@@ -22,4 +22,18 @@
 #include <pjmedia-codec/types.h>
 
+
+/**
+ * @defgroup PJMED_L16 L16 Family
+ * @ingroup PJMEDIA_CODEC
+ * @brief 16bit linear codecs (useful for debugging)
+ * @{
+ * This section describes functions to register and register L16 codec
+ * factory to the codec manager. After the codec factory has been registered,
+ * application can use @ref PJMEDIA_CODEC API to manipulate the codec.
+ *
+ * Note that the L16 codec factory registers several (about fourteen!) 
+ * L16 codec types to codec manager (different combinations of clock
+ * rate and number of channels).
+ */
 
 PJ_BEGIN_DECL
Index: /pjproject/trunk/pjmedia/include/pjmedia-codec/speex.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-codec/speex.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia-codec/speex.h	(revision 518)
@@ -20,6 +20,25 @@
 #define __PJMEDIA_CODEC_SPEEX_H__
 
+/**
+ * @file speex.h
+ * @brief Speex codec header.
+ */
+
 #include <pjmedia-codec/types.h>
 
+/**
+ * @defgroup PJMED_SPEEX Speex
+ * @ingroup PJMEDIA_CODEC
+ * @brief Implementation of Speex codecs (narrow/wide/ultrawide-band).
+ * @{
+ * This section describes functions to register and register speex codec
+ * factory to the codec manager. After the codec factory has been registered,
+ * application can use @ref PJMEDIA_CODEC API to manipulate the codec.
+ *
+ * By default, the speex codec factory registers three Speex codecs:
+ * "speex/8000" narrowband codec, "speex/16000" wideband codec, and 
+ * "speex/32000" ultra-wideband codec. This behavior can be changed by
+ * specifying #pjmedia_speex_options flags during initialization.
+ */
 
 PJ_BEGIN_DECL
@@ -60,9 +79,4 @@
  *
  * @param endpt		The pjmedia endpoint.
- * @param options	Bitmask of pjmedia_speex_options (default=0).
- * @param quality	Specify encoding quality, or use -1 for default 
- *			(default=8).
- * @param complexity	Specify encoding complexity , or use -1 for default 
- *			(default=8).
  *
  * @return		PJ_SUCCESS on success.
@@ -83,4 +97,7 @@
 PJ_END_DECL
 
+/**
+ * @}
+ */
 
 #endif	/* __PJMEDIA_CODEC_SPEEX_H__ */
Index: /pjproject/trunk/pjmedia/include/pjmedia.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia.h	(revision 518)
@@ -44,4 +44,5 @@
 #include <pjmedia/silencedet.h>
 #include <pjmedia/session.h>
+#include <pjmedia/transport.h>
 #include <pjmedia/transport_udp.h>
 #include <pjmedia/sound.h>
Index: /pjproject/trunk/pjmedia/include/pjmedia/clock.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/clock.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/clock.h	(revision 518)
@@ -27,4 +27,21 @@
 
 
+/**
+ * @addtogroup PJMEDIA_CLOCK Clock Generator
+ * @ingroup PJMEDIA_PORT_CLOCK
+ * @brief Interface for generating clock.
+ * @{
+ * 
+ * The clock generator provides the application with media timing,
+ * and it is used by the @ref PJMEDIA_MASTER_PORT for its sound clock.
+ *
+ * The clock generator may be configured to run <b>asynchronously</b> 
+ * (the default behavior) or <b>synchronously</b>. When it is run 
+ * asynchronously, it will call the application's callback every time
+ * the clock <b>tick</b> expires. When it is run synchronously, 
+ * application must continuously polls the clock generator to synchronize
+ * the timing.
+ */
+
 PJ_BEGIN_DECL
 
@@ -36,8 +53,17 @@
 
 
+/**
+ * Options when creating the clock.
+ */
 enum pjmedia_clock_options
 {
+    /**
+     * Prevents the clock from running asynchronously. In this case,
+     * application must poll the clock continuously by calling
+     * #pjmedia_clock_wait() in order to synchronize timing.
+     */
     PJMEDIA_CLOCK_NO_ASYNC  = 1,
 };
+
 
 /**
@@ -138,4 +164,7 @@
 PJ_END_DECL
 
+/**
+ * @}
+ */
 
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/codec.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/codec.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/codec.h	(revision 518)
@@ -33,15 +33,155 @@
 
 /**
- * @defgroup PJMED_CODEC Codec framework.
+ * @defgroup PJMEDIA_CODEC Codec Framework
  * @ingroup PJMEDIA
+ * @brief Media codec framework and management
  * @{
  *
+ * @section codec_mgmt_sec Codec Management
+ * @subsection codec_fact_sec Codec Manager
+ *
  * The codec manager is used to manage all codec capabilities in the endpoint.
- * Library implementors can extend PJMEDIA codec capabilities by creating 
- * a codec factory for a new codec, and register the codec factory to
- * codec manager so that the codec can be used by the rest of application.
- *
  * When used with media endpoint (pjmedia_endpt), application can retrieve
  * the codec manager instance by calling #pjmedia_endpt_get_codec_mgr().
+ *
+ * @subsection reg_new_codec Registering New Codec
+ *
+ * New codec types can be registered to PJMEDIA (or to be precise, to the 
+ * codec manager) during run-time. 
+ * To do this, application needs to initialize an instance of
+ * codec factory (#pjmedia_codec_factory) and registers this codec factory
+ * by calling #pjmedia_codec_mgr_register_factory().
+ *
+ * For codecs implemented/supported by PJMEDIA, this process is normally
+ * concealed in an easy to use function such as #pjmedia_codec_g711_init().
+ *
+ * @subsection codec_factory Codec Factory
+ *
+ * A codec factory (#pjmedia_codec_factory) is registered to codec manager, 
+ * and it is used to create and release codec instance.
+ *
+ * The most important member of the codec factory is the "virtual" function
+ * table #pjmedia_codec_factory_op, where it contains, among other thing, 
+ * pointer to functions to allocate and deallocate codec instance.
+ *
+ * @subsection codec_inst Codec Instance
+ *
+ * Application allocates codec instance by calling #pjmedia_codec_mgr_alloc_codec().
+ * One codec instance (#pjmedia_codec) can be used for simultaneous encoding
+ * and decoding.
+ *
+ * The most important member of the codec instance is the "virtual" function
+ * table #pjmedia_codec_op, where it holds pointer to functions to
+ * encode/decode media frames.
+ *
+ * @subsection codec_ident Codec Identification
+ *
+ * A particular codec type in PJMEDIA can be uniquely identified by two
+ * keys: by #pjmedia_codec_info, or by #pjmedia_codec_id string. A fully
+ * qualified codec ID string consists of codec name, sampling rate, and
+ * number of channels. However, application may use only first parts of
+ * the tokens as long as it will make to codec ID unique. For example, "gsm"
+ * is a fully qualified codec name, since it will always have 8000 clock
+ * rate and 1 channel. Other examples of fully qualified codec ID strings
+ * are "pcma", "speex/8000", "speex/16000", and "L16/16000/1". A codec
+ * id "speex" (without clock rate) is not fully qualified, since it will
+ * match the narrowband, wideband, and ultrawideband Speex codec.
+ *
+ * The two keys can be converted to one another, with
+ * #pjmedia_codec_info_to_id() and #pjmedia_codec_mgr_find_codecs_by_id()
+ * functions.
+ *
+ * Codec ID string is not case sensitive.
+ *
+ *
+ * @section using_codec Using the Codec Framework
+ * @subsection init_alloc_codec Allocating Codec
+ *
+ * Application needs to allocate one codec instance for encoding and decoding
+ * media frames. One codec instance can be used to perform both encoding
+ * and decoding.
+ *
+ * Application allocates codec by calling #pjmedia_codec_mgr_alloc_codec().
+ * This function takes #pjmedia_codec_info argument, which is used to locate
+ * the particular codec factory to be used to allocate the codec.
+ *
+ * Application can build #pjmedia_codec_info structure manually for
+ * the specific codec, or alternatively it may get the #pjmedia_codec_info
+ * from the codec ID string, by using #pjmedia_codec_mgr_find_codecs_by_id()
+ * function.
+ *
+ * The following snippet shows an example to allocate a codec:
+ *
+ \code
+    pj_str_t codec_id;
+    pjmedia_codec_info *codec_info;
+    unsigned count = 1;
+    pjmedia_codec *codec;
+
+    codec_id = pj_str("pcma");
+
+    // Find codec info for the specified coded ID (i.e. "pcma").
+    status = pjmedia_codec_mgr_find_codecs_by_id( codec_mgr, &codec_id,
+						  &count, &codec_info, NULL);
+
+    // Allocate the codec.
+    status = pjmedia_codec_mgr_alloc_codec( codec_mgr, codec_info, &codec );
+
+ \endcode
+ *
+ *
+ * @subsection opening_codec Initializing Codec
+ *
+ * Once codec is allocated, application needs to initialize the codec
+ * by calling <b><tt>open</tt></b> member of the codec. This function
+ * takes #pjmedia_codec_param as the argument, which contains the
+ * settings for the codec.
+ *
+ * Application shoud use #pjmedia_codec_mgr_get_default_param() function
+ * to initiaize #pjmedia_codec_param. The <tt>setting</tt> part of
+ * #pjmedia_codec_param then can be tuned to suit the application's
+ * requirements.
+ *
+ * The following snippet shows an example to initialize codec:
+ *
+ \code
+    pjmedia_codec_param param;
+
+    // Retrieve default codec param for the specified codec.
+    pjmedia_codec_mgr_get_default_param(codec_mgr, codec_info
+					&param);
+
+    // Application may change the "settings" part of codec param,
+    // for example, to disable VAD
+    param.setting.vad = 0;
+
+    // Open the codec using the specified settings.
+    codec->op->open( codec, &param );
+
+ \endcode
+ *
+ *
+ * @subsection enc_dec_codec Encoding and Decoding Media Frames
+ *
+ * Application encodes and decodes media frames by calling
+ * <tt>encode</tt> and <tt>decode</tt> member of the codec's "virtual"
+ * function table (#pjmedia_codec_op).
+ *
+ * @subsection plc_codec Concealing Lost Frames
+ *
+ * All codecs has Packet Lost Concealment (PLC) feature, and application
+ * can activate the PLC to conceal lost frames by calling <tt>recover</tt>
+ * member of the codec's "virtual" function table (#pjmedia_codec_op).
+ *
+ * If the codec's algorithm supports PLC, the <tt>recover</tt> function
+ * will use the codec's PLC. Otherwise for codecs that don't have
+ * intrinsic PLC, PJMEDIA will suply the PLC implementation from the
+ * @ref PJMED_PLC implementation.
+ *
+ * @subsection close_codec Closing and Releasing the Codec
+ *
+ * The codec must be closed by calling <tt>close</tt> member of the codec's
+ * operation. Then it must be released by calling 
+ * #pjmedia_codec_mgr_dealloc_codec().
  */
 
@@ -50,5 +190,6 @@
  * Standard RTP static payload types, as defined by RFC 3551. 
  * The header file <pjmedia-codec/types.h> also declares dynamic payload
- * types that are supported by pjmedia-codec library.
+ * type numbers that are used by PJMEDIA when advertising the capability
+ * for example in SDP message.
  */
 enum pjmedia_rtp_pt
@@ -89,5 +230,5 @@
  * codec specification. 
  */
-struct pjmedia_codec_info
+typedef struct pjmedia_codec_info
 {
     pjmedia_type    type;	    /**< Media type.			*/
@@ -96,11 +237,5 @@
     unsigned	    clock_rate;	    /**< Sampling rate.			*/
     unsigned	    channel_cnt;    /**< Channel count.			*/
-};
-
-
-/**
- * @see pjmedia_codec_info
- */
-typedef struct pjmedia_codec_info pjmedia_codec_info;
+} pjmedia_codec_info;
 
 
@@ -109,5 +244,5 @@
  * the capability of codec factories.
  */
-struct pjmedia_codec_param
+typedef struct pjmedia_codec_param
 {
     /**
@@ -143,14 +278,10 @@
 	unsigned    reserved:1;	    /**< Reserved, must be zero.	*/
     } setting;
-};
-
-/**
- * @see pjmedia_codec_param
- */
-typedef struct pjmedia_codec_param pjmedia_codec_param;
-
-
-/**
- * @see pjmedia_codec
+} pjmedia_codec_param;
+
+
+
+/*
+ * Forward declaration for pjmedia_codec.
  */
 typedef struct pjmedia_codec pjmedia_codec;
@@ -161,5 +292,5 @@
  * all of these functions.
  */
-struct pjmedia_codec_op
+typedef struct pjmedia_codec_op
 {
     /** 
@@ -259,10 +390,10 @@
 
     /**
-     * Instruct the codec to recover a missing frame. Not all codec has
-     * this capability, so this function may be NULL.
+     * Instruct the codec to recover a missing frame.
      *
      * @param codec	The codec instance.
      * @param out_size	The length of buffer in the output frame.
-     * @param output	The output frame.
+     * @param output	The output frame where generated signal
+     *			will be placed.
      *
      * @return		PJ_SUCCESS on success;
@@ -271,15 +402,10 @@
 			   unsigned out_size,
 			   struct pjmedia_frame *output);
-};
-
-
-/**
- * Codec operation.
- */
-typedef struct pjmedia_codec_op pjmedia_codec_op;
-
-
-/**
- * @see pjmedia_codec_factory
+} pjmedia_codec_op;
+
+
+
+/*
+ * Forward declaration for pjmedia_codec_factory.
  */
 typedef struct pjmedia_codec_factory pjmedia_codec_factory;
@@ -310,5 +436,5 @@
  * factories.
  */
-struct pjmedia_codec_factory_op
+typedef struct pjmedia_codec_factory_op
 {
     /** 
@@ -381,11 +507,6 @@
 				 pjmedia_codec *codec );
 
-};
-
-
-/**
- * @see pjmedia_codec_factory_op
- */
-typedef struct pjmedia_codec_factory_op pjmedia_codec_factory_op;
+} pjmedia_codec_factory_op;
+
 
 
@@ -419,5 +540,5 @@
  * #pjmedia_codec_mgr_set_codec_priority().
  */
-enum pjmedia_codec_priority
+typedef enum pjmedia_codec_priority
 {
     /**
@@ -456,14 +577,12 @@
      */
     PJMEDIA_CODEC_PRIO_DISABLED = 0,
-};
-
-
-/**
- * @see pjmedia_codec_priority
- */
-typedef enum pjmedia_codec_priority pjmedia_codec_priority;
-
-
-/** Fully qualified codec name  (e.g. "pcmu/8000/1") */
+
+} pjmedia_codec_priority;
+
+
+/** 
+ * Codec identification (e.g. "pcmu/8000/1").
+ * See @ref codec_ident for more info.
+ */
 typedef char pjmedia_codec_id[32];
 
@@ -487,5 +606,5 @@
  * by media endpoint to instantiate the codec manager.
  */
-struct pjmedia_codec_mgr
+typedef struct pjmedia_codec_mgr
 {
     /** List of codec factories registered to codec manager. */
@@ -497,11 +616,6 @@
     /** Array of codec descriptor. */
     struct pjmedia_codec_desc	codec_desc[PJMEDIA_CODEC_MGR_MAX_CODECS];
-};
-
-
-/**
- * @see pjmedia_codec_mgr
- */
-typedef struct pjmedia_codec_mgr pjmedia_codec_mgr;
+
+} pjmedia_codec_mgr;
 
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/conference.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/conference.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/conference.h	(revision 518)
@@ -27,4 +27,10 @@
 #include <pjmedia/port.h>
 
+/**
+ * @defgroup PJMEDIA_CONF Conference Bridge
+ * @ingroup PJMEDIA_PORT
+ * @brief The implementation of conference bridge
+ * @{
+ */
 
 PJ_BEGIN_DECL
@@ -237,5 +243,5 @@
  * @param sink_slot	Sink slot.
  *
- * @reutrn		PJ_SUCCESS on success.
+ * @return		PJ_SUCCESS on success.
  */
 PJ_DECL(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf,
@@ -374,4 +380,9 @@
 
 
+/**
+ * @}
+ */
+
+
 #endif	/* __PJMEDIA_CONF_H__ */
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/config.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 518)
@@ -20,11 +20,33 @@
 #define __PJMEDIA_CONFIG_H__
 
+/**
+ * @file pjmedia/config.h Compile time config
+ * @brief Contains some compile time constants.
+ */
 #include <pj/config.h>
+
+/**
+ * @defgroup PJMEDIA_BASE Base Types and Configurations
+ * @ingroup PJMEDIA
+ */
+
+/**
+ * @defgroup PJMEDIA_CONFIG Compile time configuration
+ * @ingroup PJMEDIA_BASE
+ * @brief Some compile time configuration settings.
+ * @{
+ */
 
 /*
  * Types of sound stream backends.
  */
+
+/** Constant for NULL sound backend. */
 #define PJMEDIA_SOUND_NULL_SOUND	    0
+
+/** Constant for PortAudio sound backend. */
 #define PJMEDIA_SOUND_PORTAUDIO_SOUND	    1
+
+/** Constant for Win32 DirectSound sound backend. */
 #define PJMEDIA_SOUND_WIN32_DIRECT_SOUND    2
 
@@ -133,4 +155,8 @@
 
 
+/**
+ * @}
+ */
+
 
 #endif	/* __PJMEDIA_CONFIG_H__ */
Index: /pjproject/trunk/pjmedia/include/pjmedia/doxygen.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/doxygen.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/doxygen.h	(revision 518)
@@ -35,69 +35,293 @@
 
 /**
- * @mainpage Welcome to PJMEDIA!
- *
- * @section intro_sec What is PJMEDIA
- *
- * PJMEDIA open source (GPL) library contains objects that implements multimedia 
- * capabilities. It can be used with signaling libraries such as PJSIP to create 
- * a complete multimedia communication endpoint.
- *
- *
+ * @mainpage PJMEDIA and PJMEDIA-CODEC
+ *
+ * \n
+ * @section intro_sec PJMEDIA
+ *
+ * PJMEDIA is a rather complete media stack, distributed under Open Source/GPL
+ * terms, and featuring small footprint and good extensibility and portability.
+ *
+ * Please click the <A HREF="modules.htm"><b>Modules</b></A> link on top
+ * of this page to get the complete features currently present in PJMEDIA.
+ *
+ * Also please read the documentation about @ref PJMEDIA_PORT_CONCEPT,
+ * which is a major concept that is used for implementing many objects in 
+ * the library.
+ *
+ * \n
+ * @section pjmedia_codec_sec PJMEDIA-CODEC
+ *
+ * PJMEDIA-CODEC is a static library containing various codec implementations,
+ * wrapped into PJMEDIA codec framework. The static library is designed as
+ * such so that only codecs that are explicitly initialized are linked with 
+ * the application, therefore keeping the application size in control.
+ *
+ * Please see @ref pjmedia_codec_page on how to use the codec in 
+ * PJMEDIA-CODEC.
+ *
+ * \n
+ * @section pjmedia_lic Copying and Acknowledgements
+ *
+ * Please see @ref lic_stuffs page for the details.
+ */
+
+
+/**
+ * @page pjmedia_codec_page Using PJMEDIA-CODEC
+ *
+ * Before application can use a codec, it needs to initialize and register
+ * the codec to the codec manager. This is accomplished with using
+ * constructs like the following:
+ *
+ \code
+    #include <pjmedia.h>
+    #include <pjmedia-codec.h>
+
+    init_codecs( pjmedia_endpt *med_ept )
+    {
+	// Register G.711 codecs
+	pjmedia_codec_g711_init(med_ept);
+
+	// Register GSM codec.
+	pjmedia_codec_gsm_init(med_ept);
+
+	// Register Speex codecs.
+	// With the default flag, this will register three codecs:
+	// speex/8000, speex/16000, and speex/32000
+	pjmedia_codec_speex_init(med_ept, 0, 0, 0);
+    }
+ \endcode
+ *
+ * After the codec is registered, application may create the encoder/decoder
+ * instance, by using the API as documented in @ref PJMEDIA_CODEC.
+ */
+
+
+
+/**
+ * @page lic_stuffs Copying and Acknowledgements
+ * @section lic_stuff Copying and Acknowledgements
  * @subsection pjmedia_about_subsec About PJMEDIA
  *
- * <pre>
- * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- * </pre>
- *
- *
- * @subsection portaudio_subsec About PortAudio
- *
- * PortAudio is an excellent sound device library that is chosen as sound 
- * device abstraction in PJMEDIA. It has the following characteristics that
- * makes it perfect for our use:
- *
- *  - It is portable and complete
- *\n
- *    It supports multiple back-ends on Windows, Windows CE (WinCE)/PocketPC, 
- *    Linux, Unix, and MacOS. More platforms may be supported.
- *  - It is callback based
- *\n
- *    The callback based for supplying/retrieving frames from the audio
- *    device is perfect for our use.
- *  - No nonsense, C based library.
- *  - Actively maintained.
+ * PJMEDIA is distributed under GPL terms (other licensing schemes may be 
+ * arranged):
+ \verbatim
+    Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ \endverbatim
+ *
+ *
+ * @section other_acks Acknowlegments
+ * @subsection portaudio_subsec PortAudio
+ *
+ * PortAudio is supported as one of the sound device backend, and
+ * is used by default on Linux/Unix and MacOS X target.
  * 
- * Please visit http://www.portaudio.com for more info.
+ * Please visit <A HREF="http://www.portaudio.com">http://www.portaudio.com</A>
+ * for more info.
  *
  * PortAudio is distributed with the following condition.
- * <pre>
- * 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.
- * </pre>
+ \verbatim
+    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.
+ \endverbatim
+ *
+ *
+ * @subsection resample_ack Resample
+ *
+ * PJMEDIA uses <tt>resample-1.8.tar.gz</tt> from 
+ * <A HREF="http://www-ccrma.stanford.edu/~jos/resample/">
+ * Digital Audio Resampling Home Page</A>. This library is distibuted
+ * on LGPL terms.
+ *
+ * Some excerpts from the original source codes:
+ \verbatim
+    HISTORY
+
+    The first version of this software was written by Julius O. Smith III
+    <jos@ccrma.stanford.edu> at CCRMA <http://www-ccrma.stanford.edu> in
+    1981.  It was called SRCONV and was written in SAIL for PDP-10
+    compatible machines.  The algorithm was first published in
+
+    Smith, Julius O. and Phil Gossett. ``A Flexible Sampling-Rate
+    Conversion Method,'' Proceedings (2): 19.4.1-19.4.4, IEEE Conference
+    on Acoustics, Speech, and Signal Processing, San Diego, March 1984.
+
+    An expanded tutorial based on this paper is available at the Digital
+    Audio Resampling Home Page given above.
+
+    Circa 1988, the SRCONV program was translated from SAIL to C by
+    Christopher Lee Fraley working with Roger Dannenberg at CMU.
+
+    Since then, the C version has been maintained by jos.
+
+    Sndlib support was added 6/99 by John Gibson <jgg9c@virginia.edu>.
+
+    The resample program is free software distributed in accordance
+    with the Lesser GNU Public License (LGPL).  There is NO warranty; not
+    even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ \endverbatim
+ *
+ * @subsection jb_ack Adaptive Jitter Buffer
+ *
+ * The PJMEDIA jitter buffer is based on implementation kindly donated
+ * by <A HREF="http://www.switchlab.com">Switchlab, Ltd.</A>, and is
+ * distributed under PJMEDIA licensing terms.
+ *
+ *
+ * @subsection silence_det_ack Adaptive Silence Detector
+ *
+ * The adaptive silence detector was based on silence detector 
+ * implementation in <A HREF="http://www.openh323.org">Open H323</A> 
+ * project. I couldn't find the source code anymore, but generally
+ * Open H323 files are distributed under MPL terms and has the
+ * following excerpts:
+ \verbatim
+    Open H323 Library
+
+    Copyright (c) 1998-2000 Equivalence Pty. Ltd.
+
+    The contents of this file are subject to the Mozilla Public License
+    Version 1.0 (the "License"); you may not use this file except in
+    compliance with the License. You may obtain a copy of the License at
+    http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS IS"
+    basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+    the License for the specific language governing rights and limitations
+    under the License.
+
+    The Original Code is Open H323 Library.
+
+    The Initial Developer of the Original Code is Equivalence Pty. Ltd.
+
+    Portions of this code were written with the assisance of funding from
+    Vovida Networks, Inc. http://www.vovida.com.
+ \endverbatim
+
+ * @subsection gsm_ack GSM Codec
+ *
+ * PJMEDIA uses GSM 
+ * <A HREF="http://kbs.cs.tu-berlin.de/~jutta/toast.html">GSM 06.10</A>
+ * version 1.0 at patchlevel 12. It has the following Copyright notice:
+ *
+ \verbatim
+    Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann,
+    Technische Universitaet Berlin
+
+    Any use of this software is permitted provided that this notice is not
+    removed and that neither the authors nor the Technische Universitaet Berlin
+    are deemed to have made any representations as to the suitability of this
+    software for any purpose nor are held responsible for any defects of
+    this software.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+
+    As a matter of courtesy, the authors request to be informed about uses
+    this software has found, about bugs in this software, and about any
+    improvements that may be of general interest.
+
+    Berlin, 28.11.1994
+    Jutta Degener
+    Carsten Bormann
+ \endverbatim
+ *
+ *
+ * @subsection speex_codec_ack Speex Codec
+ *
+ * PJMEDIA uses Speex codec uses version 1.1.12 from <A HREF="http://www.speex.org">
+ * www.speex.org</A>. The Speex library comes with the following Copying
+ * notice:
+ \verbatim
+    Copyright 2002-2005 
+	    Xiph.org Foundation
+	    Jean-Marc Valin
+	    David Rowe
+	    EpicGames
+	    Analog Devices
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    - Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    - 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.
+
+    - Neither the name of the Xiph.org Foundation 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 COPYRIGHT HOLDERS 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 FOUNDATION 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.
+ \endverbatim
+ *
+ *
+ * @subsection g711_codec_ack G.711 Codec
+ *
+ * The G.711 codec algorithm came from Sun Microsystems, Inc, and it's
+ * got the following excerpts:
+ *
+ \verbatim
+    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
+ \endverbatim
+ *
  */
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/endpoint.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/endpoint.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/endpoint.h	(revision 518)
@@ -26,5 +26,5 @@
  */
 /**
- * @defgroup PJMED_ENDPT Multimedia Endpoint
+ * @defgroup PJMED_ENDPT The Endpoint
  * @ingroup PJMEDIA
  * @{
Index: /pjproject/trunk/pjmedia/include/pjmedia/errno.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 518)
@@ -20,7 +20,20 @@
 #define __PJMEDIA_ERRNO_H__
 
+/**
+ * @file errno.h Error Codes
+ * @brief PJMEDIA specific error codes.
+ */
+
 #include <pjmedia/types.h>
 #include <pj/errno.h>
 
+/**
+ * @defgroup PJMEDIA_ERRNO Error Codes
+ * @ingroup PJMEDIA_BASE
+ * @brief PJMEDIA specific error codes.
+ * @{
+ */
+
+
 PJ_BEGIN_DECL
 
@@ -32,10 +45,10 @@
 
 
-/*
+/**
  * Mapping from PortAudio error codes to pjmedia error space.
  */
 #define PJMEDIA_PORTAUDIO_ERRNO_START (PJMEDIA_ERRNO_START+PJ_ERRNO_SPACE_SIZE-1000)
 
-/*
+/**
  * Convert PortAudio error code to PJMEDIA error code.
  */
@@ -390,9 +403,4 @@
 
 /************************************************************
- * JITTER BUFFER ERRORS
- ***********************************************************/
-
-
-/************************************************************
  * PORT ERRORS
  ***********************************************************/
@@ -487,4 +495,9 @@
 PJ_END_DECL
 
+/**
+ * @}
+ */
+
+
 #endif	/* __PJMEDIA_ERRNO_H__ */
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/g711.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/g711.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/g711.h	(revision 518)
@@ -20,6 +20,20 @@
 #define __PJMEDIA_G711_H__
 
+/**
+ * @file g711.h
+ * @brief G711 Codec
+ */
+
 #include <pjmedia-codec/types.h>
 
+/**
+ * @defgroup PJMED_G711 G711
+ * @ingroup PJMEDIA_CODEC
+ * @brief Standard G.711/PCMA and PCMU codec.
+ * @{
+ * This section describes functions to register and register G.711 codec
+ * factory to the codec manager. After the codec factory has been registered,
+ * application can use @ref PJMEDIA_CODEC API to manipulate the codec.
+ */
 
 PJ_BEGIN_DECL
@@ -48,4 +62,7 @@
 PJ_END_DECL
 
+/**
+ * @}
+ */
 
 #endif	/* __PJMEDIA_G711_H__ */
Index: /pjproject/trunk/pjmedia/include/pjmedia/jbuf.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/jbuf.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/jbuf.h	(revision 518)
@@ -32,7 +32,13 @@
 /**
  * @defgroup PJMED_JBUF Adaptive jitter buffer
- * @ingroup PJMEDIA
+ * @ingroup PJMEDIA_FRAME_OP
  * @{
- *
+ * This section describes PJMEDIA's implementation of de-jitter buffer.
+ * The de-jitter buffer may be set to operate in adaptive mode or fixed
+ * delay mode.
+ *
+ * The jitter buffer is also able to report the status of the current
+ * frame (#pjmedia_jb_frame_type). This status is used for examply by
+ * @ref PJMED_STRM to invoke the codec's @ref PJMED_PLC algorithm.
  */
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/master_port.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/master_port.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/master_port.h	(revision 518)
@@ -27,4 +27,32 @@
 #include <pjmedia/port.h>
 
+/**
+ * @defgroup PJMEDIA_MASTER_PORT Master Port
+ * @ingroup PJMEDIA_PORT_CLOCK
+ * @brief Provides media clock for media ports.
+ * @{
+ * A master port has two media ports connected to it, and by convention
+ * thay are called downstream and upstream ports. The media stream flowing to
+ * the downstream port is called encoding or send direction, and media stream 
+ * flowing to the upstream port is called decoding or receive direction
+ * (imagine the downstream as stream to remote endpoint, and upstream as
+ * local media port; media flowing to remote endpoint (downstream) will need
+ * to be encoded before it is transmitted to remote endpoint).
+ *
+ * A master port internally has an instance of @ref PJMEDIA_CLOCK, which
+ * provides the essensial timing for the master port. The @ref PJMEDIA_CLOCK
+ * runs asynchronously, and whenever a clock <b>tick</b> expires, a callback
+ * will be called, and the master port performs the following tasks:
+ *  - it calls <b><tt>get_frame()</tt></b> from the downstream port,
+ *    when give the frame to the upstream port by calling <b><tt>put_frame
+ *    </tt></b> to the upstream port, and
+ *  - performs the same task, but on the reverse direction (i.e. get the stream
+ *    from upstream port and give it to the downstream port).
+ *
+ * Because master port enables media stream to flow automatically, it is
+ * said that the master port supplies @ref PJMEDIA_PORT_CLOCK to the 
+ * media ports interconnection.
+ *
+ */
 
 PJ_BEGIN_DECL
@@ -33,14 +61,4 @@
 /**
  * Opaque declaration for master port.
- * A master port has two media ports connected to it, i.e. downstream and
- * upstream ports. The media stream flowing to the downstream port is called
- * encoding or send direction, and media stream flowing to the upstream port
- * is called decoding or receive direction.
- *
- * A master port has a "clock" that periodically passes the media frame from 
- * downstream to upstream ports, and vice versa. In each run, it retrieves 
- * media frame from one side with #pjmedia_port_get_frame(), and passes the 
- * media frame to the other side with #pjmedia_port_put_frame(). In each run,
- * this process is done for twice, i.e. one for each direction.
  */
 typedef struct pjmedia_master_port pjmedia_master_port;
@@ -150,4 +168,8 @@
 PJ_END_DECL
 
+/**
+ * @}
+ */
+
 
 #endif	/* __PJMEDIA_MASTER_PORT_H__ */
Index: /pjproject/trunk/pjmedia/include/pjmedia/null_port.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/null_port.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/null_port.h	(revision 518)
@@ -27,4 +27,13 @@
 
 
+
+/**
+ * @defgroup PJMEDIA_NULL_PORT Null Port
+ * @ingroup PJMEDIA_PORT
+ * @brief Null port is the simplest type of port.
+ * @{
+ */
+
+
 PJ_BEGIN_DECL
 
@@ -33,4 +42,5 @@
  * Create Null port. 
  *
+ * @param pool			Pool to allocate memory.
  * @param sampling_rate		Sampling rate of the port.
  * @param channel_count		Number of channels.
@@ -52,4 +62,8 @@
 PJ_END_DECL
 
+/**
+ * @}
+ */
+
 
 #endif	/* __PJMEDIA_NULL_PORT_H__ */
Index: /pjproject/trunk/pjmedia/include/pjmedia/plc.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/plc.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/plc.h	(revision 518)
@@ -29,7 +29,16 @@
 /**
  * @defgroup PJMED_PLC Packet Lost Concealment
- * @ingroup PJMEDIA
+ * @ingroup PJMEDIA_FRAME_OP
  * @{
+ * This section describes PJMEDIA's implementation of Packet Lost
+ * Concealment algorithm. This algorithm is used to implement PLC for
+ * codecs that do not have built-in support for one (e.g. G.711 or GSM codecs).
  *
+ * The PLC algorithm (either built-in or external) is embedded in
+ * PJMEDIA codec instance, and application can conceal lost frames
+ * by calling <b><tt>recover()</tt></b> member of the codec's member
+ * operation (#pjmedia_codec_op).
+ *
+ * See also @ref plc_codec for more info.
  */
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/port.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/port.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/port.h	(revision 518)
@@ -28,4 +28,204 @@
 
 
+/**
+  @defgroup PJMEDIA_PORT_CONCEPT Media Ports
+  @ingroup PJMEDIA
+  @brief Extensible framework for media terminations
+  
+  @section media_port_intro Concepts
+  
+  @subsection The Media Port
+  A media port (represented with pjmedia_port "class") provides a generic
+  and extensible framework for implementing media terminations. A media
+  port interface basically has the following properties:
+  - media port information (pjmedia_port_info) to describe the
+  media port properties (sampling rate, number of channels, etc.),
+  - pointer to function to acquire frames from the port (<tt>get_frame()
+  </tt> interface), which will be called by #pjmedia_port_get_frame()
+  public API, and
+  - pointer to function to store frames to the port (<tt>put_frame()</tt>
+  interface) which will be called by #pjmedia_port_put_frame() public
+  API.
+  
+  Media ports are passive "objects". Applications (or other PJMEDIA 
+  components) must actively calls #pjmedia_port_get_frame() or 
+  #pjmedia_port_put_frame() from/to the media port in order to retrieve/
+  store media frames.
+  
+  Some media ports (such as @ref PJMEDIA_CONF and @ref PJMEDIA_RESAMPLE_PORT)
+  may be interconnected with each other, while some
+  others represent the ultimate source/sink termination for the media. 
+  The  #pjmedia_port_connect() and #pjmedia_port_disconnect() are used to
+  connect and disconnect media ports respectively. But even when ports
+  are connected with each other ports, they still remain passive.
+
+
+  @subsection port_clock_ex1 Example: Manual Resampling
+
+  For example, suppose application wants to convert the sampling rate
+  of one WAV file to another. In this case, application would create and
+  arrange media ports connection as follows:
+
+    \image html sample-manual-resampling.jpg
+
+  Application would setup the media ports using the following pseudo-
+  code:
+
+  \code
+  
+      pjmedia_port *player, *resample, *writer;
+      pj_status_t status;
+  
+      // Create the file player port.
+      status = pjmedia_wav_player_port_create(pool, 
+  					      "Input.WAV",	    // file name
+  					      20,		    // ptime.
+  					      PJMEDIA_FILE_NO_LOOP, // flags
+  					      0,		    // buffer size
+  					      NULL,		    // user data.
+  					      &player );
+      PJ_ASSERT_RETURN(status==PJ_SUCCESS, PJ_SUCCESS);
+  
+      // Create the resample port with specifying the target sampling rate, 
+      // and with the file port as the source. This will effectively
+      // connect the resample port with the player port.
+      status = pjmedia_resample_port_create( pool, player, 8000, 
+  					     0, &resample);
+      PJ_ASSERT_RETURN(status==PJ_SUCCESS, PJ_SUCCESS);
+  
+      // Create the file writer, specifying the resample port's configuration
+      // as the WAV parameters.
+      status pjmedia_wav_writer_port_create(pool, 
+  					    "Output.WAV",  // file name.
+  					    resample->info.clock_rate,
+  					    resample->info.channel_count,
+  					    resample->info.samples_per_frame,
+  					    resample->info.bits_per_sample,
+  					    0,		// flags
+  					    0,		// buffer size
+  					    NULL,	// user data.
+  					    &writer);
+  
+  \endcode
+
+  
+  After the ports have been set up, application can perform the conversion
+  process by running this loop:
+ 
+  \code
+  
+  	pj_int16_t samplebuf[MAX_FRAME];
+  	
+  	while (1) {
+  	    pjmedia_frame frame;
+  	    pj_status_t status;
+  
+  	    frame.buf = samplebuf;
+  	    frame.size = sizeof(samplebuf);
+  
+  	    // Get the frame from resample port.
+  	    status = pjmedia_port_get_frame(resample, &frame);
+  	    if (status != PJ_SUCCESS || frame.type == PJMEDIA_FRAME_TYPE_NONE) {
+  		// End-of-file, end the conversion.
+  		break;
+  	    }
+  
+  	    // Put the frame to write port.
+  	    status = pjmedia_port_put_frame(writer, &frame);
+  	    if (status != PJ_SUCCESS) {
+  		// Error in writing the file.
+  		break;
+  	    }
+  	}
+  
+  \endcode
+ 
+  For the sake of completeness, after the resampling process is done, 
+  application would need to destroy the ports:
+  
+  \code
+	// Note: by default, destroying resample port will destroy the
+	//	 the downstream port too.
+  	pjmedia_port_destroy(resample);
+  	pjmedia_port_destroy(writer);
+  \endcode
+ 
+ 
+  The above steps are okay for our simple purpose of changing file's sampling
+  rate. But for other purposes, the process of reading and writing frames
+  need to be done in timely manner (for example, sending RTP packets to
+  remote stream). And more over, as the application's scope goes bigger,
+  the same pattern of manually reading/writing frames comes up more and more often,
+  thus perhaps it would be better if PJMEDIA provides mechanism to 
+  automate this process.
+  
+  And indeed PJMEDIA does provide such mechanism, which is described in 
+  @ref PJMEDIA_PORT_CLOCK section.
+
+
+  @subsection media_port_autom Automating Media Flow
+
+  PJMEDIA provides few mechanisms to make media flows automatically
+  among media ports. This concept is described in @ref PJMEDIA_PORT_CLOCK 
+  section.
+
+ */
+
+
+/**
+ * @defgroup PJMEDIA_PORT_INTERFACE Media Port Interface
+ * @ingroup PJMEDIA_PORT_CONCEPT
+ * @brief Declares the media port interface.
+ */
+
+/**
+ * @defgroup PJMEDIA_PORT Ports
+ * @ingroup PJMEDIA_PORT_CONCEPT
+ * @brief Contains various types of media ports/terminations.
+ * @{
+ * This page lists all types of media ports currently implemented
+ * in PJMEDIA. The media port concept is explained in @ref PJMEDIA_PORT_CONCEPT.
+ * @}
+ */
+
+/**
+ @defgroup PJMEDIA_PORT_CLOCK Clock/Timing
+ @ingroup PJMEDIA_PORT_CONCEPT
+ @brief Various types of classes that provide timing.
+ @{
+
+ The media clock/timing extends the media port concept that is explained 
+ in @ref PJMEDIA_PORT_CONCEPT. When clock is present in the ports 
+ interconnection, media will flow automatically (and with correct timing too!)
+ from one media port to another.
+ 
+ There are few objects in PJMEDIA that are able to provide clock/timing
+ to media ports interconnection:
+
+ - @ref PJMED_SND_PORT\n
+   The sound device makes a good candidate as the clock source, and
+   PJMEDIA @ref PJMED_SND is designed so that it is able to invoke
+   operations according to timing driven by the sound hardware clock
+   (this may sound complicated, but actually it just means that
+   the sound device abstraction provides callbacks to be called when
+   it has/wants media frames).\n
+   See @ref PJMED_SND_PORT for more details.
+
+ - @ref PJMEDIA_MASTER_PORT\n
+   The master port uses @ref PJMEDIA_CLOCK as the clock source. By using
+   @ref PJMEDIA_MASTER_PORT, it is possible to interconnect passive
+   media ports and let the frames flow automatically in timely manner.\n
+   Please see @ref PJMEDIA_MASTER_PORT for more details.
+
+ @}
+ */
+
+/**
+ * @addtogroup PJMEDIA_PORT_INTERFACE
+ * @{
+ * This page contains the media port interface declarations. The media port
+ * concept is explained in @ref PJMEDIA_PORT_CONCEPT.
+ */
+
 PJ_BEGIN_DECL
 
@@ -69,5 +269,5 @@
  * Port info.
  */
-struct pjmedia_port_info
+typedef struct pjmedia_port_info
 {
     pj_str_t	    name;		/**< Port name.			    */
@@ -83,10 +283,5 @@
     unsigned	    samples_per_frame;	/**< No of samples per frame.	    */
     unsigned	    bytes_per_frame;	/**< No of samples per frame.	    */
-};
-
-/**
- * @see pjmedia_port_info
- */
-typedef struct pjmedia_port_info pjmedia_port_info;
+} pjmedia_port_info;
 
 
@@ -94,5 +289,5 @@
  * Types of media frame. 
  */
-enum pjmedia_frame_type
+typedef enum pjmedia_frame_type
 {
     PJMEDIA_FRAME_TYPE_NONE,	    /**< No frame.		*/
@@ -100,11 +295,5 @@
     PJMEDIA_FRAME_TYPE_AUDIO,	    /**< Normal audio frame.	*/
 
-};
-
-
-/** 
- * @see pjmedia_frame_type
- */
-typedef enum pjmedia_frame_type pjmedia_frame_type;
+} pjmedia_frame_type;
 
 
@@ -143,23 +332,6 @@
 struct pjmedia_port
 {
-    pjmedia_port_info	 info;
-    pjmedia_graph	*graph;
-    pjmedia_port	*upstream_port;
-    pjmedia_port	*downstream_port;
-    void		*user_data;
-
-    /**
-     * Called when this port is connected to an upstream port.
-     */
-    pj_status_t (*on_upstream_connect)(pj_pool_t *pool,
-				       pjmedia_port *this_port,
-				       pjmedia_port *upstream);
-
-    /**
-     * Called when this port is connected to a downstream port.
-     */
-    pj_status_t (*on_downstream_connect)(pj_pool_t *pool,
-					 pjmedia_port *this_port,
-				         pjmedia_port *upstream);
+    pjmedia_port_info	 info;		    /**< Port information.  */
+    void		*user_data;	    /**< User data.	    */
 
     /**
@@ -184,19 +356,4 @@
 
 
-
-/**
- * Connect two ports.
- */
-PJ_DECL(pj_status_t) pjmedia_port_connect( pj_pool_t *pool,
-					   pjmedia_port *upstream_port,
-					   pjmedia_port *downstream_port);
-
-/**
- * Disconnect ports.
- */
-PJ_DECL(pj_status_t) pjmedia_port_disconnect( pjmedia_port *upstream_port,
-					      pjmedia_port *downstream_port);
-
-
 /**
  * Get a frame from the port (and subsequent downstream ports).
@@ -221,4 +378,7 @@
 PJ_END_DECL
 
+/**
+ * @}
+ */
 
 #endif	/* __PJMEDIA_PORT_H__ */
Index: /pjproject/trunk/pjmedia/include/pjmedia/resample.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/resample.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/resample.h	(revision 518)
@@ -23,5 +23,5 @@
 
 /**
- * @file reample.h
+ * @file resample.h
  * @brief Sample rate converter.
  */
@@ -29,4 +29,13 @@
 #include <pjmedia/port.h>
 
+/**
+ * @defgroup PJMEDIA_RESAMPLE Resampling Algorithm
+ * @ingroup PJMEDIA_FRAME_OP
+ * @brief Functions to alter frame's clock rate.
+ * @{
+ * This section describes the base resampling functions. In addition to this,
+ * application can use the @ref PJMEDIA_RESAMPLE_PORT which provides
+ * media port abstraction for the base resampling algorithm.
+ */
 
 PJ_BEGIN_DECL
@@ -99,4 +108,42 @@
 
 /**
+ * @}
+ */
+
+/**
+ * @defgroup PJMEDIA_RESAMPLE_PORT Resample Port
+ * @ingroup PJMEDIA_PORT
+ * @brief Media port interface to change media stream's sampling rate.
+ * @{
+ * This section describes media port abstractoin for @ref PJMEDIA_RESAMPLE.
+ */
+
+
+/**
+ * Option flags that can be specified when creating resample port.
+ */
+enum pjmedia_resample_port_options
+{
+    /**
+     * Do not use high quality resampling algorithm, but use linear
+     * algorithm instead.
+     */
+    PJMEDIA_RESAMPLE_USE_LINEAR = 1,
+
+    /**
+     * Use small filter workspace when high quality resampling is
+     * used.
+     */
+    PJMEDIA_RESAMPLE_USE_SMALL_FILTER = 2,
+
+    /**
+     * Do not destroy downstream port when resample port is destroyed.
+     */
+    PJMEDIA_RESAMPLE_DONT_DESTROY_DN = 4,
+};
+
+
+
+/**
  * Create a resample port. This creates a bidirectional resample session,
  * which will resample frames when the port's get_frame() and put_frame()
@@ -104,23 +151,20 @@
  *
  * When the resample port's get_frame() is called, this port will get
- * a frame from the downstream port and resample the frame to the upstream
- * port's clock rate before returning it to the caller.
+ * a frame from the downstream port and resample the frame to the target
+ * clock rate before returning it to the caller.
  *
  * When the resample port's put_frame() is called, this port will resample
- * the frame to the downstream's port clock rate before giving the frame
+ * the frame to the downstream port's clock rate before giving the frame
  * to the downstream port.
  *
  * @param pool			Pool to allocate the structure and buffers.
- * @param high_quality		If true, then high quality conversion will be
- *				used, at the expense of more CPU and memory,
- *				because temporary buffer needs to be created.
- * @param large_filter		If true, large filter size will be used.
- * @param downstream_rate	The sampling rate of the downstream port.
- * @param upstream_rate		The sampling rate of the upstream port.
- * @param channel_count		The number of channels. This argument is only
- *				used for the port information. It does not
- *				change the behavior of the resample port.
- * @param samples_per_frame	Number of samples per frame from the downstream
- *				port.
+ * @param dn_port		The downstream port, which clock rate is to
+ *				be converted to the target clock rate.
+ * @param clock_rate		Target clock rate.
+ * @param options		Flags from #pjmedia_resample_port_options.
+ *				When this flag is zero, the default behavior
+ *				is to use high quality resampling with
+ *				large filter, and to destroy downstream port
+ *				when resample port is destroyed.
  * @param p_port		Pointer to receive the resample port instance.
  *
@@ -128,10 +172,7 @@
  */
 PJ_DECL(pj_status_t) pjmedia_resample_port_create( pj_pool_t *pool,
-						   pj_bool_t high_quality,
-						   pj_bool_t large_filter,
-						   unsigned downstream_rate,
-						   unsigned upstream_rate,
-						   unsigned channel_count,
-						   unsigned samples_per_frame,
+						   pjmedia_port *dn_port,
+						   unsigned clock_rate,
+						   unsigned options,
 						   pjmedia_port **p_port );
 
@@ -139,4 +180,9 @@
 PJ_END_DECL
 
+/**
+ * @}
+ */
+
+
 #endif	/* __PJMEDIA_RESAMPLE_H__ */
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/rtcp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/rtcp.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/rtcp.h	(revision 518)
@@ -33,6 +33,6 @@
 
 /**
- * @defgroup PJMED_RTCP RTCP Management
- * @ingroup PJMEDIA
+ * @defgroup PJMED_RTCP RTCP Session
+ * @ingroup PJMEDIA_TRANSPORT
  * @{
  */
@@ -219,4 +219,8 @@
 
 
+/**
+ * The types for keeping the average jitter value. Ideally a floating point
+ * number should be used, but this is not always available/desired.
+ */
 #if defined(PJ_HAS_FLOATING_POINT) && PJ_HAS_FLOATING_POINT!=0
   typedef double PJMEDIA_AVG_JITTER_TYPE;
Index: /pjproject/trunk/pjmedia/include/pjmedia/rtp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/rtp.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/rtp.h	(revision 518)
@@ -32,6 +32,6 @@
 
 /**
- * @defgroup PJMED_RTP RTP Packet and RTP Session Management
- * @ingroup PJMEDIA
+ * @defgroup PJMED_RTP RTP Session
+ * @ingroup PJMEDIA_TRANSPORT
  * @{
  *
@@ -40,5 +40,6 @@
  * on any transports (sockets), to promote even more use.
  *
- * An RTCP implementation is available, in separate module.
+ * An RTCP implementation is available, in separate module. Please see 
+ * @ref PJMED_RTCP.
  *
  * The functions that are provided by this module:
@@ -130,7 +131,7 @@
 struct pjmedia_rtp_dtmf_event
 {
-    pj_uint8_t	event;
-    pj_uint8_t	e_vol;
-    pj_uint16_t	duration;
+    pj_uint8_t	event;	    /**< Event type ID.	    */
+    pj_uint8_t	e_vol;	    /**< Event volume.	    */
+    pj_uint16_t	duration;   /**< Event duration.    */
 };
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/sdp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/sdp.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/sdp.h	(revision 518)
@@ -28,6 +28,6 @@
 
 /**
- * @defgroup PJ_SDP SDP Parsing and Data Structure
- * @ingroup PJMEDIA
+ * @defgroup PJMEDIA_SDP SDP Parsing and Data Structure
+ * @ingroup PJMEDIA_SESSION
  * @{
  *
Index: /pjproject/trunk/pjmedia/include/pjmedia/sdp_neg.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/sdp_neg.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/sdp_neg.h	(revision 518)
@@ -26,6 +26,6 @@
  */
 /**
- * @defgroup PJ_SDP_NEG SDP Negotiator.
- * @ingroup PJMEDIA
+ * @defgroup PJMEDIA_SDP_NEG SDP Negotiator
+ * @ingroup PJMEDIA_SESSION
  * @{
  *
Index: /pjproject/trunk/pjmedia/include/pjmedia/session.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/session.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/session.h	(revision 518)
@@ -33,6 +33,11 @@
 
 /**
+ * @defgroup PJMEDIA_SESSION Sessions
+ * @ingroup PJMEDIA
+ */
+
+/**
  * @defgroup PJMED_SES Media session
- * @ingroup PJMEDIA
+ * @ingroup PJMEDIA_SESSION
  * @{
  *
@@ -91,5 +96,4 @@
  * @param local		Local SDP session descriptor.
  * @param remote	Remote SDP session descriptor.
- * @param stream_idx	Media stream index in the session descriptor.
  *
  * @return		PJ_SUCCESS if stream info is successfully initialized.
@@ -104,5 +108,5 @@
 
 
-/*
+/**
  * This function will initialize the stream info based on information
  * in both SDP session descriptors for the specified stream index. 
@@ -264,5 +268,5 @@
  * @param session	The media session.
  * @param index		Stream index.
- * @param sta		Stream statistic.
+ * @param stat		Stream statistic.
  *
  * @return		PJ_SUCCESS on success.
Index: /pjproject/trunk/pjmedia/include/pjmedia/silencedet.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/silencedet.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/silencedet.h	(revision 518)
@@ -26,4 +26,13 @@
  */
 #include <pjmedia/types.h>
+
+
+/**
+ * @defgroup PJMEDIA_SILENCEDET Adaptive Silence Detection
+ * @ingroup PJMEDIA_FRAME_OP
+ * @brief Adaptive Silence Detector
+ * @{
+ */
+
 
 PJ_BEGIN_DECL
@@ -180,4 +189,9 @@
 
 
+/**
+ * @}
+ */
+
+
 #endif	/* __PJMEDIA_SILENCE_DET_H__ */
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/sound.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/sound.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/sound.h	(revision 518)
@@ -31,7 +31,32 @@
 
 /**
- * @defgroup PJMED_SND Sound device abstraction.
- * @ingroup PJMEDIA
+ * @defgroup PJMED_SND Sound Hardware Abstraction
+ * @ingroup PJMED_SND_PORT
+ * @brief PJMEDIA abstraction for sound device hardware
  * @{
+ *
+ * This section describes lower level abstraction for sound device
+ * hardware. Application normally uses the higher layer @ref
+ * PJMED_SND_PORT abstraction since it works seamlessly with 
+ * @ref PJMEDIA_PORT_CONCEPT.
+ *
+ * The sound hardware abstraction basically runs <b>asychronously</b>,
+ * and application must register callbacks to be called to receive/
+ * supply audio frames from/to the sound hardware.
+ *
+ * A full duplex sound stream (created with #pjmedia_snd_open()) 
+ * requires application to supply two callbacks:
+ *  - <b><tt>rec_cb</tt></b> callback to be called when it has finished
+ *    capturing one media frame, and 
+ *  - <b><tt>play_cb</tt></b> callback to be called when it needs media 
+ *    frame to be played to the sound playback hardware.
+ *
+ * Half duplex sound stream (created with #pjmedia_snd_open_rec() or
+ * #pjmedia_snd_open_player()) will only need one of the callback to
+ * be specified.
+ *
+ * After sound stream is created, application need to call
+ * #pjmedia_snd_stream_start() to start capturing/playing back media
+ * frames from/to the sound device.
  */
 
@@ -114,5 +139,6 @@
  * Create sound stream for both capturing audio and audio playback,  from the 
  * same device. This is the recommended way to create simultaneous recorder 
- * and player streams, because it should work on backends that does not allow
+ * and player streams (instead of creating separate capture and playback
+ * streams), because it works on backends that does not allow
  * a device to be opened more than once.
  *
Index: /pjproject/trunk/pjmedia/include/pjmedia/sound_port.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/sound_port.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/sound_port.h	(revision 518)
@@ -30,7 +30,34 @@
 
 /**
- * @defgroup PJMED_SND_PORT Media Port Connection Abstraction to Sound Device
- * @ingroup PJMEDIA
- * @{
+ * @defgroup PJMED_SND_PORT Sound Device Port
+ * @ingroup PJMEDIA_PORT_CLOCK
+ * @brief Media Port Connection Abstraction to the Sound Device
+ @{
+
+ As explained in @ref PJMED_SND, the sound hardware abstraction provides
+ some callbacks for its user:
+ - it calls <b><tt>rec_cb</tt></b> callback when it has finished capturing
+   one media frame, and 
+ - it calls <b><tt>play_cb</tt></b> when it needs media frame to be 
+   played to the sound playback hardware.
+
+ The @ref PJMED_SND_PORT (the object being explained here) add a
+ thin wrapper to the hardware abstraction:
+ - it will call downstream port's <tt>put_frame()</tt>
+   when <b><tt>rec_cb()</tt></b> is called (i.e. when the sound hardware 
+   has finished capturing frame), and 
+ - it will call downstream port's <tt>get_frame()</tt> when 
+   <b><tt>play_cb()</tt></b> is called (i.e. every time the 
+   sound hardware needs more frames to be played to the playback hardware).
+
+ This simple abstraction enables media to flow automatically (and
+ in timely manner) from the downstream media port to the sound device.
+ In other words, the sound device port supplies media clock to
+ the ports. The media clock concept is explained in @ref PJMEDIA_PORT_CLOCK
+ section.
+
+ Application registers downstream port to the sound device port by
+ calling #pjmedia_snd_port_connect();
+ 
  */
 
@@ -169,4 +196,5 @@
  *
  * @param snd_port	    The sound device port.
+ * @param port		    The media port to be connected.
  *
  * @return		    PJ_SUCCESS on success, or the appropriate error
Index: /pjproject/trunk/pjmedia/include/pjmedia/stream.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 518)
@@ -31,4 +31,5 @@
 #include <pjmedia/port.h>
 #include <pjmedia/rtcp.h>
+#include <pjmedia/transport.h>
 #include <pj/sock.h>
 
@@ -37,10 +38,12 @@
 
 /**
- * @defgroup PJMED_STRM Media Stream
- * @ingroup PJMEDIA
+ * @defgroup PJMED_STRM Streams
+ * @ingroup PJMEDIA_PORT
+ * @brief Media port for communicating with remote peer via the network.
  * @{
  *
  * A media stream is a bidirectional multimedia communication between two
- * endpoints. It corresponds to a media description (m= line) in SDP.
+ * endpoints. It corresponds to a media description (m= line) in SDP
+ * session descriptor.
  *
  * A media stream consists of two unidirectional channels:
@@ -48,8 +51,26 @@
  *  - decoding channel, which receives unidirectional media from remote.
  *
- * Application normally does not need to create the stream directly; it 
- * creates media session instead. The media session will create the media
- * streams as necessary, according to the media descriptors that present
- * in local and remote SDP.
+ * A media stream exports media port interface (see @ref PJMEDIA_PORT_CONCEPT)
+ * and application normally uses this interface to interconnect the stream
+ * to other PJMEDIA components.
+ *
+ * A media stream internally manages the following objects:
+ *  - an instance of media codec (see @ref PJMEDIA_CODEC),
+ *  - an @ref PJMED_JBUF,
+ *  - two instances of RTP sessions (#pjmedia_rtp_session, one for each
+ *    direction),
+ *  - one instance of RTCP session (#pjmedia_rtcp_session),
+ *  - and a reference to media transport to send and receive packets
+ *    to/from the network (see @ref PJMEDIA_TRANSPORT_H).
+ *
+ * Streams are created by calling #pjmedia_stream_create(), specifying
+ * #pjmedia_stream_info structure in the parameter. Application can construct
+ * the #pjmedia_stream_info structure manually, or use 
+ * #pjmedia_stream_info_from_sdp() or #pjmedia_session_info_from_sdp() 
+ * functions to construct the #pjmedia_stream_info from local and remote 
+ * SDP session descriptors.
+ *
+ * Application can also use @ref PJMEDIA_SESSION to indirectly create the
+ * streams.
  */
 
@@ -93,87 +114,4 @@
 
 
-/**
- * Opaque declaration for media stream.
- */
-typedef struct pjmedia_stream pjmedia_stream;
-
-
-/**
- * @see pjmedia_transport_op.
- */
-typedef struct pjmedia_transport pjmedia_transport;
-
-
-/**
- * This structure describes the operations for the stream transport.
- */
-struct pjmedia_transport_op
-{
-    /**
-     * This function is called by the stream when the transport is about
-     * to be used by the stream for the first time, and it tells the transport
-     * about remote RTP address to send the packet and some callbacks to be 
-     * called for incoming packets.
-     */
-    pj_status_t (*attach)(pjmedia_transport *tp,
-			  pjmedia_stream *strm,
-			  const pj_sockaddr_t *rem_addr,
-			  unsigned addr_len,
-			  void (*rtp_cb)(pjmedia_stream*,
-					 const void*,
-					 pj_ssize_t),
-			  void (*rtcp_cb)(pjmedia_stream*,
-					  const void*,
-					  pj_ssize_t));
-
-    /**
-     * This function is called by the stream when the stream is no longer
-     * need the transport (normally when the stream is about to be closed).
-     */
-    void (*detach)(pjmedia_transport *tp,
-		   pjmedia_stream *strm);
-
-    /**
-     * This function is called by the stream to send RTP packet using the 
-     * transport.
-     */
-    pj_status_t (*send_rtp)(pjmedia_transport *tp,
-			    const void *pkt,
-			    pj_size_t size);
-
-    /**
-     * This function is called by the stream to send RTCP packet using the
-     * transport.
-     */
-    pj_status_t (*send_rtcp)(pjmedia_transport *tp,
-			     const void *pkt,
-			     pj_size_t size);
-
-    /**
-     * This function can be called to destroy this transport.
-     */
-    pj_status_t (*destroy)(pjmedia_transport *tp);
-};
-
-
-/**
- * @see pjmedia_transport_op.
- */
-typedef struct pjmedia_transport_op pjmedia_transport_op;
-
-
-/**
- * This structure declares stream transport. A stream transport is called
- * by the stream to transmit a packet, and will notify stream when
- * incoming packet is arrived.
- */
-struct pjmedia_transport
-{
-    char		  name[PJ_MAX_OBJ_NAME];
-
-    pjmedia_transport_op *op;
-};
-
-
 
 /**
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 518)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 518)
@@ -0,0 +1,140 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJMEDIA_TRANSPORT_H__
+#define __PJMEDIA_TRANSPORT_H__
+
+
+/**
+ * @file transport.h Media Transport Interface
+ * @brief Transport interface.
+ */
+
+#include <pjmedia/types.h>
+
+/**
+ * @defgroup PJMEDIA_TRANSPORT Transports
+ * @ingroup PJMEDIA
+ * @brief Transports.
+ * Transport related components.
+ */
+
+/**
+ * @defgroup PJMEDIA_TRANSPORT_H Network Transport Interface
+ * @ingroup PJMEDIA_TRANSPORT
+ * @brief PJMEDIA object for sending/receiving media packets over the network
+ * @{
+ * The media transport (#pjmedia_transport) is the object to send and
+ * receive media packets over the network. Currently only media @ref PJMED_STRM
+ * are using the transport.
+ *
+ * Although currently only @ref PJMEDIA_TRANSPORT_UDP is implemented,
+ * media transport interface is intended to support any custom transports.
+ */
+
+PJ_BEGIN_DECL
+
+
+/*
+ * Forward declaration for media transport.
+ */
+typedef struct pjmedia_transport pjmedia_transport;
+
+
+/**
+ * This structure describes the operations for the stream transport.
+ */
+struct pjmedia_transport_op
+{
+    /**
+     * This function is called by the stream when the transport is about
+     * to be used by the stream for the first time, and it tells the transport
+     * about remote RTP address to send the packet and some callbacks to be 
+     * called for incoming packets.
+     */
+    pj_status_t (*attach)(pjmedia_transport *tp,
+			  pjmedia_stream *strm,
+			  const pj_sockaddr_t *rem_addr,
+			  unsigned addr_len,
+			  void (*rtp_cb)(pjmedia_stream*,
+					 const void*,
+					 pj_ssize_t),
+			  void (*rtcp_cb)(pjmedia_stream*,
+					  const void*,
+					  pj_ssize_t));
+
+    /**
+     * This function is called by the stream when the stream is no longer
+     * need the transport (normally when the stream is about to be closed).
+     */
+    void (*detach)(pjmedia_transport *tp,
+		   pjmedia_stream *strm);
+
+    /**
+     * This function is called by the stream to send RTP packet using the 
+     * transport.
+     */
+    pj_status_t (*send_rtp)(pjmedia_transport *tp,
+			    const void *pkt,
+			    pj_size_t size);
+
+    /**
+     * This function is called by the stream to send RTCP packet using the
+     * transport.
+     */
+    pj_status_t (*send_rtcp)(pjmedia_transport *tp,
+			     const void *pkt,
+			     pj_size_t size);
+
+    /**
+     * This function can be called to destroy this transport.
+     */
+    pj_status_t (*destroy)(pjmedia_transport *tp);
+};
+
+
+/**
+ * @see pjmedia_transport_op.
+ */
+typedef struct pjmedia_transport_op pjmedia_transport_op;
+
+
+/**
+ * This structure declares stream transport. A stream transport is called
+ * by the stream to transmit a packet, and will notify stream when
+ * incoming packet is arrived.
+ */
+struct pjmedia_transport
+{
+    /** Transport name (for logging purpose). */
+    char		  name[PJ_MAX_OBJ_NAME];
+
+    /** Transport's "virtual" function table. */
+    pjmedia_transport_op *op;
+};
+
+
+PJ_END_DECL
+
+/**
+ * @}
+ */
+
+
+#endif	/* __PJMEDIA_TRANSPORT_H__ */
+
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport_udp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport_udp.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport_udp.h	(revision 518)
@@ -22,9 +22,19 @@
 
 /**
- * @file stream_transport_udp.h
+ * @file transport_udp.h
  * @brief Stream transport with UDP.
  */
 
 #include <pjmedia/stream.h>
+
+
+/**
+ * @defgroup PJMEDIA_TRANSPORT_UDP UDP Socket Transport
+ * @ingroup PJMEDIA_TRANSPORT_H
+ * @brief Implementation of media transport with UDP sockets.
+ * @{
+ */
+
+PJ_BEGIN_DECL
 
 
@@ -93,4 +103,11 @@
 
 
+PJ_END_DECL
+
+
+/**
+ * @}
+ */
+
 
 #endif	/* __PJMEDIA_TRANSPORT_UDP_H__ */
Index: /pjproject/trunk/pjmedia/include/pjmedia/types.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/types.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/types.h	(revision 518)
@@ -20,4 +20,9 @@
 #define __PJMEDIA_TYPES_H__
 
+/**
+ * @file pjmedia/types.h Basic Types
+ * @brief Basic PJMEDIA types.
+ */
+
 #include <pjmedia/config.h>
 #include <pj/sock.h>	    /* pjmedia_sock_info	*/
@@ -25,8 +30,25 @@
 
 
+/**
+ * @defgroup PJMEDIA_FRAME_OP Frame Operations
+ * @ingroup PJMEDIA
+ */
+
+/**
+ * @defgroup PJMEDIA_MISC Misc
+ * @ingroup PJMEDIA
+ */
+
+/**
+ * @defgroup PJMEDIA_TYPES Basic Types
+ * @ingroup PJMEDIA_BASE
+ * @brief Basic PJMEDIA types and operations.
+ * @{
+ */
+
 /** 
  * Top most media type. 
  */
-enum pjmedia_type
+typedef enum pjmedia_type
 {
     /** No type. */
@@ -44,10 +66,5 @@
     PJMEDIA_TYPE_UNKNOWN = 3,
 
-};
-
-/**
- * @see pjmedia_type
- */
-typedef enum pjmedia_type pjmedia_type;
+} pjmedia_type;
 
 
@@ -56,5 +73,5 @@
  * Media direction. 
  */
-enum pjmedia_dir
+typedef enum pjmedia_dir
 {
     /** None */
@@ -70,10 +87,6 @@
     PJMEDIA_DIR_ENCODING_DECODING = 3,
 
-};
-
-/**
- * @see pjmedia_dir
- */
-typedef enum pjmedia_dir pjmedia_dir;
+} pjmedia_dir;
+
 
 
@@ -96,4 +109,11 @@
 
 
+/**
+ * Create 32bit port signature from ASCII characters.
+ */
+#define PJMEDIA_PORT_SIGNATURE(a,b,c,d)	    \
+	    (a<<24 | b<<16 | c<<8 | d)
+
+
 /** 
  * Opague declaration of media endpoint. 
@@ -102,14 +122,35 @@
 
 
-/** 
- * Media socket info. 
+/*
+ * Forward declaration for stream (needed by transport).
+ */
+typedef struct pjmedia_stream pjmedia_stream;
+
+
+/** 
+ * Media socket info is used to describe the underlying sockets
+ * to be used as media transport.
  */
 typedef struct pjmedia_sock_info
 {
-
-    pj_sock_t	    rtp_sock;	    /**< Socket for RTP.		    */
-    pj_sockaddr_in  rtp_addr_name;  /**< Local RTP address to be advertised.*/
-    pj_sock_t	    rtcp_sock;	    /**< Socket for RTCP.		    */
-    pj_sockaddr_in  rtcp_addr_name; /**< Local RTCP addr to be advertised.  */
+    /** The RTP socket handle */
+    pj_sock_t	    rtp_sock;
+
+    /** Address to be advertised as the local address for the RTP
+     *  socket, which does not need to be equal as the bound
+     *  address (for example, this address can be the address resolved
+     *  with STUN).
+     */
+    pj_sockaddr_in  rtp_addr_name;
+
+    /** The RTCP socket handle. */
+    pj_sock_t	    rtcp_sock;
+
+    /** Address to be advertised as the local address for the RTCP
+     *  socket, which does not need to be equal as the bound
+     *  address (for example, this address can be the address resolved
+     *  with STUN).
+     */
+    pj_sockaddr_in  rtcp_addr_name;
 
 } pjmedia_sock_info;
@@ -163,4 +204,9 @@
 
 
+/**
+ * @}
+ */
+
+
 #endif	/* __PJMEDIA_TYPES_H__ */
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/wav_port.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/wav_port.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/wav_port.h	(revision 518)
@@ -32,4 +32,24 @@
 
 /**
+ * @defgroup PJMEDIA_FILE_PLAY File Player
+ * @ingroup PJMEDIA_PORT
+ * @brief WAV File Player
+ * @{
+ */
+
+/**
+ * WAV file player options.
+ */
+enum pjmedia_file_player_option
+{
+    /**
+     * Tell the file player to return NULL frame when the whole
+     * file has been played.
+     */
+    PJMEDIA_FILE_NO_LOOP = 1,
+};
+
+
+/**
  * Create a media port to play streams from a WAV file.
  *
@@ -40,5 +60,5 @@
  *			duration (20ms) will be used.
  * @param flags		Port creation flags.
- * @param buf_size	Buffer size to be allocated. If the value is zero or
+ * @param buff_size	Buffer size to be allocated. If the value is zero or
  *			negative, the port will use default buffer size (which
  *			is about 4KB).
@@ -70,16 +90,30 @@
 
 /**
+ * @}
+ */
+
+
+/**
+ * @defgroup PJMEDIA_FILE_REC File Writer (Recorder)
+ * @ingroup PJMEDIA_PORT
+ * @brief WAV File Writer (Recorder)
+ * @{
+ */
+
+
+
+/**
  * Create a media port to record streams to a WAV file. Note that the port
  * must be closed properly (with #pjmedia_port_destroy()) so that the WAV
  * header can be filled with correct values (such as the file length).
  *
- * @param pool		Pool to create memory buffers for this port.
- * @param filename	File name.
- * @param clock_rate	The sampling rate.
- * @param channel_count	Number of channels.
+ * @param pool		    Pool to create memory buffers for this port.
+ * @param filename	    File name.
+ * @param clock_rate	    The sampling rate.
+ * @param channel_count	    Number of channels.
  * @param samples_per_frame Number of samples per frame.
- * @param bits_per_sampe Number of bits per sample (eg 16).
- * @param flags		Port creation flags (must be 0 at present).
- * @param buf_size	Buffer size to be allocated. If the value is zero or
+ * @param bits_per_sample   Number of bits per sample (eg 16).
+ * @param flags		    Port creation flags (must be 0 at present).
+ * @param buff_size	Buffer size to be allocated. If the value is zero or
  *			negative, the port will use default buffer size (which
  *			is about 4KB).
@@ -102,4 +136,8 @@
 
 
+/**
+ * @}
+ */
+
 
 PJ_END_DECL
Index: /pjproject/trunk/pjmedia/include/pjmedia/wave.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/wave.h	(revision 517)
+++ /pjproject/trunk/pjmedia/include/pjmedia/wave.h	(revision 518)
@@ -28,9 +28,33 @@
 
 
+/**
+ * @defgroup PJMEDIA_WAVE WAVE Header
+ * @ingroup PJMEDIA_MISC
+ * @{
+ *
+ * Supports for simple/canonical Microsoft RIFF WAVE format.
+ */
+
+
 PJ_BEGIN_DECL
 
+/**
+ * Standard RIFF tag to identify RIFF file format in the WAVE header.
+ */
 #define PJMEDIA_RIFF_TAG	('F'<<24|'F'<<16|'I'<<8|'R')
+
+/**
+ * Standard WAVE tag to identify WAVE header.
+ */
 #define PJMEDIA_WAVE_TAG	('E'<<24|'V'<<16|'A'<<8|'W')
+
+/**
+ * Standard FMT tag to identify format chunks.
+ */
 #define PJMEDIA_FMT_TAG		(' '<<24|'t'<<16|'m'<<8|'f')
+
+/**
+ * Standard DATA tag to identify data chunks.
+ */
 #define PJMEDIA_DATA_TAG	('a'<<24|'t'<<16|'a'<<8|'d')
 
@@ -42,24 +66,27 @@
 struct pjmedia_wave_hdr
 {
+    /** This structure describes RIFF WAVE file header */
     struct {
-	pj_uint32_t riff;
-	pj_uint32_t file_len;
-	pj_uint32_t wave;
+	pj_uint32_t riff;		/**< "RIFF" ASCII tag.		*/
+	pj_uint32_t file_len;		/**< File length minus 8 bytes	*/
+	pj_uint32_t wave;		/**< "WAVE" ASCII tag.		*/
     } riff_hdr;
 
+    /** This structure describes format chunks/header  */
     struct {
-	pj_uint32_t fmt;
-	pj_uint32_t len;
-	pj_uint16_t fmt_tag;
-	pj_uint16_t nchan;
-	pj_uint32_t sample_rate;
-	pj_uint32_t bytes_per_sec;
-	pj_uint16_t block_align;
-	pj_uint16_t bits_per_sample;
+	pj_uint32_t fmt;		/**< "fmt " ASCII tag.		*/
+	pj_uint32_t len;		/**< 16 for PCM.		*/
+	pj_uint16_t fmt_tag;		/**< 1 for PCM			*/
+	pj_uint16_t nchan;		/**< Number of channels.	*/
+	pj_uint32_t sample_rate;	/**< Sampling rate.		*/
+	pj_uint32_t bytes_per_sec;	/**< Average bytes per second.	*/
+	pj_uint16_t block_align;	/**< nchannels * bits / 8	*/
+	pj_uint16_t bits_per_sample;	/**< Bits per sample.		*/
     } fmt_hdr;
 
+    /** The data header preceeds the actual data in the file. */
     struct {
-	pj_uint32_t data;
-	pj_uint32_t len;
+	pj_uint32_t data;		/**< "data" ASCII tag.		*/
+	pj_uint32_t len;		/**< Data length.		*/
     } data_hdr;
 };
@@ -99,4 +126,9 @@
 PJ_END_DECL
 
+/**
+ * @}
+ */
+
+
 #endif	/* __PJMEDIA_WAVE_H__ */
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/port.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/port.c	(revision 517)
+++ /pjproject/trunk/pjmedia/src/pjmedia/port.c	(revision 518)
@@ -26,82 +26,4 @@
 
 /**
- * Connect two ports.
- */
-PJ_DEF(pj_status_t) pjmedia_port_connect( pj_pool_t *pool,
-					  pjmedia_port *upstream_port,
-					  pjmedia_port *downstream_port)
-{
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(pool && upstream_port && downstream_port, PJ_EINVAL);
-
-#if 0
-    /* They both MUST have the same media type. */
-    PJ_ASSERT_RETURN(upstream_port->info.type ==
-		     downstream_port->info.type, PJMEDIA_ENCTYPE);
-
-    /* They both MUST have the same clock rate. */
-    PJ_ASSERT_RETURN(upstream_port->info.sample_rate ==
-		     downstream_port->info.sample_rate, PJMEDIA_ENCCLOCKRATE);
-
-    /* They both MUST have the same samples per frame */
-    PJ_ASSERT_RETURN(upstream_port->info.samples_per_frame ==
-		     downstream_port->info.samples_per_frame, 
-		     PJMEDIA_ENCSAMPLESPFRAME);
-
-    /* They both MUST have the same bits per sample */
-    PJ_ASSERT_RETURN(upstream_port->info.bits_per_sample ==
-		     downstream_port->info.bits_per_sample, 
-		     PJMEDIA_ENCBITS);
-
-    /* They both MUST have the same bytes per frame */
-    PJ_ASSERT_RETURN(upstream_port->info.bytes_per_frame ==
-		     downstream_port->info.bytes_per_frame, 
-		     PJMEDIA_ENCBYTES);
-#endif
-
-    /* Create mutual attachment. */
-    if (upstream_port->on_downstream_connect) {
-	status = upstream_port->on_downstream_connect( pool, upstream_port,
-						       downstream_port );
-	if (status != PJ_SUCCESS)
-	    return status;
-    }
-
-    if (downstream_port->on_upstream_connect) {
-	status = downstream_port->on_upstream_connect( pool, downstream_port,
-						       upstream_port );
-	if (status != PJ_SUCCESS)
-	    return status;
-    }
-
-    /* Save the attachment. */
-    upstream_port->downstream_port = downstream_port;
-    downstream_port->upstream_port = upstream_port;
-    
-    /* Done. */
-    return PJ_SUCCESS;
-}
-
-
-/**
- * Disconnect ports.
- */
-PJ_DEF(pj_status_t) pjmedia_port_disconnect( pjmedia_port *upstream_port,
-					     pjmedia_port *downstream_port)
-{
-    PJ_ASSERT_RETURN(upstream_port && downstream_port, PJ_EINVAL);
-
-    if (upstream_port->downstream_port == downstream_port)
-	upstream_port->downstream_port = NULL;
-
-    if (downstream_port->upstream_port == upstream_port)
-	downstream_port->upstream_port = NULL;
-
-    return PJ_SUCCESS;
-}
-
-
-/**
  * Get a frame from the port (and subsequent downstream ports).
  */
@@ -114,5 +36,4 @@
     return port->get_frame(port, frame);
 }
-
 
 
@@ -140,14 +61,4 @@
     PJ_ASSERT_RETURN(port, PJ_EINVAL);
 
-    /* Recursively call this function again to destroy downstream
-     * port first.
-     */
-    if (port->downstream_port) {
-	status = pjmedia_port_destroy(port->downstream_port);
-	if (status != PJ_SUCCESS)
-	    return status;
-	pjmedia_port_disconnect(port, port->downstream_port);
-    }
-
     if (port->on_destroy)
 	status = port->on_destroy(port);
@@ -160,3 +71,2 @@
 
 
-
Index: /pjproject/trunk/pjmedia/src/pjmedia/resample_port.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/resample_port.c	(revision 517)
+++ /pjproject/trunk/pjmedia/src/pjmedia/resample_port.c	(revision 518)
@@ -29,10 +29,10 @@
 {
     pjmedia_port	 base;
+    pjmedia_port	*dn_port;
+    unsigned		 options;
     pjmedia_resample	*resample_get;
     pjmedia_resample	*resample_put;
     pj_int16_t		*get_buf;
     pj_int16_t		*put_buf;
-    unsigned		 downstream_frame_size;
-    unsigned		 upstream_frame_size;
 };
 
@@ -43,32 +43,37 @@
 static pj_status_t resample_get_frame(pjmedia_port *this_port, 
 				      pjmedia_frame *frame);
+static pj_status_t resample_destroy(pjmedia_port *this_port);
 
 
 
 PJ_DEF(pj_status_t) pjmedia_resample_port_create( pj_pool_t *pool,
-						  pj_bool_t high_quality,
-						  pj_bool_t large_filter,
-						  unsigned downstream_rate,
-						  unsigned upstream_rate,
-						  unsigned channel_count,
-						  unsigned samples_per_frame,
-						  pjmedia_port **p_port )
+						  pjmedia_port *dn_port,
+						  unsigned clock_rate,
+						  unsigned opt,
+						  pjmedia_port **p_port  )
 {
     struct resample_port *rport;
-    unsigned upstream_samples_per_frame;
+    unsigned ptime;
     pj_status_t status;
 
-    PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
-
-    upstream_samples_per_frame = (unsigned)(samples_per_frame * 1.0 *
-					    upstream_rate / downstream_rate);
-
+    /* Validate arguments. */
+    PJ_ASSERT_RETURN(pool && dn_port && clock_rate && p_port, PJ_EINVAL);
+
+    /* Only supports 16bit samples per frame */
+    PJ_ASSERT_RETURN(dn_port->info.bits_per_sample == 16, PJMEDIA_ENCBITS);
+
+    ptime = dn_port->info.samples_per_frame * 1000 / 
+	    dn_port->info.clock_rate;
+    
     /* Create and initialize port. */
     rport = pj_pool_zalloc(pool, sizeof(struct resample_port));
     PJ_ASSERT_RETURN(rport != NULL, PJ_ENOMEM);
 
-    rport->base.info.bits_per_sample = 16;
-    rport->base.info.bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE;
-    rport->base.info.channel_count = channel_count;
+    rport->base.info.clock_rate = clock_rate;
+    rport->base.info.samples_per_frame = clock_rate * ptime / 1000;
+    rport->base.info.bytes_per_frame = rport->base.info.samples_per_frame *
+				       BYTES_PER_SAMPLE;
+    rport->base.info.bits_per_sample = BYTES_PER_SAMPLE * 8;
+    rport->base.info.channel_count = dn_port->info.channel_count;
     rport->base.info.encoding_name = pj_str("pcm");
     rport->base.info.has_info = 1;
@@ -76,11 +81,10 @@
     rport->base.info.need_info = 0;
     rport->base.info.pt = 0xFF;
-    rport->base.info.clock_rate = upstream_rate;
-    rport->base.info.samples_per_frame = upstream_samples_per_frame;
-    rport->base.info.signature = 0;
+    rport->base.info.signature = PJMEDIA_PORT_SIGNATURE('R','S','M','P');
     rport->base.info.type = PJMEDIA_TYPE_AUDIO;
 
-    rport->downstream_frame_size = samples_per_frame;
-    rport->upstream_frame_size = upstream_samples_per_frame;
+    rport->dn_port = dn_port;
+    rport->options = opt;
+
 
     /* Create buffers. 
@@ -88,27 +92,35 @@
      * both functions may run simultaneously.
      */
-    rport->get_buf = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE);
-    PJ_ASSERT_RETURN(rport->get_buf, PJ_ENOMEM);
-
-    rport->put_buf = pj_pool_alloc(pool, samples_per_frame * BYTES_PER_SAMPLE);
-    PJ_ASSERT_RETURN(rport->put_buf, PJ_ENOMEM);
+    rport->get_buf = pj_pool_alloc(pool, rport->base.info.bytes_per_frame);
+    PJ_ASSERT_RETURN(rport->get_buf != NULL, PJ_ENOMEM);
+
+    rport->put_buf = pj_pool_alloc(pool, rport->base.info.bytes_per_frame);
+    PJ_ASSERT_RETURN(rport->put_buf != NULL, PJ_ENOMEM);
 
 
     /* Create "get_frame" resample */
-    status = pjmedia_resample_create( pool, high_quality, large_filter,
-				      downstream_rate, upstream_rate,
-				      samples_per_frame, &rport->resample_get);
+    status = pjmedia_resample_create(pool, 
+				     (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0,
+				     (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0,
+				     dn_port->info.clock_rate, 
+				     rport->base.info.clock_rate,
+				     dn_port->info.samples_per_frame, 
+				     &rport->resample_get);
     if (status != PJ_SUCCESS)
 	return status;
 
     /* Create "put_frame" resample */
-    status = pjmedia_resample_create( pool, high_quality, large_filter,
-				      upstream_rate, downstream_rate,
-				      upstream_samples_per_frame,
-				      &rport->resample_put);
-
-    /* Set get_frame and put_frame interface */
+    status = pjmedia_resample_create(pool, 
+				     (opt&PJMEDIA_RESAMPLE_USE_LINEAR)==0, 
+				     (opt&PJMEDIA_RESAMPLE_USE_SMALL_FILTER)==0,
+				     rport->base.info.clock_rate, 
+				     dn_port->info.clock_rate,
+				     rport->base.info.samples_per_frame,
+				     &rport->resample_put);
+
+    /* Media port interface */
     rport->base.get_frame = &resample_get_frame;
     rport->base.put_frame = &resample_put_frame;
+    rport->base.on_destroy = &resample_destroy;
 
 
@@ -128,14 +140,14 @@
 
     /* Return if we don't have downstream port. */
-    if (this_port->downstream_port == NULL) {
+    if (rport->dn_port == NULL) {
 	return PJ_SUCCESS;
     }
 
     if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO) {
-	pjmedia_resample_run( rport->resample_put, frame->buf, rport->put_buf);
+	pjmedia_resample_run( rport->resample_put, frame->buf, 
+			      rport->put_buf);
 
 	downstream_frame.buf = rport->put_buf;
-	downstream_frame.size = rport->downstream_frame_size * 
-				BYTES_PER_SAMPLE;
+	downstream_frame.size = rport->dn_port->info.bytes_per_frame;
     } else {
 	downstream_frame.buf = frame->buf;
@@ -146,6 +158,5 @@
     downstream_frame.timestamp.u64 = frame->timestamp.u64;
 
-    return pjmedia_port_put_frame( this_port->downstream_port, 
-				   &downstream_frame );
+    return pjmedia_port_put_frame( rport->dn_port, &downstream_frame );
 }
 
@@ -156,26 +167,34 @@
 {
     struct resample_port *rport = (struct resample_port*) this_port;
-    pjmedia_frame downstream_frame;
+    pjmedia_frame tmp_frame;
     pj_status_t status;
 
     /* Return silence if we don't have downstream port */
-    if (this_port->downstream_port == NULL) {
+    if (rport->dn_port == NULL) {
 	pj_memset(frame->buf, frame->size, 0);
 	return PJ_SUCCESS;
     }
 
-    downstream_frame.buf = rport->get_buf;
-    downstream_frame.size = rport->downstream_frame_size * BYTES_PER_SAMPLE;
-    downstream_frame.timestamp.u64 = frame->timestamp.u64;
-    downstream_frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
-
-    status = pjmedia_port_get_frame( this_port->downstream_port,
-				     &downstream_frame);
+    tmp_frame.buf = rport->get_buf;
+    tmp_frame.size = rport->dn_port->info.bytes_per_frame;
+    tmp_frame.timestamp.u64 = frame->timestamp.u64;
+    tmp_frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
+
+    status = pjmedia_port_get_frame( rport->dn_port, &tmp_frame);
     if (status != PJ_SUCCESS)
 	return status;
 
-    pjmedia_resample_run( rport->resample_get, rport->get_buf, frame->buf);
-
-    frame->size = rport->upstream_frame_size * BYTES_PER_SAMPLE;
+    if (tmp_frame.type != PJMEDIA_FRAME_TYPE_AUDIO) {
+	frame->type = tmp_frame.type;
+	frame->timestamp = tmp_frame.timestamp;
+	frame->size = tmp_frame.size;
+	if (tmp_frame.size)
+	    pj_memcpy(frame->buf, tmp_frame.buf, tmp_frame.size);
+	return PJ_SUCCESS;
+    }
+
+    pjmedia_resample_run( rport->resample_get, tmp_frame.buf, frame->buf);
+
+    frame->size = rport->base.info.bytes_per_frame;
     frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
 
@@ -184,2 +203,16 @@
 
 
+static pj_status_t resample_destroy(pjmedia_port *this_port)
+{
+    struct resample_port *rport = (struct resample_port*) this_port;
+
+    if ((rport->options & PJMEDIA_RESAMPLE_DONT_DESTROY_DN)==0) {
+	pjmedia_port_destroy(rport->dn_port);
+	rport->dn_port = NULL;
+    }
+
+    /* Nothing else to do */
+
+    return PJ_SUCCESS;
+}
+
Index: /pjproject/trunk/pjmedia/src/pjmedia/wav_player.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/wav_player.c	(revision 517)
+++ /pjproject/trunk/pjmedia/src/pjmedia/wav_player.c	(revision 518)
@@ -56,4 +56,6 @@
 {
     pjmedia_port     base;
+    unsigned	     options;
+    pj_bool_t	     eof;
     pj_size_t	     bufsize;
     char	    *buf;
@@ -114,4 +116,8 @@
     pj_ssize_t size;
     pj_status_t status;
+
+    if (fport->eof) {
+	return PJ_EEOF;
+    }
 
     while (size_left > 0) {
@@ -136,9 +142,17 @@
 	 */
 	if (size < (pj_ssize_t)size_to_read) {
-	    PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, rewinding..",
-		      (int)fport->base.info.name.slen,
-		      fport->base.info.name.ptr));
-	    fport->fpos = sizeof(struct pjmedia_wave_hdr);
-	    pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET);
+	    if (fport->options & PJMEDIA_FILE_NO_LOOP) {
+		PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, stopping..",
+			  (int)fport->base.info.name.slen,
+			  fport->base.info.name.ptr));
+		fport->eof = PJ_TRUE;
+		return PJ_EEOF;
+	    } else {
+		PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, rewinding..",
+			  (int)fport->base.info.name.slen,
+			  fport->base.info.name.ptr));
+		fport->fpos = sizeof(struct pjmedia_wave_hdr);
+		pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET);
+	    }
 	}
     }
@@ -157,5 +171,5 @@
 						     const char *filename,
 						     unsigned ptime,
-						     unsigned flags,
+						     unsigned options,
 						     pj_ssize_t buff_size,
 						     void *user_data,
@@ -167,6 +181,4 @@
     pj_status_t status;
 
-
-    PJ_UNUSED_ARG(flags);
 
     /* Check arguments. */
@@ -261,4 +273,5 @@
     /* Initialize */
     fport->base.user_data = user_data;
+    fport->options = options;
 
     /* Update port info. */
@@ -338,4 +351,5 @@
     pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET);
 
+    fport->eof = PJ_FALSE;
     return fill_buffer(fport);
 }
@@ -385,6 +399,9 @@
 
 	    status = fill_buffer(fport);
-	    if (status != PJ_SUCCESS)
+	    if (status != PJ_SUCCESS) {
+		frame->type = PJMEDIA_FRAME_TYPE_NONE;
+		frame->size = 0;
 		return status;
+	    }
 	}
     } else {
Index: /pjproject/trunk/pjsip-apps/src/samples/resampleplay.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/resampleplay.c	(revision 517)
+++ /pjproject/trunk/pjsip-apps/src/samples/resampleplay.c	(revision 518)
@@ -128,22 +128,9 @@
 
     /* Create the resample port. */
-    status = pjmedia_resample_port_create( pool, 1, 1,
-					   file_port->info.clock_rate,
-					   sampling_rate,
-					   channel_count,
-					   (unsigned)(
-					   samples_per_frame * 1.0 *
-					    file_port->info.clock_rate / 
-					    sampling_rate),
+    status = pjmedia_resample_port_create( pool, file_port,
+					   sampling_rate, 0,
 					   &resample_port);
     if (status != PJ_SUCCESS) {
 	app_perror(THIS_FILE, "Unable to create resample port", status);
-	return 1;
-    }
-
-    /* Connect resample port to file port */
-    status = pjmedia_port_connect( pool, resample_port, file_port);
-    if (status != PJ_SUCCESS) {
-	app_perror(THIS_FILE, "Error connecting ports", status);
 	return 1;
     }
