Index: /pjproject/trunk/pjmedia/include/pjmedia/transport_srtp.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/transport_srtp.h	(revision 5620)
+++ /pjproject/trunk/pjmedia/include/pjmedia/transport_srtp.h	(revision 5621)
@@ -269,4 +269,37 @@
 
 /**
+ * This structure specifies DTLS-SRTP negotiation parameters.
+ */
+typedef struct pjmedia_srtp_dtls_nego_param
+{
+    /**
+     * Fingerprint of remote certificate, should be formatted as
+     * "SHA-256/1 XX:XX:XX...". If this is not set, fingerprint verification
+     * will not be performed.
+     */
+    pj_str_t		 rem_fingerprint;
+
+    /**
+     * Remote address and port.
+     */
+    pj_sockaddr		 rem_addr;
+
+    /**
+     * Remote RTCP address and port.
+     */
+    pj_sockaddr		 rem_rtcp;
+
+    /**
+     * Set to PJ_TRUE if our role is active. Active role will initiates
+     * the DTLS negotiation. Passive role will wait for incoming DTLS
+     * negotiation packet.
+     */
+    pj_bool_t		 is_role_active;
+
+} pjmedia_srtp_dtls_nego_param;
+
+
+
+/**
  * Initialize SRTP library. This function should be called before
  * any SRTP functions, however calling #pjmedia_transport_srtp_create() 
@@ -308,4 +341,48 @@
 				       const pjmedia_srtp_setting *opt,
 				       pjmedia_transport **p_tp);
+
+/**
+ * Get fingerprint of local DTLS-SRTP certificate.
+ *
+ * @param srtp	    The SRTP transport.
+ * @param hash	    Fingerprint hash algorithm, currently valid values are
+ *		    "SHA-256" and "SHA-1".
+ * @param buf	    Buffer for fingerprint output. The output will be
+ *		    formatted as "SHA-256/1 XX:XX:XX..." and null terminated.
+ * @param len	    On input, the size of the buffer.
+ *		    On output, the length of the fingerprint.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_srtp_dtls_get_fingerprint(
+				pjmedia_transport *srtp,
+				const char *hash,
+				char *buf, pj_size_t *len);
+
+
+/**
+ * Manually start DTLS-SRTP negotiation 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 DTLS-SRTP
+ * negotiation will be handled by pjmedia_transport_media_create(),
+ * pjmedia_transport_media_start(), pjmedia_transport_media_encode_sdp(), and
+ * pjmedia_transport_media_stop().
+ *
+ * When the negotiation completes, application will be notified via SRTP
+ * callback on_srtp_nego_complete(), if set. If the negotiation is successful,
+ * SRTP will be automatically started.
+ *
+ * Note that if the SRTP member transport is an ICE transport, application
+ * should only call this function after ICE negotiation is completed
+ * successfully.
+ *
+ * @param srtp	    The SRTP transport.
+ * @param param	    DTLS-SRTP nego parameter.
+ *
+ * @return	    PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_transport_srtp_dtls_start_nego(
+				pjmedia_transport *srtp,
+				const pjmedia_srtp_dtls_nego_param *param);
 
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5620)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp.c	(revision 5621)
@@ -403,4 +403,24 @@
 #if defined(PJMEDIA_SRTP_HAS_DTLS) && (PJMEDIA_SRTP_HAS_DTLS != 0)
 #  include "transport_srtp_dtls.c"
+#else
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_dtls_start_nego(
+				pjmedia_transport *srtp,
+				const pjmedia_srtp_dtls_nego_param *param)
+{
+    PJ_UNUSED_ARG(srtp);
+    PJ_UNUSED_ARG(param);
+    return PJ_ENOTSUP;
+}
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_dtls_get_fingerprint(
+				pjmedia_transport *srtp,
+				const char *hash,
+				char *buf, pj_size_t *len)
+{
+    PJ_UNUSED_ARG(srtp);
+    PJ_UNUSED_ARG(hash);
+    PJ_UNUSED_ARG(buf);
+    PJ_UNUSED_ARG(len);
+    return PJ_ENOTSUP;
+}
 #endif
 
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_dtls.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_dtls.c	(revision 5620)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_dtls.c	(revision 5621)
@@ -188,5 +188,5 @@
 
     *p_keying = &ds->base;
-    PJ_LOG(5,(THIS_FILE, "SRTP keying DTLS-SRTP created"));
+    PJ_LOG(5,(srtp->pool->obj_name, "SRTP keying DTLS-SRTP created"));
     return PJ_SUCCESS;
 }
@@ -549,6 +549,6 @@
 	is_sha256 = PJ_FALSE;
     else {
-	PJ_LOG(4,(ds->base.name, "Remote hash algo in SDP for "
-		  "DTLS-SRTP is not supported"));
+	PJ_LOG(4,(ds->base.name, "Hash algo specified in remote SDP for "
+		  "its DTLS certificate fingerprint is not supported"));
 	return PJ_ENOTSUP;
     }
@@ -641,6 +641,8 @@
 	ds->srtp->keying_pending_cnt--;
 
+	/* Copy negotiated policy to SRTP */
 	ds->srtp->tx_policy_neg = ds->tx_crypto;
 	ds->srtp->rx_policy_neg = ds->rx_crypto;
+
 	status = start_srtp(ds->srtp);
 	if (status != PJ_SUCCESS)
@@ -716,5 +718,5 @@
     /* Finally, DTLS nego started! */
     ds->nego_started = PJ_TRUE;
-    PJ_LOG(2,(ds->base.name, "DTLS-SRTP negotiation initiated as %s",
+    PJ_LOG(4,(ds->base.name, "DTLS-SRTP negotiation initiated as %s",
 	      (ds->setup==DTLS_SETUP_ACTIVE? "client":"server")));
 
@@ -1248,12 +1250,14 @@
 	ds->srtp->rx_policy_neg = ds->rx_crypto;
 
-	/* Verify remote fingerprint if not yet */
+	/* Verify remote fingerprint (if available) */
 	if (ds->rem_fingerprint.slen && ds->rem_fprint_status == PJ_EPENDING)
+	{
 	    ds->rem_fprint_status = ssl_match_fingerprint(ds);
-	if (ds->rem_fprint_status != PJ_SUCCESS) {
-	    pj_perror(4, ds->base.name, ds->rem_fprint_status,
-		      "Fingerprint specified in remote SDP doesn't match "
-		      "to actual remote certificate fingerprint!");
-	    return ds->rem_fprint_status;
+	    if (ds->rem_fprint_status != PJ_SUCCESS) {
+		pj_perror(4, ds->base.name, ds->rem_fprint_status,
+			  "Fingerprint specified in remote SDP doesn't match "
+			  "to actual remote certificate fingerprint!");
+		return ds->rem_fprint_status;
+	    }
 	}
 
@@ -1345,2 +1349,91 @@
     return PJ_SUCCESS;
 }
+
+
+/* Get fingerprint of local DTLS-SRTP certificate. */
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_dtls_get_fingerprint(
+				pjmedia_transport *tp,
+				const char *hash,
+				char *buf, pj_size_t *len)
+{
+    PJ_ASSERT_RETURN(dtls_cert, PJ_EINVALIDOP);
+    PJ_ASSERT_RETURN(tp && hash && buf && len, PJ_EINVAL);
+    PJ_ASSERT_RETURN(pj_ansi_strcmp(hash, "SHA-256")==0 ||
+		     pj_ansi_strcmp(hash, "SHA-1")==0, PJ_EINVAL);
+    PJ_UNUSED_ARG(tp);
+
+    return ssl_get_fingerprint(dtls_cert,
+			       pj_ansi_strcmp(hash, "SHA-256")==0,
+			       buf, len);
+}
+
+
+/* Manually start DTLS-SRTP negotiation (without SDP offer/answer) */
+PJ_DEF(pj_status_t) pjmedia_transport_srtp_dtls_start_nego(
+				pjmedia_transport *tp,
+				const pjmedia_srtp_dtls_nego_param *param)
+{
+    transport_srtp *srtp = (transport_srtp*)tp;
+    dtls_srtp *ds = NULL;
+    unsigned j;
+    pjmedia_transport_attach_param ap;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(tp && param, PJ_EINVAL);
+    PJ_ASSERT_RETURN(pj_sockaddr_has_addr(&param->rem_addr), PJ_EINVAL);
+
+    /* Find DTLS keying and destroy any other keying. */
+    for (j = 0; j < srtp->keying_cnt; ++j) {
+	if (srtp->keying[j]->op == &dtls_op)
+	    ds = (dtls_srtp*)srtp->keying[j];
+	else
+	    pjmedia_transport_close(srtp->keying[j]);
+    }
+
+    /* DTLS-SRTP is not enabled */
+    if (!ds)
+	return PJ_ENOTSUP;
+
+    /* Set SRTP keying to DTLS-SRTP only */
+    srtp->keying_cnt = 1;
+    srtp->keying[0] = &ds->base;
+    srtp->keying_pending_cnt = 1;
+
+    /* Apply param to DTLS-SRTP internal states */
+    pj_strdup(ds->pool, &ds->rem_fingerprint, &param->rem_fingerprint);
+    ds->rem_fprint_status = PJ_EPENDING;
+    ds->rem_addr = param->rem_addr;
+    ds->rem_rtcp = param->rem_rtcp;
+    ds->setup = param->is_role_active? DTLS_SETUP_ACTIVE:DTLS_SETUP_PASSIVE;
+
+    /* Pending start SRTP */
+    ds->pending_start = PJ_TRUE;
+    srtp->keying_pending_cnt++;
+
+    /* Create SSL */
+    status = ssl_create(ds);
+    if (status != PJ_SUCCESS)
+	goto on_return;
+
+    /* Attach member transport, so we can send/receive DTLS init packets */
+    pj_bzero(&ap, sizeof(ap));
+    pj_sockaddr_cp(&ap.rem_addr, &ds->rem_addr);
+    pj_sockaddr_cp(&ap.rem_rtcp, &ds->rem_rtcp);
+    ap.addr_len = pj_sockaddr_get_len(&ap.rem_addr);
+    status = pjmedia_transport_attach2(&ds->srtp->base, &ap);
+    if (status != PJ_SUCCESS)
+	goto on_return;
+
+    /* Start DTLS handshake */
+    pj_bzero(&srtp->rx_policy_neg, sizeof(srtp->rx_policy_neg));
+    pj_bzero(&srtp->tx_policy_neg, sizeof(srtp->tx_policy_neg));
+    status = ssl_handshake(ds);
+    if (status != PJ_SUCCESS)
+	goto on_return;
+
+on_return:
+    if (status != PJ_SUCCESS) {
+	ssl_destroy(ds);
+    }
+    return status;
+}
Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_sdes.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_sdes.c	(revision 5620)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_srtp_sdes.c	(revision 5621)
@@ -77,5 +77,6 @@
 
     sdes = PJ_POOL_ZALLOC_T(srtp->pool, pjmedia_transport);
-    pj_ansi_strncpy(sdes->name, "SDES", PJ_MAX_OBJ_NAME);
+    pj_ansi_strncpy(sdes->name, srtp->pool->obj_name, PJ_MAX_OBJ_NAME);
+    pj_memcpy(sdes->name, "sdes", 4);
     sdes->type = PJMEDIA_TRANSPORT_TYPE_SRTP;
     sdes->op = &sdes_op;
@@ -83,5 +84,5 @@
 
     *p_keying = sdes;
-    PJ_LOG(5,(THIS_FILE, "SRTP keying SDES created"));
+    PJ_LOG(5,(srtp->pool->obj_name, "SRTP keying SDES created"));
     return PJ_SUCCESS;
 }
Index: /pjproject/trunk/pjsip-apps/src/samples/streamutil.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/samples/streamutil.c	(revision 5620)
+++ /pjproject/trunk/pjsip-apps/src/samples/streamutil.c	(revision 5621)
@@ -88,7 +88,9 @@
  "                             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"
+ "                        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"
+ "  --srtp-dtls-client    Use DTLS for SRTP keying, as DTLS client      \n"
+ "  --srtp-dtls-server    Use DTLS for SRTP keying, as DTLS server      \n"
 #endif
 
@@ -147,4 +149,6 @@
 				  const pj_str_t *srtp_tx_key,
 				  const pj_str_t *srtp_rx_key,
+				  pj_bool_t is_dtls_client,
+				  pj_bool_t is_dtls_server,
 #endif
 				  pjmedia_stream **p_stream )
@@ -287,6 +291,4 @@
     /* 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);
@@ -294,15 +296,35 @@
 	    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;
+	if (is_dtls_client || is_dtls_server) {
+	    char fp[128];
+	    pj_size_t fp_len = sizeof(fp);
+	    pjmedia_srtp_dtls_nego_param dtls_param;
+	    
+	    pjmedia_transport_srtp_dtls_get_fingerprint(srtp_tp, "SHA-256", fp, &fp_len);
+	    PJ_LOG(3, (THIS_FILE, "Local cert fingerprint: %s", fp));
+
+	    pj_bzero(&dtls_param, sizeof(dtls_param));
+	    pj_sockaddr_cp(&dtls_param.rem_addr, rem_addr);
+	    pj_sockaddr_cp(&dtls_param.rem_rtcp, rem_addr);
+	    dtls_param.is_role_active = is_dtls_client;
+
+	    status = pjmedia_transport_srtp_dtls_start_nego(srtp_tp, &dtls_param);
+	    if (status != PJ_SUCCESS)
+		return status;
+	} else {
+	    pjmedia_srtp_crypto tx_plc, rx_plc;
+
+	    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;
@@ -362,4 +384,6 @@
     pj_str_t  srtp_rx_key = {NULL, 0};
     pj_str_t  srtp_crypto_suite = {NULL, 0};
+    pj_bool_t is_dtls_client = PJ_FALSE;
+    pj_bool_t is_dtls_server = PJ_FALSE;
     int	tmp_key_len;
 #endif
@@ -392,4 +416,6 @@
 	OPT_SRTP_TX_KEY	= 'x',
 	OPT_SRTP_RX_KEY	= 'y',
+	OPT_SRTP_DTLS_CLIENT = 'd',
+	OPT_SRTP_DTLS_SERVER = 'D',
 	OPT_HELP	= 'h',
     };
@@ -409,4 +435,6 @@
 	{ "srtp-tx-key",    1, 0, OPT_SRTP_TX_KEY },
 	{ "srtp-rx-key",    1, 0, OPT_SRTP_RX_KEY },
+	{ "srtp-dtls-client", 0, 0, OPT_SRTP_DTLS_CLIENT },
+	{ "srtp-dtls-server", 0, 0, OPT_SRTP_DTLS_SERVER },
 #endif
 	{ "help",	    0, 0, OPT_HELP },
@@ -510,4 +538,18 @@
 	    pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
 	    break;
+	case OPT_SRTP_DTLS_CLIENT:
+	    is_dtls_client = PJ_TRUE;
+	    if (is_dtls_server) {
+		printf("Error: Cannot be as both DTLS server & client\n");
+		return 1;
+	    }
+	    break;
+	case OPT_SRTP_DTLS_SERVER:
+	    is_dtls_server = PJ_TRUE;
+	    if (is_dtls_client) {
+		printf("Error: Cannot be as both DTLS server & client\n");
+		return 1;
+	    }
+	    break;
 #endif
 
@@ -525,5 +567,5 @@
 
     /* Verify arguments. */
-    if (dir & PJMEDIA_DIR_ENCODING) {
+    if (dir & PJMEDIA_DIR_ENCODING || is_dtls_client || is_dtls_server) {
 	if (remote_addr.sin_addr.s_addr == 0) {
 	    printf("Error: remote address must be set\n");
@@ -540,5 +582,6 @@
     /* SRTP validation */
     if (use_srtp) {
-	if (!srtp_tx_key.slen || !srtp_rx_key.slen)
+	if (!is_dtls_client && !is_dtls_server && 
+	    (!srtp_tx_key.slen || !srtp_rx_key.slen))
 	{
 	    printf("Error: Key for each SRTP stream direction must be set\n");
@@ -596,4 +639,5 @@
 			   use_srtp, &srtp_crypto_suite, 
 			   &srtp_tx_key, &srtp_rx_key,
+			   is_dtls_client, is_dtls_server,
 #endif
 			   &stream);
