Index: /pjproject/trunk/build.mak.in
===================================================================
--- /pjproject/trunk/build.mak.in	(revision 1734)
+++ /pjproject/trunk/build.mak.in	(revision 1735)
@@ -9,5 +9,5 @@
 
 # Determine which party libraries to use
-export APP_THIRD_PARTY_LIBS := -lresample-$(TARGET_NAME) -lmilenage-$(TARGET_NAME)
+export APP_THIRD_PARTY_LIBS := -lresample-$(TARGET_NAME) -lmilenage-$(TARGET_NAME) -lsrtp-$(TARGET_NAME)
 
 ifneq (@ac_no_gsm_codec@,1)
Index: /pjproject/trunk/pjmedia/build/Makefile
===================================================================
--- /pjproject/trunk/pjmedia/build/Makefile	(revision 1734)
+++ /pjproject/trunk/pjmedia/build/Makefile	(revision 1735)
@@ -3,4 +3,8 @@
 THIRD_PARTY:=$(PJDIR)/third_party
 PA_DIR := $(THIRD_PARTY)/build/portaudio/src
+
+SRTP_INC=$(CC_INC)$(THIRD_PARTY)/build/srtp \
+	 $(CC_INC)$(THIRD_PARTY)/srtp/crypto/include \
+	 $(CC_INC)$(THIRD_PARTY)/srtp/include
 
 include $(PJDIR)/build/common.mak
@@ -26,5 +30,6 @@
 		   $(CC_INC)../../pjlib-util/include \
 		   $(CC_INC)../../pjnath/include \
-		   $(CC_INC)../..
+		   $(CC_INC)../.. \
+		   $(SRTP_INC) 
 export _CXXFLAGS:= $(_CFLAGS) $(CC_CXXFLAGS) $(OS_CXXFLAGS) $(M_CXXFLAGS) \
 		   $(HOST_CXXFLAGS) $(CXXFLAGS)
@@ -49,5 +54,6 @@
 			resample_port.o rtcp.o rtp.o sdp.o sdp_cmp.o sdp_neg.o \
 			session.o silencedet.o sound_port.o stream.o \
-			tonegen.o transport_ice.o transport_udp.o \
+			tonegen.o transport_ice.o transport_srtp.o \
+			transport_udp.o \
 			wav_player.o wav_playlist.o wav_writer.o wave.o \
 			$(SOUND_OBJS) $(NULLSOUND_OBJS)
Index: /pjproject/trunk/pjmedia/build/pjmedia.dsp
===================================================================
--- /pjproject/trunk/pjmedia/build/pjmedia.dsp	(revision 1734)
+++ /pjproject/trunk/pjmedia/build/pjmedia.dsp	(revision 1735)
@@ -43,5 +43,5 @@
 F90=df.exe
 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD CPP /nologo /MD /W4 /GX /Zi /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjnath/include" /I "../../third_party/portaudio/include" /I "../../third_party/speex/include" /I "../.." /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
+# ADD CPP /nologo /MD /W4 /GX /Zi /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjnath/include" /I "../../third_party/portaudio/include" /I "../../third_party/speex/include" /I "../../third_party/build/srtp" /I "../../third_party/srtp/crypto/include" /I "../../third_party/srtp/include" /I "../.." /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
 # SUBTRACT CPP /YX
 # ADD BASE RSC /l 0x409 /d "NDEBUG"
@@ -68,5 +68,5 @@
 F90=df.exe
 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjnath/include" /I "../../third_party/portaudio/include" /I "../../third_party/speex/include" /I "../.." /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjnath/include" /I "../../third_party/portaudio/include" /I "../../third_party/speex/include" /I "../../third_party/build/srtp" /I "../../third_party/srtp/crypto/include" /I "../../third_party/srtp/include" /I "../.." /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c
 # SUBTRACT CPP /YX
 # ADD BASE RSC /l 0x409 /d "_DEBUG"
@@ -250,4 +250,8 @@
 # Begin Source File
 
+SOURCE=..\src\pjmedia\transport_srtp.c
+# End Source File
+# Begin Source File
+
 SOURCE=..\src\pjmedia\transport_udp.c
 # End Source File
@@ -407,4 +411,8 @@
 
 SOURCE=..\include\pjmedia\transport_ice.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjmedia\transport_srtp.h
 # End Source File
 # Begin Source File
Index: /pjproject/trunk/pjmedia/build/pjmedia.vcproj
===================================================================
--- /pjproject/trunk/pjmedia/build/pjmedia.vcproj	(revision 1734)
+++ /pjproject/trunk/pjmedia/build/pjmedia.vcproj	(revision 1735)
@@ -44,5 +44,5 @@
 				Optimization="2"
 				InlineFunctionExpansion="1"
-				AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../.."
+				AdditionalIncludeDirectories="../include;../../pjlib/include;&quot;../../pjlib-util/include&quot;;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../.."
 				PreprocessorDefinitions="NDEBUG;WIN32;_LIB;PJ_WIN32=1;PJ_M_I386=1"
 				StringPooling="true"
@@ -120,5 +120,5 @@
 				Name="VCCLCompilerTool"
 				Optimization="0"
-				AdditionalIncludeDirectories="../include,../../pjlib/include,../../pjlib-util/include,../../pjnath/include,../../third_party/portaudio/include,../../third_party/speex/include,../.."
+				AdditionalIncludeDirectories="../include;../../pjlib/include;&quot;../../pjlib-util/include&quot;;../../pjnath/include;../../third_party/portaudio/include;../../third_party/speex/include;../../third_party/build/srtp;../../third_party/srtp/include;../../third_party/srtp/crypto/include;../.."
 				PreprocessorDefinitions="_DEBUG;WIN32;_LIB;PJ_WIN32=1;PJ_M_I386=1"
 				MinimalRebuild="true"
@@ -967,4 +967,8 @@
 			</File>
 			<File
+				RelativePath="..\src\pjmedia\transport_srtp.c"
+				>
+			</File>
+			<File
 				RelativePath="..\src\pjmedia\transport_udp.c"
 				>
@@ -1218,4 +1222,8 @@
 			</File>
 			<File
+				RelativePath="..\include\pjmedia\transport_srtp.h"
+				>
+			</File>
+			<File
 				RelativePath="..\include\pjmedia\transport_udp.h"
 				>
Index: /pjproject/trunk/pjmedia/include/pjmedia.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia.h	(revision 1734)
+++ /pjproject/trunk/pjmedia/include/pjmedia.h	(revision 1735)
@@ -55,4 +55,5 @@
 #include <pjmedia/transport.h>
 #include <pjmedia/transport_ice.h>
+#include <pjmedia/transport_srtp.h>
 #include <pjmedia/transport_udp.h>
 #include <pjmedia/wav_playlist.h>
Index: /pjproject/trunk/pjmedia/include/pjmedia/config.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 1734)
+++ /pjproject/trunk/pjmedia/include/pjmedia/config.h	(revision 1735)
@@ -485,4 +485,12 @@
 
 
+/**
+ * SRTP Transport
+ * By default it is enabled.
+ */
+#ifndef PJMEDIA_HAS_SRTP
+#   define PJMEDIA_HAS_SRTP			    1
+#endif
+
 
 /**
Index: /pjproject/trunk/pjmedia/include/pjmedia/errno.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 1734)
+++ /pjproject/trunk/pjmedia/include/pjmedia/errno.h	(revision 1735)
@@ -43,4 +43,5 @@
  */
 #define PJMEDIA_ERRNO_START       (PJ_ERRNO_START_USER + PJ_ERRNO_SPACE_SIZE)
+#define PJMEDIA_ERRNO_END         (PJMEDIA_ERRNO_START + PJ_ERRNO_SPACE_SIZE - 1)
 
 
@@ -48,11 +49,27 @@
  * Mapping from PortAudio error codes to pjmedia error space.
  */
-#define PJMEDIA_PORTAUDIO_ERRNO_START (PJMEDIA_ERRNO_START+PJ_ERRNO_SPACE_SIZE-1000)
-
+#define PJMEDIA_PORTAUDIO_ERRNO_START (PJMEDIA_ERRNO_END-10000)
+#define PJMEDIA_PORTAUDIO_ERRNO_END   (PJMEDIA_PORTAUDIO_ERRNO_START + 10000 -1)
 /**
  * Convert PortAudio error code to PJMEDIA error code.
- */
-#define PJMEDIA_ERRNO_FROM_PORTAUDIO(err)   (err+PJMEDIA_PORTAUDIO_ERRNO_START)
-
+ * PortAudio error code range: 0 >= err >= -10000
+ */
+#define PJMEDIA_ERRNO_FROM_PORTAUDIO(err)   ((int)PJMEDIA_PORTAUDIO_ERRNO_START-err)
+
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+
+ /**
+ * Mapping from LibSRTP error codes to pjmedia error space.
+ */
+#define PJMEDIA_LIBSRTP_ERRNO_START (PJMEDIA_ERRNO_END-10200)
+#define PJMEDIA_LIBSRTP_ERRNO_END   (PJMEDIA_LIBSRTP_ERRNO_START + 200 - 1)
+/**
+ * Convert LibSRTP error code to PJMEDIA error code.
+ * LibSRTP error code range: 0 <= err < 200
+ */
+#define PJMEDIA_ERRNO_FROM_LIBSRTP(err)   (PJMEDIA_LIBSRTP_ERRNO_START+err)
+
+#endif
 
 /************************************************************
@@ -525,4 +542,62 @@
  */
 #define PJMEDIA_ESNDINSAMPLEFMT	    (PJMEDIA_ERRNO_START+203)    /* 220203 */
+
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+/************************************************************
+ * SRTP TRANSPORT ERRORS
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * SRTP crypto-suite name not match the offerer tag.
+ */
+#define PJMEDIA_SRTP_ECRYPTONOTMATCH (PJMEDIA_ERRNO_START+220)   /* 220220 */
+/**
+ * @hideinitializer
+ * Invalid SRTP key length for specific crypto.
+ */
+#define PJMEDIA_SRTP_EINKEYLEN	    (PJMEDIA_ERRNO_START+221)    /* 220221 */
+/**
+ * @hideinitializer
+ * Unsupported SRTP crypto-suite.
+ */
+#define PJMEDIA_SRTP_ENOTSUPCRYPTO  (PJMEDIA_ERRNO_START+222)    /* 220222 */
+/**
+ * @hideinitializer
+ * SRTP SDP contains ambigue answer.
+ */
+#define PJMEDIA_SRTP_ESDPAMBIGUEANS (PJMEDIA_ERRNO_START+223)    /* 220223 */
+/**
+ * @hideinitializer
+ * Duplicated crypto tag.
+ */
+#define PJMEDIA_SRTP_ESDPDUPCRYPTOTAG (PJMEDIA_ERRNO_START+224)  /* 220224 */
+/**
+ * @hideinitializer
+ * Invalid crypto attribute.
+ */
+#define PJMEDIA_SRTP_ESDPINCRYPTO   (PJMEDIA_ERRNO_START+225)    /* 220225 */
+/**
+ * @hideinitializer
+ * Invalid crypto tag.
+ */
+#define PJMEDIA_SRTP_ESDPINCRYPTOTAG (PJMEDIA_ERRNO_START+226)   /* 220226 */
+/**
+ * @hideinitializer
+ * Invalid SDP media transport for SRTP.
+ */
+#define PJMEDIA_SRTP_ESDPINTRANSPORT (PJMEDIA_ERRNO_START+227)   /* 220227 */
+/**
+ * @hideinitializer
+ * SRTP crypto attribute required in SDP.
+ */
+#define PJMEDIA_SRTP_ESDPREQCRYPTO  (PJMEDIA_ERRNO_START+228)    /* 220228 */
+/**
+ * @hideinitializer
+ * Secure transport required in SDP media descriptor.
+ */
+#define PJMEDIA_SRTP_ESDPREQSECTP   (PJMEDIA_ERRNO_START+229)    /* 220229 */
+
+#endif /* PJMEDIA_HAS_SRTP */
 
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 1734)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport.h	(revision 1735)
@@ -167,4 +167,5 @@
 PJ_BEGIN_DECL
 
+#include <pjmedia/sdp.h>
 
 /*
@@ -243,4 +244,48 @@
 			     const void *pkt,
 			     pj_size_t size);
+
+    /**
+     * This function is called by application to generate the SDP parts
+     * related to transport type, e.g: ICE, SRTP.
+     *
+     * Application should call #pjmedia_transport_media_create() instead of 
+     * calling this function directly.
+     */
+    pj_status_t (*media_create)(pjmedia_transport *tp,
+				pj_pool_t *pool,
+				pjmedia_sdp_session *sdp_local,
+				const pjmedia_sdp_session *sdp_remote,
+				unsigned media_index);
+
+    /**
+     * This function is called by application to start the transport
+     * based on SDP negotiation result.
+     *
+     * Application should call #pjmedia_transport_media_start() instead of 
+     * calling this function directly.
+     */
+    pj_status_t (*media_start) (pjmedia_transport *tp,
+			        pj_pool_t *pool,
+			        pjmedia_sdp_session *sdp_local,
+			        const pjmedia_sdp_session *sdp_remote,
+				unsigned media_index);
+
+    /**
+     * This function is called by application to stop the transport.
+     *
+     * Application should call #pjmedia_transport_media_stop() instead of 
+     * calling this function directly.
+     */
+    pj_status_t (*media_stop)  (pjmedia_transport *tp);
+
+    /**
+     * This function can be called to simulate packet lost.
+     *
+     * Application should call #pjmedia_transport_simulate_lost() instead of 
+     * calling this function directly.
+     */
+    pj_status_t (*simulate_lost)(pjmedia_transport *tp,
+				 pjmedia_dir dir,
+				 unsigned pct_lost);
 
     /**
@@ -411,4 +456,65 @@
 
 /**
+ * Generate local SDP parts that are related to the specified media transport.
+ * Remote SDP might be needed as reference when application is in deciding
+ * side of negotiation (callee side), otherwise it should be NULL.
+ * This is just a simple wrapper which calls <tt>media_create()</tt> member 
+ * of the transport.
+ *
+ * @param tp		The media transport.
+ * @param pool		The memory pool.
+ * @param sdp_local	Local SDP.
+ * @param sdp_remote	Remote SDP.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_INLINE(pj_status_t) pjmedia_transport_media_create(pjmedia_transport *tp,
+				    pj_pool_t *pool,
+				    pjmedia_sdp_session *sdp_local,
+				    const pjmedia_sdp_session *sdp_remote,
+				    unsigned media_index)
+{
+    return (*tp->op->media_create)(tp, pool, sdp_local, sdp_remote, 
+				   media_index);
+}
+
+/**
+ * Start the transport with regards to SDP negotiation result. 
+ * This is just a simple wrapper which calls <tt>media_start()</tt> member 
+ * of the transport.
+ *
+ * @param tp		The media transport.
+ * @param pool		The memory pool.
+ * @param sdp_local	Local SDP.
+ * @param sdp_remote	Remote SDP.
+ * @param media_index	Media index to start.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_INLINE(pj_status_t) pjmedia_transport_media_start(pjmedia_transport *tp,
+				    pj_pool_t *pool,
+				    pjmedia_sdp_session *sdp_local,
+				    const pjmedia_sdp_session *sdp_remote,
+				    unsigned media_index)
+{
+    return (*tp->op->media_start)(tp, pool, sdp_local, sdp_remote, media_index);
+}
+
+
+/**
+ * Stop the transport. 
+ * This is just a simple wrapper which calls <tt>media_stop()</tt> member 
+ * of the transport.
+ *
+ * @param tp		The media transport.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_INLINE(pj_status_t) pjmedia_transport_media_stop(pjmedia_transport *tp)
+{
+    return (*tp->op->media_stop)(tp);
+}
+
+/**
  * Close media transport. This is just a simple wrapper which calls 
  * <tt>destroy()</tt> member of the transport. This function will free
@@ -427,4 +533,23 @@
 }
 
+/**
+ * Simulate packet lost in the specified direction (for testing purposes).
+ * When enabled, the transport will randomly drop packets to the specified
+ * direction.
+ *
+ * @param tp	    The media transport.
+ * @param dir	    Media direction to which packets will be randomly dropped.
+ * @param pct_lost  Percent lost (0-100). Set to zero to disable packet
+ *		    lost simulation.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_INLINE(pj_status_t) pjmedia_transport_simulate_lost(pjmedia_transport *tp,
+						       pjmedia_dir dir,
+						       unsigned pct_lost)
+{
+    return (*tp->op->simulate_lost)(tp, dir, pct_lost);
+}
+
 
 PJ_END_DECL
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h	(revision 1734)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport_ice.h	(revision 1735)
@@ -17,6 +17,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#ifndef __pjmedia_ice_H__
-#define __pjmedia_ice_H__
+#ifndef __PJMEDIA_TRANSPORT_ICE_H__
+#define __PJMEDIA_TRANSPORT_ICE_H__
 
 
@@ -75,13 +75,4 @@
 					const pjmedia_ice_cb *cb,
 					pjmedia_transport **p_tp);
-
-/**
- * Destroy the media transport.
- *
- * @param tp		The media transport.
- *
- * @return		PJ_SUCCESS.
- */
-PJ_DECL(pj_status_t) pjmedia_ice_destroy(pjmedia_transport *tp);
 
 
@@ -170,69 +161,4 @@
 					  const pj_str_t *local_passwd);
 
-/**
- * Modify the SDP to add ICE specific SDP attributes before sending
- * the SDP to remote host.
- *
- * @param tp		The media transport.
- * @param pool		Pool to allocate memory for the SDP elements.
- * @param sdp		The SDP descriptor to be modified.
- *
- * @return		PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjmedia_ice_modify_sdp(pjmedia_transport *tp,
-					    pj_pool_t *pool,
-					    pjmedia_sdp_session *sdp);
-
-/**
- * Start ICE connectivity checks.
- *
- * This function will pair the local and remote candidates to create 
- * check list. Once the check list is created and sorted based on the
- * priority, ICE periodic checks will be started. This function will 
- * return immediately, and application will be notified about the 
- * connectivity check status in the callback.
- *
- * @param tp		The media transport.
- * @param pool		Memory pool to parse the SDP.
- * @param rem_sdp	The SDP received from remote agent.
- * @param media_index	The media index (in SDP) to process.
- *
- * @return		PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp,
-					   pj_pool_t *pool,
-					   const pjmedia_sdp_session *rem_sdp,
-					   unsigned media_index);
-
-/**
- * Stop the ICE session (typically when the call is terminated). Application
- * may restart the ICE session again by calling #pjmedia_ice_init_ice(),
- * for example to use this media transport for the next call.
- *
- * @param tp		The media transport.
- *
- * @return		PJ_SUCCESS, or the appropriate error code.
- */
-PJ_DECL(pj_status_t) pjmedia_ice_stop_ice(pjmedia_transport *tp);
-
-
-/**
- * Simulate packet lost in the specified direction (for testing purposes).
- * When enabled, the transport will randomly drop packets to the specified
- * direction.
- *
- * @param tp	    The ICE media transport.
- * @param dir	    Media direction to which packets will be randomly dropped.
- * @param pct_lost  Percent lost (0-100). Set to zero to disable packet
- *		    lost simulation.
- *
- * @return	    PJ_SUCCESS on success.
- */
-PJ_DECL(pj_status_t) pjmedia_ice_simulate_lost(pjmedia_transport *tp,
-					       pjmedia_dir dir,
-					       unsigned pct_lost);
-
-
-
 
 PJ_END_DECL
@@ -244,5 +170,5 @@
 
 
-#endif	/* __pjmedia_ice_H__ */
+#endif	/* __PJMEDIA_TRANSPORT_ICE_H__ */
 
 
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport_srtp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport_srtp.h	(revision 1735)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport_srtp.h	(revision 1735)
@@ -0,0 +1,200 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2007 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_SRTP_H__
+#define __PJMEDIA_TRANSPORT_SRTP_H__
+
+/**
+ * @file srtp.h
+ * @brief transport SRTP encapsulates secure media transport.
+ */
+
+#include <pjmedia/transport.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * Crypto option.
+ */
+typedef enum pjmedia_srtp_crypto_option
+{
+    /** When this flag is specified, encryption will be disabled. */
+    PJMEDIA_SRTP_NO_ENCRYPTION  = 1,
+
+    /** When this flag is specified, authentication will be disabled. */
+    PJMEDIA_SRTP_NO_AUTHENTICATION  = 2
+
+} pjmedia_srtp_crypto_option;
+
+
+/**
+ * This structure describes an individual crypto setting.
+ */
+typedef struct pjmedia_srtp_crypto
+{
+    /** Optional key. If empty, a random key will be autogenerated. */
+    pj_str_t	key;
+
+    /** Crypto name.   */
+    pj_str_t	name;
+
+    /* Flags, bitmask from #pjmedia_srtp_crypto_option */
+    unsigned	flags;
+
+} pjmedia_srtp_crypto;
+
+
+/**
+ * This enumeration specifies the behavior of the SRTP transport regarding
+ * media security offer and answer.
+ */
+typedef enum pjmedia_srtp_use
+{
+    /**
+     * When this flag is specified, SRTP will be disabled, and the transport
+     * will reject RTP/SAVP offer.
+     */
+    PJMEDIA_SRTP_DISABLED,
+
+    /**
+     * When this flag is specified, SRTP will be advertised as optional and
+     * incoming SRTP offer will be accepted.
+     */
+    PJMEDIA_SRTP_OPTIONAL,
+
+    /**
+     * When this flag is specified, the transport will require that RTP/SAVP
+     * media shall be used.
+     */
+    PJMEDIA_SRTP_MANDATORY
+
+} pjmedia_srtp_use;
+
+
+/**
+ * Settings to be given when creating SRTP transport. Application should call
+ * #pjmedia_srtp_setting_default() to initialize this structure with its 
+ * default values.
+ */
+typedef struct pjmedia_srtp_setting
+{
+    /**
+     * Specify the usage policy. Default is PJMEDIA_SRTP_OPTIONAL.
+     */
+    pjmedia_srtp_use use;
+
+    /**
+     * Specify whether the SRTP transport should close the member transport 
+     * when it is destroyed. Default: PJ_TRUE.
+     */
+    pj_bool_t			close_member_tp;
+
+    /**
+     * Specify the number of crypto suite settings.
+     */
+    unsigned			crypto_count;
+
+    /**
+     * Specify individual crypto suite setting.
+     */
+    pjmedia_srtp_crypto		crypto[8];
+
+} pjmedia_srtp_setting;
+
+
+/**
+ * Initialize SRTP setting with its default values.
+ *
+ * @param opt	SRTP setting to be initialized.
+ */
+PJ_DECL(void) pjmedia_srtp_setting_default(pjmedia_srtp_setting *opt);
+
+
+/**
+ * Create an SRTP media transport.
+ *
+ * @param endpt	    The media endpoint instance.
+ * @param tp	    The actual media transport to send and receive 
+ *		    RTP/RTCP packets. This media transport will be
+ *		    kept as member transport of this SRTP instance.
+ * @param opt	    Optional settings. If NULL is given, default
+ *		    settings will be used.
+ * @param p_tp	    Pointer to receive the transport SRTP instance.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_srtp_create(
+				       pjmedia_endpt *endpt,
+				       pjmedia_transport *tp,
+				       const pjmedia_srtp_setting *opt,
+				       pjmedia_transport **p_tp);
+
+
+/**
+ * Manually start SRTP session with the given parameters. Application only
+ * needs to call this function when the SRTP transport is used without SDP
+ * offer/answer. When SDP offer/answer framework is used, the SRTP transport
+ * will be started/stopped by #pjmedia_transport_media_start() and 
+ * #pjmedia_transport_media_stop() respectively.
+ *
+ * Please note that even if an RTP stream is only one direction, application
+ * will still need to provide both crypto suites, because it is needed by 
+ * RTCP.
+
+ * If application specifies the crypto keys, the keys for transmit and receive
+ * direction MUST be different.
+ *
+ * @param srtp	    The SRTP transport.
+ * @param tx	    Crypto suite setting for transmit direction.
+ * @param rx	    Crypto suite setting for receive direction.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_srtp_start(
+					    pjmedia_transport *tp,
+					    const pjmedia_srtp_crypto *tx,
+					    const pjmedia_srtp_crypto *rx);
+
+/**
+ * Stop SRTP session.
+ *
+ * @param srtp	    The SRTP media transport.
+ *
+ * @return	    PJ_SUCCESS on success.
+ *
+ * @see #pjmedia_transport_srtp_start() 
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_srtp_stop(pjmedia_transport *tp);
+
+
+/**
+ * Query member transport of SRTP.
+ *
+ * @param srtp		    The SRTP media transport.
+ *
+ * @return		    member media transport.
+ */
+PJ_DECL(pjmedia_transport*) pjmedia_transport_srtp_get_member(
+						    pjmedia_transport *tp);
+
+
+PJ_END_DECL
+
+#endif /* __PJMEDIA_TRANSPORT_SRTP_H__ */
Index: /pjproject/trunk/pjmedia/include/pjmedia/transport_udp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport_udp.h	(revision 1734)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport_udp.h	(revision 1735)
@@ -54,17 +54,4 @@
     PJMEDIA_UDP_NO_SRC_ADDR_CHECKING = 1
 };
-
-
-/**
- * UDP transport info.
- */
-typedef struct pjmedia_transport_udp_info
-{
-    /**
-     * Media socket info.
-     */
-    pjmedia_sock_info	skinfo;
-
-} pjmedia_transport_udp_info;
 
 
@@ -138,16 +125,4 @@
 						   pjmedia_transport **p_tp);
 
-/**
- * Get media socket info from the specified UDP transport.
- *
- * @param tp	    The UDP transport interface.
- * @param info	    Media socket info to be initialized.
- *
- * @return	    PJ_SUCCESS on success.
- */
-PJ_DECL(pj_status_t) 
-pjmedia_transport_udp_get_info( pjmedia_transport *tp,
-				pjmedia_transport_udp_info *info);
-
 
 /**
@@ -170,34 +145,4 @@
 
 
-/**
- * Simulate packet lost in the specified direction (for testing purposes).
- * When enabled, the transport will randomly drop packets to the specified
- * direction.
- *
- * @param tp	    The UDP media transport.
- * @param dir	    Media direction to which packets will be randomly dropped.
- * @param pct_lost  Percent lost (0-100). Set to zero to disable packet
- *		    lost simulation.
- *
- * @return	    PJ_SUCCESS on success.
- */
-PJ_DECL(pj_status_t) pjmedia_transport_udp_simulate_lost(pjmedia_transport *tp,
-							 pjmedia_dir dir,
-							 unsigned pct_lost);
-
-
-
-/**
- * Close UDP transport. Application can also use the "destroy" member of
- * media transport interface to close the UDP transport.
- *
- * @param tp	    The UDP media transport.
- *
- * @return	    PJ_SUCCESS on success.
- */
-PJ_DECL(pj_status_t) pjmedia_transport_udp_close(pjmedia_transport *tp);
-
-
-
 PJ_END_DECL
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/errno.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 1734)
+++ /pjproject/trunk/pjmedia/src/pjmedia/errno.c	(revision 1735)
@@ -24,4 +24,7 @@
 #endif
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    const char* get_libsrtp_errstr(int err);
+#endif
 
 
@@ -142,4 +145,19 @@
     PJ_BUILD_ERR( PJMEDIA_ESNDINDEVID,	    "Invalid sound device ID" ),
     PJ_BUILD_ERR( PJMEDIA_ESNDINSAMPLEFMT,  "Invalid sample format for sound device" ),
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* SRTP transport errors: */
+    PJ_BUILD_ERR( PJMEDIA_SRTP_ECRYPTONOTMATCH, "SRTP crypto-suite name not match the offerer tag" ),
+    PJ_BUILD_ERR( PJMEDIA_SRTP_EINKEYLEN,	"Invalid SRTP key length for specific crypto" ),
+    PJ_BUILD_ERR( PJMEDIA_SRTP_ENOTSUPCRYPTO,   "Unsupported SRTP crypto-suite" ),
+    PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPAMBIGUEANS,  "SRTP SDP contains ambigue answer" ),
+    PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPDUPCRYPTOTAG,"Duplicated SRTP crypto tag" ),
+    PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPINCRYPTO,    "Invalid SRTP crypto attribute" ),
+    PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPINCRYPTOTAG, "Invalid SRTP crypto tag" ),
+    PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPINTRANSPORT, "Invalid SDP media transport for SRTP" ),
+    PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPREQCRYPTO,   "SRTP crypto attribute required" ),
+    PJ_BUILD_ERR( PJMEDIA_SRTP_ESDPREQSECTP,    "Secure transport required in SDP media descriptor" )
+#endif
+
 };
 
@@ -160,9 +178,10 @@
     /* See if the error comes from PortAudio. */
 #if PJMEDIA_SOUND_IMPLEMENTATION==PJMEDIA_SOUND_PORTAUDIO_SOUND
-    if (statcode >= PJMEDIA_ERRNO_FROM_PORTAUDIO(paNotInitialized) &&
-	statcode <  PJMEDIA_ERRNO_FROM_PORTAUDIO(paNotInitialized + 10000))
+    if (statcode >= PJMEDIA_PORTAUDIO_ERRNO_START &&
+	statcode <= PJMEDIA_PORTAUDIO_ERRNO_END)
     {
 
-	int pa_err = statcode - PJMEDIA_ERRNO_FROM_PORTAUDIO(0);
+	//int pa_err = statcode - PJMEDIA_ERRNO_FROM_PORTAUDIO(0);
+	int pa_err = PJMEDIA_PORTAUDIO_ERRNO_START - statcode;
 	pj_str_t msg;
 	
@@ -176,6 +195,24 @@
     } else 
 #endif	/* PJMEDIA_SOUND_IMPLEMENTATION */
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* LIBSRTP error */
+    if (statcode >= PJMEDIA_LIBSRTP_ERRNO_START &&
+	statcode <  PJMEDIA_LIBSRTP_ERRNO_END)
+    {
+	int err = statcode - PJMEDIA_PORTAUDIO_ERRNO_START;
+	pj_str_t msg;
+	
+	msg = pj_str((char*)get_libsrtp_errstr(err));
+
+	pj_strncpy_with_null(&errstr, &msg, bufsize);
+	return errstr;
+    
+    } else
+#endif
+    
+    /* PJMEDIA error */
     if (statcode >= PJMEDIA_ERRNO_START && 
-	       statcode < PJMEDIA_ERRNO_START + PJ_ERRNO_SPACE_SIZE)
+	       statcode < PJMEDIA_ERRNO_END)
     {
 	/* Find the error in the table.
@@ -212,6 +249,5 @@
 
 	} 
-    }
-
+    } 
 #endif	/* PJ_HAS_ERROR_STRING */
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1734)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1735)
@@ -52,25 +52,40 @@
  * These are media transport operations.
  */
-static pj_status_t tp_get_info(pjmedia_transport *tp,
-			       pjmedia_sock_info *info);
-static pj_status_t tp_attach( pjmedia_transport *tp,
-			      void *stream,
-			      const pj_sockaddr_t *rem_addr,
-			      const pj_sockaddr_t *rem_rtcp,
-			      unsigned addr_len,
-			      void (*rtp_cb)(void*,
-					     const void*,
-					     pj_ssize_t),
-			      void (*rtcp_cb)(void*,
-					      const void*,
-					      pj_ssize_t));
-static void	   tp_detach( pjmedia_transport *tp,
-			      void *strm);
-static pj_status_t tp_send_rtp( pjmedia_transport *tp,
-			        const void *pkt,
-			        pj_size_t size);
-static pj_status_t tp_send_rtcp( pjmedia_transport *tp,
-			         const void *pkt,
-			         pj_size_t size);
+static pj_status_t transport_get_info (pjmedia_transport *tp,
+				       pjmedia_sock_info *info);
+static pj_status_t transport_attach   (pjmedia_transport *tp,
+				       void *user_data,
+				       const pj_sockaddr_t *rem_addr,
+				       const pj_sockaddr_t *rem_rtcp,
+				       unsigned addr_len,
+				       void (*rtp_cb)(void*,
+						      const void*,
+						      pj_ssize_t),
+				       void (*rtcp_cb)(void*,
+						       const void*,
+						       pj_ssize_t));
+static void	   transport_detach   (pjmedia_transport *tp,
+				       void *strm);
+static pj_status_t transport_send_rtp( pjmedia_transport *tp,
+				       const void *pkt,
+				       pj_size_t size);
+static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
+				       const void *pkt,
+				       pj_size_t size);
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+				       pj_pool_t *pool,
+				       pjmedia_sdp_session *sdp_local,
+				       const pjmedia_sdp_session *sdp_remote,
+				       unsigned media_index);
+static pj_status_t transport_media_start (pjmedia_transport *tp,
+				       pj_pool_t *pool,
+				       pjmedia_sdp_session *sdp_local,
+				       const pjmedia_sdp_session *sdp_remote,
+				       unsigned media_index);
+static pj_status_t transport_media_stop(pjmedia_transport *tp);
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+				       pjmedia_dir dir,
+				       unsigned pct_lost);
+static pj_status_t transport_destroy  (pjmedia_transport *tp);
 
 /*
@@ -85,12 +100,16 @@
 
 
-static pjmedia_transport_op tp_ice_op = 
-{
-    &tp_get_info,
-    &tp_attach,
-    &tp_detach,
-    &tp_send_rtp,
-    &tp_send_rtcp,
-    &pjmedia_ice_destroy
+static pjmedia_transport_op transport_ice_op = 
+{
+    &transport_get_info,
+    &transport_attach,
+    &transport_detach,
+    &transport_send_rtp,
+    &transport_send_rtcp,
+    &transport_media_create,
+    &transport_media_start,
+    &transport_media_stop,
+    &transport_simulate_lost,
+    &transport_destroy
 };
 
@@ -133,5 +152,5 @@
     tp_ice->ice_st = ice_st;
     pj_ansi_strcpy(tp_ice->base.name, ice_st->obj_name);
-    tp_ice->base.op = &tp_ice_op;
+    tp_ice->base.op = &transport_ice_op;
     tp_ice->base.type = PJMEDIA_TRANSPORT_TYPE_ICE;
 
@@ -144,23 +163,4 @@
     if (p_tp)
 	*p_tp = &tp_ice->base;
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * Destroy ICE media transport.
- */
-PJ_DEF(pj_status_t) pjmedia_ice_destroy(pjmedia_transport *tp)
-{
-    struct transport_ice *tp_ice = (struct transport_ice*)tp;
-
-    if (tp_ice->ice_st) {
-	pj_ice_strans_destroy(tp_ice->ice_st);
-	/*Must not touch tp_ice after ice_st is destroyed!
-	 (it has the pool)
-	 tp_ice->ice_st = NULL;
-	 */
-    }
 
     return PJ_SUCCESS;
@@ -231,5 +231,6 @@
 		     comp, PJ_EINVAL);
 
-    pj_memcpy(comp, tp_ice->ice_st->comp[comp_id-1], sizeof(pj_ice_strans_comp));
+    pj_memcpy(comp, tp_ice->ice_st->comp[comp_id-1], 
+	      sizeof(pj_ice_strans_comp));
     return PJ_SUCCESS;		    
 }
@@ -247,5 +248,6 @@
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
-    return pj_ice_strans_init_ice(tp_ice->ice_st, role, local_ufrag, local_passwd);
+    return pj_ice_strans_init_ice(tp_ice->ice_st, role, local_ufrag, 
+				  local_passwd);
 }
 
@@ -255,13 +257,26 @@
  * This will add ICE attributes to the SDP.
  */
-PJ_DEF(pj_status_t) pjmedia_ice_modify_sdp(pjmedia_transport *tp,
-					   pj_pool_t *pool,
-					   pjmedia_sdp_session *sdp)
-{
-    struct transport_ice *tp_ice = (struct transport_ice*)tp;
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+				       pj_pool_t *pool,
+				       pjmedia_sdp_session *sdp_local,
+				       const pjmedia_sdp_session *sdp_remote,
+				       unsigned media_index)
+{
+    struct transport_ice *tp_ice = (struct transport_ice*)tp;
+    pj_ice_sess_role ice_role;
     enum { MAXLEN = 256 };
     char *buffer;
     pjmedia_sdp_attr *attr;
     unsigned i, cand_cnt;
+    pj_status_t status;
+
+    /* Init ICE */
+    ice_role = (sdp_remote==NULL ? PJ_ICE_SESS_ROLE_CONTROLLING : 
+				   PJ_ICE_SESS_ROLE_CONTROLLED);
+
+    status = pjmedia_ice_init_ice(tp, ice_role, NULL, NULL);
+    if (status != PJ_SUCCESS)
+	return status;
+
 
     buffer = (char*) pj_pool_alloc(pool, MAXLEN);
@@ -270,10 +285,10 @@
     attr = pjmedia_sdp_attr_create(pool, "ice-ufrag", 
 				   &tp_ice->ice_st->ice->rx_ufrag);
-    sdp->attr[sdp->attr_count++] = attr;
+    sdp_local->attr[sdp_local->attr_count++] = attr;
 
     /* Create ice-pwd attribute */
     attr = pjmedia_sdp_attr_create(pool, "ice-pwd", 
 				   &tp_ice->ice_st->ice->rx_pass);
-    sdp->attr[sdp->attr_count++] = attr;
+    sdp_local->attr[sdp_local->attr_count++] = attr;
 
     /* Add all candidates (to media level) */
@@ -281,4 +296,5 @@
     for (i=0; i<cand_cnt; ++i) {
 	pj_ice_sess_cand *cand;
+	pjmedia_sdp_media *m;
 	pj_str_t value;
 	int len;
@@ -330,5 +346,6 @@
 	value = pj_str(buffer);
 	attr = pjmedia_sdp_attr_create(pool, "candidate", &value);
-	sdp->media[0]->attr[sdp->media[0]->attr_count++] = attr;
+	m = sdp_local->media[media_index];
+	m->attr[m->attr_count++] = attr;
     }
 
@@ -457,5 +474,5 @@
     PJ_LOG(4,(tp_ice->ice_st->obj_name, 
 	      "Disabling local ICE, reason=%s", reason));
-    pjmedia_ice_stop_ice(&tp_ice->base);
+    transport_media_stop(&tp_ice->base);
 }
 
@@ -464,8 +481,9 @@
  * Start ICE checks when both offer and answer are available.
  */
-PJ_DEF(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp,
-					  pj_pool_t *pool,
-					  const pjmedia_sdp_session *rem_sdp,
-					  unsigned media_index)
+static pj_status_t transport_media_start(pjmedia_transport *tp,
+				         pj_pool_t *pool,
+				         pjmedia_sdp_session *sdp_local,
+				         const pjmedia_sdp_session *sdp_remote,
+				         unsigned media_index)
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
@@ -482,8 +500,10 @@
     pj_status_t status;
 
-    PJ_ASSERT_RETURN(tp && pool && rem_sdp, PJ_EINVAL);
-    PJ_ASSERT_RETURN(media_index < rem_sdp->media_count, PJ_EINVAL);
-
-    sdp_med = rem_sdp->media[media_index];
+    PJ_UNUSED_ARG(sdp_local);
+
+    PJ_ASSERT_RETURN(tp && pool && sdp_remote, PJ_EINVAL);
+    PJ_ASSERT_RETURN(media_index < sdp_remote->media_count, PJ_EINVAL);
+
+    sdp_med = sdp_remote->media[media_index];
 
     /* Get the SDP connection for the media stream.
@@ -493,5 +513,5 @@
     conn = sdp_med->conn;
     if (conn == NULL)
-	conn = rem_sdp->conn;
+	conn = sdp_remote->conn;
 
     if (conn == NULL) {
@@ -508,5 +528,5 @@
     if (attr == NULL) {
 	/* Find ice-ufrag attribute in session descriptor */
-	attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr,
+	attr = pjmedia_sdp_attr_find2(sdp_remote->attr_count, sdp_remote->attr,
 				      "ice-ufrag", NULL);
 	if (attr == NULL) {
@@ -522,5 +542,5 @@
     if (attr == NULL) {
 	/* Find ice-pwd attribute in session descriptor */
-	attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr,
+	attr = pjmedia_sdp_attr_find2(sdp_remote->attr_count, sdp_remote->attr,
 				      "ice-pwd", NULL);
 	if (attr == NULL) {
@@ -609,5 +629,5 @@
 
 
-PJ_DEF(pj_status_t) pjmedia_ice_stop_ice(pjmedia_transport *tp)
+static pj_status_t transport_media_stop(pjmedia_transport *tp)
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
@@ -616,6 +636,6 @@
 
 
-static pj_status_t tp_get_info(pjmedia_transport *tp,
-			       pjmedia_sock_info *info)
+static pj_status_t transport_get_info(pjmedia_transport *tp,
+				      pjmedia_sock_info *info)
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
@@ -649,15 +669,15 @@
 
 
-static pj_status_t tp_attach( pjmedia_transport *tp,
-			      void *stream,
-			      const pj_sockaddr_t *rem_addr,
-			      const pj_sockaddr_t *rem_rtcp,
-			      unsigned addr_len,
-			      void (*rtp_cb)(void*,
-					     const void*,
-					     pj_ssize_t),
-			      void (*rtcp_cb)(void*,
-					      const void*,
-					      pj_ssize_t))
+static pj_status_t transport_attach  (pjmedia_transport *tp,
+				      void *stream,
+				      const pj_sockaddr_t *rem_addr,
+				      const pj_sockaddr_t *rem_rtcp,
+				      unsigned addr_len,
+				      void (*rtp_cb)(void*,
+						     const void*,
+						     pj_ssize_t),
+				      void (*rtcp_cb)(void*,
+						      const void*,
+						      pj_ssize_t))
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
@@ -674,6 +694,6 @@
 
 
-static void tp_detach(pjmedia_transport *tp,
-		      void *strm)
+static void transport_detach(pjmedia_transport *tp,
+			     void *strm)
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
@@ -687,7 +707,7 @@
 
 
-static pj_status_t tp_send_rtp(pjmedia_transport *tp,
-			       const void *pkt,
-			       pj_size_t size)
+static pj_status_t transport_send_rtp(pjmedia_transport *tp,
+				      const void *pkt,
+				      pj_size_t size)
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
@@ -709,7 +729,7 @@
 
 
-static pj_status_t tp_send_rtcp(pjmedia_transport *tp,
-			        const void *pkt,
-			        pj_size_t size)
+static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
+				       const void *pkt,
+				       pj_size_t size)
 {
     struct transport_ice *tp_ice = (struct transport_ice*)tp;
@@ -799,7 +819,7 @@
 
 /* Simulate lost */
-PJ_DEF(pj_status_t) pjmedia_ice_simulate_lost( pjmedia_transport *tp,
-					       pjmedia_dir dir,
-					       unsigned pct_lost)
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+					   pjmedia_dir dir,
+					   unsigned pct_lost)
 {
     struct transport_ice *ice = (struct transport_ice*) tp;
@@ -816,2 +836,21 @@
 }
 
+
+/*
+ * Destroy ICE media transport.
+ */
+static pj_status_t transport_destroy(pjmedia_transport *tp)
+{
+    struct transport_ice *tp_ice = (struct transport_ice*)tp;
+
+    if (tp_ice->ice_st) {
+	pj_ice_strans_destroy(tp_ice->ice_st);
+	/*Must not touch tp_ice after ice_st is destroyed!
+	 (it has the pool)
+	 tp_ice->ice_st = NULL;
+	 */
+    }
+
+    return PJ_SUCCESS;
+}
+
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 1735)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 1735)
@@ -0,0 +1,1253 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
+ */
+
+#include <pjmedia/transport_srtp.h>
+#include <pjmedia/endpoint.h>
+#include <pjlib-util/base64.h>
+#include <pj/assert.h>
+#include <pj/lock.h>
+#include <pj/log.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+
+#include <srtp.h>
+
+#define THIS_FILE   "transport_srtp.c"
+
+/* Maximum size of packet */
+#define MAX_BUFFER_LEN	1500
+#define MAX_KEY_LEN	32
+#define DEACTIVATE_MEDIA(pool, m) {\
+	    attr = pjmedia_sdp_attr_create(pool, ID_INACTIVE.ptr, NULL); \
+	    m->attr[m->attr_count++] = attr; \
+	    m->desc.port = 0; \
+	}
+
+static const pj_str_t ID_RTP_AVP  = { "RTP/AVP", 7 };
+static const pj_str_t ID_RTP_SAVP = { "RTP/SAVP", 8 };
+static const pj_str_t ID_INACTIVE = { "inactive", 8 };
+static const pj_str_t ID_CRYPTO   = { "crypto", 6 };
+
+typedef struct crypto_suite
+{
+    char		*name;
+    cipher_type_id_t	 cipher_type;
+    unsigned		 cipher_key_len;
+    auth_type_id_t	 auth_type;
+    unsigned		 auth_key_len;
+    unsigned		 srtp_auth_tag_len;
+    unsigned		 srtcp_auth_tag_len;
+    sec_serv_t		 service;
+} crypto_suite;
+
+/* Crypto suites as defined on RFC 4568 */
+static crypto_suite crypto_suites[] = {
+    /* plain RTP/RTCP (no cipher & no auth) */
+    {"NULL", NULL_CIPHER, 0, NULL_AUTH, 0, 0, 0, sec_serv_none},
+
+    /* cipher AES_CM, auth HMAC_SHA1, auth tag len = 10 octets */
+    {"AES_CM_128_HMAC_SHA1_80", AES_128_ICM, 30, HMAC_SHA1, 20, 10, 10, 
+	sec_serv_conf_and_auth},
+
+    /* cipher AES_CM, auth HMAC_SHA1, auth tag len = 4 octets */
+    {"AES_CM_128_HMAC_SHA1_32", AES_128_ICM, 30, HMAC_SHA1, 20, 4, 10,
+	sec_serv_conf_and_auth},
+
+    /* 
+     * F8_128_HMAC_SHA1_8 not supported by libsrtp?
+     * {"F8_128_HMAC_SHA1_8", NULL_CIPHER, 0, NULL_AUTH, 0, 0, 0, sec_serv_none}
+     */
+};
+
+typedef struct transport_srtp
+{
+    pjmedia_transport	 base;	    /**< Base transport interface. */
+    pj_pool_t		*pool;
+    pj_lock_t		*mutex;
+    char		 tx_buffer[MAX_BUFFER_LEN];
+    char		 rx_buffer[MAX_BUFFER_LEN];
+
+    pjmedia_srtp_setting setting;
+    /* SRTP policy */
+    pj_bool_t		 session_inited;
+    pj_bool_t		 offerer_side;
+    pj_bool_t		 bypass_srtp;
+    char		 tx_key[MAX_KEY_LEN];
+    char		 rx_key[MAX_KEY_LEN];
+    pjmedia_srtp_crypto  tx_policy;
+    pjmedia_srtp_crypto  rx_policy;
+
+    /* libSRTP contexts */
+    srtp_t		 srtp_tx_ctx;
+    srtp_t		 srtp_rx_ctx;
+
+    /* Stream information */
+    void		*user_data;
+    void		(*rtp_cb)( void *user_data,
+				   const void *pkt,
+				   pj_ssize_t size);
+    void		(*rtcp_cb)(void *user_data,
+				   const void *pkt,
+				   pj_ssize_t size);
+        
+    /* Transport information */
+    pjmedia_transport	*real_tp; /**< Underlying transport.       */
+
+} transport_srtp;
+
+
+/*
+ * This callback is called by transport when incoming rtp is received
+ */
+static void srtp_rtp_cb( void *user_data, const void *pkt, pj_ssize_t size);
+
+/*
+ * This callback is called by transport when incoming rtcp is received
+ */
+static void srtp_rtcp_cb( void *user_data, const void *pkt, pj_ssize_t size);
+
+
+/*
+ * These are media transport operations.
+ */
+static pj_status_t transport_get_info (pjmedia_transport *tp,
+				       pjmedia_sock_info *info);
+static pj_status_t transport_attach   (pjmedia_transport *tp,
+				       void *user_data,
+				       const pj_sockaddr_t *rem_addr,
+				       const pj_sockaddr_t *rem_rtcp,
+				       unsigned addr_len,
+				       void (*rtp_cb)(void*,
+						      const void*,
+						      pj_ssize_t),
+				       void (*rtcp_cb)(void*,
+						       const void*,
+						       pj_ssize_t));
+static void	   transport_detach   (pjmedia_transport *tp,
+				       void *strm);
+static pj_status_t transport_send_rtp( pjmedia_transport *tp,
+				       const void *pkt,
+				       pj_size_t size);
+static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
+				       const void *pkt,
+				       pj_size_t size);
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+				       pj_pool_t *pool,
+				       pjmedia_sdp_session *sdp_local,
+				       const pjmedia_sdp_session *sdp_remote,
+				       unsigned media_index);
+static pj_status_t transport_media_start (pjmedia_transport *tp,
+				       pj_pool_t *pool,
+				       pjmedia_sdp_session *sdp_local,
+				       const pjmedia_sdp_session *sdp_remote,
+				       unsigned media_index);
+static pj_status_t transport_media_stop(pjmedia_transport *tp);
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+				       pjmedia_dir dir,
+				       unsigned pct_lost);
+static pj_status_t transport_destroy  (pjmedia_transport *tp);
+
+
+
+static pjmedia_transport_op transport_srtp_op = 
+{
+    &transport_get_info,
+    &transport_attach,
+    &transport_detach,
+    &transport_send_rtp,
+    &transport_send_rtcp,
+    &transport_media_create,
+    &transport_media_start,
+    &transport_media_stop,
+    &transport_simulate_lost,
+    &transport_destroy
+};
+
+const char* get_libsrtp_errstr(int err)
+{
+#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
+    static char *liberr[] = {
+	"ok",				    /* err_status_ok            = 0  */
+	"unspecified failure",		    /* err_status_fail          = 1  */
+	"unsupported parameter",	    /* err_status_bad_param     = 2  */
+	"couldn't allocate memory",	    /* err_status_alloc_fail    = 3  */
+	"couldn't deallocate properly",	    /* err_status_dealloc_fail  = 4  */
+	"couldn't initialize",		    /* err_status_init_fail     = 5  */
+	"can't process as much data as requested", 
+					    /* err_status_terminus      = 6  */
+	"authentication failure",	    /* err_status_auth_fail     = 7  */
+	"cipher failure",		    /* err_status_cipher_fail   = 8  */
+	"replay check failed (bad index)",  /* err_status_replay_fail   = 9  */
+	"replay check failed (index too old)", 
+					    /* err_status_replay_old    = 10 */
+	"algorithm failed test routine",    /* err_status_algo_fail     = 11 */
+	"unsupported operation",	    /* err_status_no_such_op    = 12 */
+	"no appropriate context found",	    /* err_status_no_ctx        = 13 */
+	"unable to perform desired validation", 
+					    /* err_status_cant_check    = 14 */
+	"can't use key any more",	    /* err_status_key_expired   = 15 */
+	"error in use of socket",	    /* err_status_socket_err    = 16 */
+	"error in use POSIX signals",	    /* err_status_signal_err    = 17 */
+	"nonce check failed",		    /* err_status_nonce_bad     = 18 */
+	"couldn't read data",		    /* err_status_read_fail     = 19 */
+	"couldn't write data",		    /* err_status_write_fail    = 20 */
+	"error pasring data",		    /* err_status_parse_err     = 21 */
+	"error encoding data",		    /* err_status_encode_err    = 22 */
+	"error while using semaphores",	    /* err_status_semaphore_err = 23 */
+	"error while using pfkey"	    /* err_status_pfkey_err     = 24 */
+    };
+    return liberr[err];
+#else
+    return NULL;
+#endif
+}
+
+static pj_status_t pjmedia_srtp_init_lib(void)
+{
+    static pj_bool_t initialized = PJ_FALSE;
+
+    if (initialized == PJ_FALSE) {
+	err_status_t err;
+	err = srtp_init();
+	if (err != err_status_ok) { 
+	    PJ_LOG(4, (THIS_FILE, "Failed to init libsrtp."));
+	    return PJMEDIA_ERRNO_FROM_LIBSRTP(err);
+	}
+
+	initialized = PJ_TRUE;
+    }
+    
+    return PJ_SUCCESS;
+}
+
+static int get_crypto_idx(const pj_str_t* crypto_name)
+{
+    int i;
+    int cs_cnt = sizeof(crypto_suites)/sizeof(crypto_suites[0]);
+    
+    /* treat unspecified crypto_name as crypto 'NULL' */
+    if (crypto_name->slen == 0)
+	return 0;
+
+    for (i=0; i<cs_cnt; ++i) {
+	if (!pj_stricmp2(crypto_name, crypto_suites[i].name))
+	    return i;
+    }
+
+    return -1;
+}
+
+PJ_DEF(void) pjmedia_srtp_setting_default(pjmedia_srtp_setting *opt)
+{
+    int i;
+
+    pj_bzero(opt, sizeof(pjmedia_srtp_setting));
+    opt->close_member_tp = PJ_TRUE;
+    opt->use = PJMEDIA_SRTP_OPTIONAL;
+
+    /* Copy default crypto-suites, but skip crypto 'NULL' */
+    opt->crypto_count = sizeof(crypto_suites)/sizeof(crypto_suites[0]) - 1;
+    for (i=0; i<opt->crypto_count; ++i)
+	opt->crypto[i].name = pj_str(crypto_suites[i+1].name);
+}
+
+
+/*
+ * Create an SRTP media transport.
+ */
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_create(
+				       pjmedia_endpt *endpt,
+				       pjmedia_transport *tp,
+				       const pjmedia_srtp_setting *opt,
+				       pjmedia_transport **p_tp)
+{
+    pj_pool_t *pool;
+    transport_srtp *srtp;
+    pj_status_t status;
+    int i;
+
+    PJ_ASSERT_RETURN(endpt && p_tp, PJ_EINVAL);
+
+    /* Check crypto availability */
+    if (opt->crypto_count == 0 && 
+	opt->use == PJMEDIA_SRTP_MANDATORY)
+	return PJMEDIA_SRTP_ESDPREQCRYPTO;
+
+    /* Check crypto */
+    if (opt->use != PJMEDIA_SRTP_DISABLED) {
+	for (i=0; i < opt->crypto_count; ++i) {
+	    int cs_idx = get_crypto_idx(&opt->crypto[i].name);
+
+	    /* check crypto name */
+	    if (cs_idx == -1)
+		return PJMEDIA_SRTP_ENOTSUPCRYPTO;
+
+	    /* check key length */
+	    if (opt->crypto[i].key.slen && 
+		opt->crypto[i].key.slen < 
+		(pj_ssize_t)crypto_suites[cs_idx].cipher_key_len)
+		return PJMEDIA_SRTP_EINKEYLEN;
+	}
+    }
+
+    /* Init libsrtp. */
+    status = pjmedia_srtp_init_lib();
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pool = pjmedia_endpt_create_pool(endpt, "srtp%p", 1000, 1000);
+    srtp = PJ_POOL_ZALLOC_T(pool, transport_srtp);
+
+    srtp->pool = pool;
+    srtp->session_inited = PJ_FALSE;
+    srtp->bypass_srtp = PJ_FALSE;
+
+    if (opt) {
+	srtp->setting = *opt;
+	if (opt->use == PJMEDIA_SRTP_DISABLED)
+	    srtp->setting.crypto_count = 0;
+
+	for (i=0; i < srtp->setting.crypto_count; ++i) {
+	    int cs_idx = get_crypto_idx(&opt->crypto[i].name);
+	    pj_str_t tmp_key = opt->crypto[i].key;
+
+	    /* re-set crypto */
+	    srtp->setting.crypto[i].name = pj_str(crypto_suites[cs_idx].name);
+	    /* cut key length */
+	    if (tmp_key.slen)
+		tmp_key.slen = crypto_suites[cs_idx].cipher_key_len;
+	    pj_strdup(pool, &srtp->setting.crypto[i].key, &tmp_key);
+	}
+    } else {
+	pjmedia_srtp_setting_default(&srtp->setting);
+    }
+
+    status = pj_lock_create_recursive_mutex(pool, pool->obj_name, &srtp->mutex);
+    if (status != PJ_SUCCESS) {
+	pj_pool_release(pool);
+	return status;
+    }
+
+    /* Initialize base pjmedia_transport */
+    pj_memcpy(srtp->base.name, pool->obj_name, PJ_MAX_OBJ_NAME);
+    srtp->base.type = tp->type;
+    srtp->base.op = &transport_srtp_op;
+
+    /* Set underlying transport */
+    srtp->real_tp = tp;
+
+    /* Done */
+    *p_tp = &srtp->base;
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Initialize and start SRTP session with the given parameters.
+ */
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_start(
+			   pjmedia_transport *tp, 
+			   const pjmedia_srtp_crypto *tx,
+			   const pjmedia_srtp_crypto *rx)
+{
+    transport_srtp  *srtp = (transport_srtp*) tp;
+    srtp_policy_t    tx_;
+    srtp_policy_t    rx_;
+    err_status_t     err;
+    int		     cr_tx_idx = 0;
+    int		     au_tx_idx = 0;
+    int		     cr_rx_idx = 0;
+    int		     au_rx_idx = 0;
+    int		     crypto_suites_cnt;
+
+    if (srtp->session_inited) {
+	PJ_LOG(4, (THIS_FILE, "SRTP could not be re-init'd before deinit'd"));
+	return PJ_EINVALIDOP;
+    }
+
+    crypto_suites_cnt = sizeof(crypto_suites)/sizeof(crypto_suites[0]);
+
+    /* Get encryption and authentication method */
+    cr_tx_idx = au_tx_idx = get_crypto_idx(&tx->name);
+    if (tx->flags && PJMEDIA_SRTP_NO_ENCRYPTION)
+	cr_tx_idx = 0;
+    if (tx->flags && PJMEDIA_SRTP_NO_AUTHENTICATION)
+	au_tx_idx = 0;
+
+    cr_rx_idx = au_rx_idx = get_crypto_idx(&rx->name);
+    if (rx->flags && PJMEDIA_SRTP_NO_ENCRYPTION)
+	cr_rx_idx = 0;
+    if (rx->flags && PJMEDIA_SRTP_NO_AUTHENTICATION)
+	au_rx_idx = 0;
+
+    /* Check whether the crypto-suite requested is supported */
+    if (cr_tx_idx == -1 || cr_rx_idx == -1 || au_tx_idx == -1 || 
+	au_rx_idx == -1)
+	return PJMEDIA_SRTP_ENOTSUPCRYPTO;
+
+    /* If all options points to 'NULL' method, just bypass SRTP */
+    if (cr_tx_idx == 0 && cr_rx_idx == 0 && au_tx_idx == 0 && au_rx_idx == 0) {
+	srtp->bypass_srtp = PJ_TRUE;
+	return PJ_SUCCESS;
+    }
+
+    /* Check key length */
+    if (tx->key.slen != (pj_ssize_t)crypto_suites[cr_tx_idx].cipher_key_len ||
+        rx->key.slen != (pj_ssize_t)crypto_suites[cr_rx_idx].cipher_key_len)
+	return PJMEDIA_SRTP_EINKEYLEN;
+
+    /* Init transmit direction */
+    pj_bzero(&tx_, sizeof(srtp_policy_t));
+    pj_memmove(srtp->tx_key, tx->key.ptr, tx->key.slen);
+    if (cr_tx_idx && au_tx_idx)
+	tx_.rtp.sec_serv    = sec_serv_conf_and_auth;
+    else if (cr_tx_idx)
+	tx_.rtp.sec_serv    = sec_serv_conf;
+    else if (au_tx_idx)
+	tx_.rtp.sec_serv    = sec_serv_auth;
+    else
+	tx_.rtp.sec_serv    = sec_serv_none;
+    tx_.key		    = (uint8_t*)srtp->tx_key;
+    tx_.ssrc.type	    = ssrc_any_outbound;
+    tx_.ssrc.value	    = 0;
+    tx_.rtp.cipher_type	    = crypto_suites[cr_tx_idx].cipher_type;
+    tx_.rtp.cipher_key_len  = crypto_suites[cr_tx_idx].cipher_key_len;
+    tx_.rtp.auth_type	    = crypto_suites[au_tx_idx].auth_type;
+    tx_.rtp.auth_key_len    = crypto_suites[au_tx_idx].auth_key_len;
+    tx_.rtp.auth_tag_len    = crypto_suites[au_tx_idx].srtp_auth_tag_len;
+    tx_.rtcp		    = tx_.rtp;
+    tx_.rtcp.auth_tag_len   = crypto_suites[au_tx_idx].srtcp_auth_tag_len;
+    tx_.next		    = NULL;
+    err = srtp_create(&srtp->srtp_tx_ctx, &tx_);
+    if (err != err_status_ok) {
+	return PJMEDIA_ERRNO_FROM_LIBSRTP(err);
+    }
+    srtp->tx_policy = *tx;
+    pj_strset(&srtp->tx_policy.key,  srtp->tx_key, tx->key.slen);
+    srtp->tx_policy.name = 
+			pj_str(crypto_suites[get_crypto_idx(&tx->name)].name);
+
+
+    /* Init receive direction */
+    pj_bzero(&rx_, sizeof(srtp_policy_t));
+    pj_memmove(srtp->rx_key, rx->key.ptr, rx->key.slen);
+    if (cr_rx_idx && au_rx_idx)
+	rx_.rtp.sec_serv    = sec_serv_conf_and_auth;
+    else if (cr_rx_idx)
+	rx_.rtp.sec_serv    = sec_serv_conf;
+    else if (au_rx_idx)
+	rx_.rtp.sec_serv    = sec_serv_auth;
+    else
+	rx_.rtp.sec_serv    = sec_serv_none;
+    rx_.key		    = (uint8_t*)srtp->rx_key;
+    rx_.ssrc.type	    = ssrc_any_inbound;
+    rx_.ssrc.value	    = 0;
+    rx_.rtp.sec_serv	    = crypto_suites[cr_rx_idx].service;
+    rx_.rtp.cipher_type	    = crypto_suites[cr_rx_idx].cipher_type;
+    rx_.rtp.cipher_key_len  = crypto_suites[cr_rx_idx].cipher_key_len;
+    rx_.rtp.auth_type	    = crypto_suites[au_rx_idx].auth_type;
+    rx_.rtp.auth_key_len    = crypto_suites[au_rx_idx].auth_key_len;
+    rx_.rtp.auth_tag_len    = crypto_suites[au_rx_idx].srtp_auth_tag_len;
+    rx_.rtcp		    = rx_.rtp;
+    rx_.rtcp.auth_tag_len   = crypto_suites[au_rx_idx].srtcp_auth_tag_len;
+    rx_.next		    = NULL;
+    err = srtp_create(&srtp->srtp_rx_ctx, &rx_);
+    if (err != err_status_ok) {
+	srtp_dealloc(srtp->srtp_tx_ctx);
+	return PJMEDIA_ERRNO_FROM_LIBSRTP(err);
+    }
+    srtp->rx_policy = *rx;
+    pj_strset(&srtp->rx_policy.key,  srtp->rx_key, rx->key.slen);
+    srtp->rx_policy.name = 
+			pj_str(crypto_suites[get_crypto_idx(&rx->name)].name);
+
+    /* Declare SRTP session initialized */
+    srtp->session_inited = PJ_TRUE;
+
+    PJ_LOG(5, (THIS_FILE, "TX: %s key=%s", srtp->tx_policy.name.ptr,
+	    octet_string_hex_string(tx->key.ptr, tx->key.slen)));
+    if (srtp->tx_policy.flags) {
+	PJ_LOG(5, (THIS_FILE, "TX: disable%s%s", (cr_tx_idx?"":" enc"),
+						 (au_tx_idx?"":" auth")));
+    }
+
+    PJ_LOG(5, (THIS_FILE, "RX: %s key=%s", srtp->rx_policy.name.ptr,
+	    octet_string_hex_string(rx->key.ptr, rx->key.slen)));
+    if (srtp->rx_policy.flags) {
+	PJ_LOG(5, (THIS_FILE, "RX: disable%s%s", (cr_rx_idx?"":" enc"),
+						 (au_rx_idx?"":" auth")));
+    }
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * Stop SRTP session.
+ */
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_stop(pjmedia_transport *srtp)
+{
+    transport_srtp *p_srtp = (transport_srtp*) srtp;
+    err_status_t err;
+
+    if (!p_srtp->session_inited)
+	return PJ_SUCCESS;
+
+    err = srtp_dealloc(p_srtp->srtp_rx_ctx);
+    if (err != err_status_ok) {
+	PJ_LOG(4, (THIS_FILE, "Failed to dealloc RX SRTP context"));
+    }
+    err = srtp_dealloc(p_srtp->srtp_tx_ctx);
+    if (err != err_status_ok) {
+	PJ_LOG(4, (THIS_FILE, "Failed to dealloc TX SRTP context"));
+    }
+
+    p_srtp->session_inited = PJ_FALSE;
+
+    return PJ_SUCCESS;
+}
+
+PJ_DEF(pjmedia_transport *) pjmedia_transport_srtp_get_member(
+						pjmedia_transport *tp)
+{
+    transport_srtp *srtp = (transport_srtp*) tp;
+
+    PJ_ASSERT_RETURN(tp, NULL);
+
+    return srtp->real_tp;
+}
+
+
+static pj_status_t transport_get_info(pjmedia_transport *tp,
+				      pjmedia_sock_info *info)
+{
+    transport_srtp *srtp = (transport_srtp*) tp;
+
+    /* put SRTP info as well? */
+    return pjmedia_transport_get_info(srtp->real_tp, info);
+}
+
+static pj_status_t transport_attach(pjmedia_transport *tp,
+				    void *user_data,
+				    const pj_sockaddr_t *rem_addr,
+				    const pj_sockaddr_t *rem_rtcp,
+				    unsigned addr_len,
+				    void (*rtp_cb) (void*, const void*,
+						    pj_ssize_t),
+				    void (*rtcp_cb)(void*, const void*,
+						    pj_ssize_t))
+{
+    transport_srtp *srtp = (transport_srtp*) tp;
+    pj_status_t status;
+
+    /* Attach itself to transport */
+    status = pjmedia_transport_attach(srtp->real_tp, srtp, rem_addr, rem_rtcp,
+				      addr_len, &srtp_rtp_cb, &srtp_rtcp_cb);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Save the callbacks */
+    srtp->rtp_cb = rtp_cb;
+    srtp->rtcp_cb = rtcp_cb;
+    srtp->user_data = user_data;
+
+    return status;
+}
+
+static void transport_detach(pjmedia_transport *tp, void *strm)
+{
+    transport_srtp *srtp = (transport_srtp*) tp;
+
+    PJ_ASSERT_ON_FAIL(tp && srtp->real_tp, return);
+
+    PJ_UNUSED_ARG(strm);
+    pjmedia_transport_detach(srtp->real_tp, srtp);
+
+    /* Clear up application infos from transport */
+    srtp->rtp_cb = NULL;
+    srtp->rtcp_cb = NULL;
+    srtp->user_data = NULL;
+}
+
+static pj_status_t transport_send_rtp( pjmedia_transport *tp,
+				       const void *pkt,
+				       pj_size_t size)
+{
+    pj_status_t status;
+    transport_srtp *srtp = (transport_srtp*) tp;
+    int len = size;
+    err_status_t err;
+
+    if (srtp->bypass_srtp)
+	return pjmedia_transport_send_rtp(srtp->real_tp, pkt, size);
+
+    if (!srtp->session_inited)
+	return PJ_SUCCESS;
+
+    if (size > sizeof(srtp->tx_buffer))
+	return PJ_ETOOBIG;
+
+    pj_lock_acquire(srtp->mutex);
+    pj_memcpy(srtp->tx_buffer, pkt, size);
+    
+    err = srtp_protect(srtp->srtp_tx_ctx, srtp->tx_buffer, &len);
+    if (err == err_status_ok) {
+	status = pjmedia_transport_send_rtp(srtp->real_tp, srtp->tx_buffer, len);
+    } else {
+	status = PJMEDIA_ERRNO_FROM_LIBSRTP(err);
+    }
+    
+    pj_lock_release(srtp->mutex);
+
+    return status;
+}
+
+static pj_status_t transport_send_rtcp(pjmedia_transport *tp,
+				       const void *pkt,
+				       pj_size_t size)
+{
+    pj_status_t status;
+    transport_srtp *srtp = (transport_srtp*) tp;
+    int len = size;
+    err_status_t err;
+
+    if (srtp->bypass_srtp)
+	return pjmedia_transport_send_rtcp(srtp->real_tp, pkt, size);
+
+    if (!srtp->session_inited)
+	return PJ_SUCCESS;
+
+    if (size > sizeof(srtp->tx_buffer))
+	return PJ_ETOOBIG;
+
+    pj_lock_acquire(srtp->mutex);
+    pj_memcpy(srtp->tx_buffer, pkt, size);
+
+    err = srtp_protect_rtcp(srtp->srtp_tx_ctx, srtp->tx_buffer, &len);
+    
+    if (err == err_status_ok) {
+	status = pjmedia_transport_send_rtcp(srtp->real_tp, srtp->tx_buffer, 
+					     len);
+    } else {
+	status = PJMEDIA_ERRNO_FROM_LIBSRTP(err);
+    }
+
+    pj_lock_release(srtp->mutex);
+
+    return status;
+}
+
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+					   pjmedia_dir dir,
+					   unsigned pct_lost)
+{
+    transport_srtp *srtp = (transport_srtp *) tp;
+
+    return pjmedia_transport_simulate_lost(srtp->real_tp, dir, pct_lost);
+}
+
+static pj_status_t transport_destroy  (pjmedia_transport *tp)
+{
+    transport_srtp *srtp = (transport_srtp *) tp;
+    pj_status_t status;
+
+    pj_lock_acquire(srtp->mutex);
+
+    pjmedia_transport_detach(tp, NULL);
+    
+    if (srtp->setting.close_member_tp) {
+	pjmedia_transport_close(srtp->real_tp);
+    }
+
+    status = pjmedia_transport_srtp_stop(tp);
+
+    pj_lock_release(srtp->mutex);
+
+    pj_lock_destroy(srtp->mutex);
+    pj_pool_release(srtp->pool);
+
+    return status;
+}
+
+/*
+ * This callback is called by transport when incoming rtp is received
+ */
+static void srtp_rtp_cb( void *user_data, const void *pkt, pj_ssize_t size)
+{
+    transport_srtp *srtp = (transport_srtp *) user_data;
+    int len = size;
+    err_status_t err;
+
+    if (srtp->bypass_srtp) {
+	srtp->rtp_cb(srtp->user_data, pkt, size);
+	return;
+    }
+
+    if (size < 0 || size > sizeof(srtp->rx_buffer) || !srtp->session_inited) {
+	return;
+    }
+
+    pj_lock_acquire(srtp->mutex);
+    pj_memcpy(srtp->rx_buffer, pkt, size);
+
+    err = srtp_unprotect(srtp->srtp_rx_ctx, srtp->rx_buffer, &len);
+    
+    if (err == err_status_ok) {
+	srtp->rtp_cb(srtp->user_data, srtp->rx_buffer, len);
+    } else {
+	PJ_LOG(5, (THIS_FILE, "Failed to unprotect SRTP size=%d, err=%d", 
+		   size, err));
+    }
+
+    pj_lock_release(srtp->mutex);
+}
+
+/*
+ * This callback is called by transport when incoming rtcp is received
+ */
+static void srtp_rtcp_cb( void *user_data, const void *pkt, pj_ssize_t size)
+{
+    transport_srtp *srtp = (transport_srtp *) user_data;
+    int len = size;
+    err_status_t err;
+
+    if (srtp->bypass_srtp) {
+	srtp->rtcp_cb(srtp->user_data, pkt, size);
+	return;
+    }
+
+    if (size < 0 || size > sizeof(srtp->rx_buffer) || !srtp->session_inited) {
+	return;
+    }
+
+    pj_lock_acquire(srtp->mutex);
+    pj_memcpy(srtp->rx_buffer, pkt, size);
+
+    err = srtp_unprotect_rtcp(srtp->srtp_rx_ctx, srtp->rx_buffer, &len);
+
+    if (err == err_status_ok) {
+	srtp->rtcp_cb(srtp->user_data, srtp->rx_buffer, len);
+    } else {
+	PJ_LOG(5, (THIS_FILE, "Failed to unprotect SRTCP size=%d, err=%d",
+		   size, err));
+    }
+    
+    pj_lock_release(srtp->mutex);
+}
+
+/* Generate crypto attribute, including crypto key.
+ * If crypto-suite chosen is crypto NULL, just return PJ_SUCCESS,
+ * and set buffer_len = 0.
+ */
+static pj_status_t generate_crypto_attr_value(pj_pool_t *pool,
+					      char *buffer, int *buffer_len, 
+					      pjmedia_srtp_crypto *crypto,
+					      int tag)
+{
+    pj_status_t status;
+    int cs_idx = get_crypto_idx(&crypto->name);
+    char b64_key[PJ_BASE256_TO_BASE64_LEN(MAX_KEY_LEN)+1];
+    int b64_key_len = sizeof(b64_key);
+
+    if (cs_idx == -1)
+	return PJMEDIA_SRTP_ENOTSUPCRYPTO;
+
+    /* Crypto-suite NULL. */
+    if (cs_idx == 0) {
+	*buffer_len = 0;
+	return PJ_SUCCESS;
+    }
+
+    /* Generate key if not specified. */
+    if (crypto->key.slen == 0) {
+	pj_bool_t key_ok;
+	char key[MAX_KEY_LEN];
+	err_status_t err;
+	int i;
+
+	PJ_ASSERT_RETURN(MAX_KEY_LEN >= crypto_suites[cs_idx].cipher_key_len,
+			 PJ_ETOOSMALL);
+
+	do {
+	    key_ok = PJ_TRUE;
+
+	    err = crypto_get_random((unsigned char*)key, 
+				     crypto_suites[cs_idx].cipher_key_len);
+	    if (err != err_status_ok) {
+		PJ_LOG(5,(THIS_FILE, "Failed generating random key"));
+		return PJMEDIA_ERRNO_FROM_LIBSRTP(err);
+	    }
+	    for (i=0; i<crypto_suites[cs_idx].cipher_key_len && key_ok; ++i)
+		if (key[i] == 0) key_ok = PJ_FALSE;
+
+	} while (!key_ok);
+	crypto->key.ptr = pj_pool_zalloc(pool, 
+					 crypto_suites[cs_idx].cipher_key_len);
+	pj_memcpy(crypto->key.ptr, key, crypto_suites[cs_idx].cipher_key_len);
+	crypto->key.slen = crypto_suites[cs_idx].cipher_key_len;
+    }
+
+    if (crypto->key.slen != (pj_ssize_t)crypto_suites[cs_idx].cipher_key_len)
+	return PJMEDIA_SRTP_EINKEYLEN;
+
+    /* Key transmitted via SDP should be base64 encoded. */
+    status = pj_base64_encode((pj_uint8_t*)crypto->key.ptr, crypto->key.slen,
+			      b64_key, &b64_key_len);
+    if (status != PJ_SUCCESS) {
+	PJ_LOG(5,(THIS_FILE, "Failed encoding plain key to base64"));
+	return status;
+    }
+
+    b64_key[b64_key_len] = '\0';
+    
+    PJ_ASSERT_RETURN(*buffer_len >= (crypto->name.slen + \
+		     b64_key_len + 16), PJ_ETOOSMALL);
+
+    /* Print the crypto attribute value. */
+    *buffer_len = pj_ansi_snprintf(buffer, *buffer_len, "%d %s inline:%s",
+				   tag, 
+				   crypto_suites[cs_idx].name,
+				   b64_key);
+
+    return PJ_SUCCESS;
+}
+
+/* Parse crypto attribute line */
+static pj_status_t parse_attr_crypto(pj_pool_t *pool,
+				     const pjmedia_sdp_attr *attr,
+				     pjmedia_srtp_crypto *crypto,
+				     int *tag)
+{
+    pj_str_t input;
+    char *token;
+    pj_str_t tmp;
+    pj_status_t status;
+    int itmp;
+
+    pj_bzero(crypto, sizeof(*crypto));
+    pj_strdup_with_null(pool, &input, &attr->value);
+
+    /* Tag */
+    token = strtok(input.ptr, " ");
+    if (!token) {
+	PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting tag"));
+	return PJMEDIA_SDP_EINATTR;
+    }
+    *tag = atoi(token);
+    if (*tag == 0)
+	return PJMEDIA_SDP_EINATTR;
+
+    /* Crypto-suite */
+    token = strtok(NULL, " ");
+    if (!token) {
+	PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting crypto suite"));
+	return PJMEDIA_SDP_EINATTR;
+    }
+    crypto->name = pj_str(token);
+
+    /* Key method */
+    token = strtok(NULL, ":");
+    if (!token) {
+	PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key method"));
+	return PJMEDIA_SDP_EINATTR;
+    }
+    if (pj_ansi_stricmp(token, "inline")) {
+	PJ_LOG(4,(THIS_FILE, "Attribute crypto key method '%s' not supported!",
+	          token));
+	return PJMEDIA_SDP_EINATTR;
+    }
+
+    /* Key */
+    token = strtok(NULL, "| ");
+    if (!token) {
+	PJ_LOG(4,(THIS_FILE, "Attribute crypto expecting key"));
+	return PJMEDIA_SDP_EINATTR;
+    }
+    tmp = pj_str(token);
+    crypto->key.ptr = pj_pool_zalloc(pool, MAX_KEY_LEN);
+
+    /* Decode key */
+    itmp = MAX_KEY_LEN;
+    status = pj_base64_decode(&tmp, (pj_uint8_t*)crypto->key.ptr, 
+			      &itmp);
+    if (status != PJ_SUCCESS) {
+	PJ_LOG(4,(THIS_FILE, "Failed decoding crypto key from base64"));
+	return status;
+    }
+    crypto->key.slen = itmp;
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+				          pj_pool_t *pool,
+				          pjmedia_sdp_session *sdp_local,
+				          const pjmedia_sdp_session *sdp_remote,
+					  unsigned media_index)
+{
+    struct transport_srtp *srtp = (struct transport_srtp*) tp;
+    pjmedia_sdp_media *m_rem, *m_loc;
+    enum { MAXLEN = 512 };
+    char buffer[MAXLEN];
+    int buffer_len;
+    pj_status_t status;
+    pjmedia_sdp_attr *attr;
+    pj_str_t attr_value;
+    int i, j;
+
+    PJ_ASSERT_RETURN(tp && pool && sdp_local, PJ_EINVAL);
+
+    pj_bzero(&srtp->rx_policy, sizeof(srtp->tx_policy));
+    pj_bzero(&srtp->tx_policy, sizeof(srtp->rx_policy));
+
+    m_rem = sdp_remote ? sdp_remote->media[media_index] : NULL;
+    m_loc = sdp_local->media[media_index];
+
+    /* bypass if media transport is not RTP/AVP or RTP/SAVP */
+    if (pj_stricmp(&m_loc->desc.transport, &ID_RTP_AVP)  != 0 && 
+	pj_stricmp(&m_loc->desc.transport, &ID_RTP_SAVP) != 0)
+	goto BYPASS_SRTP;
+
+    /* If the media is inactive, do nothing. */
+    if (pjmedia_sdp_media_find_attr(m_loc, &ID_INACTIVE, NULL) || 
+	(m_rem && pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL)))
+    {
+	goto BYPASS_SRTP;
+    }
+
+    srtp->offerer_side = !sdp_remote;
+
+    /* Check remote media transport & set local media transport 
+     * based on SRTP usage option.
+     */
+    if (srtp->offerer_side) {
+	if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+	    goto BYPASS_SRTP;
+	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
+	    m_loc->desc.transport = ID_RTP_AVP;
+	} else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
+	    m_loc->desc.transport = ID_RTP_SAVP;
+	}
+    } else {
+	if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+	    if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0) {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SRTP_ESDPINTRANSPORT;
+	    }
+	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
+		m_loc->desc.transport = m_rem->desc.transport;
+	} else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
+	    if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0) {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SRTP_ESDPINTRANSPORT;
+	    }
+	    m_loc->desc.transport = ID_RTP_SAVP;
+	}
+    }
+
+    /* Generate crypto attribute */
+    if (srtp->offerer_side) {
+	for (i=0; i<srtp->setting.crypto_count; ++i) {
+	    /* Offer crypto-suites based on setting. */
+	    buffer_len = MAXLEN;
+	    status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len,
+						&srtp->setting.crypto[i],
+						i+1);
+	    if (status != PJ_SUCCESS)
+		return status;
+
+	    /* If buffer_len==0, just skip the crypto attribute. */
+	    if (buffer_len) {
+		pj_strset(&attr_value, buffer, buffer_len);
+		attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr, 
+					       &attr_value);
+		m_loc->attr[m_loc->attr_count++] = attr;
+	    }
+	}
+    } else {
+	/* find supported crypto-suite, get the tag, and assign policy_local */
+	pjmedia_srtp_crypto tmp_rx_crypto;
+	pj_bool_t has_crypto_attr = PJ_FALSE;
+	pj_bool_t has_match = PJ_FALSE;
+	int chosen_tag = 0;
+	int tags[64]; /* assume no more than 64 crypto attrs in a media */
+	int cr_attr_count = 0;
+	int k;
+
+	for (i=0; i<m_rem->attr_count; ++i) {
+	    if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0)
+		continue;
+
+	    /* SRTP is disabled but there is crypto attr in remote media */
+	    /* Put the checking here to save a bit memory for parsing */
+	    if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SRTP_ESDPINTRANSPORT;
+	    }
+
+	    has_crypto_attr = PJ_TRUE;
+
+	    status = parse_attr_crypto(srtp->pool, m_rem->attr[i], 
+				       &tmp_rx_crypto, &tags[cr_attr_count]);
+	    if (status != PJ_SUCCESS)
+		return status;
+	 
+	    /* Check duplicated tag */
+	    for (k=0; k<cr_attr_count; ++k) {
+		if (tags[k] == tags[cr_attr_count]) {
+		    DEACTIVATE_MEDIA(pool, m_loc);
+		    return PJMEDIA_SRTP_ESDPDUPCRYPTOTAG;
+		}
+	    }
+
+	    if (!has_match) {
+		/* lets see if the crypto-suite offered is supported */
+		for (j=0; j<srtp->setting.crypto_count; ++j)
+		    if (pj_stricmp(&tmp_rx_crypto.name, 
+				   &srtp->setting.crypto[j].name) == 0)
+		    {
+			int cs_idx = get_crypto_idx(&tmp_rx_crypto.name);
+
+			/* Force to use test key */
+			//char *hex_test_key = "58b29c5c8f42308120ce857e439f2d"
+			//		     "7810a8b10ad0b1446be5470faea496";
+			//pj_str_t* test_key = &srtp->setting.crypto[j].key;
+			//char  *raw_test_key = pj_pool_zalloc(srtp->pool, 64);
+			//hex_string_to_octet_string(
+			//		raw_test_key,
+			//		hex_test_key,
+			//		strlen(hex_test_key));
+			//pj_strset(test_key, raw_test_key, 
+			//	  crypto_suites[cs_idx].cipher_key_len);
+
+			if (tmp_rx_crypto.key.slen != 
+			    (int)crypto_suites[cs_idx].cipher_key_len)
+			    return PJMEDIA_SRTP_EINKEYLEN;
+
+			srtp->tx_policy = srtp->setting.crypto[j];
+			srtp->rx_policy = tmp_rx_crypto;
+			chosen_tag = tags[cr_attr_count];
+			has_match = PJ_TRUE;
+    			break;
+		    }
+	    }
+	    cr_attr_count++;
+	}
+
+	if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+	    /* At this point, it is ensured remote has no crypto attr */
+	    goto BYPASS_SRTP;
+	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
+	    /* bypass SRTP when no crypto-attr but remote uses RTP/AVP */
+	    if (!has_crypto_attr && 
+		pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0)
+		goto BYPASS_SRTP;
+	    /* bypass SRTP when nothing match but remote uses RTP/AVP */
+	    if (!has_match && 
+		pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP) == 0)
+		goto BYPASS_SRTP;
+	} else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
+	    /* do nothing, this is intended */
+	}
+
+	/* No crypto attr */
+	if (!has_crypto_attr) {
+	    DEACTIVATE_MEDIA(pool, m_loc);
+	    return PJMEDIA_SRTP_ESDPREQCRYPTO;
+	}
+
+	/* No crypto match */
+	if (!has_match) {
+	    DEACTIVATE_MEDIA(pool, m_loc);
+	    return PJMEDIA_SRTP_ENOTSUPCRYPTO;
+	}
+
+	/* we have to generate crypto answer, 
+	 * with srtp->tx_policy matched the offer
+	 * and rem_tag contains matched offer tag.
+	 */
+	buffer_len = MAXLEN;
+	status = generate_crypto_attr_value(srtp->pool, buffer, &buffer_len,
+					    &srtp->tx_policy,
+					    chosen_tag);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	/* If buffer_len==0, just skip the crypto attribute. */
+	if (buffer_len) {
+	    pj_strset(&attr_value, buffer, buffer_len);
+	    attr = pjmedia_sdp_attr_create(srtp->pool, ID_CRYPTO.ptr, 
+					   &attr_value);
+	    m_loc->attr[m_loc->attr_count++] = attr;
+	}
+
+	/* At this point,
+	 * we should have valid rx_policy & tx_policy.
+	 */
+    }
+    goto PROPAGATE_MEDIA_CREATE;
+
+BYPASS_SRTP:
+    srtp->bypass_srtp = PJ_TRUE;
+
+PROPAGATE_MEDIA_CREATE:
+    return pjmedia_transport_media_create(srtp->real_tp, pool, sdp_local, 
+					   sdp_remote, media_index);
+}
+
+
+
+static pj_status_t transport_media_start(pjmedia_transport *tp,
+				         pj_pool_t *pool,
+				         pjmedia_sdp_session *sdp_local,
+				         const pjmedia_sdp_session *sdp_remote,
+				         unsigned media_index)
+{
+    struct transport_srtp *srtp = (struct transport_srtp*) tp;
+    pjmedia_sdp_media *m_rem, *m_loc;
+    pj_status_t status;
+    pjmedia_sdp_attr *attr;
+    int i;
+
+    PJ_ASSERT_RETURN(tp && pool && sdp_local && sdp_remote, PJ_EINVAL);
+
+    if (srtp->bypass_srtp)
+	goto BYPASS_SRTP;
+
+    m_rem = sdp_remote->media[media_index];
+    m_loc = sdp_local->media[media_index];
+
+    /* For answerer side, this function will just have to start SRTP */
+
+    /* Check remote media transport & set local media transport 
+     * based on SRTP usage option.
+     */
+    if (srtp->offerer_side) {
+	if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+	    if (pjmedia_sdp_media_find_attr(m_rem, &ID_CRYPTO, NULL)) {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SRTP_ESDPINCRYPTO;
+	    }
+	    goto BYPASS_SRTP;
+	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
+	    if (pj_stricmp(&m_rem->desc.transport, &m_loc->desc.transport)) {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SDP_EINPROTO;
+	    }
+	} else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
+	    if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP)) {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SDP_EINPROTO;
+	    }
+	}
+    }
+    
+    if (srtp->offerer_side) {
+	/* find supported crypto-suite, get the tag, and assign policy_local */
+	pjmedia_srtp_crypto tmp_tx_crypto;
+	pj_bool_t has_crypto_attr = PJ_FALSE;
+	int rem_tag;
+
+	for (i=0; i<m_rem->attr_count; ++i) {
+	    if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0)
+		continue;
+
+	    /* more than one crypto attribute in media answer */
+	    if (has_crypto_attr) {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SRTP_ESDPAMBIGUEANS;
+	    }
+
+	    has_crypto_attr = PJ_TRUE;
+
+	    status = parse_attr_crypto(srtp->pool, m_rem->attr[i], 
+				       &tmp_tx_crypto, &rem_tag);
+	    if (status != PJ_SUCCESS)
+		return status;
+
+
+	    /* our offer tag is always ordered by setting */
+	    if (rem_tag < 1 || rem_tag > srtp->setting.crypto_count) {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SRTP_ESDPINCRYPTOTAG;
+	    }
+
+	    /* match the crypto name */
+	    if (pj_stricmp(&tmp_tx_crypto.name, 
+		&srtp->setting.crypto[rem_tag-1].name) != 0)
+	    {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SRTP_ECRYPTONOTMATCH;
+	    }
+
+	    srtp->tx_policy = srtp->setting.crypto[rem_tag-1];
+	    srtp->rx_policy = tmp_tx_crypto;
+	}
+
+	if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+	    /* should never reach here */
+	    goto BYPASS_SRTP;
+	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
+	    if (!has_crypto_attr)
+		goto BYPASS_SRTP;
+	} else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
+	    if (!has_crypto_attr) {
+		DEACTIVATE_MEDIA(pool, m_loc);
+		return PJMEDIA_SRTP_ESDPREQCRYPTO;
+	    }
+	}
+
+	/* At this point,
+	 * we should have valid rx_policy & tx_policy.
+	 */
+    }
+
+    /* Got policy_local & policy_remote, let's initalize the SRTP */
+    status = pjmedia_transport_srtp_start(tp, &srtp->tx_policy, &srtp->rx_policy);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    goto PROPAGATE_MEDIA_START;
+
+BYPASS_SRTP:
+    srtp->bypass_srtp = PJ_TRUE;
+
+PROPAGATE_MEDIA_START:
+    return pjmedia_transport_media_start(srtp->real_tp, pool, 
+					 sdp_local, sdp_remote,
+				         media_index);
+}
+
+static pj_status_t transport_media_stop(pjmedia_transport *tp)
+{
+    struct transport_srtp *srtp = (struct transport_srtp*) tp;
+    pj_status_t status;
+
+    status = pjmedia_transport_media_stop(srtp->real_tp);
+    if (status != PJ_SUCCESS)
+	PJ_LOG(4, (THIS_FILE, "SRTP failed stop underlying media transport."));
+
+    return pjmedia_transport_srtp_stop(tp);
+}
+
+#endif
+
+
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 1734)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_udp.c	(revision 1735)
@@ -95,7 +95,10 @@
                        pj_ssize_t bytes_read);
 
-static pj_status_t transport_get_info(pjmedia_transport *tp,
-				      pjmedia_sock_info *info);
-static pj_status_t transport_attach(   pjmedia_transport *tp,
+/*
+ * These are media transport operations.
+ */
+static pj_status_t transport_get_info (pjmedia_transport *tp,
+				       pjmedia_sock_info *info);
+static pj_status_t transport_attach   (pjmedia_transport *tp,
 				       void *user_data,
 				       const pj_sockaddr_t *rem_addr,
@@ -108,5 +111,5 @@
 						       const void*,
 						       pj_ssize_t));
-static void	   transport_detach(   pjmedia_transport *tp,
+static void	   transport_detach   (pjmedia_transport *tp,
 				       void *strm);
 static pj_status_t transport_send_rtp( pjmedia_transport *tp,
@@ -116,4 +119,19 @@
 				       const void *pkt,
 				       pj_size_t size);
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+				       pj_pool_t *pool,
+				       pjmedia_sdp_session *sdp_local,
+				       const pjmedia_sdp_session *sdp_remote,
+				       unsigned media_index);
+static pj_status_t transport_media_start (pjmedia_transport *tp,
+				       pj_pool_t *pool,
+				       pjmedia_sdp_session *sdp_local,
+				       const pjmedia_sdp_session *sdp_remote,
+				       unsigned media_index);
+static pj_status_t transport_media_stop(pjmedia_transport *tp);
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+				       pjmedia_dir dir,
+				       unsigned pct_lost);
+static pj_status_t transport_destroy  (pjmedia_transport *tp);
 
 
@@ -125,5 +143,9 @@
     &transport_send_rtp,
     &transport_send_rtcp,
-    &pjmedia_transport_udp_close
+    &transport_media_create,
+    &transport_media_start,
+    &transport_media_stop,
+    &transport_simulate_lost,
+    &transport_destroy
 };
 
@@ -342,16 +364,6 @@
 
 on_error:
-    pjmedia_transport_udp_close(&tp->base);
+    transport_destroy(&tp->base);
     return status;
-}
-
-
-/*
- * Get media socket info.
- */
-PJ_DEF(pj_status_t) pjmedia_transport_udp_get_info( pjmedia_transport *tp,
-				pjmedia_transport_udp_info *inf)
-{
-    return transport_get_info(tp, &inf->skinfo);
 }
 
@@ -360,5 +372,5 @@
  * Close UDP transport.
  */
-PJ_DEF(pj_status_t) pjmedia_transport_udp_close(pjmedia_transport *tp)
+static pj_status_t transport_destroy(pjmedia_transport *tp)
 {
     struct transport_udp *udp = (struct transport_udp*) tp;
@@ -727,7 +739,43 @@
 
 
-PJ_DEF(pj_status_t) pjmedia_transport_udp_simulate_lost(pjmedia_transport *tp,
-							pjmedia_dir dir,
-							unsigned pct_lost)
+static pj_status_t transport_media_create(pjmedia_transport *tp,
+				  pj_pool_t *pool,
+				  pjmedia_sdp_session *sdp_local,
+				  const pjmedia_sdp_session *sdp_remote,
+				  unsigned media_index)
+{
+    PJ_UNUSED_ARG(tp);
+    PJ_UNUSED_ARG(pool);
+    PJ_UNUSED_ARG(sdp_local);
+    PJ_UNUSED_ARG(sdp_remote);
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t transport_media_start(pjmedia_transport *tp,
+				  pj_pool_t *pool,
+				  pjmedia_sdp_session *sdp_local,
+				  const pjmedia_sdp_session *sdp_remote,
+				  unsigned media_index)
+{
+    PJ_UNUSED_ARG(tp);
+    PJ_UNUSED_ARG(pool);
+    PJ_UNUSED_ARG(sdp_local);
+    PJ_UNUSED_ARG(sdp_remote);
+    PJ_UNUSED_ARG(media_index);
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t transport_media_stop(pjmedia_transport *tp)
+{
+    PJ_UNUSED_ARG(tp);
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t transport_simulate_lost(pjmedia_transport *tp,
+					   pjmedia_dir dir,
+					   unsigned pct_lost)
 {
     struct transport_udp *udp = (struct transport_udp*)tp;
Index: /pjproject/trunk/pjproject-vs8.sln
===================================================================
--- /pjproject/trunk/pjproject-vs8.sln	(revision 1734)
+++ /pjproject/trunk/pjproject-vs8.sln	(revision 1735)
@@ -1,5 +1,5 @@
 ﻿
 Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual C++ Express 2005
+# Visual Studio 2005
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pjlib", "pjlib\build\pjlib.vcproj", "{DA0E03ED-53A7-4050-8A85-90541C5509F8}"
 EndProject
@@ -13,6 +13,6 @@
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pjlib_util_test", "pjlib-util\build\pjlib_util_test.vcproj", "{ED02BE13-8297-4770-8097-27DC2CCABF9A}"
 	ProjectSection(ProjectDependencies) = postProject
-		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
-		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
+		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
+		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
 	EndProjectSection
 EndProject
@@ -29,63 +29,65 @@
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pjsua", "pjsip-apps\build\pjsua.vcproj", "{8310649E-A25E-4AF0-91E8-9E3CC659BB89}"
 	ProjectSection(ProjectDependencies) = postProject
+		{F0DBAA03-1BA3-4E3B-A2CA-727E3D3AB858} = {F0DBAA03-1BA3-4E3B-A2CA-727E3D3AB858}
 		{2BB84911-C1B4-4747-B93D-36AA82CC5031} = {2BB84911-C1B4-4747-B93D-36AA82CC5031}
 		{4BF51C21-5A30-423B-82FE-1ED410E5769D} = {4BF51C21-5A30-423B-82FE-1ED410E5769D}
+		{A5D9AA24-08ED-48B9-BD65-F0A25E96BFC4} = {A5D9AA24-08ED-48B9-BD65-F0A25E96BFC4}
+		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
+		{6794B975-4E84-4F49-B2DC-C31F2224E03E} = {6794B975-4E84-4F49-B2DC-C31F2224E03E}
+		{7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65} = {7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65}
+		{3CF9FFA9-8387-4635-9D1B-E7944CBEFEAA} = {3CF9FFA9-8387-4635-9D1B-E7944CBEFEAA}
+		{4B059DBA-CD9C-4D0F-BE8C-FFB4EFD498E9} = {4B059DBA-CD9C-4D0F-BE8C-FFB4EFD498E9}
+		{855DC8C0-D3E9-4A2E-AE47-116605A7BC9B} = {855DC8C0-D3E9-4A2E-AE47-116605A7BC9B}
+		{4B5945CD-0CB3-49AA-A7FF-7612D93F82C0} = {4B5945CD-0CB3-49AA-A7FF-7612D93F82C0}
+		{B8719FD5-E8A6-4A36-943C-891D07F5DD21} = {B8719FD5-E8A6-4A36-943C-891D07F5DD21}
+		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
+		{B5FE16F8-3EDB-4110-BD80-B4238CC01E8D} = {B5FE16F8-3EDB-4110-BD80-B4238CC01E8D}
+		{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37} = {9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}
 		{E53AA5FF-B737-40AA-BD13-387EFA99023D} = {E53AA5FF-B737-40AA-BD13-387EFA99023D}
-		{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37} = {9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pjsua_lib", "pjsip\build\pjsua_lib.vcproj", "{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_debug", "pjsip-apps\build\sample_debug.vcproj", "{A0F1AA62-0F6F-420D-B09A-AC04B6862821}"
+	ProjectSection(ProjectDependencies) = postProject
+		{A5D9AA24-08ED-48B9-BD65-F0A25E96BFC4} = {A5D9AA24-08ED-48B9-BD65-F0A25E96BFC4}
+		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
+		{6794B975-4E84-4F49-B2DC-C31F2224E03E} = {6794B975-4E84-4F49-B2DC-C31F2224E03E}
+		{7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65} = {7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65}
+		{3CF9FFA9-8387-4635-9D1B-E7944CBEFEAA} = {3CF9FFA9-8387-4635-9D1B-E7944CBEFEAA}
+		{4B059DBA-CD9C-4D0F-BE8C-FFB4EFD498E9} = {4B059DBA-CD9C-4D0F-BE8C-FFB4EFD498E9}
+		{855DC8C0-D3E9-4A2E-AE47-116605A7BC9B} = {855DC8C0-D3E9-4A2E-AE47-116605A7BC9B}
+		{4B5945CD-0CB3-49AA-A7FF-7612D93F82C0} = {4B5945CD-0CB3-49AA-A7FF-7612D93F82C0}
+		{B8719FD5-E8A6-4A36-943C-891D07F5DD21} = {B8719FD5-E8A6-4A36-943C-891D07F5DD21}
+		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
 		{B5FE16F8-3EDB-4110-BD80-B4238CC01E8D} = {B5FE16F8-3EDB-4110-BD80-B4238CC01E8D}
-		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
-		{B8719FD5-E8A6-4A36-943C-891D07F5DD21} = {B8719FD5-E8A6-4A36-943C-891D07F5DD21}
-		{4B5945CD-0CB3-49AA-A7FF-7612D93F82C0} = {4B5945CD-0CB3-49AA-A7FF-7612D93F82C0}
-		{855DC8C0-D3E9-4A2E-AE47-116605A7BC9B} = {855DC8C0-D3E9-4A2E-AE47-116605A7BC9B}
-		{4B059DBA-CD9C-4D0F-BE8C-FFB4EFD498E9} = {4B059DBA-CD9C-4D0F-BE8C-FFB4EFD498E9}
-		{3CF9FFA9-8387-4635-9D1B-E7944CBEFEAA} = {3CF9FFA9-8387-4635-9D1B-E7944CBEFEAA}
-		{7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65} = {7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65}
-		{6794B975-4E84-4F49-B2DC-C31F2224E03E} = {6794B975-4E84-4F49-B2DC-C31F2224E03E}
-		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
-		{A5D9AA24-08ED-48B9-BD65-F0A25E96BFC4} = {A5D9AA24-08ED-48B9-BD65-F0A25E96BFC4}
-	EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pjsua_lib", "pjsip\build\pjsua_lib.vcproj", "{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_debug", "pjsip-apps\build\sample_debug.vcproj", "{A0F1AA62-0F6F-420D-B09A-AC04B6862821}"
-	ProjectSection(ProjectDependencies) = postProject
+		{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37} = {9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}
 		{E53AA5FF-B737-40AA-BD13-387EFA99023D} = {E53AA5FF-B737-40AA-BD13-387EFA99023D}
-		{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37} = {9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}
-		{B5FE16F8-3EDB-4110-BD80-B4238CC01E8D} = {B5FE16F8-3EDB-4110-BD80-B4238CC01E8D}
-		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
-		{B8719FD5-E8A6-4A36-943C-891D07F5DD21} = {B8719FD5-E8A6-4A36-943C-891D07F5DD21}
-		{4B5945CD-0CB3-49AA-A7FF-7612D93F82C0} = {4B5945CD-0CB3-49AA-A7FF-7612D93F82C0}
-		{855DC8C0-D3E9-4A2E-AE47-116605A7BC9B} = {855DC8C0-D3E9-4A2E-AE47-116605A7BC9B}
-		{4B059DBA-CD9C-4D0F-BE8C-FFB4EFD498E9} = {4B059DBA-CD9C-4D0F-BE8C-FFB4EFD498E9}
-		{3CF9FFA9-8387-4635-9D1B-E7944CBEFEAA} = {3CF9FFA9-8387-4635-9D1B-E7944CBEFEAA}
-		{7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65} = {7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65}
-		{6794B975-4E84-4F49-B2DC-C31F2224E03E} = {6794B975-4E84-4F49-B2DC-C31F2224E03E}
-		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
-		{A5D9AA24-08ED-48B9-BD65-F0A25E96BFC4} = {A5D9AA24-08ED-48B9-BD65-F0A25E96BFC4}
-		{2BB84911-C1B4-4747-B93D-36AA82CC5031} = {2BB84911-C1B4-4747-B93D-36AA82CC5031}
+		{2BB84911-C1B4-4747-B93D-36AA82CC5031} = {2BB84911-C1B4-4747-B93D-36AA82CC5031}
+		{F0DBAA03-1BA3-4E3B-A2CA-727E3D3AB858} = {F0DBAA03-1BA3-4E3B-A2CA-727E3D3AB858}
 	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "samples", "pjsip-apps\build\samples.vcproj", "{E378A1FC-0C9C-4462-860F-7E60BC1BF84E}"
 	ProjectSection(ProjectDependencies) = postProject
-		{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37} = {9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}
-		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
-		{B8719FD5-E8A6-4A36-943C-891D07F5DD21} = {B8719FD5-E8A6-4A36-943C-891D07F5DD21}
-		{4B5945CD-0CB3-49AA-A7FF-7612D93F82C0} = {4B5945CD-0CB3-49AA-A7FF-7612D93F82C0}
-		{855DC8C0-D3E9-4A2E-AE47-116605A7BC9B} = {855DC8C0-D3E9-4A2E-AE47-116605A7BC9B}
-		{7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65} = {7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65}
-		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
-		{2BB84911-C1B4-4747-B93D-36AA82CC5031} = {2BB84911-C1B4-4747-B93D-36AA82CC5031}
+		{2BB84911-C1B4-4747-B93D-36AA82CC5031} = {2BB84911-C1B4-4747-B93D-36AA82CC5031}
+		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
+		{7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65} = {7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65}
+		{855DC8C0-D3E9-4A2E-AE47-116605A7BC9B} = {855DC8C0-D3E9-4A2E-AE47-116605A7BC9B}
+		{4B5945CD-0CB3-49AA-A7FF-7612D93F82C0} = {4B5945CD-0CB3-49AA-A7FF-7612D93F82C0}
+		{B8719FD5-E8A6-4A36-943C-891D07F5DD21} = {B8719FD5-E8A6-4A36-943C-891D07F5DD21}
+		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
+		{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37} = {9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}
 	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_pjsip", "pjsip\build\test_pjsip.vcproj", "{B3F7D4E9-702F-4EB4-ADA8-098D0A83D770}"
 	ProjectSection(ProjectDependencies) = postProject
-		{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37} = {9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}
-		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
-		{B8719FD5-E8A6-4A36-943C-891D07F5DD21} = {B8719FD5-E8A6-4A36-943C-891D07F5DD21}
-		{4B5945CD-0CB3-49AA-A7FF-7612D93F82C0} = {4B5945CD-0CB3-49AA-A7FF-7612D93F82C0}
-		{855DC8C0-D3E9-4A2E-AE47-116605A7BC9B} = {855DC8C0-D3E9-4A2E-AE47-116605A7BC9B}
-		{7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65} = {7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65}
-		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
-		{2BB84911-C1B4-4747-B93D-36AA82CC5031} = {2BB84911-C1B4-4747-B93D-36AA82CC5031}
+		{2BB84911-C1B4-4747-B93D-36AA82CC5031} = {2BB84911-C1B4-4747-B93D-36AA82CC5031}
+		{FE07F272-AE7F-4549-9E9F-EF9B80CB1693} = {FE07F272-AE7F-4549-9E9F-EF9B80CB1693}
+		{7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65} = {7FDE3880-A4AB-49E3-B439-EBEF0A0C7A65}
+		{855DC8C0-D3E9-4A2E-AE47-116605A7BC9B} = {855DC8C0-D3E9-4A2E-AE47-116605A7BC9B}
+		{4B5945CD-0CB3-49AA-A7FF-7612D93F82C0} = {4B5945CD-0CB3-49AA-A7FF-7612D93F82C0}
+		{B8719FD5-E8A6-4A36-943C-891D07F5DD21} = {B8719FD5-E8A6-4A36-943C-891D07F5DD21}
+		{DA0E03ED-53A7-4050-8A85-90541C5509F8} = {DA0E03ED-53A7-4050-8A85-90541C5509F8}
+		{9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37} = {9CA0FDFB-2172-41FC-B7F1-5CE915EDCB37}
 	EndProjectSection
 EndProject
@@ -105,4 +107,6 @@
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmilenage", "third_party\build\milenage\libmilenage.vcproj", "{4BF51C21-5A30-423B-82FE-1ED410E5769D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsrtp", "third_party\build\srtp\libsrtp.vcproj", "{F0DBAA03-1BA3-4E3B-A2CA-727E3D3AB858}"
 EndProject
 Global
@@ -200,4 +204,8 @@
 		{4BF51C21-5A30-423B-82FE-1ED410E5769D}.Release|Win32.ActiveCfg = Release|Win32
 		{4BF51C21-5A30-423B-82FE-1ED410E5769D}.Release|Win32.Build.0 = Release|Win32
+		{F0DBAA03-1BA3-4E3B-A2CA-727E3D3AB858}.Debug|Win32.ActiveCfg = Debug|Win32
+		{F0DBAA03-1BA3-4E3B-A2CA-727E3D3AB858}.Debug|Win32.Build.0 = Debug|Win32
+		{F0DBAA03-1BA3-4E3B-A2CA-727E3D3AB858}.Release|Win32.ActiveCfg = Release|Win32
+		{F0DBAA03-1BA3-4E3B-A2CA-727E3D3AB858}.Release|Win32.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
Index: /pjproject/trunk/pjproject.dsw
===================================================================
--- /pjproject/trunk/pjproject.dsw	(revision 1734)
+++ /pjproject/trunk/pjproject.dsw	(revision 1735)
@@ -4,101 +4,113 @@
 ###############################################################################
 
-Project: "libgsmcodec"=.\THIRD_PARTY\BUILD\GSM\libgsmcodec.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "libilbccodec"=.\THIRD_PARTY\BUILD\ILBC\libilbccodec.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "libmilenage"=.\third_party\build\milenage\libmilenage.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "libportaudio"=.\THIRD_PARTY\BUILD\PORTAUDIO\libportaudio.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "libresample"=.\THIRD_PARTY\BUILD\RESAMPLE\libresample.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "libresample_dll"=.\THIRD_PARTY\BUILD\RESAMPLE\libresample_dll.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "libspeex"=.\third_party\build\speex\libspeex.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "pjlib"=.\pjlib\build\pjlib.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "pjlib_test"=.\pjlib\build\pjlib_test.dsp - Package Owner=<4>
+Project: "libgsmcodec"=".\THIRD_PARTY\BUILD\GSM\libgsmcodec.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libilbccodec"=".\THIRD_PARTY\BUILD\ILBC\libilbccodec.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libmilenage"=".\third_party\build\milenage\libmilenage.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libportaudio"=".\THIRD_PARTY\BUILD\PORTAUDIO\libportaudio.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libresample"=".\THIRD_PARTY\BUILD\RESAMPLE\libresample.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libresample_dll"=".\THIRD_PARTY\BUILD\RESAMPLE\libresample_dll.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libspeex"=".\third_party\build\speex\libspeex.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libsrtp"=".\third_party\build\srtp\libsrtp.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pjlib"=".\pjlib\build\pjlib.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pjlib_test"=".\pjlib\build\pjlib_test.dsp" - Package Owner=<4>
 
 Package=<5>
@@ -145,65 +157,65 @@
 ###############################################################################
 
-Project: "pjmedia"=.\pjmedia\build\pjmedia.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "pjmedia_codec"=.\pjmedia\build\pjmedia_codec.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "pjnath"=.\pjnath\build\pjnath.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "pjsip_core"=.\pjsip\build\pjsip_core.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "pjsip_simple"=.\pjsip\build\pjsip_simple.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Project: "pjsip_ua"=.\pjsip\build\pjsip_ua.dsp - Package Owner=<4>
+Project: "pjmedia"=".\pjmedia\build\pjmedia.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pjmedia_codec"=".\pjmedia\build\pjmedia_codec.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pjnath"=".\pjnath\build\pjnath.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pjsip_core"=".\pjsip\build\pjsip_core.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pjsip_simple"=".\pjsip\build\pjsip_simple.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pjsip_ua"=".\pjsip\build\pjsip_ua.dsp" - Package Owner=<4>
 
 Package=<5>
@@ -270,9 +282,12 @@
     Project_Dep_Name libmilenage
     End Project Dependency
-}}}
-
-###############################################################################
-
-Project: "pjsua_lib"=.\pjsip\build\pjsua_lib.dsp - Package Owner=<4>
+    Begin Project Dependency
+    Project_Dep_Name libsrtp
+    End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "pjsua_lib"=".\pjsip\build\pjsua_lib.dsp" - Package Owner=<4>
 
 Package=<5>
@@ -394,5 +409,5 @@
 ###############################################################################
 
-Project: "test_pjsip"=.\pjsip\build\test_pjsip.dsp - Package Owner=<4>
+Project: "test_pjsip"=".\pjsip\build\test_pjsip.dsp" - Package Owner=<4>
 
 Package=<5>
Index: /pjproject/trunk/pjsip-apps/build/Samples-vc.mak
===================================================================
--- /pjproject/trunk/pjsip-apps/build/Samples-vc.mak	(revision 1734)
+++ /pjproject/trunk/pjsip-apps/build/Samples-vc.mak	(revision 1735)
@@ -24,7 +24,8 @@
 RESAMPLE_LIB = ..\..\third_party\lib\libresample-$(TARGET)$(LIBEXT)
 SPEEX_LIB = ..\..\third_party\lib\libspeex-$(TARGET)$(LIBEXT)
+SRTP_LIB = ..\..\third_party\lib\libsrtp-$(TARGET)$(LIBEXT)
 
 THIRD_PARTY_LIBS = $(GSM_LIB) $(ILBC_LIB) $(PORTAUDIO_LIB) $(RESAMPLE_LIB) \
-				   $(SPEEX_LIB)
+				   $(SPEEX_LIB) $(SRTP_LIB)
 
 LIBS = $(PJSUA_LIB_LIB) $(PJSIP_UA_LIB) $(PJSIP_SIMPLE_LIB) \
Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 1734)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 1735)
@@ -121,4 +121,7 @@
     puts  ("SIP Account options:");
     puts  ("  --use-ims           Enable 3GPP/IMS related settings on this account");
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    puts  ("  --use-srtp=N        Use SRTP N= 0: disabled, 1: optional, 2: mandatory");
+#endif
     puts  ("  --registrar=url     Set the URL of registrar server");
     puts  ("  --id=url            Set the URL of local ID (used in From header)");
@@ -383,5 +386,5 @@
 	   OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
 	   OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_AUTO_PLAY, OPT_AUTO_LOOP,
-	   OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_USE_ICE,
+	   OPT_AUTO_CONF, OPT_CLOCK_RATE, OPT_USE_ICE, OPT_USE_SRTP,
 	   OPT_PLAY_FILE, OPT_PLAY_TONE, OPT_RTP_PORT, OPT_ADD_CODEC, 
 	   OPT_ILBC_MODE, OPT_REC_FILE, OPT_AUTO_REC,
@@ -442,4 +445,7 @@
 	{ "rtp-port",	1, 0, OPT_RTP_PORT},
 	{ "use-ice",    0, 0, OPT_USE_ICE},
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	{ "use-srtp",   1, 0, OPT_USE_SRTP},
+#endif
 	{ "add-codec",  1, 0, OPT_ADD_CODEC},
 	{ "dis-codec",  1, 0, OPT_DIS_CODEC},
@@ -797,4 +803,14 @@
 	    break;
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	case OPT_USE_SRTP:
+	    app_config.cfg.use_srtp = my_atoi(pj_optarg);
+	    if (!pj_isdigit(*pj_optarg) || app_config.cfg.use_srtp > 2) {
+		PJ_LOG(1,(THIS_FILE, "Invalid value for --use-srtp option"));
+		return -1;
+	    }
+	    break;
+#endif
+
 	case OPT_RTP_PORT:
 	    cfg->rtp_cfg.port = my_atoi(pj_optarg);
@@ -1111,4 +1127,13 @@
 	pj_strcat2(result, line);
     }
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* SRTP */
+    if (acc_cfg->use_srtp) {
+	pj_ansi_sprintf(line, "--use-srtp %i\n",
+			(int)acc_cfg->use_srtp);
+	pj_strcat2(result, line);
+    }
+#endif
 
     /* Proxy */
Index: /pjproject/trunk/pjsip-apps/src/samples/simpleua.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/simpleua.c	(revision 1734)
+++ /pjproject/trunk/pjsip-apps/src/samples/simpleua.c	(revision 1735)
@@ -286,11 +286,5 @@
      * the SDP).
      */
-    {
-	pjmedia_transport_udp_info udp_info;
-
-	pjmedia_transport_udp_get_info(g_med_transport, &udp_info);
-	pj_memcpy(&g_med_skinfo, &udp_info.skinfo, 
-		  sizeof(pjmedia_sock_info));
-    }
+    pjmedia_transport_get_info(g_med_transport, &g_med_skinfo);
 
 
Index: /pjproject/trunk/pjsip-apps/src/samples/siprtp.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 1734)
+++ /pjproject/trunk/pjsip-apps/src/samples/siprtp.c	(revision 1735)
@@ -1006,5 +1006,5 @@
     pjmedia_sdp_media *m;
     pjmedia_sdp_attr *attr;
-    pjmedia_transport_udp_info tpinfo;
+    pjmedia_sock_info tpinfo;
     struct media_stream *audio = &call->media[0];
 
@@ -1013,5 +1013,5 @@
 
     /* Get transport info */
-    pjmedia_transport_udp_get_info(audio->transport, &tpinfo);
+    pjmedia_transport_get_info(audio->transport, &tpinfo);
 
     /* Create and initialize basic SDP session */
@@ -1047,5 +1047,5 @@
     /* Standard media info: */
     m->desc.media = pj_str("audio");
-    m->desc.port = pj_ntohs(tpinfo.skinfo.rtp_addr_name.ipv4.sin_port);
+    m->desc.port = pj_ntohs(tpinfo.rtp_addr_name.ipv4.sin_port);
     m->desc.port_count = 1;
     m->desc.transport = pj_str("RTP/AVP");
Index: /pjproject/trunk/pjsip-apps/src/samples/streamutil.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/streamutil.c	(revision 1734)
+++ /pjproject/trunk/pjsip-apps/src/samples/streamutil.c	(revision 1735)
@@ -56,4 +56,15 @@
  "  --send-only           Set stream direction to send only		\n"
  "  --recv-only           Set stream direction to recv only (default)   \n"
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ "  --use-srtp[=NAME]     Enable SRTP with crypto suite NAME            \n"
+ "                        e.g: AES_CM_128_HMAC_SHA1_80 (default),       \n"
+ "                             AES_CM_128_HMAC_SHA1_32                  \n"
+ "                        Use this option along with the TX & RX keys,  \n"
+ "                        formated of 60 hex digits (e.g: E148DA..)      \n"
+ "  --srtp-tx-key         SRTP key for transmiting                      \n"
+ "  --srtp-rx-key         SRTP key for receiving                        \n"
+#endif
+
  "\n"
 ;
@@ -65,4 +76,5 @@
 #include <pjmedia.h>
 #include <pjmedia-codec.h>
+#include <pjmedia/transport_srtp.h>
 
 #include <stdlib.h>	/* atoi() */
@@ -79,4 +91,6 @@
 static void print_stream_stat(pjmedia_stream *stream);
 
+/* Prototype for LIBSRTP utility in file datatypes.c */
+int hex_string_to_octet_string(char *raw, char *hex, int len);
 
 /* 
@@ -123,9 +137,18 @@
 				  pj_uint16_t local_port,
 				  const pj_sockaddr_in *rem_addr,
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+				  pj_bool_t use_srtp,
+				  const pj_str_t *crypto_suite,
+				  const pj_str_t *srtp_tx_key,
+				  const pj_str_t *srtp_rx_key,
+#endif
 				  pjmedia_stream **p_stream )
 {
     pjmedia_stream_info info;
-    pjmedia_transport *transport;
+    pjmedia_transport *transport = NULL;
     pj_status_t status;
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    pjmedia_transport *srtp_tp = NULL;
+#endif
 
 
@@ -159,4 +182,29 @@
 	return status;
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* Check if SRTP enabled */
+    if (use_srtp) {
+	pjmedia_srtp_crypto tx_plc, rx_plc;
+
+	status = pjmedia_transport_srtp_create(med_endpt, transport, 
+					       NULL, &srtp_tp);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
+	pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
+
+	tx_plc.key = *srtp_tx_key;
+	tx_plc.name = *crypto_suite;
+	rx_plc.key = *srtp_rx_key;
+	rx_plc.name = *crypto_suite;
+	
+	status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	transport = srtp_tp;
+    }
+#endif
 
     /* Now that the stream info is initialized, we can create the 
@@ -165,9 +213,10 @@
 
     status = pjmedia_stream_create( med_endpt, pool, &info, 
-				    transport, NULL, p_stream);
+				    transport, 
+				    NULL, p_stream);
 
     if (status != PJ_SUCCESS) {
 	app_perror(THIS_FILE, "Error creating stream", status);
-	pjmedia_transport_udp_close(transport);
+	pjmedia_transport_close(transport);
 	return status;
     }
@@ -202,4 +251,14 @@
     pj_status_t status; 
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* SRTP variables */
+    pj_bool_t use_srtp = PJ_FALSE;
+    char tmp_tx_key[64];
+    char tmp_rx_key[64];
+    pj_str_t  srtp_tx_key = {NULL, 0};
+    pj_str_t  srtp_rx_key = {NULL, 0};
+    pj_str_t  srtp_crypto_suite = {NULL, 0};
+    int	tmp_key_len;
+#endif
 
     /* Default values */
@@ -221,4 +280,9 @@
 	OPT_SEND_ONLY	= 's',
 	OPT_RECV_ONLY	= 'i',
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	OPT_USE_SRTP	= 'S',
+#endif
+	OPT_SRTP_TX_KEY	= 'x',
+	OPT_SRTP_RX_KEY	= 'y',
 	OPT_HELP	= 'h',
     };
@@ -233,4 +297,9 @@
 	{ "send-only",      0, 0, OPT_SEND_ONLY },
 	{ "recv-only",      0, 0, OPT_RECV_ONLY },
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	{ "use-srtp",	    2, 0, OPT_USE_SRTP },
+	{ "srtp-tx-key",    1, 0, OPT_SRTP_TX_KEY },
+	{ "srtp-rx-key",    1, 0, OPT_SRTP_RX_KEY },
+#endif
 	{ "help",	    0, 0, OPT_HELP },
 	{ NULL, 0, 0, 0 },
@@ -299,4 +368,25 @@
 	    break;
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+	case OPT_USE_SRTP:
+	    use_srtp = PJ_TRUE;
+	    if (pj_optarg) {
+		pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
+	    } else {
+		srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
+	    }
+	    break;
+
+	case OPT_SRTP_TX_KEY:
+	    tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg, strlen(pj_optarg));
+	    pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
+	    break;
+
+	case OPT_SRTP_RX_KEY:
+	    tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg, strlen(pj_optarg));
+	    pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
+	    break;
+#endif
+
 	case OPT_HELP:
 	    usage();
@@ -324,4 +414,14 @@
     }
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* SRTP validation */
+    if (use_srtp) {
+	if (!srtp_tx_key.slen || !srtp_rx_key.slen)
+	{
+	    printf("Error: Key for each SRTP stream direction must be set\n");
+	    return 1;
+	}
+    }
+#endif
 
     /* Must create a pool factory before we can allocate any memory. */
@@ -369,5 +469,10 @@
     /* Create stream based on program arguments */
     status = create_stream(pool, med_endpt, codec_info, dir, local_port, 
-			   &remote_addr, &stream);
+			   &remote_addr, 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+			   use_srtp, &srtp_crypto_suite, 
+			   &srtp_tx_key, &srtp_rx_key,
+#endif
+			   &stream);
     if (status != PJ_SUCCESS)
 	goto on_exit;
@@ -538,5 +643,6 @@
 	tp = pjmedia_stream_get_transport(stream);
 	pjmedia_stream_destroy(stream);
-	pjmedia_transport_udp_close(tp);
+	
+	pjmedia_transport_close(tp);
     }
 
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 1734)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 1735)
@@ -404,5 +404,26 @@
 #endif
 
-
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+
+/**
+ * Default value of SRTP mode usage. Valid values are PJMEDIA_SRTP_DISABLED, 
+ * PJMEDIA_SRTP_OPTIONAL, and PJMEDIA_SRTP_MANDATORY.
+ */
+#ifndef PJSUA_DEFAULT_USE_SRTP
+    #define PJSUA_DEFAULT_USE_SRTP  PJMEDIA_SRTP_DISABLED
+#endif
+
+/**
+ * Default value of secure signaling requirement for SRTP.
+ * Valid values are:
+ *	0: SRTP does not require secure signaling
+ *	1: SRTP requires secure transport such as TLS
+ *	2: SRTP requires secure end-to-end transport (SIPS)
+ */
+#ifndef PJSUA_DEFAULT_SRTP_SECURE_SIGNALING
+    #define PJSUA_DEFAULT_SRTP_SECURE_SIGNALING 1
+#endif
+
+#endif
 
 /**
@@ -1035,4 +1056,34 @@
     pj_str_t	    user_agent;
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /**
+     * Specify default value of secure media transport usage. 
+     * Valid values are PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, and
+     * PJMEDIA_SRTP_MANDATORY.
+     *
+     * Note that this setting can be further customized in account 
+     * configuration (#pjsua_acc_config).
+     *
+     * Default: #PJSUA_DEFAULT_USE_SRTP
+     */
+    pjmedia_srtp_use	use_srtp;
+
+    /**
+     * Specify whether SRTP requires secure signaling to be used. This option
+     * is only used when \a use_srtp option above is non-zero.
+     *
+     * Valid values are:
+     *	0: SRTP does not require secure signaling
+     *	1: SRTP requires secure transport such as TLS
+     *	2: SRTP requires secure end-to-end transport (SIPS)
+     *
+     * Note that this setting can be further customized in account 
+     * configuration (#pjsua_acc_config).
+     *
+     * Default: #PJSUA_DEFAULT_SRTP_SECURE_SIGNALING
+     */
+    int		     srtp_secure_signaling;
+#endif
+
 } pjsua_config;
 
@@ -1971,4 +2022,28 @@
      */
     pj_str_t	     ka_data;
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /**
+     * Specify whether secure media transport should be used for this account.
+     * Valid values are PJMEDIA_SRTP_DISABLED, PJMEDIA_SRTP_OPTIONAL, and
+     * PJMEDIA_SRTP_MANDATORY.
+     *
+     * Default: #PJSUA_DEFAULT_USE_SRTP
+     */
+    pjmedia_srtp_use	use_srtp;
+
+    /**
+     * Specify whether SRTP requires secure signaling to be used. This option
+     * is only used when \a use_srtp option above is non-zero.
+     *
+     * Valid values are:
+     *	0: SRTP does not require secure signaling
+     *	1: SRTP requires secure transport such as TLS
+     *	2: SRTP requires secure end-to-end transport (SIPS)
+     *
+     * Default: #PJSUA_DEFAULT_SRTP_SECURE_SIGNALING
+     */
+    int		     srtp_secure_signaling;
+#endif
 
 } pjsua_acc_config;
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 1734)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 1735)
@@ -51,5 +51,6 @@
     pjsip_evsub		*xfer_sub;  /**< Xfer server subscription, if this
 					 call was triggered by xfer.	    */
-    pjmedia_transport	*med_tp;    /**< Media transport.		    */
+    pjmedia_transport	*med_tp;    /**< Current media transport.	    */
+    pjmedia_transport	*med_orig;  /**< Original media transport	    */
     pj_timer_entry	 refresh_tm;/**< Timer to send re-INVITE.	    */
     pj_timer_entry	 hangup_tm; /**< Timer to hangup call.		    */
@@ -314,10 +315,12 @@
  */
 pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
-				    pjsip_role_e role);
+				     pjsip_role_e role,
+				     int security_level);
 pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, 
 					   pj_pool_t *pool,
+					   const pjmedia_sdp_session *rem_sdp,
 					   pjmedia_sdp_session **p_sdp);
 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
-				       const pjmedia_sdp_session *local_sdp,
+				       pjmedia_sdp_session *local_sdp,
 				       const pjmedia_sdp_session *remote_sdp);
 pj_status_t pjsua_media_channel_deinit(pjsua_call_id call_id);
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 1734)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 1735)
@@ -256,4 +256,42 @@
 }
 
+static pj_bool_t pj_stristr(const pj_str_t *str, const pj_str_t *substr)
+{
+    int i;
+
+    for (i=0; i<(str->slen-substr->slen); ++i) {
+	pj_str_t s;
+	s.ptr = str->ptr+i;
+	s.slen = substr->slen;
+
+	if (pj_stricmp(&s, substr)==0)
+	    return PJ_TRUE;
+    }
+    return PJ_FALSE;
+}
+
+/* Get signaling secure level.
+ * Return:
+ *  0: if signaling is not secure
+ *  1: if TLS transport is used for immediate hop
+ *  2: if end-to-end signaling is secure.
+ *
+ * NOTE:
+ *  THIS IS WRONG. It should take into account the route-set.
+ */
+static int get_secure_level(const pj_str_t *dst_uri)
+{
+    const pj_str_t tls = pj_str(";transport=tls");
+    const pj_str_t sips = pj_str("sips:");
+
+    PJ_TODO(Fix_get_secure_level);
+
+    if (pj_stristr(dst_uri, &sips))
+	return 2;
+    if (pj_stristr(dst_uri, &tls))
+	return 1;
+    return 0;
+}
+
 /*
  * Make outgoing call to the specified URI using the specified account.
@@ -363,5 +401,6 @@
 
     /* Init media channel */
-    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC);
+    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC, 
+				      get_secure_level(dest_uri));
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Error initializing media channel", status);
@@ -373,5 +412,5 @@
     offer = NULL;
 #else
-    status = pjsua_media_channel_create_sdp(call->index, dlg->pool, &offer);
+    status = pjsua_media_channel_create_sdp(call->index, dlg->pool, NULL, &offer);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "pjmedia unable to create SDP", status);
@@ -520,5 +559,6 @@
     pjsua_call *call;
     int call_id = -1;
-    pjmedia_sdp_session *answer;
+    int secure_level;
+    pjmedia_sdp_session *offer, *answer;
     pj_status_t status;
 
@@ -615,25 +655,4 @@
     }
 
-
-    /* Init media channel */
-    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS);
-    if (status != PJ_SUCCESS) {
-	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
-				      NULL, NULL);
-	PJSUA_UNLOCK();
-	return PJ_TRUE;
-    }
-
-
-    /* Get media capability from media endpoint: */
-    status = pjsua_media_channel_create_sdp(call->index, rdata->tp_info.pool, &answer);
-    if (status != PJ_SUCCESS) {
-	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
-				      NULL, NULL);
-	pjsua_media_channel_deinit(call->index);
-	PJSUA_UNLOCK();
-	return PJ_TRUE;
-    }
-
     /* 
      * Get which account is most likely to be associated with this incoming
@@ -643,4 +662,70 @@
     acc_id = call->acc_id = pjsua_acc_find_for_incoming(rdata);
 
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* Get signaling security level, only when required by SRTP */
+    if (pjsua_var.acc[acc_id].cfg.srtp_secure_signaling < 2) {
+	secure_level = PJSIP_TRANSPORT_IS_SECURE(rdata->tp_info.transport)!=0;
+    } else 
+#endif
+
+    {
+	char *uri;
+	int uri_len;
+	pj_str_t dst;
+
+	uri = pj_pool_alloc(rdata->tp_info.pool, PJSIP_MAX_URL_SIZE);
+	uri_len = pjsip_uri_print(PJSIP_URI_IN_REQ_URI,
+				  rdata->msg_info.msg->line.req.uri,
+				  uri, PJSIP_MAX_URL_SIZE);
+	if (uri_len < 1) {
+	    pjsua_perror(THIS_FILE, "Error analyzing dst URI", 
+			 PJSIP_EURITOOLONG);
+	    uri_len = 0;
+	}
+
+	dst.ptr = uri;
+	dst.slen = uri_len;
+
+	secure_level = get_secure_level(&dst);
+    }
+
+    /* Init media channel */
+    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS, 
+				      secure_level);
+    if (status != PJ_SUCCESS) {
+	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
+				      NULL, NULL);
+	PJSUA_UNLOCK();
+	return PJ_TRUE;
+    }
+
+    /* Parse SDP from incoming request */
+    if (rdata->msg_info.msg->body) {
+	status = pjmedia_sdp_parse(rdata->tp_info.pool, 
+				   rdata->msg_info.msg->body->data,
+				   rdata->msg_info.msg->body->len, &offer);
+	if (status != PJ_SUCCESS) {
+	    pjsua_perror(THIS_FILE, "Error parsing SDP in incoming INVITE", status);
+	    pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 400, NULL,
+					  NULL, NULL);
+	    pjsua_media_channel_deinit(call->index);
+	    PJSUA_UNLOCK();
+	    return PJ_TRUE;
+	}
+    } else {
+	offer = NULL;
+    }
+
+    /* Get media capability from media endpoint: */
+    status = pjsua_media_channel_create_sdp(call->index, rdata->tp_info.pool, 
+					    offer, &answer);
+    if (status != PJ_SUCCESS) {
+	pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL,
+				      NULL, NULL);
+	pjsua_media_channel_deinit(call->index);
+	PJSUA_UNLOCK();
+	return PJ_TRUE;
+    }
+
     /* Verify that we can handle the request. */
     options |= PJSIP_INV_SUPPORT_100REL;
@@ -648,6 +733,6 @@
 	options |= PJSIP_INV_REQUIRE_100REL;
 
-    status = pjsip_inv_verify_request(rdata, &options, answer, NULL,
-				      pjsua_var.endpt, &response);
+    status = pjsip_inv_verify_request2(rdata, &options, offer, answer, NULL,
+				       pjsua_var.endpt, &response);
     if (status != PJ_SUCCESS) {
 
@@ -1339,5 +1424,6 @@
 
     /* Init media channel */
-    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC);
+    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC,
+				      get_secure_level(&dlg->remote.info_str));
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Error initializing media channel", status);
@@ -1349,5 +1435,6 @@
     PJ_UNUSED_ARG(unhold);
     PJ_TODO(create_active_inactive_sdp_based_on_unhold_arg);
-    status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, &sdp);
+    status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, 
+					    NULL, &sdp);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint", 
@@ -1407,5 +1494,6 @@
 
     /* Init media channel */
-    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC);
+    status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC,
+				      get_secure_level(&dlg->remote.info_str));
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Error initializing media channel", status);
@@ -1415,5 +1503,6 @@
 
     /* Create SDP */
-    status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, &sdp);
+    status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, 
+					    NULL, &sdp);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint", 
@@ -2356,5 +2445,6 @@
 {
     pjsua_call *call;
-    const pjmedia_sdp_session *local_sdp;
+    const pjmedia_sdp_session *c_local;
+    pjmedia_sdp_session *local_sdp;
     const pjmedia_sdp_session *remote_sdp;
 
@@ -2385,5 +2475,5 @@
 
     /* Get local and remote SDP */
-    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp);
+    status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &c_local);
     if (status != PJ_SUCCESS) {
 	pjsua_perror(THIS_FILE, 
@@ -2394,4 +2484,5 @@
 	return;
     }
+    local_sdp = (pjmedia_sdp_session*) c_local;
 
     status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp);
@@ -2525,4 +2616,5 @@
 	status = create_inactive_sdp( call, &answer );
     } else {
+	int secure_level;
 
 	PJ_LOG(4,(THIS_FILE, "Call %d: received updated media offer",
@@ -2530,5 +2622,7 @@
 
 	/* Init media channel */
-	status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS);
+	secure_level = get_secure_level(&call->inv->dlg->remote.info_str);
+	status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAS,
+					  secure_level);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Error initializing media channel", status);
@@ -2537,5 +2631,6 @@
 	}
 
-	status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, &answer);
+	status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, 
+					        offer, &answer);
     }
 
@@ -2577,4 +2672,5 @@
 	status = create_inactive_sdp( call, offer );
     } else {
+	int secure_level;
 
 	PJ_LOG(4,(THIS_FILE, "Call %d: asked to send a new offer",
@@ -2582,5 +2678,7 @@
 
 	/* Init media channel */
-	status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC);
+	secure_level = get_secure_level(&call->inv->dlg->remote.info_str);
+	status = pjsua_media_channel_init(call->index, PJSIP_ROLE_UAC,
+					  secure_level);
 	if (status != PJ_SUCCESS) {
 	    pjsua_perror(THIS_FILE, "Error initializing media channel", status);
@@ -2589,5 +2687,6 @@
 	}
 
-	status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, offer);
+	status = pjsua_media_channel_create_sdp(call->index, call->inv->pool, 
+					        NULL, offer);
     }
 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 1734)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 1735)
@@ -88,4 +88,8 @@
     cfg->thread_cnt = 1;
     cfg->nat_type_in_sdp = 1;
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    cfg->use_srtp = PJSUA_DEFAULT_USE_SRTP;
+    cfg->srtp_secure_signaling = PJSUA_DEFAULT_SRTP_SECURE_SIGNALING;
+#endif
 }
 
@@ -143,4 +147,8 @@
     cfg->ka_interval = 15;
     cfg->ka_data = pj_str("\r\n");
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    cfg->use_srtp = pjsua_var.ua_cfg.use_srtp;
+    cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling;
+#endif
 }
 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1734)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 1735)
@@ -535,4 +535,5 @@
 	    goto on_error;
 	}
+
 	status = pjmedia_transport_udp_attach(pjsua_var.med_endpt, NULL,
 					      &skinfo, 0,
@@ -544,11 +545,11 @@
 	}
 
-	pjmedia_transport_udp_simulate_lost(pjsua_var.calls[i].med_tp,
-					    PJMEDIA_DIR_ENCODING,
-					    pjsua_var.media_cfg.tx_drop_pct);
-
-	pjmedia_transport_udp_simulate_lost(pjsua_var.calls[i].med_tp,
-					    PJMEDIA_DIR_DECODING,
-					    pjsua_var.media_cfg.rx_drop_pct);
+	pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp,
+					PJMEDIA_DIR_ENCODING,
+					pjsua_var.media_cfg.tx_drop_pct);
+
+	pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp,
+					PJMEDIA_DIR_DECODING,
+					pjsua_var.media_cfg.rx_drop_pct);
 
     }
@@ -646,11 +647,11 @@
 	}
 
-	pjmedia_ice_simulate_lost(pjsua_var.calls[i].med_tp,
-				  PJMEDIA_DIR_ENCODING,
-				  pjsua_var.media_cfg.tx_drop_pct);
-
-	pjmedia_ice_simulate_lost(pjsua_var.calls[i].med_tp,
-				  PJMEDIA_DIR_DECODING,
-				  pjsua_var.media_cfg.rx_drop_pct);
+	pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp,
+				        PJMEDIA_DIR_ENCODING,
+				        pjsua_var.media_cfg.tx_drop_pct);
+
+	pjmedia_transport_simulate_lost(pjsua_var.calls[i].med_tp,
+				        PJMEDIA_DIR_DECODING,
+				        pjsua_var.media_cfg.rx_drop_pct);
 
 	status = pjmedia_ice_start_init(pjsua_var.calls[i].med_tp, 0, &addr,
@@ -745,34 +746,17 @@
 
 pj_status_t pjsua_media_channel_init(pjsua_call_id call_id,
-				     pjsip_role_e role)
+				     pjsip_role_e role,
+				     int security_level)
 {
     pjsua_call *call = &pjsua_var.calls[call_id];
 
-    if (pjsua_var.media_cfg.enable_ice) {
-	pj_ice_sess_role ice_role;
-	pj_status_t status;
-
-	ice_role = (role==PJSIP_ROLE_UAC ? PJ_ICE_SESS_ROLE_CONTROLLING : 
-				           PJ_ICE_SESS_ROLE_CONTROLLED);
-
-	/* Restart ICE */
-	pjmedia_ice_stop_ice(call->med_tp);
-
-	status = pjmedia_ice_init_ice(call->med_tp, ice_role, NULL, NULL);
-	if (status != PJ_SUCCESS)
-	    return status;
-    }
-
-    return PJ_SUCCESS;
-}
-
-pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, 
-					   pj_pool_t *pool,
-					   pjmedia_sdp_session **p_sdp)
-{
-    pjmedia_sdp_session *sdp;
-    pjmedia_sock_info skinfo;
-    pjsua_call *call = &pjsua_var.calls[call_id];
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    pjsua_acc *acc = &pjsua_var.acc[call->acc_id];
+    pjmedia_srtp_setting srtp_opt;
+    pjmedia_transport *srtp;
     pj_status_t status;
+#endif
+
+    PJ_UNUSED_ARG(role);
 
     /* Return error if media transport has not been created yet
@@ -783,9 +767,59 @@
     }
 
+    /* Stop media transport (for good measure!) */
+    pjmedia_transport_media_stop(call->med_tp);
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+    /* Check if SRTP requires secure signaling */
+    if (acc->cfg.use_srtp != PJMEDIA_SRTP_DISABLED) {
+	if (security_level < acc->cfg.srtp_secure_signaling) {
+	    return PJSIP_ESESSIONINSECURE;
+	}
+    }
+
+    /* Always create SRTP adapter */
+    pjmedia_srtp_setting_default(&srtp_opt);
+    srtp_opt.close_member_tp = PJ_FALSE;
+    srtp_opt.use = acc->cfg.use_srtp;
+    status = pjmedia_transport_srtp_create(pjsua_var.med_endpt, 
+					   call->med_tp,
+					   &srtp_opt, &srtp);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Set SRTP as current media transport */
+    call->med_orig = call->med_tp;
+    call->med_tp = srtp;
+#else
+    call->med_orig = call->med_tp;
+    PJ_UNUSED_ARG(security_level);
+#endif
+
+    return PJ_SUCCESS;
+}
+
+pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, 
+					   pj_pool_t *pool,
+					   const pjmedia_sdp_session *rem_sdp,
+					   pjmedia_sdp_session **p_sdp)
+{
+    enum { MAX_MEDIA = 1, MEDIA_IDX = 0 };
+    pjmedia_sdp_session *sdp;
+    pjmedia_sock_info skinfo;
+    pjsua_call *call = &pjsua_var.calls[call_id];
+    pj_status_t status;
+
+    /* Return error if media transport has not been created yet
+     * (e.g. application is starting)
+     */
+    if (call->med_tp == NULL) {
+	return PJ_EBUSY;
+    }
+
     /* Get media socket info */
     pjmedia_transport_get_info(call->med_tp, &skinfo);
 
     /* Create SDP */
-    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, 1,
+    status = pjmedia_endpt_create_sdp(pjsua_var.med_endpt, pool, MAX_MEDIA,
 				      &skinfo, &sdp);
     if (status != PJ_SUCCESS)
@@ -816,9 +850,9 @@
     }
 
-    if (pjsua_var.media_cfg.enable_ice) {
-	status = pjmedia_ice_modify_sdp(call->med_tp, pool, sdp);
-	if (status != PJ_SUCCESS)
-	    goto on_error;
-    }
+    /* Give the SDP to media transport */
+    status = pjmedia_transport_media_create(call->med_tp, pool, 
+					    sdp, rem_sdp, MEDIA_IDX);
+    if (status != PJ_SUCCESS)
+	goto on_error;
 
     *p_sdp = sdp;
@@ -859,8 +893,10 @@
     stop_media_session(call_id);
 
-    if (pjsua_var.media_cfg.enable_ice) {
-	pjmedia_ice_stop_ice(call->med_tp);
-    }
-
+    pjmedia_transport_media_stop(call->med_tp);
+
+    if (call->med_tp != call->med_orig) {
+	pjmedia_transport_close(call->med_tp);
+	call->med_tp = call->med_orig;
+    }
     return PJ_SUCCESS;
 }
@@ -878,5 +914,5 @@
 	pjsua_call_id call_id;
 
-	call_id = (pjsua_call_id)user_data;
+	call_id = (pjsua_call_id)(long)user_data;
 	pjsua_var.ua_cfg.cb.on_dtmf_digit(call_id, digit);
     }
@@ -885,5 +921,5 @@
 
 pj_status_t pjsua_media_channel_update(pjsua_call_id call_id,
-				       const pjmedia_sdp_session *local_sdp,
+				       pjmedia_sdp_session *local_sdp,
 				       const pjmedia_sdp_session *remote_sdp)
 {
@@ -912,5 +948,6 @@
     for (i=0; i < sess_info.stream_cnt; ++i) {
 	if (sess_info.stream_info[i].type == PJMEDIA_TYPE_AUDIO &&
-	    sess_info.stream_info[i].proto == PJMEDIA_TP_PROTO_RTP_AVP)
+	    (sess_info.stream_info[i].proto == PJMEDIA_TP_PROTO_RTP_AVP ||
+	     sess_info.stream_info[i].proto == PJMEDIA_TP_PROTO_RTP_SAVP))
 	{
 	    si = &sess_info.stream_info[i];
@@ -946,19 +983,16 @@
 	call->media_dir = PJMEDIA_DIR_NONE;
 
-	/* Shutdown ICE session */
-	if (pjsua_var.media_cfg.enable_ice) {
-	    pjmedia_ice_stop_ice(call->med_tp);
-	}
+	/* Shutdown transport's session */
+	pjmedia_transport_media_stop(call->med_tp);
 
 	/* No need because we need keepalive? */
 
     } else {
-	/* Start ICE */
-	if (pjsua_var.media_cfg.enable_ice) {
-	    status = pjmedia_ice_start_ice(call->med_tp, call->inv->pool, 
-					   remote_sdp, 0);
-	    if (status != PJ_SUCCESS)
-		return status;
-	}
+	/* Start media transport */
+	status = pjmedia_transport_media_start(call->med_tp, 
+					       call->inv->pool,
+					       local_sdp, remote_sdp, 0);
+	if (status != PJ_SUCCESS)
+	    return status;
 
 	/* Override ptime, if this option is specified. */
@@ -1001,5 +1035,5 @@
 	    pjmedia_session_set_dtmf_callback(call->session, 0, 
 					      &dtmf_callback, 
-					      (void*)(call->index));
+					      (void*)(long)(call->index));
 	}
 
