Index: /pjproject/trunk/aconfigure
===================================================================
--- /pjproject/trunk/aconfigure	(revision 5629)
+++ /pjproject/trunk/aconfigure	(revision 5630)
@@ -628,4 +628,5 @@
 ac_no_webrtc
 ac_no_yuv
+ac_no_bcg729
 opus_present
 opus_h_present
@@ -827,4 +828,6 @@
 with_opus
 enable_opus
+with_bcg729
+enable_bcg729
 enable_libyuv
 enable_libwebrtc
@@ -1507,4 +1510,5 @@
                           autodetect)
 
+  --disable-bcg729        Disable bcg729 (default: not disabled)
   --disable-libyuv        Exclude libyuv in the build
   --disable-libwebrtc     Exclude libwebrtc in the build
@@ -1559,4 +1563,5 @@
   --with-silk=DIR         Specify alternate SILK prefix
   --with-opus=DIR         Specify alternate OPUS prefix
+  --with-bcg729=DIR       Specify alternate bcg729 prefix
 
 Some influential environment variables:
@@ -8473,4 +8478,97 @@
 
 
+# Check whether --with-bcg729 was given.
+if test "${with_bcg729+set}" = set; then :
+  withval=$with_bcg729;
+else
+  with_bcg729=no
+
+fi
+
+
+if test "x$ac_cross_compile" != "x" -a "x$with_bcg729" = "xno"; then
+    enable_bcg729=no
+fi
+
+
+# Check whether --enable-bcg729 was given.
+if test "${enable_bcg729+set}" = set; then :
+  enableval=$enable_bcg729;
+		if test "$enable_bcg729" = "no"; then
+		  ac_no_bcg729=1
+		  $as_echo "#define PJMEDIA_HAS_BCG729 0" >>confdefs.h
+
+		  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if bcg729 is disabled... yes" >&5
+$as_echo "Checking if bcg729 is disabled... yes" >&6; }
+		fi
+
+else
+
+		  if test "x$with_bcg729" != "xno" -a "x$with_bcg729" != "x"; then
+		        BCG729_PREFIX=$with_bcg729
+		  	BCG729_CFLAGS="-I$BCG729_PREFIX/include"
+			BCG729_LDFLAGS="-L$BCG729_PREFIX/lib"
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Using bcg729 prefix... $with_bcg729" >&5
+$as_echo "Using bcg729 prefix... $with_bcg729" >&6; }
+		  else
+		  	BCG729_CFLAGS=""
+			BCG729_LDFLAGS=""
+		  fi
+
+		  { $as_echo "$as_me:${as_lineno-$LINENO}: checking bcg729 usability" >&5
+$as_echo_n "checking bcg729 usability... " >&6; }
+
+		  BCG729_LIBS="-lbcg729"
+
+		  SAVED_LIBS="$LIBS"
+		  SAVED_LDFLAGS="$LDFLAGS"
+		  SAVED_CFLAGS="$CFLAGS"
+
+		  LIBS="$BCG729_LIBS $LIBS"
+		  LDFLAGS="$BCG729_LDFLAGS $LDFLAGS"
+		  CFLAGS="$BCG729_CFLAGS $CFLAGS"
+
+		  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <bcg729/encoder.h>
+		                                    #include <bcg729/decoder.h>
+
+int
+main ()
+{
+initBcg729EncoderChannel(0);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+				   $as_echo "#define PJMEDIA_HAS_BCG729 1" >>confdefs.h
+
+		  		   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+
+else
+
+				   ac_no_bcg729=1
+				   $as_echo "#define PJMEDIA_HAS_BCG729 0" >>confdefs.h
+
+				   LIBS="$SAVED_LIBS"
+				   LDFLAGS="$SAVED_LDFLAGS"
+				   CFLAGS="$SAVED_CFLAGS"
+		  		   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+
+fi
+
+
+
+
 # Check whether --enable-libyuv was given.
 if test "${enable_libyuv+set}" = set; then :
Index: /pjproject/trunk/aconfigure.ac
===================================================================
--- /pjproject/trunk/aconfigure.ac	(revision 5629)
+++ /pjproject/trunk/aconfigure.ac	(revision 5630)
@@ -1788,4 +1788,73 @@
 	      ])
 
+dnl # bcg729 prefix
+AC_ARG_WITH(bcg729,
+            AS_HELP_STRING([--with-bcg729=DIR],
+		           [Specify alternate bcg729 prefix]),
+            [],
+            [with_bcg729=no]
+            )
+
+dnl # Do not use default bcg729 installation if we are cross-compiling
+if test "x$ac_cross_compile" != "x" -a "x$with_bcg729" = "xno"; then
+    enable_bcg729=no
+fi
+
+dnl # bcg729
+AC_SUBST(ac_no_bcg729)
+AC_ARG_ENABLE(bcg729,
+	      AS_HELP_STRING([--disable-bcg729],
+			     [Disable bcg729 (default: not disabled)]),
+	      [
+		if test "$enable_bcg729" = "no"; then
+		  [ac_no_bcg729=1]
+		  AC_DEFINE(PJMEDIA_HAS_BCG729,0)
+		  AC_MSG_RESULT([Checking if bcg729 is disabled... yes])
+		fi
+	      ],
+	      [
+		  if test "x$with_bcg729" != "xno" -a "x$with_bcg729" != "x"; then
+		        BCG729_PREFIX=$with_bcg729
+		  	BCG729_CFLAGS="-I$BCG729_PREFIX/include"
+			BCG729_LDFLAGS="-L$BCG729_PREFIX/lib" 
+			AC_MSG_RESULT([Using bcg729 prefix... $with_bcg729])
+		  else
+		  	BCG729_CFLAGS=""
+			BCG729_LDFLAGS="" 
+		  fi
+
+		  AC_MSG_CHECKING([bcg729 usability])
+
+		  BCG729_LIBS="-lbcg729"
+		  
+		  SAVED_LIBS="$LIBS"
+		  SAVED_LDFLAGS="$LDFLAGS"
+		  SAVED_CFLAGS="$CFLAGS"
+		  
+		  LIBS="$BCG729_LIBS $LIBS"
+		  LDFLAGS="$BCG729_LDFLAGS $LDFLAGS"
+		  CFLAGS="$BCG729_CFLAGS $CFLAGS"
+		  
+		  AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <bcg729/encoder.h>
+		                                    #include <bcg729/decoder.h>
+					          ]],
+					          [initBcg729EncoderChannel(0);]
+					         )],
+		  		 [ 
+				   AC_DEFINE(PJMEDIA_HAS_BCG729,1)
+		  		   AC_MSG_RESULT(ok)
+		  		  ],
+		  		 [
+				   [ac_no_bcg729=1]
+				   AC_DEFINE(PJMEDIA_HAS_BCG729,0)
+				   LIBS="$SAVED_LIBS"
+				   LDFLAGS="$SAVED_LDFLAGS"
+				   CFLAGS="$SAVED_CFLAGS"
+		  		   AC_MSG_RESULT(no)
+		  		 ])
+
+	      ])
+		  
+
 dnl # Include libyuv
 AC_SUBST(ac_no_yuv)
Index: /pjproject/trunk/pjmedia/build/os-auto.mak.in
===================================================================
--- /pjproject/trunk/pjmedia/build/os-auto.mak.in	(revision 5629)
+++ /pjproject/trunk/pjmedia/build/os-auto.mak.in	(revision 5630)
@@ -72,4 +72,5 @@
 AC_NO_OPENCORE_AMRNB=@ac_no_opencore_amrnb@
 AC_NO_OPENCORE_AMRWB=@ac_no_opencore_amrwb@
+AC_NO_BCG729=@ac_no_bcg729@
 
 export CODEC_OBJS=
@@ -138,4 +139,8 @@
 export CODEC_OBJS += opencore_amr.o
 endif
+endif
+
+ifeq ($(AC_NO_BCG729),)
+export CODEC_OBJS += bcg729.o
 endif
 
Index: /pjproject/trunk/pjmedia/build/pjmedia_codec.vcxproj
===================================================================
--- /pjproject/trunk/pjmedia/build/pjmedia_codec.vcxproj	(revision 5629)
+++ /pjproject/trunk/pjmedia/build/pjmedia_codec.vcxproj	(revision 5630)
@@ -195,6 +195,7 @@
   <PropertyGroup>
     <PlatformToolset>$(BuildToolset)</PlatformToolset>
-    <CharacterSet Condition="'$(API_Family)'!='WinDesktop'"></CharacterSet>
-  </PropertyGroup>  
+    <CharacterSet Condition="'$(API_Family)'!='WinDesktop'">
+    </CharacterSet>
+  </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
@@ -511,4 +512,5 @@
     <ClCompile Include="..\src\pjmedia-codec\amr_sdp_match.c" />
     <ClCompile Include="..\src\pjmedia-codec\audio_codecs.c" />
+    <ClCompile Include="..\src\pjmedia-codec\bcg729.c" />
     <ClCompile Include="..\src\pjmedia-codec\ffmpeg_vid_codecs.c" />
     <ClCompile Include="..\src\pjmedia-codec\g722.c" />
@@ -535,4 +537,5 @@
     <ClInclude Include="..\include\pjmedia-codec\amr_sdp_match.h" />
     <ClInclude Include="..\include\pjmedia-codec\audio_codecs.h" />
+    <ClInclude Include="..\include\pjmedia-codec\bcg729.h" />
     <ClInclude Include="..\include\pjmedia-codec\config.h" />
     <ClInclude Include="..\include\pjmedia-codec\ffmpeg_vid_codecs.h" />
Index: /pjproject/trunk/pjmedia/build/pjmedia_codec.vcxproj.filters
===================================================================
--- /pjproject/trunk/pjmedia/build/pjmedia_codec.vcxproj.filters	(revision 5629)
+++ /pjproject/trunk/pjmedia/build/pjmedia_codec.vcxproj.filters	(revision 5630)
@@ -75,4 +75,7 @@
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\src\pjmedia-codec\bcg729.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
@@ -146,4 +149,7 @@
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\include\pjmedia-codec\bcg729.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
Index: /pjproject/trunk/pjmedia/include/pjmedia-codec.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-codec.h	(revision 5629)
+++ /pjproject/trunk/pjmedia/include/pjmedia-codec.h	(revision 5630)
@@ -41,4 +41,5 @@
 #include <pjmedia-codec/silk.h>
 #include <pjmedia-codec/opus.h>
+#include <pjmedia-codec/bcg729.h>
 
 
Index: /pjproject/trunk/pjmedia/include/pjmedia-codec/bcg729.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-codec/bcg729.h	(revision 5630)
+++ /pjproject/trunk/pjmedia/include/pjmedia-codec/bcg729.h	(revision 5630)
@@ -0,0 +1,121 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#ifndef __PJMEDIA_CODEC_BCG729_H__
+#define __PJMEDIA_CODEC_BCG729_H__
+
+/**
+ * @file bcg729.h
+ * @brief BCG729 codec.
+ */
+
+#include <pjmedia-codec/types.h>
+
+/**
+ * @defgroup PJMED_BCG729 BCG729 Codec
+ * @ingroup PJMEDIA_CODEC_CODECS
+ * @brief Implementation of BCG729 codecs.
+ * @{
+ *
+ * This section describes functions to initialize and register BCG729 codec
+ * factory to the codec manager. After the codec factory has been registered,
+ * application can use @ref PJMEDIA_CODEC API to manipulate the codec.
+ *
+ * This codec factory contains G.729 codec.
+ * 
+ * \section pjmedia_codec_bcg729 BCG729
+ *
+ * BCG729 is compliant with ITU-T G.729 and Annexes A, B specifications.
+ *
+ * BCGG729 supports 16-bit PCM audio signal with sampling rate 8000Hz, 
+ * frame length 10ms, and resulting in bitrate 8000bps.
+ *
+ * \subsection codec_setting Codec Settings
+ *
+ * General codec settings for this codec such as VAD and PLC can be 
+ * manipulated through the <tt>setting</tt> field in #pjmedia_codec_param. 
+ * Please see the documentation of #pjmedia_codec_param for more info.
+ *
+ * Note that G.729 VAD status should be signalled in SDP, see more
+ * description below.
+ *
+ * \subsubsection annexb Annex B
+ *
+ * The capability of VAD/DTX is specified in Annex B.
+ *
+ * By default, Annex B is enabled. This default setting of Annex B can 
+ * be modified using #pjmedia_codec_mgr_set_default_param().
+ *
+ * In #pjmedia_codec_param, Annex B is configured via VAD setting and
+ * format parameter "annexb" in the SDP "a=fmtp" attribute in
+ * decoding fmtp field. Valid values are "yes" and "no",
+ * the implementation default is "yes". When this parameter is omitted
+ * in the SDP, the value will be "yes" (RFC 4856 Section 2.1.9).
+ *
+ * Here is an example of modifying default setting of Annex B to
+ * be disabled using #pjmedia_codec_mgr_set_default_param():
+ \code
+    pjmedia_codec_param param;
+
+    pjmedia_codec_mgr_get_default_param(.., &param);
+    ...
+    // Set VAD
+    param.setting.vad = 0;
+    // Set SDP format parameter
+    param.setting.dec_fmtp.cnt = 1;
+    param.setting.dec_fmtp.param[0].name = pj_str("annexb");
+    param.setting.dec_fmtp.param[0].val  = pj_str("no");
+    ...
+    pjmedia_codec_mgr_set_default_param(.., &param);
+ \endcode
+ *
+ * \note
+ * The difference of Annex B status in SDP offer/answer may be considered as 
+ * incompatible codec in SDP negotiation.
+ *
+ */
+
+PJ_BEGIN_DECL
+
+/**
+ * Initialize and register BCG729 codec factory to pjmedia endpoint. 
+ *
+ * @param endpt		The pjmedia endpoint.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_codec_bcg729_init(pjmedia_endpt *endpt);
+
+/**
+ * Unregister BCG729 codec factory from pjmedia endpoint and deinitialize
+ * the BCG729 codec library.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_codec_bcg729_deinit(void);
+
+
+PJ_END_DECL
+
+
+/**
+ * @}
+ */
+
+#endif	/* __PJMEDIA_CODEC_BCG729_H__ */
+
Index: /pjproject/trunk/pjmedia/include/pjmedia-codec/config.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-codec/config.h	(revision 5629)
+++ /pjproject/trunk/pjmedia/include/pjmedia-codec/config.h	(revision 5630)
@@ -470,4 +470,15 @@
 #endif
 
+
+/**
+ * Enable G.729 codec using BCG729 backend.
+ *
+ * Default: 0 
+ */
+#ifndef PJMEDIA_HAS_BCG729
+#   define PJMEDIA_HAS_BCG729				0
+#endif
+
+
 /**
  * Specify if FFMPEG codecs are available.
Index: /pjproject/trunk/pjmedia/include/pjmedia-codec/config_auto.h.in
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia-codec/config_auto.h.in	(revision 5629)
+++ /pjproject/trunk/pjmedia/include/pjmedia-codec/config_auto.h.in	(revision 5630)
@@ -90,4 +90,9 @@
 #endif
 
+/* G.729 codec with BCG729 backend */
+#ifndef PJMEDIA_HAS_BCG729
+#undef PJMEDIA_HAS_BCG729
+#endif
+
 #endif	/* __PJMEDIA_CODEC_CONFIG_AUTO_H_ */
 
Index: /pjproject/trunk/pjmedia/src/pjmedia-codec/audio_codecs.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia-codec/audio_codecs.c	(revision 5629)
+++ /pjproject/trunk/pjmedia/src/pjmedia-codec/audio_codecs.c	(revision 5630)
@@ -129,4 +129,11 @@
 #endif
 
+#if PJMEDIA_HAS_BCG729
+    /* Register BCG729 */
+    status = pjmedia_codec_bcg729_init(endpt);
+    if (status != PJ_SUCCESS)
+	return status;
+#endif
+
     return PJ_SUCCESS;
 }
Index: /pjproject/trunk/pjmedia/src/pjmedia-codec/bcg729.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia-codec/bcg729.c	(revision 5630)
+++ /pjproject/trunk/pjmedia/src/pjmedia-codec/bcg729.c	(revision 5630)
@@ -0,0 +1,622 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2017 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+#include <pjmedia-codec/bcg729.h>
+#include <pjmedia/codec.h>
+#include <pjmedia/endpoint.h>
+#include <pjmedia/errno.h>
+#include <pjmedia/port.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+#include <pj/assert.h>
+#include <pj/log.h>
+
+#if defined(PJMEDIA_HAS_BCG729) && (PJMEDIA_HAS_BCG729!=0)
+
+#include <bcg729/encoder.h>
+#include <bcg729/decoder.h>
+
+#define THIS_FILE		"bcg729.c"
+
+/* Prototypes for BCG729 factory */
+static pj_status_t bcg729_test_alloc(pjmedia_codec_factory *factory,
+				     const pjmedia_codec_info *id);
+static pj_status_t bcg729_default_attr(pjmedia_codec_factory *factory,
+				       const pjmedia_codec_info *id,
+				       pjmedia_codec_param *attr);
+static pj_status_t bcg729_enum_codecs (pjmedia_codec_factory *factory,
+				       unsigned *count,
+				       pjmedia_codec_info codecs[]);
+static pj_status_t bcg729_alloc_codec(pjmedia_codec_factory *factory,
+				      const pjmedia_codec_info *id,
+				      pjmedia_codec **p_codec);
+static pj_status_t bcg729_dealloc_codec(pjmedia_codec_factory *factory,
+				        pjmedia_codec *codec);
+
+/* Prototypes for BCG729 implementation. */
+static pj_status_t  bcg729_codec_init(pjmedia_codec *codec,
+				      pj_pool_t *pool );
+static pj_status_t  bcg729_codec_open(pjmedia_codec *codec,
+				      pjmedia_codec_param *attr);
+static pj_status_t  bcg729_codec_close(pjmedia_codec *codec);
+static pj_status_t  bcg729_codec_modify(pjmedia_codec *codec,
+				        const pjmedia_codec_param *attr);
+static pj_status_t  bcg729_codec_parse(pjmedia_codec *codec,
+				       void *pkt,
+				       pj_size_t pkt_size,
+				       const pj_timestamp *timestamp,
+				       unsigned *frame_cnt,
+				       pjmedia_frame frames[]);
+static pj_status_t  bcg729_codec_encode(pjmedia_codec *codec,
+				        const struct pjmedia_frame *input,
+				        unsigned output_buf_len,
+				        struct pjmedia_frame *output);
+static pj_status_t  bcg729_codec_decode(pjmedia_codec *codec,
+				        const struct pjmedia_frame *input,
+				        unsigned output_buf_len,
+				        struct pjmedia_frame *output);
+static pj_status_t  bcg729_codec_recover(pjmedia_codec *codec,
+					 unsigned output_buf_len,
+					 struct pjmedia_frame *output);
+
+/* Codec const. */
+#define G729_TAG 		"G729"
+#define G729_CLOCK_RATE 	8000
+#define G729_CHANNEL_COUNT 	1
+#define G729_SAMPLES_PER_FRAME	80
+#define G729_DEFAULT_BIT_RATE	8000
+#define G729_MAX_BIT_RATE	11800
+#define G729_FRAME_PER_PACKET	2
+#define G729_FRAME_SIZE		10
+
+/* Definition for BCG729 codec operations. */
+static pjmedia_codec_op bcg729_op =
+{
+    &bcg729_codec_init,
+    &bcg729_codec_open,
+    &bcg729_codec_close,
+    &bcg729_codec_modify,
+    &bcg729_codec_parse,
+    &bcg729_codec_encode,
+    &bcg729_codec_decode,
+    &bcg729_codec_recover
+};
+
+/* Definition for BCG729 codec factory operations. */
+static pjmedia_codec_factory_op bcg729_factory_op =
+{
+    &bcg729_test_alloc,
+    &bcg729_default_attr,
+    &bcg729_enum_codecs,
+    &bcg729_alloc_codec,
+    &bcg729_dealloc_codec,
+    &pjmedia_codec_bcg729_deinit
+};
+
+
+/* BCG729 factory private data */
+static struct bcg729_factory
+{
+    pjmedia_codec_factory	base;
+    pjmedia_endpt	       *endpt;
+    pj_pool_t		       *pool;
+    pj_mutex_t		       *mutex;
+} bcg729_factory;
+
+
+/* BCG729 codec private data. */
+typedef struct bcg729_private
+{
+    pj_pool_t	*pool;		/**< Pool for each instance.    */
+
+    bcg729EncoderChannelContextStruct	*encoder;
+    bcg729DecoderChannelContextStruct	*decoder;
+
+    pj_bool_t		 vad_enabled;
+    pj_bool_t		 plc_enabled;
+} bcg729_private;
+
+
+PJ_DEF(pj_status_t) pjmedia_codec_bcg729_init(pjmedia_endpt *endpt)
+{
+    pjmedia_codec_mgr *codec_mgr;
+    pj_status_t status;
+
+    if (bcg729_factory.endpt != NULL) {
+	/* Already initialized. */
+	return PJ_SUCCESS;
+    }
+
+    /* Init factory */
+    pj_bzero(&bcg729_factory, sizeof(bcg729_factory));
+    bcg729_factory.base.op = &bcg729_factory_op;
+    bcg729_factory.base.factory_data = NULL;
+    bcg729_factory.endpt = endpt;
+
+    /* Create pool */
+    bcg729_factory.pool = pjmedia_endpt_create_pool(endpt, "bcg729", 4000,
+						    4000);
+    if (!bcg729_factory.pool)
+	return PJ_ENOMEM;
+
+    /* Create mutex. */
+    status = pj_mutex_create_simple(bcg729_factory.pool, "bcg729",
+				    &bcg729_factory.mutex);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Get the codec manager. */
+    codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
+    if (!codec_mgr) {
+	status = PJ_EINVALIDOP;
+	goto on_error;
+    }
+
+    /* Register codec factory to endpoint. */
+    status = pjmedia_codec_mgr_register_factory(codec_mgr,
+						&bcg729_factory.base);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    PJ_LOG(4,(THIS_FILE, "BCG729 codec initialized"));
+    return PJ_SUCCESS;
+
+on_error:
+    if (bcg729_factory.mutex) {
+	pj_mutex_destroy(bcg729_factory.mutex);
+	bcg729_factory.mutex = NULL;
+    }
+    if (bcg729_factory.pool) {
+	pj_pool_release(bcg729_factory.pool);
+	bcg729_factory.pool = NULL;
+    }
+
+    return status;
+}
+
+/*
+ * Unregister BCG729 codec factory from pjmedia endpoint and deinitialize
+ * the BCG729 codec library.
+ */
+PJ_DEF(pj_status_t) pjmedia_codec_bcg729_deinit(void)
+{
+    pjmedia_codec_mgr *codec_mgr;
+    pj_status_t status;
+
+    if (bcg729_factory.endpt == NULL) {
+	/* Not registered. */
+	return PJ_SUCCESS;
+    }
+
+    /* Lock mutex. */
+    pj_mutex_lock(bcg729_factory.mutex);
+
+    /* Get the codec manager. */
+    codec_mgr = pjmedia_endpt_get_codec_mgr(bcg729_factory.endpt);
+    if (!codec_mgr) {
+	bcg729_factory.endpt = NULL;
+	pj_mutex_unlock(bcg729_factory.mutex);
+	return PJ_EINVALIDOP;
+    }
+
+    /* Unregister bcg729 codec factory. */
+    status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
+						  &bcg729_factory.base);
+    bcg729_factory.endpt = NULL;
+
+    /* Destroy mutex. */
+    pj_mutex_unlock(bcg729_factory.mutex);
+    pj_mutex_destroy(bcg729_factory.mutex);
+    bcg729_factory.mutex = NULL;
+
+    /* Release pool. */
+    pj_pool_release(bcg729_factory.pool);
+    bcg729_factory.pool = NULL;
+
+    return status;
+}
+
+
+/*
+ * Check if factory can allocate the specified codec.
+ */
+static pj_status_t bcg729_test_alloc(pjmedia_codec_factory *factory,
+				     const pjmedia_codec_info *info )
+{
+    pj_str_t g729_tag = pj_str(G729_TAG);
+    PJ_UNUSED_ARG(factory);
+    PJ_ASSERT_RETURN(factory==&bcg729_factory.base, PJ_EINVAL);
+
+    /* Type MUST be audio. */
+    if (info->type != PJMEDIA_TYPE_AUDIO)
+	return PJMEDIA_CODEC_EUNSUP;
+
+    /* Check encoding name. */
+    if (pj_stricmp(&info->encoding_name, &g729_tag) != 0)
+	return PJMEDIA_CODEC_EUNSUP;
+
+    /* Channel count must be one */
+    if (info->channel_cnt != G729_CHANNEL_COUNT)
+	return PJMEDIA_CODEC_EUNSUP;
+
+    /* Check clock-rate */
+    if (info->clock_rate != G729_CLOCK_RATE)
+	return PJMEDIA_CODEC_EUNSUP;	
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Generate default attribute.
+ */
+static pj_status_t bcg729_default_attr(pjmedia_codec_factory *factory,
+				       const pjmedia_codec_info *id,
+				       pjmedia_codec_param *attr )
+{    
+    PJ_ASSERT_RETURN(factory==&bcg729_factory.base, PJ_EINVAL);
+
+    if (id->pt != PJMEDIA_RTP_PT_G729)
+	return PJMEDIA_CODEC_EUNSUP;
+
+    pj_bzero(attr, sizeof(pjmedia_codec_param));
+    attr->info.pt = PJMEDIA_RTP_PT_G729;
+    attr->info.channel_cnt = G729_CHANNEL_COUNT;
+    attr->info.clock_rate = G729_CLOCK_RATE;
+    attr->info.avg_bps = G729_DEFAULT_BIT_RATE;
+    attr->info.max_bps = G729_MAX_BIT_RATE;
+
+    attr->info.pcm_bits_per_sample = G729_FRAME_PER_PACKET * 8;
+    attr->info.frm_ptime =  (pj_uint16_t)
+			    (G729_SAMPLES_PER_FRAME * 1000 /
+			     G729_CHANNEL_COUNT /
+			     G729_CLOCK_RATE);
+    attr->setting.frm_per_pkt = G729_FRAME_PER_PACKET;
+
+    /* Default flags. */
+    attr->setting.plc = 1;
+    attr->setting.penh= 0;
+    attr->setting.vad = 1;
+    attr->setting.cng = attr->setting.vad;
+
+    if (attr->setting.vad == 0) {
+	attr->setting.dec_fmtp.cnt = 1;
+	pj_strset2(&attr->setting.dec_fmtp.param[0].name, "annexb");
+	pj_strset2(&attr->setting.dec_fmtp.param[0].val, "no");
+    }
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Enum codecs supported by this factory.
+ */
+static pj_status_t bcg729_enum_codecs(pjmedia_codec_factory *factory,
+				    unsigned *count,
+				    pjmedia_codec_info codecs[])
+{
+    PJ_ASSERT_RETURN(factory==&bcg729_factory.base, PJ_EINVAL);
+    PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
+
+    pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
+    codecs[0].encoding_name = pj_str(G729_TAG);
+    codecs[0].pt = PJMEDIA_RTP_PT_G729;
+    codecs[0].type = PJMEDIA_TYPE_AUDIO;
+    codecs[0].clock_rate = G729_CLOCK_RATE;
+    codecs[0].channel_cnt = G729_CHANNEL_COUNT;
+
+    *count = 1;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Allocate a new BCG729 codec instance.
+ */
+static pj_status_t bcg729_alloc_codec(pjmedia_codec_factory *factory,
+				      const pjmedia_codec_info *id,
+				      pjmedia_codec **p_codec)
+{
+    pj_pool_t *pool;
+    pjmedia_codec *codec;
+    bcg729_private *bcg729_data;
+
+    PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
+    PJ_ASSERT_RETURN(factory == &bcg729_factory.base, PJ_EINVAL);
+
+    pj_mutex_lock(bcg729_factory.mutex);
+
+    /* Create pool for codec instance */
+    pool = pjmedia_endpt_create_pool(bcg729_factory.endpt, "bcg729", 512, 512);
+
+    /* Allocate codec */
+    codec = PJ_POOL_ZALLOC_T(pool, pjmedia_codec);
+    codec->op = &bcg729_op;
+    codec->factory = factory;
+    codec->codec_data = PJ_POOL_ZALLOC_T(pool, bcg729_private);
+    bcg729_data = (bcg729_private*) codec->codec_data;
+    bcg729_data->pool = pool;
+
+    pj_mutex_unlock(bcg729_factory.mutex);
+
+    *p_codec = codec;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Free codec.
+ */
+static pj_status_t bcg729_dealloc_codec(pjmedia_codec_factory *factory,
+				        pjmedia_codec *codec )
+{
+    bcg729_private *bcg729_data;
+
+    PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
+    PJ_ASSERT_RETURN(factory == &bcg729_factory.base, PJ_EINVAL);
+
+    bcg729_data = (bcg729_private*)codec->codec_data;
+
+    /* Close codec, if it's not closed. */
+    if (bcg729_data->encoder || bcg729_data->decoder) {
+    	bcg729_codec_close(codec);
+    }
+
+    pj_pool_release(bcg729_data->pool);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Init codec.
+ */
+static pj_status_t bcg729_codec_init(pjmedia_codec *codec,
+				   pj_pool_t *pool )
+{
+    PJ_UNUSED_ARG(codec);
+    PJ_UNUSED_ARG(pool);
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Open codec.
+ */
+static pj_status_t bcg729_codec_open(pjmedia_codec *codec,
+				     pjmedia_codec_param *attr )
+{
+    bcg729_private *bcg729_data;
+    unsigned i;
+
+    PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
+
+    bcg729_data = (bcg729_private*) codec->codec_data;
+
+    /* Already open? */
+    if (bcg729_data->encoder && bcg729_data->decoder)
+	return PJ_SUCCESS;
+
+    bcg729_data->vad_enabled = (attr->setting.vad != 0);
+    bcg729_data->plc_enabled = (attr->setting.plc != 0);
+
+    /* Check if G729 Annex B is signaled to be disabled */
+    for (i = 0; i < attr->setting.enc_fmtp.cnt; ++i) {
+	if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].name, "annexb")==0)
+	{
+	    if (pj_stricmp2(&attr->setting.enc_fmtp.param[i].val, "no")==0)
+	    {
+		attr->setting.vad = 0;
+		bcg729_data->vad_enabled = PJ_FALSE;
+	    }
+	    break;
+	}
+    }
+
+    bcg729_data->encoder = initBcg729EncoderChannel(
+						 bcg729_data->vad_enabled?1:0);
+    if (!bcg729_data->encoder)
+        return PJMEDIA_CODEC_EFAILED;
+
+    bcg729_data->decoder = initBcg729DecoderChannel();
+    if (!bcg729_data->decoder)
+        return PJMEDIA_CODEC_EFAILED;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Close codec.
+ */
+static pj_status_t bcg729_codec_close( pjmedia_codec *codec )
+{
+    bcg729_private *bcg729_data;
+
+    PJ_ASSERT_RETURN(codec, PJ_EINVAL);
+
+    bcg729_data = (bcg729_private *)codec->codec_data;
+
+    if (bcg729_data->encoder) {
+        closeBcg729EncoderChannel(bcg729_data->encoder);
+        bcg729_data->encoder = NULL;
+    }
+    if (bcg729_data->decoder) {
+        closeBcg729DecoderChannel(bcg729_data->decoder);
+        bcg729_data->decoder = NULL;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get frames in the packet.
+ */
+static pj_status_t  bcg729_codec_parse(pjmedia_codec *codec,
+				       void *pkt,
+				       pj_size_t pkt_size,
+				       const pj_timestamp *ts,
+				       unsigned *frame_cnt,
+				       pjmedia_frame frames[])
+{
+    unsigned count = 0;
+    PJ_UNUSED_ARG(codec);
+
+    PJ_ASSERT_RETURN(codec && ts && frames && frame_cnt, PJ_EINVAL);
+
+    while (pkt_size >= G729_FRAME_SIZE && count < *frame_cnt) {
+        frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
+        frames[count].buf = pkt;
+        frames[count].size = G729_FRAME_SIZE;
+        frames[count].timestamp.u64 = ts->u64 + count * G729_SAMPLES_PER_FRAME;
+
+        pkt = ((char*)pkt) + 10;
+        pkt_size -= 10;
+
+        ++count;
+    }
+
+    *frame_cnt = count;
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Modify codec settings.
+ */
+static pj_status_t  bcg729_codec_modify(pjmedia_codec *codec,
+				        const pjmedia_codec_param *attr )
+{
+    PJ_UNUSED_ARG(codec);
+    PJ_UNUSED_ARG(attr);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Encode frame.
+ */
+static pj_status_t bcg729_codec_encode(pjmedia_codec *codec,
+				       const struct pjmedia_frame *input,
+				       unsigned output_buf_len,
+				       struct pjmedia_frame *output)
+{
+    bcg729_private *bcg729_data;
+    pj_int16_t *pcm_in;
+    unsigned nsamples;    
+    pj_uint8_t stream_len;
+
+    PJ_ASSERT_RETURN(codec && input && output_buf_len && output, PJ_EINVAL);
+
+    bcg729_data = (bcg729_private*)codec->codec_data;
+    pcm_in   = (pj_int16_t*)input->buf;
+
+    /* Check frame in size */
+    nsamples = input->size >> 1;
+    output->size = 0;
+
+    /* Encode */
+    while (nsamples >= G729_SAMPLES_PER_FRAME) {
+        bcg729Encoder(bcg729_data->encoder, pcm_in,
+                      (unsigned char*)output->buf + output->size, &stream_len);
+
+	pcm_in += G729_SAMPLES_PER_FRAME;
+	nsamples -= G729_SAMPLES_PER_FRAME;
+
+	if (stream_len == 0) {
+	    /* Untransmitted */
+	    break;
+	} else {
+	    output->size += stream_len;
+	    if (stream_len == 2) {
+		/* SID */
+		break;
+            }
+	}
+    }
+    
+    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
+    output->timestamp = input->timestamp;
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_status_t bcg729_codec_decode(pjmedia_codec *codec,
+				       const struct pjmedia_frame *input,
+				       unsigned output_buf_len,
+				       struct pjmedia_frame *output)
+{
+    bcg729_private *bcg729_data;
+
+    PJ_ASSERT_RETURN(codec && input && output_buf_len && output, PJ_EINVAL);
+
+    bcg729_data = (struct bcg729_private*) codec->codec_data;
+
+    bcg729Decoder(bcg729_data->decoder,
+                  (unsigned char*)input->buf,
+                  G729_FRAME_SIZE,
+                  0,
+                  0,
+                  0,
+                  (short*)output->buf);
+
+    output->size = G729_SAMPLES_PER_FRAME * G729_FRAME_PER_PACKET;
+    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
+    output->timestamp = input->timestamp;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Recover lost frame.
+ */
+static pj_status_t  bcg729_codec_recover(pjmedia_codec *codec,
+				         unsigned output_buf_len,
+				         struct pjmedia_frame *output)
+{
+    bcg729_private *bcg729_data;
+
+    PJ_ASSERT_RETURN(codec && output_buf_len && output, PJ_EINVAL);
+
+    bcg729_data = (struct bcg729_private*) codec->codec_data;
+
+    output->size = G729_SAMPLES_PER_FRAME * G729_FRAME_PER_PACKET;
+    output->type = PJMEDIA_FRAME_TYPE_AUDIO;
+
+    if (bcg729_data->plc_enabled) {
+	bcg729Decoder(bcg729_data->decoder,
+		      NULL,
+		      G729_FRAME_SIZE,
+		      1,
+		      0,
+		      0,
+		      (short*)output->buf);
+    } else {
+	pjmedia_zero_samples((pj_int16_t*)output->buf, G729_SAMPLES_PER_FRAME);
+    }
+
+    return PJ_SUCCESS;
+}
+
+#endif /* PJMEDIA_HAS_BCG729 */
