Index: /pjproject/trunk/pjmedia/include/pjmedia/echo.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/echo.h	(revision 6139)
+++ /pjproject/trunk/pjmedia/include/pjmedia/echo.h	(revision 6140)
@@ -154,4 +154,86 @@
 
 
+/** Statistic not specified. */
+#define PJMEDIA_ECHO_STAT_NOT_SPECIFIED		999999
+
+/**
+ * Echo cancellation statistics.
+ */
+typedef struct pjmedia_echo_stat
+{
+    /**
+     * The name of the EC backend.
+     * NULL if not specified.
+     */    
+    const char *name;
+
+    /**
+     * Echo delay median value (in ms).
+     * PJMEDIA_ECHO_STAT_NOT_SPECIFIED if unavailable.
+     */
+    int 	median;
+
+    /**
+     * Echo delay standard deviation (in ms).
+     * PJMEDIA_ECHO_STAT_NOT_SPECIFIED if unavailable.
+     */
+    int 	std;
+
+    /**
+     * Fraction of poor delay. Value between 0 to 1. The closer to 1,
+     * the poorer the EC quality.
+     * PJMEDIA_ECHO_STAT_NOT_SPECIFIED if unavailable.
+     */
+    float 	frac_delay;
+
+    /**
+     * Learning still in progress? PJ_TRUE if yes, false if done.
+     * PJMEDIA_ECHO_STAT_NOT_SPECIFIED if unavailable.
+     */
+    unsigned 	learning;
+
+    /**
+     * Learning duration (in ms).
+     * PJMEDIA_ECHO_STAT_NOT_SPECIFIED if unavailable.
+     */
+    unsigned 	duration;
+
+    /**
+     * Detected echo tail length (in ms).
+     * PJMEDIA_ECHO_STAT_NOT_SPECIFIED if unavailable.
+     */
+    unsigned 	tail;
+
+    /**
+     * Minimum scaling factor (in ms).
+     * PJMEDIA_ECHO_STAT_NOT_SPECIFIED if unavailable.
+     */
+    int 	min_factor;
+
+    /**
+     * Average scaling factor (in ms).
+     * PJMEDIA_ECHO_STAT_NOT_SPECIFIED if unavailable.
+     */
+    int 	avg_factor;
+
+    /**
+     * Text describing the statistic.
+     */
+    pj_str_t	stat_info;
+
+    /**
+     * Internal buffer.
+     */
+    char 	buf_[128];
+
+} pjmedia_echo_stat;
+
+
+/**
+ * Initialize Echo cancellation stat.
+ *
+ * @param stat		    The statistic to be initialized.
+ */
+PJ_DECL(void) pjmedia_echo_stat_default(pjmedia_echo_stat *stat);
 
 
@@ -233,4 +315,16 @@
 
 /**
+ * Get the echo canceller statistics.
+ *
+ * @param echo		The Echo Canceller.
+ * @param p_stat	Pointer to receive the stat.
+ *
+ * @return		PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_echo_get_stat(pjmedia_echo_state *echo,
+					   pjmedia_echo_stat *p_stat);
+
+
+/**
  * Let the Echo Canceller know that a frame has been played to the speaker.
  * The Echo Canceller will keep the frame in its internal buffer, to be used
Index: /pjproject/trunk/pjmedia/include/pjmedia/sound_port.h
===================================================================
--- /pjproject/trunk/pjmedia/include/pjmedia/sound_port.h	(revision 6139)
+++ /pjproject/trunk/pjmedia/include/pjmedia/sound_port.h	(revision 6140)
@@ -28,4 +28,5 @@
 #include <pjmedia/clock.h>
 #include <pjmedia/port.h>
+#include <pjmedia/echo.h>
 
 PJ_BEGIN_DECL
@@ -318,4 +319,17 @@
 
 /**
+ * Get echo canceller statistics.
+ *
+ * @param snd_port	    The sound device port.
+ * @param p_stat	    Pointer to receive the stat.
+ *
+ * @return		    PJ_SUCCESS on success, or the appropriate error
+ *			    code.
+ */
+PJ_DECL(pj_status_t) pjmedia_snd_port_get_ec_stat(pjmedia_snd_port *snd_port,
+						  pjmedia_echo_stat *p_stat);
+
+
+/**
  * Get a clock source from the sound port.
  *
Index: /pjproject/trunk/pjmedia/src/pjmedia/echo_common.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/echo_common.c	(revision 6139)
+++ /pjproject/trunk/pjmedia/src/pjmedia/echo_common.c	(revision 6140)
@@ -80,4 +80,6 @@
 			     pj_int16_t *rec_frm,
 			     unsigned options );
+    pj_status_t	(*ec_get_stat)(void *state,
+    			     pjmedia_echo_stat *stat);
 };
 
@@ -89,5 +91,8 @@
     &echo_supp_destroy,
     &echo_supp_reset,
-    &echo_supp_cancel_echo
+    &echo_supp_cancel_echo,
+    NULL,
+    NULL,
+    &echo_supp_get_stat
 };
 
@@ -135,7 +140,22 @@
     &webrtc_aec_destroy,
     &webrtc_aec_reset,
-    &webrtc_aec_cancel_echo
-};
-#endif
+    &webrtc_aec_cancel_echo,
+    NULL,
+    NULL,
+    &webrtc_aec_get_stat
+};
+#endif
+
+PJ_DEF(void) pjmedia_echo_stat_default(pjmedia_echo_stat *stat)
+{
+    pj_bzero(stat, sizeof(pjmedia_echo_stat));
+    stat->median = PJMEDIA_ECHO_STAT_NOT_SPECIFIED;
+    stat->std = PJMEDIA_ECHO_STAT_NOT_SPECIFIED;
+    stat->frac_delay = (float)PJMEDIA_ECHO_STAT_NOT_SPECIFIED;
+    stat->duration = PJMEDIA_ECHO_STAT_NOT_SPECIFIED;
+    stat->tail = PJMEDIA_ECHO_STAT_NOT_SPECIFIED;
+    stat->min_factor = PJMEDIA_ECHO_STAT_NOT_SPECIFIED;
+    stat->avg_factor = PJMEDIA_ECHO_STAT_NOT_SPECIFIED;
+}
 
 /*
@@ -425,2 +445,17 @@
 }
 
+
+/*
+ * Get the Echo Canceller stats. 
+ */
+PJ_DEF(pj_status_t) pjmedia_echo_get_stat(pjmedia_echo_state *echo,
+					  pjmedia_echo_stat *p_stat)
+{
+    PJ_ASSERT_RETURN(p_stat, PJ_EINVAL);
+
+    if (echo->op->ec_get_stat)
+    	return (*echo->op->ec_get_stat)(echo->state, p_stat);
+
+    return PJ_ENOTSUP;
+}
+
Index: /pjproject/trunk/pjmedia/src/pjmedia/echo_internal.h
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/echo_internal.h	(revision 6139)
+++ /pjproject/trunk/pjmedia/src/pjmedia/echo_internal.h	(revision 6140)
@@ -22,4 +22,5 @@
 
 #include <pjmedia/types.h>
+#include <pjmedia/echo.h>
 
 PJ_BEGIN_DECL
@@ -36,4 +37,6 @@
 				      void **p_state );
 PJ_DECL(pj_status_t) echo_supp_destroy(void *state);
+PJ_DECL(pj_status_t) echo_supp_get_stat(void *state,
+					pjmedia_echo_stat *p_stat);
 PJ_DECL(void) echo_supp_reset(void *state);
 PJ_DECL(pj_status_t) echo_supp_cancel_echo(void *state,
@@ -86,4 +89,6 @@
                                        void **p_echo );
 PJ_DECL(pj_status_t) webrtc_aec_destroy(void *state );
+PJ_DECL(pj_status_t) webrtc_aec_get_stat(void *state,
+					 pjmedia_echo_stat *p_stat);
 PJ_DECL(void) webrtc_aec_reset(void *state );
 PJ_DECL(pj_status_t) webrtc_aec_cancel_echo(void *state,
Index: /pjproject/trunk/pjmedia/src/pjmedia/echo_suppress.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/echo_suppress.c	(revision 6139)
+++ /pjproject/trunk/pjmedia/src/pjmedia/echo_suppress.c	(revision 6140)
@@ -805,2 +805,30 @@
 }
 
+
+PJ_DEF(pj_status_t) echo_supp_get_stat( void *state,
+					pjmedia_echo_stat *p_stat)
+{
+    echo_supp *ec = (echo_supp*) state;
+
+    pjmedia_echo_stat_default(p_stat);
+    p_stat->name = "Echo suppressor";
+    p_stat->learning = ec->learning;
+    p_stat->duration = ec->update_cnt * SEGMENT_PTIME;
+    p_stat->tail = (ec->tail_cnt-ec->tail_index) * SEGMENT_PTIME;
+    p_stat->min_factor = (int)(ec->min_factor[ec->tail_index] * 1000);
+    p_stat->avg_factor = (int)(ec->avg_factor[ec->tail_index] * 1000);
+
+    p_stat->stat_info.ptr = p_stat->buf_;
+    p_stat->stat_info.slen =
+    	pj_ansi_snprintf(p_stat->buf_, sizeof(p_stat->buf_),
+	        "Echo suppressor learning %s at t=%03d.%03ds, tail=%d ms,\n"
+	        "          factor min/avg=%d.%03d/%d.%03d",
+	        (ec->learning? "in progress": "done"),
+	        (p_stat->duration/1000), (p_stat->duration%1000),
+	        p_stat->tail,
+	        p_stat->min_factor/1000, p_stat->min_factor%1000,
+	        p_stat->avg_factor/1000, p_stat->avg_factor%1000);
+
+    return PJ_SUCCESS;
+}
+
Index: /pjproject/trunk/pjmedia/src/pjmedia/echo_webrtc.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/echo_webrtc.c	(revision 6139)
+++ /pjproject/trunk/pjmedia/src/pjmedia/echo_webrtc.c	(revision 6140)
@@ -23,4 +23,5 @@
 #include <pj/log.h>
 #include <pj/pool.h>
+#include <pj/string.h>
 
 #if defined(PJMEDIA_HAS_WEBRTC_AEC) && PJMEDIA_HAS_WEBRTC_AEC != 0
@@ -50,5 +51,4 @@
     #define WebRtcAec_BufferFarend WebRtcAecm_BufferFarend
     #define AecConfig AecmConfig
-    #define SHOW_DELAY_METRICS	0
     typedef short sample;
 #else
@@ -57,14 +57,10 @@
     typedef float sample;
 
-    /* If SHOW_DELAY_METRICS is set to non-zero, delay metrics stats will
-     * be printed every SHOW_DELAY_METRICS-th call to webrtc_aec_cancel_echo().
-     * For example, if ptime is 20ms, set this to 250 to print the metrics
-     * every 250*20/1000=5 seconds.
-     */
-    #define SHOW_DELAY_METRICS	0
-    
 #endif
 
 #define BUF_LEN			160
+
+/* Set this to 0 to disable metrics calculation. */
+#define SHOW_DELAY_METRICS	1
 
 typedef struct webrtc_ec
@@ -80,7 +76,4 @@
     sample      tmp_buf[BUF_LEN];
     sample      tmp_buf2[BUF_LEN];
-#if SHOW_DELAY_METRICS
-    unsigned	counter;
-#endif
 } webrtc_ec;
 
@@ -356,22 +349,30 @@
     }
 
-#if SHOW_DELAY_METRICS
-    if (++echo->counter >= SHOW_DELAY_METRICS) {
-    	int median, std;
-    	float frac_delay;
-
-        if (WebRtcAec_GetDelayMetrics(echo->AEC_inst, &median, &std,
-        			      &frac_delay) == 0)
-        {
-            PJ_LOG(3, (THIS_FILE, "WebRTC delay metrics: median=%d, std=%d, "
-            			  "fraction of poor delays=%f",
-            			  median, std, frac_delay));
-        }
-        echo->counter = 0;
-    }
-#endif
-
     return PJ_SUCCESS;
 }
 
-#endif
+
+PJ_DEF(pj_status_t) webrtc_aec_get_stat(void *state,
+					pjmedia_echo_stat *p_stat)
+{
+    webrtc_ec *echo = (webrtc_ec*) state;
+
+    if (WebRtcAec_GetDelayMetrics(echo->AEC_inst, &p_stat->median,
+    				  &p_stat->std, &p_stat->frac_delay) != 0)
+    {
+        return PJ_EUNKNOWN;
+    }
+
+    p_stat->name = "WebRTC AEC";
+    p_stat->stat_info.ptr = p_stat->buf_;
+    p_stat->stat_info.slen =
+        pj_ansi_snprintf(p_stat->buf_, sizeof(p_stat->buf_),
+		     	 "WebRTC delay metric: median=%d, std=%d, "
+            	     	 "frac of poor delay=%.02f",
+            	     	 p_stat->median, p_stat->std, p_stat->frac_delay);
+
+    return PJ_SUCCESS;
+}
+
+
+#endif
Index: /pjproject/trunk/pjmedia/src/pjmedia/sound_port.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/sound_port.c	(revision 6139)
+++ /pjproject/trunk/pjmedia/src/pjmedia/sound_port.c	(revision 6140)
@@ -715,4 +715,20 @@
 
 /*
+ * Get echo canceller statistics.
+ */
+PJ_DEF(pj_status_t) pjmedia_snd_port_get_ec_stat( pjmedia_snd_port *snd_port,
+						  pjmedia_echo_stat *p_stat)
+{
+    PJ_ASSERT_RETURN(snd_port && p_stat, PJ_EINVAL);
+
+    if (snd_port->ec_state) {
+    	return pjmedia_echo_get_stat(snd_port->ec_state, p_stat);
+    } else {
+    	return PJ_ENOTFOUND;
+    }
+}
+
+						  
+/*
  * Get clock source.
  */
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 6139)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 6140)
@@ -7453,4 +7453,15 @@
 
 /**
+ * Get echo canceller statistics.
+ *
+ * @param p_stat	    Pointer to receive the stat.
+ *
+ * @return		    PJ_SUCCESS on success, or the appropriate error
+ *			    code.
+ */
+PJ_DECL(pj_status_t) pjsua_get_ec_stat(pjmedia_echo_stat *p_stat);
+
+
+/**
  * Check whether the sound device is currently active. The sound device
  * may be inactive if the application has set the auto close feature to
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c	(revision 6139)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_aud.c	(revision 6140)
@@ -2278,4 +2278,17 @@
 
 /*
+ * Get echo canceller statistics.
+ */
+PJ_DEF(pj_status_t) pjsua_get_ec_stat(pjmedia_echo_stat *p_stat)
+{
+    if (pjsua_var.snd_port) {
+    	return pjmedia_snd_port_get_ec_stat(pjsua_var.snd_port, p_stat);
+    } else {
+    	return PJ_ENOTFOUND;
+    }
+}
+
+
+/*
  * Check whether the sound device is currently active.
  */
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_dump.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_dump.c	(revision 6139)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_dump.c	(revision 6140)
@@ -370,4 +370,24 @@
 	p += len;
 
+	if (call_med->type == PJMEDIA_TYPE_AUDIO) {
+	    if (pjsua_snd_is_active()) {
+	    	pjmedia_echo_stat stat;
+	    	pj_status_t status;
+	    	
+	    	status = pjsua_get_ec_stat(&stat);
+	    	if (status == PJ_SUCCESS) {
+		    len = pj_ansi_snprintf(p, end-p, "   %s  EC stat: %.*s\n",
+		    			   indent,
+		    			   (int)stat.stat_info.slen,
+		    			   stat.stat_info.ptr);
+		    if (len < 1 || len >= end-p) {
+	    	    	*p = '\0';
+	    	    	return;
+		    }
+		    p += len;
+	    	}
+	    }
+	}
+
 	/* Get and ICE SRTP status */
 	if (call_med->tp) {
