Index: pjproject/trunk/pjmedia/include/pjmedia/session.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/session.h	(revision 862)
+++ pjproject/trunk/pjmedia/include/pjmedia/session.h	(revision 863)
@@ -322,4 +322,27 @@
 
 /**
+ * Set callback to be called upon receiving DTMF digits. If callback is
+ * registered, the stream will not buffer incoming DTMF but rather call
+ * the callback as soon as DTMF digit is received completely.
+ *
+ * @param session	The media session.
+ * @param index		The stream index.
+ * @param cb		Callback to be called upon receiving DTMF digits.
+ *			The DTMF digits will be given to the callback as
+ *			ASCII digits.
+ * @param user_data	User data to be returned back when the callback
+ *			is called.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t)
+pjmedia_session_set_dtmf_callback(pjmedia_session *session,
+				  unsigned index,
+				  void (*cb)(pjmedia_stream*, 
+				 	     void *user_data, 
+					     int digit), 
+				  void *user_data);
+
+/**
  * Destroy media session.
  *
Index: pjproject/trunk/pjmedia/include/pjmedia/stream.h
===================================================================
--- pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 862)
+++ pjproject/trunk/pjmedia/include/pjmedia/stream.h	(revision 863)
@@ -278,4 +278,25 @@
 
 /**
+ * Set callback to be called upon receiving DTMF digits. If callback is
+ * registered, the stream will not buffer incoming DTMF but rather call
+ * the callback as soon as DTMF digit is received completely.
+ *
+ * @param stream	The media stream.
+ * @param cb		Callback to be called upon receiving DTMF digits.
+ *			The DTMF digits will be given to the callback as
+ *			ASCII digits.
+ * @param user_data	User data to be returned back when the callback
+ *			is called.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t)
+pjmedia_stream_set_dtmf_callback(pjmedia_stream *stream,
+				 void (*cb)(pjmedia_stream*, 
+					    void *user_data, 
+					    int digit), 
+				 void *user_data);
+
+/**
  * @}
  */
Index: pjproject/trunk/pjmedia/src/pjmedia/session.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/session.c	(revision 862)
+++ pjproject/trunk/pjmedia/src/pjmedia/session.c	(revision 863)
@@ -734,2 +734,19 @@
 				   size);
 }
+
+/*
+ * Install DTMF callback.
+ */
+PJ_DEF(pj_status_t)
+pjmedia_session_set_dtmf_callback(pjmedia_session *session,
+				  unsigned index,
+				  void (*cb)(pjmedia_stream*, 
+				 	     void *user_data, 
+					     int digit), 
+				  void *user_data)
+{
+    PJ_ASSERT_RETURN(session && index < session->stream_cnt, PJ_EINVAL);
+    return pjmedia_stream_set_dtmf_callback(session->stream[index], cb,
+					    user_data);
+}
+
Index: pjproject/trunk/pjmedia/src/pjmedia/stream.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 862)
+++ pjproject/trunk/pjmedia/src/pjmedia/stream.c	(revision 863)
@@ -114,4 +114,8 @@
     unsigned		     rx_dtmf_count; /**< # of digits in dtmf rx buf.*/
     char		     rx_dtmf_buf[32];/**< Incoming DTMF buffer.	    */
+
+    /* DTMF callback */
+    void		    (*dtmf_cb)(pjmedia_stream*, void*, int);
+    void		     *dtmf_cb_user_data;
 };
 
@@ -380,8 +384,9 @@
 	pj_mutex_unlock(stream->jb_mutex);
 
-	if (stream->tx_dtmf_count)
+	if (stream->tx_dtmf_count) {
 	    PJ_LOG(5,(stream->port.info.name.ptr,
 		      "Sending DTMF digit id %c", 
 		      digitmap[stream->tx_dtmf_buf[0].event]));
+	}
 
     } else if (duration == 0) {
@@ -664,16 +669,27 @@
     stream->last_dtmf_dur = pj_ntohs(event->duration);
 
-    /* By convention, we use jitter buffer's mutex to access shared
-     * DTMF variables.
+    /* If DTMF callback is installed, call the callback, otherwise keep
+     * the DTMF digits in the buffer.
      */
-    pj_mutex_lock(stream->jb_mutex);
-    if (stream->rx_dtmf_count >= PJ_ARRAY_SIZE(stream->rx_dtmf_buf)) {
-	/* DTMF digits overflow.  Discard the oldest digit. */
-	pj_array_erase(stream->rx_dtmf_buf, sizeof(stream->rx_dtmf_buf[0]),
-		       stream->rx_dtmf_count, 0);
-	--stream->rx_dtmf_count;
-    }
-    stream->rx_dtmf_buf[stream->rx_dtmf_count++] = digitmap[event->event];
-    pj_mutex_unlock(stream->jb_mutex);
+    if (stream->dtmf_cb) {
+
+	stream->dtmf_cb(stream, stream->dtmf_cb_user_data, 
+			digitmap[event->event]);
+
+    } else {
+	/* By convention, we use jitter buffer's mutex to access shared
+	 * DTMF variables.
+	 */
+	pj_mutex_lock(stream->jb_mutex);
+	if (stream->rx_dtmf_count >= PJ_ARRAY_SIZE(stream->rx_dtmf_buf)) {
+	    /* DTMF digits overflow.  Discard the oldest digit. */
+	    pj_array_erase(stream->rx_dtmf_buf, 
+			   sizeof(stream->rx_dtmf_buf[0]),
+			   stream->rx_dtmf_count, 0);
+	    --stream->rx_dtmf_count;
+	}
+	stream->rx_dtmf_buf[stream->rx_dtmf_count++] = digitmap[event->event];
+	pj_mutex_unlock(stream->jb_mutex);
+    }
 }
 
@@ -1369,2 +1385,29 @@
     return PJ_SUCCESS;
 }
+
+
+/*
+ * Set callback to be called upon receiving DTMF digits.
+ */
+PJ_DEF(pj_status_t)
+pjmedia_stream_set_dtmf_callback(pjmedia_stream *stream,
+				 void (*cb)(pjmedia_stream*, 
+					    void *user_data, 
+					    int digit), 
+				 void *user_data)
+{
+    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
+
+    /* By convention, we use jitter buffer's mutex to access DTMF
+     * digits resources.
+     */
+    pj_mutex_lock(stream->jb_mutex);
+
+    stream->dtmf_cb = cb;
+    stream->dtmf_cb_user_data = user_data;
+
+    pj_mutex_unlock(stream->jb_mutex);
+
+    return PJ_SUCCESS;
+}
+
Index: pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 862)
+++ pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 863)
@@ -1623,4 +1623,11 @@
 }
 
+/*
+ * DTMF callback.
+ */
+static void call_on_dtmf_callback(pjsua_call_id call_id, int dtmf)
+{
+    PJ_LOG(3,(THIS_FILE, "Incoming DTMF on call %d: %c", call_id, dtmf));
+}
 
 /*
@@ -2819,4 +2826,5 @@
     app_config.cfg.cb.on_call_media_state = &on_call_media_state;
     app_config.cfg.cb.on_incoming_call = &on_incoming_call;
+    app_config.cfg.cb.on_dtmf_digit = &call_on_dtmf_callback;
     app_config.cfg.cb.on_reg_state = &on_reg_state;
     app_config.cfg.cb.on_buddy_state = &on_buddy_state;
Index: pjproject/trunk/pjsip/include/pjsip.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip.h	(revision 862)
+++ pjproject/trunk/pjsip/include/pjsip.h	(revision 863)
@@ -41,7 +41,5 @@
 #include <pjsip/sip_transport_loop.h>
 #include <pjsip/sip_transport_tcp.h>
-#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
-#   include <pjsip/sip_transport_tls.h>
-#endif
+#include <pjsip/sip_transport_tls.h>
 #include <pjsip/sip_resolve.h>
 
Index: pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 862)
+++ pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 863)
@@ -287,4 +287,7 @@
      * Application may then query the call info to get the
      * detail call states.
+     *
+     * @param call_id	The call index.
+     * @param e		Event which causes the call state to change.
      */
     void (*on_call_state)(pjsua_call_id call_id, pjsip_event *e);
@@ -292,4 +295,9 @@
     /**
      * Notify application on incoming call.
+     *
+     * @param acc_id	The account which match the incoming call.
+     * @param call_id	The call id that has just been created for
+     *			the call.
+     * @param rdata	The incoming INVITE request.
      */
     void (*on_incoming_call)(pjsua_acc_id acc_id, pjsua_call_id call_id,
@@ -300,6 +308,16 @@
      * Normal application would need to implement this callback, e.g.
      * to connect the call's media to sound device.
+     *
+     * @param call_id	The call index.
      */
     void (*on_call_media_state)(pjsua_call_id call_id);
+
+    /**
+     * Notify application upon incoming DTMF digits.
+     *
+     * @param call_id	The call index.
+     * @param digit	DTMF ASCII digit.
+     */
+    void (*on_dtmf_digit)(pjsua_call_id call_id, int digit);
 
     /**
@@ -309,4 +327,10 @@
      * is not defined, the default behavior is to accept the
      * transfer.
+     *
+     * @param call_id	The call index.
+     * @param dst	The destination where the call will be 
+     *			transfered to.
+     * @param code	Status code to be returned for the call transfer
+     *			request. On input, it contains status code 200.
      */
     void (*on_call_transfer_request)(pjsua_call_id call_id,
@@ -373,4 +397,6 @@
      * Application may then query the account info to get the
      * registration details.
+     *
+     * @param acc_id	    Account ID.
      */
     void (*on_reg_state)(pjsua_acc_id acc_id);
@@ -379,4 +405,6 @@
      * Notify application when the buddy state has changed.
      * Application may then query the buddy into to get the details.
+     *
+     * @param buddy_id	    The buddy id.
      */
     void (*on_buddy_state)(pjsua_buddy_id buddy_id);
@@ -386,4 +414,13 @@
      * Argument call_id will be -1 if MESSAGE request is not related to an
      * existing call.
+     *
+     * @param call_id	    Containts the ID of the call where the IM was
+     *			    sent, or PJSUA_INVALID_ID if the IM was sent
+     *			    outside call context.
+     * @param from	    URI of the sender.
+     * @param to	    URI of the destination message.
+     * @param contact	    The Contact URI of the sender, if present.
+     * @param mime_type	    MIME type of the message.
+     * @param body	    The message content.
      */
     void (*on_pager)(pjsua_call_id call_id, const pj_str_t *from,
@@ -414,4 +451,13 @@
     /**
      * Notify application about typing indication.
+     *
+     * @param call_id	    Containts the ID of the call where the IM was
+     *			    sent, or PJSUA_INVALID_ID if the IM was sent
+     *			    outside call context.
+     * @param from	    URI of the sender.
+     * @param to	    URI of the destination message.
+     * @param contact	    The Contact URI of the sender, if present.
+     * @param is_typing	    Non-zero if peer is typing, or zero if peer
+     *			    has stopped typing a message.
      */
     void (*on_typing)(pjsua_call_id call_id, const pj_str_t *from,
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 862)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_call.c	(revision 863)
@@ -2051,4 +2051,20 @@
 
 /*
+ * DTMF callback from the stream.
+ */
+static void dtmf_callback(pjmedia_stream *strm, void *user_data,
+			  int digit)
+{
+    PJ_UNUSED_ARG(strm);
+
+    if (pjsua_var.ua_cfg.cb.on_dtmf_digit) {
+	pjsua_call_id call_id;
+
+	call_id = (pjsua_call_id)user_data;
+	pjsua_var.ua_cfg.cb.on_dtmf_digit(call_id, digit);
+    }
+}
+
+/*
  * Callback to be called when SDP offer/answer negotiation has just completed
  * in the session. This function will start/update media if negotiation
@@ -2189,4 +2205,12 @@
 	}
 
+	/* If DTMF callback is installed by application, install our
+	 * callback to the session.
+	 */
+	if (pjsua_var.ua_cfg.cb.on_dtmf_digit) {
+	    pjmedia_session_set_dtmf_callback(call->session, 0, 
+					      &dtmf_callback, 
+					      (void*)(call->index));
+	}
 
 	/* Get the port interface of the first stream in the session.
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 862)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_media.c	(revision 863)
@@ -443,5 +443,5 @@
 
     /* Close media transports */
-    for (i=0; i<(int)pjsua_var.ua_cfg.max_calls; ++i) {
+    for (i=0; i<pjsua_var.ua_cfg.max_calls; ++i) {
 	if (pjsua_var.calls[i].med_tp) {
 	    (*pjsua_var.calls[i].med_tp->op->destroy)(pjsua_var.calls[i].med_tp);
