Index: /pjproject/trunk/pjmedia/include/pjmedia/transport_srtp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport_srtp.h	(revision 5754)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport_srtp.h	(revision 5755)
@@ -191,10 +191,12 @@
 
     /**
-     * Specify the number of crypto suite settings.
+     * Specify the number of crypto suite settings. If set to zero, all
+     * available cryptos will be enabled. Default: zero.
      */
     unsigned			 crypto_count;
 
     /**
-     * Specify individual crypto suite setting.
+     * Specify individual crypto suite setting and its priority order.
+     *
      * Notes for DTLS-SRTP keying:
      *  - Currently only supports these cryptos: AES_CM_128_HMAC_SHA1_80,
@@ -205,6 +207,9 @@
 
     /**
-     * Specify the number of enabled keying methods.
-     * Default is PJMEDIA_SRTP_MAX_KEYINGS (all enabled).
+     * Specify the number of enabled keying methods. If set to zero, all
+     * keyings will be enabled. Maximum value is PJMEDIA_SRTP_MAX_KEYINGS.
+     *
+     * Default is zero (all keyings are enabled with priority order:
+     * SDES, DTLS-SRTP).
      */
     unsigned			 keying_count;
@@ -215,7 +220,4 @@
      * for example as currently only one keying is supported in the SDP offer,
      * keying with first priority will be likely used in the SDP offer.
-     *
-     * Default is that all supported keying methods (i.e: currently SDES and
-     * DTLS-SRTP) will be enabled and with priority order: SDES, DTLS-SRTP.
      */
     pjmedia_srtp_keying_method	 keying[PJMEDIA_SRTP_KEYINGS_COUNT];
@@ -321,4 +323,32 @@
  */
 PJ_DECL(void) pjmedia_srtp_setting_default(pjmedia_srtp_setting *opt);
+
+
+/**
+ * Enumerate available SRTP crypto name.
+ *
+ * @param count	    On input, specifies the maximum length of crypto
+ *		    array. On output, the number of available crypto
+ *		    initialized by this function.
+ * @param crypto    The SRTP crypto array output.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_srtp_enum_crypto(unsigned *count,
+					      pjmedia_srtp_crypto crypto[]);
+
+
+/**
+ * Enumerate available SRTP keying methods.
+ *
+ * @param count	    On input, specifies the maximum length of keying method
+ *		    array. On output, the number of available keying method
+ *		    initialized by this function.
+ * @param crypto    The SRTP keying method array output.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_srtp_enum_keying(unsigned *count,
+				      pjmedia_srtp_keying_method keying[]);
 
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5754)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5755)
@@ -610,6 +610,4 @@
 PJ_DEF(void) pjmedia_srtp_setting_default(pjmedia_srtp_setting *opt)
 {
-    unsigned i;
-
     pj_assert(opt);
 
@@ -617,17 +615,52 @@
     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);
-
-    /* Keying method */
-    opt->keying_count = PJMEDIA_SRTP_KEYINGS_COUNT;
-    opt->keying[0] = PJMEDIA_SRTP_KEYING_SDES;
-    opt->keying[1] = PJMEDIA_SRTP_KEYING_DTLS_SRTP;
-
-    /* Just for reminder to add any new keying to the array above */
-    pj_assert(PJMEDIA_SRTP_KEYINGS_COUNT == 2);
+}
+
+/*
+ * Enumerate all SRTP cryptos, except "NULL".
+ */
+PJ_DEF(pj_status_t) pjmedia_srtp_enum_crypto(unsigned *count,
+					     pjmedia_srtp_crypto crypto[])
+{
+    unsigned i, max;
+
+    PJ_ASSERT_RETURN(count && crypto, PJ_EINVAL);
+
+    max = sizeof(crypto_suites) / sizeof(crypto_suites[0]) - 1;
+    if (*count > max)
+	*count = max;
+
+    for (i=0; i<*count; ++i) {
+	pj_bzero(&crypto[i], sizeof(crypto[0]));
+	crypto[i].name = pj_str(crypto_suites[i+1].name);
+    }
+    
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Enumerate available SRTP keying methods.
+ */
+PJ_DEF(pj_status_t) pjmedia_srtp_enum_keying(unsigned *count,
+				      pjmedia_srtp_keying_method keying[])
+{
+    unsigned max;
+
+    PJ_ASSERT_RETURN(count && keying, PJ_EINVAL);
+
+    max = *count;
+    *count = 0;
+
+#if defined(PJMEDIA_SRTP_HAS_SDES) && (PJMEDIA_SRTP_HAS_SDES != 0)
+    if (*count < max)
+	keying[(*count)++] = PJMEDIA_SRTP_KEYING_SDES;
+#endif
+#if defined(PJMEDIA_SRTP_HAS_DTLS) && (PJMEDIA_SRTP_HAS_DTLS != 0)
+    if (*count < max)
+	keying[(*count)++] = PJMEDIA_SRTP_KEYING_DTLS_SRTP;
+#endif
+    
+    return PJ_SUCCESS;
 }
 
@@ -704,5 +737,15 @@
     }
 
-    status = pj_lock_create_recursive_mutex(pool, pool->obj_name, &srtp->mutex);
+    /* If crypto count is set to zero, setup default crypto-suites,
+     * i.e: all available crypto but 'NULL'.
+     */
+    if (srtp->setting.crypto_count == 0) {
+	srtp->setting.crypto_count = PJMEDIA_SRTP_MAX_CRYPTOS;
+	pjmedia_srtp_enum_crypto(&srtp->setting.crypto_count,
+				 srtp->setting.crypto);
+    }
+
+    status = pj_lock_create_recursive_mutex(pool, pool->obj_name,
+					    &srtp->mutex);
     if (status != PJ_SUCCESS) {
 	pj_pool_release(pool);
@@ -724,4 +767,11 @@
     /* Initialize peer's SRTP usage mode. */
     srtp->peer_use = srtp->setting.use;
+
+    /* If keying count set to zero, setup default keying count & priorities */
+    if (srtp->setting.keying_count == 0) {
+	srtp->setting.keying_count = PJMEDIA_SRTP_KEYINGS_COUNT;
+	pjmedia_srtp_enum_keying(&srtp->setting.keying_count,
+				 srtp->setting.keying);
+    }
 
     /* Initialize SRTP keying method. */
@@ -1414,7 +1464,13 @@
 
     if (srtp->offerer_side && srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+	/* If we are offerer and SRTP is disabled, simply bypass SRTP and
+	 * skip keying.
+	 */
 	srtp->bypass_srtp = PJ_TRUE;
 	srtp->keying_cnt = 0;
     } else {
+	/* If we are answerer and SRTP is disabled, we need to verify that
+	 * SRTP is disabled too in remote SDP, so we can't just skip keying.
+	 */
 	srtp->bypass_srtp = PJ_FALSE;
 	srtp->keying_cnt = srtp->all_keying_cnt;
@@ -1431,5 +1487,17 @@
 	return status;
 
-    /* Invoke media_create() of all keying methods */
+    /* Invoke media_create() of all keying methods, keying actions for each
+     * SRTP mode:
+     * - DISABLED:
+     *   - as offerer, nothing (keying is skipped).
+     *   - as answerer, verify remote SDP, make sure it has SRTP disabled too,
+     *     if not, return error.
+     * - OPTIONAL:
+     *   - as offerer, general initialization.
+     *   - as answerer, optionally verify SRTP attr in remote SDP (if any).
+     * - MANDATORY:
+     *   - as offerer, general initialization.
+     *   - as answerer, verify SRTP attr in remote SDP.
+     */
     for (i=0; i < srtp->keying_cnt; ) {
 	pj_status_t st;
@@ -1458,4 +1526,12 @@
 	return keying_status;
 
+    /* Bypass SRTP & skip keying as SRTP is disabled and verification on
+     * remote SDP has been done.
+     */
+    if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+	srtp->bypass_srtp = PJ_TRUE;
+	srtp->keying_cnt = 0;
+    }
+
     return PJ_SUCCESS;
 }
@@ -1484,5 +1560,19 @@
 	return status;
 
-    /* Invoke encode_sdp() of all keying methods */
+    /* Invoke encode_sdp() of all keying methods, keying actions for each
+     * SRTP mode:
+     * - DISABLED: nothing (keying is skipped)
+     * - OPTIONAL:
+     *   - as offerer, generate offer.
+     *   - as answerer, if remote has the same SRTP keying in SDP, verify it,
+     *     generate answer, start crypto nego.
+     * - MANDATORY:
+     *   - as offerer, generate offer.
+     *   - as answerer, verify remote SDP, generate answer, start crypto nego.
+     *
+     * Note: because the SDP will be processed by other keying/components,
+     *       keying must do verification on remote SDP first (e.g: keying
+     *       is being used) before touching local SDP.
+     */
     for (i=0; i < srtp->keying_cnt; ) {
 	pj_status_t st;
@@ -1544,5 +1634,17 @@
 	return status;
 
-    /* Invoke media_start() of all keying methods */
+    /* Invoke media_start() of all keying methods, keying actions for each
+     * SRTP mode:
+     * - DISABLED: nothing (keying is skipped)
+     * - OPTIONAL:
+     *   - as offerer, if remote answer has the same SRTP keying in SDP,
+     *     verify it and start crypto nego.
+     *   - as answerer, start crypto nego if not yet (usually initated in
+     *     encode_sdp()).
+     * - MANDATORY:
+     *   - as offerer, verify remote answer and start crypto nego.
+     *   - as answerer, start crypto nego if not yet (usually initated in
+     *     encode_sdp()).
+     */
     for (i=0; i < srtp->keying_cnt; ) {
 	status = pjmedia_transport_media_start(srtp->keying[i], pool,
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_dtls.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_dtls.c	(revision 5754)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_dtls.c	(revision 5755)
@@ -1016,4 +1016,5 @@
 	 */
 	pjmedia_sdp_media *m_rem = sdp_remote->media[media_index];
+	pjmedia_sdp_attr *attr_setup;
 
 	if (pj_stricmp(&m_rem->desc.transport, &ID_TP_DTLS_SRTP)!=0) {
@@ -1021,4 +1022,22 @@
 	    status = PJMEDIA_SRTP_ESDPINTRANSPORT;
 	    goto on_return;
+	}
+
+	/* Check for a=setup in remote SDP. */
+	attr_setup = pjmedia_sdp_media_find_attr(m_rem, &ID_SETUP, NULL);
+	if (!attr_setup)
+	    attr_setup = pjmedia_sdp_attr_find(sdp_remote->attr_count,
+				      sdp_remote->attr, &ID_SETUP, NULL);
+	switch (ds->srtp->setting.use) {
+	    case PJMEDIA_SRTP_DISABLED:
+		if (attr_setup)
+		    return PJMEDIA_SRTP_ESDPINTRANSPORT;
+		break;
+	    case PJMEDIA_SRTP_OPTIONAL:
+		break;
+	    case PJMEDIA_SRTP_MANDATORY:
+		if (!attr_setup)
+		    return PJMEDIA_SRTP_ESDPINTRANSPORT;
+		break;
 	}
     }
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_sdes.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_sdes.c	(revision 5754)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_sdes.c	(revision 5755)
@@ -278,4 +278,14 @@
     PJ_UNUSED_ARG(sdp_pool);
 
+    /* Verify remote media transport, it has to be RTP/AVP or RTP/SAVP */
+    if (!srtp->offerer_side) {
+	pjmedia_sdp_media *m = sdp_remote->media[media_index];
+	if (pj_stricmp(&m->desc.transport, &ID_RTP_AVP)  != 0 &&
+	    pj_stricmp(&m->desc.transport, &ID_RTP_SAVP) != 0)
+	{
+	    return PJMEDIA_SRTP_ESDPINTRANSPORT;
+	}
+    }
+
     /* Validations */
     if (srtp->offerer_side) {
@@ -284,8 +294,4 @@
 	pjmedia_sdp_media *m_rem = sdp_remote->media[media_index];
 
-	/* Nothing to do on inactive media stream */
-	if (pjmedia_sdp_media_find_attr(m_rem, &ID_INACTIVE, NULL))
-	    srtp->bypass_srtp = PJ_TRUE;
-
 	/* Validate remote media transport based on SRTP usage option. */
 	switch (srtp->setting.use) {
@@ -293,5 +299,4 @@
 		if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
 		    return PJMEDIA_SRTP_ESDPINTRANSPORT;
-		srtp->bypass_srtp = PJ_TRUE;
 		break;
 	    case PJMEDIA_SRTP_OPTIONAL:
@@ -326,9 +331,12 @@
     m_loc = sdp_local->media[media_index];
 
-    /* Bypass SDES 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)
+    /* Verify media transport, it has to be RTP/AVP or RTP/SAVP */
     {
-	return PJ_SUCCESS;
+	pjmedia_sdp_media *m = sdp_remote? m_rem : m_loc;
+	if (pj_stricmp(&m->desc.transport, &ID_RTP_AVP)  != 0 &&
+	    pj_stricmp(&m->desc.transport, &ID_RTP_SAVP) != 0)
+	{
+	    return PJMEDIA_SRTP_ESDPINTRANSPORT;
+	}
     }
 
@@ -353,5 +361,5 @@
 	switch (srtp->setting.use) {
 	    case PJMEDIA_SRTP_DISABLED:
-		pj_assert(!"Shouldn't reach here");
+		/* Should never reach here */
 		return PJ_SUCCESS;
 	    case PJMEDIA_SRTP_OPTIONAL:
@@ -407,14 +415,13 @@
 	switch (srtp->setting.use) {
 	    case PJMEDIA_SRTP_DISABLED:
+		/* Should never reach here */
 		if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
 		    return PJMEDIA_SRTP_ESDPINTRANSPORT;
 		return PJ_SUCCESS;
 	    case PJMEDIA_SRTP_OPTIONAL:
-		m_loc->desc.transport = m_rem->desc.transport;
 		break;
 	    case PJMEDIA_SRTP_MANDATORY:
 		if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0)
 		    return PJMEDIA_SRTP_ESDPINTRANSPORT;
-		m_loc->desc.transport = ID_RTP_SAVP;
 		break;
 	}
@@ -480,5 +487,5 @@
 	    switch (srtp->setting.use) {
 		case PJMEDIA_SRTP_DISABLED:
-		    pj_assert(!"Should never reach here");
+		    /* Should never reach here */
 		    break;
 
@@ -536,4 +543,7 @@
 	    /* At this point, we get valid rx_policy_neg & tx_policy_neg. */
 	}
+
+	/* Update transport description in local media SDP */
+	m_loc->desc.transport = m_rem->desc.transport;
     }
 
@@ -590,7 +600,19 @@
     pjmedia_srtp_crypto	loc_crypto[PJMEDIA_SRTP_MAX_CRYPTOS];
     int loc_cryto_cnt = PJMEDIA_SRTP_MAX_CRYPTOS;
+    pjmedia_srtp_crypto tmp_tx_crypto;
+    pj_bool_t has_crypto_attr = PJ_FALSE;
+    int rem_tag;
+    int j;
+
 
     m_rem = sdp_remote->media[media_index];
     m_loc = sdp_local->media[media_index];
+
+    /* Verify media transport, it has to be RTP/AVP or RTP/SAVP */
+    if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_AVP)  != 0 &&
+	pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) != 0)
+    {
+	return PJMEDIA_SRTP_ESDPINTRANSPORT;
+    }
 
     if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
@@ -599,106 +621,101 @@
 	srtp->peer_use = PJMEDIA_SRTP_OPTIONAL;
 
-    /* For answerer side, this function will just have to start SRTP */
+    /* For answerer side, this function will just have to start SRTP as
+     * SRTP crypto policies have been populated in media_encode_sdp().
+     */
+    if (!srtp->offerer_side)
+	return PJ_SUCCESS;
 
     /* 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;
-	    }
+    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;
+	}
+	return PJ_SUCCESS;
+    } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
+	// Regardless the answer's transport type (RTP/AVP or RTP/SAVP),
+	// the answer must be processed through in optional mode.
+	// Please note that at this point transport type is ensured to be
+	// RTP/AVP or RTP/SAVP, see sdes_media_create()
+	//if (pj_stricmp(&m_rem->desc.transport, &m_loc->desc.transport)) {
+	    //DEACTIVATE_MEDIA(pool, m_loc);
+	    //return PJMEDIA_SDP_EINPROTO;
+	//}
+	fill_local_crypto(srtp->pool, m_loc, loc_crypto, &loc_cryto_cnt);
+    } 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;
+	}
+	fill_local_crypto(srtp->pool, m_loc, loc_crypto, &loc_cryto_cnt);
+    }
+
+    /* find supported crypto-suite, get the tag, and assign policy_local */
+    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;
+
+
+	/* Tag range check, our tags in the offer must be in the SRTP 
+	 * setting range, so does the remote answer's. The remote answer's 
+	 * tag must not exceed the tag range of the local offer.
+	 */
+	if (rem_tag < 1 || rem_tag > (int)srtp->setting.crypto_count ||
+	    rem_tag > loc_cryto_cnt) 
+	{
+	    DEACTIVATE_MEDIA(pool, m_loc);
+	    return PJMEDIA_SRTP_ESDPINCRYPTOTAG;
+	}
+
+	/* match the crypto name */
+	if (pj_stricmp(&tmp_tx_crypto.name, &loc_crypto[rem_tag-1].name))
+	{
+	    DEACTIVATE_MEDIA(pool, m_loc);
+	    return PJMEDIA_SRTP_ECRYPTONOTMATCH;
+	}
+
+	/* Find the crypto from the setting. */
+	for (j = 0; j < (int)srtp->setting.crypto_count; ++j) {
+	    if (pj_stricmp(&tmp_tx_crypto.name, 
+			   &srtp->setting.crypto[j].name) == 0) 
+	    {
+		srtp->tx_policy_neg = srtp->setting.crypto[j];
+		break;
+	    }		
+	}
+
+	srtp->rx_policy_neg = tmp_tx_crypto;
+    }
+
+    if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
+	/* should never reach here */
+	return PJ_SUCCESS;
+    } else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
+	if (!has_crypto_attr)
 	    return PJ_SUCCESS;
-	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
-	    // Regardless the answer's transport type (RTP/AVP or RTP/SAVP),
-	    // the answer must be processed through in optional mode.
-	    // Please note that at this point transport type is ensured to be
-	    // RTP/AVP or RTP/SAVP, see sdes_media_create()
-	    //if (pj_stricmp(&m_rem->desc.transport, &m_loc->desc.transport)) {
-		//DEACTIVATE_MEDIA(pool, m_loc);
-		//return PJMEDIA_SDP_EINPROTO;
-	    //}
-	    fill_local_crypto(srtp->pool, m_loc, loc_crypto, &loc_cryto_cnt);
-	} 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;
-	    }
-	    fill_local_crypto(srtp->pool, m_loc, loc_crypto, &loc_cryto_cnt);
-	}
-    }
-
-    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;
-	int j;
-
-	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;
-
-
-	    /* Tag range check, our tags in the offer must be in the SRTP 
-	     * setting range, so does the remote answer's. The remote answer's 
-	     * tag must not exceed the tag range of the local offer.
-	     */
-	    if (rem_tag < 1 || rem_tag > (int)srtp->setting.crypto_count ||
-		rem_tag > loc_cryto_cnt) 
-	    {
-		DEACTIVATE_MEDIA(pool, m_loc);
-		return PJMEDIA_SRTP_ESDPINCRYPTOTAG;
-	    }
-
-	    /* match the crypto name */
-	    if (pj_stricmp(&tmp_tx_crypto.name, &loc_crypto[rem_tag-1].name))
-	    {
-		DEACTIVATE_MEDIA(pool, m_loc);
-		return PJMEDIA_SRTP_ECRYPTONOTMATCH;
-	    }
-
-	    /* Find the crypto from the setting. */
-	    for (j = 0; j < (int)srtp->setting.crypto_count; ++j) {
-		if (pj_stricmp(&tmp_tx_crypto.name, 
-			       &srtp->setting.crypto[j].name) == 0) 
-		{
-		    srtp->tx_policy_neg = srtp->setting.crypto[j];
-		    break;
-		}		
-	    }
-
-	    srtp->rx_policy_neg = tmp_tx_crypto;
-	}
-
-	if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
-	    /* should never reach here */
-	    return PJ_SUCCESS;
-	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
-	    if (!has_crypto_attr)
-		return PJ_SUCCESS;
-	} 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 get valid rx_policy_neg & tx_policy_neg. */
-    }
+    } 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 get valid rx_policy_neg & tx_policy_neg. */
 
     return PJ_SUCCESS;
Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 5754)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 5755)
@@ -1011,23 +1011,4 @@
 }
 
-/*
- * This callback is called when media transport SRTP needs to be created.
- */
-static void on_create_media_transport_srtp(pjsua_call_id call_id,
-					   unsigned media_idx,
-					   pjmedia_srtp_setting *srtp_opt)
-{
-    PJ_UNUSED_ARG(call_id);
-    PJ_UNUSED_ARG(media_idx);
-
-    /* Set SRTP keying to use DTLS over SDES */
-    if (app_config.srtp_keying == 1) {
-	srtp_opt->keying_count = 2;
-	srtp_opt->keying[0] = PJMEDIA_SRTP_KEYING_DTLS_SRTP;
-	srtp_opt->keying[1] = PJMEDIA_SRTP_KEYING_SDES;
-    }
-}
-
-
 #ifdef TRANSPORT_ADAPTER_SAMPLE
 /*
@@ -1363,6 +1344,4 @@
     app_config.cfg.cb.on_snd_dev_operation = &on_snd_dev_operation;
     app_config.cfg.cb.on_call_media_event = &on_call_media_event;
-    app_config.cfg.cb.on_create_media_transport_srtp =
-					    &on_create_media_transport_srtp;
 #ifdef TRANSPORT_ADAPTER_SAMPLE
     app_config.cfg.cb.on_create_media_transport = &on_create_media_transport;
Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_config.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_config.c	(revision 5754)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_config.c	(revision 5755)
@@ -1055,4 +1055,15 @@
 		return -1;
 	    }
+	    /* Set SRTP keying to use DTLS over SDES */
+	    if (app_config.srtp_keying == 1) {
+		pjsua_srtp_opt *srtp_opt = &app_config.cfg.srtp_opt;
+		srtp_opt->keying_count = 2;
+		srtp_opt->keying[0] = PJMEDIA_SRTP_KEYING_DTLS_SRTP;
+		srtp_opt->keying[1] = PJMEDIA_SRTP_KEYING_SDES;
+
+		cur_acc->srtp_opt.keying_count = 2;
+		cur_acc->srtp_opt.keying[0] = PJMEDIA_SRTP_KEYING_DTLS_SRTP;
+		cur_acc->srtp_opt.keying[1] = PJMEDIA_SRTP_KEYING_SDES;
+	    }
 	    break;
 #endif
Index: /pjproject/trunk/pjsip-apps/src/swig/symbols.i
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5754)
+++ /pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5755)
@@ -48,4 +48,6 @@
 
 typedef enum pjmedia_srtp_crypto_option {PJMEDIA_SRTP_NO_ENCRYPTION = 1, PJMEDIA_SRTP_NO_AUTHENTICATION = 2} pjmedia_srtp_crypto_option;
+
+typedef enum pjmedia_srtp_keying_method {PJMEDIA_SRTP_KEYING_SDES = 0, PJMEDIA_SRTP_KEYING_DTLS_SRTP = 1, PJMEDIA_SRTP_KEYINGS_COUNT = 2} pjmedia_srtp_keying_method;
 
 typedef enum pjmedia_vid_stream_rc_method {PJMEDIA_VID_STREAM_RC_NONE = 0, PJMEDIA_VID_STREAM_RC_SIMPLE_BLOCKING = 1} pjmedia_vid_stream_rc_method;
Index: /pjproject/trunk/pjsip-apps/src/swig/symbols.lst
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5754)
+++ /pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5755)
@@ -9,5 +9,5 @@
 
 pjmedia/event.h                 pjmedia_event_type
-pjmedia/transport_srtp.h	pjmedia_srtp_use pjmedia_srtp_crypto_option
+pjmedia/transport_srtp.h	pjmedia_srtp_use pjmedia_srtp_crypto_option pjmedia_srtp_keying_method
 pjmedia/vid_stream.h		pjmedia_vid_stream_rc_method
 pjmedia-videodev/videodev.h	pjmedia_vid_dev_index pjmedia_vid_dev_std_index pjmedia_vid_dev_cap
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 5754)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 5755)
@@ -636,4 +636,50 @@
 
 } pjsua_create_media_transport_flag;
+
+
+/**
+ * Specify SRTP media transport settings.
+ */
+typedef struct pjsua_srtp_opt
+{
+    /**
+     * Specify the number of crypto suite settings. If set to zero, all
+     * available cryptos will be enabled. Note that available crypto names
+     * can be enumerated using pjmedia_srtp_enum_crypto().
+     *
+     * Default is zero.
+     */
+    unsigned			 crypto_count;
+
+    /**
+     * Specify individual crypto suite setting and its priority order.
+     *
+     * Notes for DTLS-SRTP keying:
+     *  - Currently only supports these cryptos: AES_CM_128_HMAC_SHA1_80,
+     *    AES_CM_128_HMAC_SHA1_32, AEAD_AES_256_GCM, and AEAD_AES_128_GCM.
+     *  - SRTP key is not configurable.
+     */
+    pjmedia_srtp_crypto		 crypto[PJMEDIA_SRTP_MAX_CRYPTOS];
+
+    /**
+     * Specify the number of enabled keying methods. If set to zero, all
+     * keyings will be enabled. Maximum value is PJMEDIA_SRTP_MAX_KEYINGS.
+     * Note that available keying methods can be enumerated using
+     * pjmedia_srtp_enum_keying().
+     *
+     * Default is zero (all keyings are enabled with priority order:
+     * SDES, DTLS-SRTP).
+     */
+    unsigned			 keying_count;
+
+    /**
+     * Specify enabled keying methods and its priority order. Keying method
+     * with higher priority will be given earlier chance to process the SDP,
+     * for example as currently only one keying is supported in the SDP offer,
+     * keying with first priority will be likely used in the SDP offer.
+     */
+    pjmedia_srtp_keying_method	 keying[PJMEDIA_SRTP_KEYINGS_COUNT];
+
+} pjsua_srtp_opt;
 
 
@@ -1520,10 +1566,16 @@
 
     /**
-     * This callback is called when SRTP media transport is created.
+     * Warning: deprecated and may be removed in future release. Application
+     * can set SRTP crypto settings (including keys) and keying methods
+     * via pjsua_srtp_opt in pjsua_config and pjsua_acc_config.
+     * See also ticket #2100.
+     *
+     * This callback is called before SRTP media transport is created.
      * Application can modify the SRTP setting \a srtp_opt to specify
-     * the cryptos and keys which are going to be used. Note that
-     * application should not modify the field
-     * \a pjmedia_srtp_setting.close_member_tp and can only modify
-     * the field \a pjmedia_srtp_setting.use for initial INVITE.
+     * the cryptos & keys and keying methods which are going to be used.
+     * Note that only some fields of pjmedia_srtp_setting can be overriden
+     * from this callback, i.e: "crypto_count", "crypto", "keying_count",
+     * "keying", and "use" (only for initial INVITE), any modification in
+     * other fields will be ignored.
      *
      * @param call_id       Call ID
@@ -1901,4 +1953,10 @@
      */
     pj_bool_t	     srtp_optional_dup_offer;
+
+    /**
+     * Specify SRTP transport setting. Application can initialize it with
+     * default values using pjsua_srtp_opt_default().
+     */
+    pjsua_srtp_opt   srtp_opt;
 
     /**
@@ -3224,4 +3282,5 @@
 } pjsua_nat64_opt;
 
+
 /**
  * This structure describes account configuration to be specified when
@@ -3741,4 +3800,10 @@
      */
     pj_bool_t	     srtp_optional_dup_offer;
+
+    /**
+     * Specify SRTP transport setting. Application can initialize it with
+     * default values using pjsua_srtp_opt_default().
+     */
+    pjsua_srtp_opt   srtp_opt;
 
     /**
@@ -3891,4 +3956,13 @@
                                     pjsua_turn_config *dst,
                                     const pjsua_turn_config *src);
+
+
+/**
+ * Call this function to initialize SRTP config with default values.
+ *
+ * @param cfg	    The SRTP config to be initialized.
+ */
+PJ_DECL(void) pjsua_srtp_opt_default(pjsua_srtp_opt *cfg);
+
 
 /**
Index: /pjproject/trunk/pjsip/include/pjsua2/account.hpp
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua2/account.hpp	(revision 5754)
+++ /pjproject/trunk/pjsip/include/pjsua2/account.hpp	(revision 5755)
@@ -704,4 +704,87 @@
 
 /**
+ * SRTP crypto.
+ */
+struct SrtpCrypto
+{
+    /**
+     * Optional key. If empty, a random key will be autogenerated.
+     */
+    string	key;
+
+    /**
+     * Crypto name.
+     */
+    string	name;
+
+    /**
+     * Flags, bitmask from #pjmedia_srtp_crypto_option
+     */
+    unsigned	flags;
+
+public:
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjmedia_srtp_crypto &prm);
+
+    /**
+     * Convert to pjsip
+     */
+    pjmedia_srtp_crypto toPj() const;
+};
+
+struct SrtpOpt : public PersistentObject
+{
+    /**
+     * Specify SRTP cryptos. If empty, all crypto will be enabled.
+     * Available crypto can be enumerated using Endpoint::srtpCryptoEnum().
+     *
+     * Default: empty.
+     */
+    vector<SrtpCrypto>		cryptos;
+
+    /**
+     * Specify SRTP keying methods, valid keying method is defined in
+     * pjmedia_srtp_keying_method. If empty, all keying methods will be
+     * enabled with priority order: SDES, DTLS-SRTP.
+     *
+     * Default: empty.
+     */
+    IntVector			keyings;
+
+public:
+    /**
+     * Default constructor initializes with default values.
+     */
+    SrtpOpt();
+
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjsua_srtp_opt &prm);
+
+    /**
+     * Convert to pjsip
+     */
+    pjsua_srtp_opt toPj() const;
+
+public:
+    /**
+     * Read this object from a container node.
+     *
+     * @param node		Container to read values from.
+     */
+    virtual void readObject(const ContainerNode &node) throw(Error);
+
+    /**
+     * Write this object to a container node.
+     *
+     * @param node		Container to write values to.
+     */
+    virtual void writeObject(ContainerNode &node) const throw(Error);
+};
+
+/**
  * Account media config (applicable for both audio and video). This will be
  * specified in AccountConfig.
@@ -753,4 +836,9 @@
      */
     int			srtpSecureSignaling;
+
+    /**
+     * Specify SRTP settings, like cryptos and keying methods.
+     */
+    SrtpOpt		srtpOpt;
 
     /**
Index: /pjproject/trunk/pjsip/include/pjsua2/call.hpp
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua2/call.hpp	(revision 5754)
+++ /pjproject/trunk/pjsip/include/pjsua2/call.hpp	(revision 5755)
@@ -965,25 +965,4 @@
      */
     unsigned        flags;
-};
-
-/**
- * SRTP crypto.
- */
-struct SrtpCrypto
-{
-    /**
-     * Optional key. If empty, a random key will be autogenerated.
-     */
-    string	key;
-
-    /**
-     * Crypto name.
-     */
-    string	name;
-
-    /**
-     * Flags, bitmask from #pjmedia_srtp_crypto_option
-     */
-    unsigned	flags;
 };
 
@@ -1808,4 +1787,9 @@
 
     /**
+     * Warning: deprecated and may be removed in future release.
+     * Application can set SRTP crypto settings (including keys) and
+     * keying methods via AccountConfig.mediaConfig.srtpOpt.
+     * See also ticket #2100.
+     *
      * This callback is called when SRTP media transport is created.
      * Application can modify the SRTP setting \a srtpOpt to specify
Index: /pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp	(revision 5754)
+++ /pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp	(revision 5755)
@@ -1482,4 +1482,11 @@
      */
     void resetVideoCodecParam(const string &codec_id) throw(Error);
+
+    /**
+     * Enumerate all SRTP crypto-suite names.
+     *
+     * @return		The list of SRTP crypto-suite name.
+     */
+    StringVector srtpCryptoEnum() throw(Error);
 
     /*************************************************************************
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 5754)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 5755)
@@ -115,4 +115,5 @@
     cfg->use_timer = PJSUA_SIP_TIMER_OPTIONAL;
     pjsip_timer_setting_default(&cfg->timer_setting);
+    pjsua_srtp_opt_default(&cfg->srtp_opt);
 }
 
@@ -253,4 +254,11 @@
     }
 }
+
+
+PJ_DEF(void) pjsua_srtp_opt_default(pjsua_srtp_opt *cfg)
+{
+    pj_bzero(cfg, sizeof(*cfg));
+}
+
 
 PJ_DEF(void) pjsua_acc_config_default(pjsua_acc_config *cfg)
@@ -289,4 +297,5 @@
     cfg->srtp_secure_signaling = pjsua_var.ua_cfg.srtp_secure_signaling;
     cfg->srtp_optional_dup_offer = pjsua_var.ua_cfg.srtp_optional_dup_offer;
+    cfg->srtp_opt = pjsua_var.ua_cfg.srtp_opt;
     cfg->reg_retry_interval = PJSUA_REG_RETRY_INTERVAL;
     cfg->reg_retry_random_interval = 10;
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 5754)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 5755)
@@ -1536,5 +1536,7 @@
     if (!call_med->tp_orig) {
 	pjmedia_srtp_setting srtp_opt;
+	pjsua_srtp_opt *acc_srtp_opt = &acc->cfg.srtp_opt;
 	pjmedia_transport *srtp = NULL;
+	unsigned i;
 
 	/* Check if SRTP requires secure signaling */
@@ -1552,4 +1554,12 @@
 	srtp_opt.cb.on_srtp_nego_complete = &on_srtp_nego_complete;
 	srtp_opt.user_data = call_med;
+
+	/* Get crypto and keying settings from account settings */
+	srtp_opt.crypto_count = acc_srtp_opt->crypto_count;
+	for (i = 0; i < srtp_opt.crypto_count; ++i)
+	    srtp_opt.crypto[i] = acc_srtp_opt->crypto[i];
+	srtp_opt.keying_count = acc_srtp_opt->keying_count;
+	for (i = 0; i < srtp_opt.keying_count; ++i)
+	    srtp_opt.keying[i] = acc_srtp_opt->keying[i];
 
 	/* If media session has been ever established, let's use remote's 
@@ -1560,19 +1570,29 @@
 	else
 	    srtp_opt.use = acc->cfg.use_srtp;
-	    
+
 	if (pjsua_var.ua_cfg.cb.on_create_media_transport_srtp) {
+	    pjmedia_srtp_setting srtp_opt2 = srtp_opt;
 	    pjsua_call *call = call_med->call;
-	    pjmedia_srtp_use srtp_use = srtp_opt.use;
+
+	    /* Warn that this callback is deprecated (see also #2100) */
+	    PJ_LOG(1,(THIS_FILE, "Warning: on_create_media_transport_srtp "
+				 "is deprecated and will be removed in the "
+				 "future release"));
 
 	    (*pjsua_var.ua_cfg.cb.on_create_media_transport_srtp)
-		(call->index, call_med->idx, &srtp_opt);
-
-	    /* Close_member_tp must not be overwritten by app */
-	    srtp_opt.close_member_tp = PJ_TRUE;
-
-	    /* Revert SRTP usage policy if media is reinitialized */
-	    if (call->inv && call->inv->state == PJSIP_INV_STATE_CONFIRMED) {
-		srtp_opt.use = srtp_use;
-	    }
+		(call->index, call_med->idx, &srtp_opt2);
+
+	    /* Only apply SRTP usage policy if this is initial INVITE */
+	    if (call->inv && call->inv->state < PJSIP_INV_STATE_CONFIRMED) {
+		srtp_opt.use = srtp_opt2.use;
+	    }
+
+	    /* Apply crypto and keying settings from callback */
+	    srtp_opt.crypto_count = srtp_opt2.crypto_count;
+	    for (i = 0; i < srtp_opt.crypto_count; ++i)
+		srtp_opt.crypto[i] = srtp_opt2.crypto[i];
+	    srtp_opt.keying_count = srtp_opt2.keying_count;
+	    for (i = 0; i < srtp_opt.keying_count; ++i)
+		srtp_opt.keying[i] = srtp_opt2.keying[i];
     	}
 
Index: /pjproject/trunk/pjsip/src/pjsua2/account.cpp
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua2/account.cpp	(revision 5754)
+++ /pjproject/trunk/pjsip/src/pjsua2/account.cpp	(revision 5755)
@@ -27,4 +27,107 @@
 
 #define THIS_FILE		"account.cpp"
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SrtpCrypto::fromPj(const pjmedia_srtp_crypto &prm)
+{
+    this->key	    = pj2Str(prm.key);
+    this->name	    = pj2Str(prm.name);
+    this->flags	    = prm.flags;
+}
+
+pjmedia_srtp_crypto SrtpCrypto::toPj() const
+{
+    pjmedia_srtp_crypto crypto;
+    
+    crypto.key	    = str2Pj(this->key);
+    crypto.name	    = str2Pj(this->name);
+    crypto.flags    = this->flags;
+
+    return crypto;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SrtpOpt::SrtpOpt()
+{
+    pjsua_srtp_opt opt;
+    pjsua_srtp_opt_default(&opt);
+    fromPj(opt);
+}
+
+void SrtpOpt::fromPj(const pjsua_srtp_opt &prm)
+{
+    this->cryptos.clear();
+    for (unsigned i = 0; i < prm.crypto_count; ++i) {
+	SrtpCrypto crypto;
+	crypto.fromPj(prm.crypto[i]);
+	this->cryptos.push_back(crypto);
+    }
+
+    this->keyings.clear();
+    for (unsigned i = 0; i < prm.keying_count; ++i) {
+	this->keyings.push_back(prm.keying[i]);
+    }
+}
+
+pjsua_srtp_opt SrtpOpt::toPj() const
+{
+    pjsua_srtp_opt opt;
+
+    pj_bzero(&opt, sizeof(opt));
+
+    opt.crypto_count = this->cryptos.size();
+    for (unsigned i = 0; i < opt.crypto_count; ++i) {
+	opt.crypto[i] = this->cryptos[i].toPj();
+    }
+
+    opt.keying_count = this->keyings.size();
+    for (unsigned i = 0; i < opt.keying_count; ++i) {
+	opt.keying[i] = (pjmedia_srtp_keying_method)this->keyings[i];
+    }
+
+    return opt;
+}
+
+void SrtpOpt::readObject(const ContainerNode &node) throw(Error)
+{
+    ContainerNode this_node = node.readContainer("SrtpOpt");
+
+    ContainerNode crypto_node = this_node.readArray("cryptos");
+    this->cryptos.clear();
+    while (crypto_node.hasUnread()) {
+	SrtpCrypto crypto;
+	NODE_READ_STRING	(crypto_node, crypto.key);
+	NODE_READ_STRING	(crypto_node, crypto.name);
+	NODE_READ_UNSIGNED	(crypto_node, crypto.flags);
+	this->cryptos.push_back(crypto);
+    }
+
+    ContainerNode keying_node = this_node.readArray("keyings");
+    this->keyings.clear();
+    while (keying_node.hasUnread()) {
+	unsigned keying;
+	NODE_READ_UNSIGNED	(keying_node, keying);
+	this->keyings.push_back(keying);
+    }
+}
+
+void SrtpOpt::writeObject(ContainerNode &node) const throw(Error)
+{
+    ContainerNode this_node = node.writeNewContainer("SrtpOpt");
+
+    ContainerNode crypto_node = this_node.writeNewArray("cryptos");
+    for (unsigned i=0; i<this->cryptos.size(); ++i) {
+	NODE_WRITE_STRING	(crypto_node, this->cryptos[i].key);
+	NODE_WRITE_STRING	(crypto_node, this->cryptos[i].name);
+	NODE_WRITE_UNSIGNED	(crypto_node, this->cryptos[i].flags);
+    }
+
+    ContainerNode keying_node = this_node.writeNewArray("keyings");
+    for (unsigned i=0; i<this->keyings.size(); ++i) {
+	NODE_WRITE_UNSIGNED	(keying_node, this->keyings[i]);
+    }
+}
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -253,4 +356,5 @@
     NODE_READ_NUM_T   ( this_node, pjmedia_srtp_use, srtpUse);
     NODE_READ_INT     ( this_node, srtpSecureSignaling);
+    NODE_READ_OBJ     ( this_node, srtpOpt);
     NODE_READ_NUM_T   ( this_node, pjsua_ipv6_use, ipv6Use);
     NODE_READ_OBJ     ( this_node, transportConfig);
@@ -265,4 +369,5 @@
     NODE_WRITE_NUM_T   ( this_node, pjmedia_srtp_use, srtpUse);
     NODE_WRITE_INT     ( this_node, srtpSecureSignaling);
+    NODE_WRITE_OBJ     ( this_node, srtpOpt);
     NODE_WRITE_NUM_T   ( this_node, pjsua_ipv6_use, ipv6Use);
     NODE_WRITE_OBJ     ( this_node, transportConfig);
@@ -453,4 +558,5 @@
     ret.use_srtp		= mediaConfig.srtpUse;
     ret.srtp_secure_signaling	= mediaConfig.srtpSecureSignaling;
+    ret.srtp_opt		= mediaConfig.srtpOpt.toPj();
     ret.ipv6_media_use		= mediaConfig.ipv6Use;
 
@@ -627,4 +733,5 @@
     mediaConfig.srtpUse		= prm.use_srtp;
     mediaConfig.srtpSecureSignaling = prm.srtp_secure_signaling;
+    mediaConfig.srtpOpt.fromPj(prm.srtp_opt);
     mediaConfig.ipv6Use		= prm.ipv6_media_use;
 
Index: /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 5754)
+++ /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 5755)
@@ -1092,5 +1092,5 @@
     prm.stream = param->stream;
     prm.streamIdx = param->stream_idx;
-    prm.destroyPort = param->destroy_port;
+    prm.destroyPort = (param->destroy_port != PJ_FALSE);
     prm.pPort = (MediaPort)param->port;
     
@@ -2082,4 +2082,21 @@
 }
 
+/*
+ * Enumerate all SRTP crypto-suite names.
+ */
+StringVector Endpoint::srtpCryptoEnum() throw(Error)
+{
+    unsigned cnt = PJMEDIA_SRTP_MAX_CRYPTOS;
+    pjmedia_srtp_crypto cryptos[PJMEDIA_SRTP_MAX_CRYPTOS];
+    StringVector result;
+
+    PJSUA2_CHECK_EXPR(pjmedia_srtp_enum_crypto(&cnt, cryptos));
+
+    for (unsigned i = 0; i < cnt; ++i)
+	result.push_back(pj2Str(cryptos[i].name));
+
+    return result;
+}
+
 void Endpoint::handleIpChange(const IpChangeParam &param) throw(Error)
 {
